xref: /titanic_44/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision b5a2d8455dfa3190fc977c4bec53e91c99012767)
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(const entity_t *ient, const scf_snaplevel_t *running,
3307     void *ent)
3308 {
3309 	scf_propertygroup_t *ud_run_mfsts_pg = NULL;
3310 	scf_property_t *ud_run_prop = NULL;
3311 	scf_iter_t *ud_prop_iter;
3312 	scf_value_t *fname_value;
3313 	pgroup_t *mfst_pgroup;
3314 	property_t *mfst_prop;
3315 	property_t *old_prop;
3316 	char *pname = malloc(MAXPATHLEN);
3317 	char *fval;
3318 	char *old_pname;
3319 	char *old_fval;
3320 	int mfst_seen;
3321 	int r;
3322 
3323 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3324 
3325 	/*
3326 	 * This should always be the service base on the code
3327 	 * path, and the fact that the manifests pg is a service
3328 	 * level property group only.
3329 	 */
3330 	ud_run_mfsts_pg = scf_pg_create(g_hndl);
3331 	ud_run_prop = scf_property_create(g_hndl);
3332 	ud_prop_iter = scf_iter_create(g_hndl);
3333 	fname_value = scf_value_create(g_hndl);
3334 
3335 	/* Fetch the running version of the "manifests" property group */
3336 	if (running != NULL)
3337 		r = scf_snaplevel_get_pg(running, SCF_PG_MANIFESTFILES,
3338 		    ud_run_mfsts_pg);
3339 	else
3340 		r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3341 		    ud_run_mfsts_pg);
3342 
3343 	if (r != 0) {
3344 		switch (scf_error()) {
3345 		case SCF_ERROR_NOT_FOUND:
3346 			break;
3347 
3348 		case SCF_ERROR_DELETED:
3349 		case SCF_ERROR_CONNECTION_BROKEN:
3350 			return (scferror2errno(scf_error()));
3351 
3352 		case SCF_ERROR_NOT_SET:
3353 		case SCF_ERROR_INVALID_ARGUMENT:
3354 		case SCF_ERROR_HANDLE_MISMATCH:
3355 		case SCF_ERROR_NOT_BOUND:
3356 		default:
3357 			bad_error(running ? "scf_snaplevel_get_pg" :
3358 			    "entity_get_pg", scf_error());
3359 		}
3360 	}
3361 
3362 	/* Fetch the new manifests property group */
3363 	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3364 	    mfst_pgroup != NULL;
3365 	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3366 		if (strcmp(mfst_pgroup->sc_pgroup_name,
3367 		    SCF_PG_MANIFESTFILES) == 0)
3368 			break;
3369 	}
3370 
3371 	if (scf_iter_pg_properties(ud_prop_iter, ud_run_mfsts_pg) !=
3372 	    SCF_SUCCESS)
3373 		return (-1);
3374 
3375 	while ((r = scf_iter_next_property(ud_prop_iter, ud_run_prop)) == 1) {
3376 		mfst_seen = 0;
3377 		if (scf_property_get_name(ud_run_prop, pname, MAXPATHLEN) < 0)
3378 			continue;
3379 
3380 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3381 		    mfst_prop != NULL;
3382 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3383 		    mfst_prop)) {
3384 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3385 				mfst_seen = 1;
3386 			}
3387 		}
3388 
3389 		/*
3390 		 * If the manifest is not seen then add it to the new mfst
3391 		 * property list to get proccessed into the repo.
3392 		 */
3393 		if (mfst_seen == 0) {
3394 			fval = malloc(MAXPATHLEN);
3395 
3396 			/*
3397 			 * If we cannot get the value then there is no
3398 			 * reasont to attempt to attach the value to
3399 			 * the property group
3400 			 */
3401 			if (fval != NULL &&
3402 			    prop_get_val(ud_run_prop, fname_value) == 0 &&
3403 			    scf_value_get_astring(fname_value, fval,
3404 			    MAXPATHLEN) != -1)  {
3405 				/*
3406 				 * First check to see if the manifest is there
3407 				 * if not then there is no need to add it.
3408 				 */
3409 				if (access(fval, F_OK) == -1) {
3410 					free(fval);
3411 					continue;
3412 				}
3413 				old_pname = safe_strdup(pname);
3414 				old_fval = safe_strdup(fval);
3415 				old_prop = internal_property_create(old_pname,
3416 				    SCF_TYPE_ASTRING, 1, old_fval);
3417 
3418 				/*
3419 				 * Already checked to see if the property exists
3420 				 * in the group, and it does not.
3421 				 */
3422 				(void) internal_attach_property(mfst_pgroup,
3423 				    old_prop);
3424 			}
3425 		}
3426 	}
3427 
3428 	return (r);
3429 }
3430 
3431 /*
3432  * prop is taken to be a property in the "dependents" property group of snpl,
3433  * which is taken to be the snaplevel of a last-import snapshot corresponding
3434  * to ient.  If prop is a valid dependents property, upgrade the dependent it
3435  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
3436  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
3437  * of the entity ient represents (possibly in the running snapshot).  If it
3438  * needs to be changed, an entry will be added to tx, if not NULL.
3439  *
3440  * Returns
3441  *   0 - success
3442  *   ECONNABORTED - repository connection broken
3443  *   ENOMEM - out of memory
3444  *   ENOSPC - configd was out of resources
3445  *   ECANCELED - snpl's entity was deleted
3446  *   EINVAL - dependent target is invalid (error printed)
3447  *	    - dependent is invalid (error printed)
3448  *   EBADF - snpl is corrupt (error printed)
3449  *	   - snpl has corrupt pg (error printed)
3450  *	   - dependency pg in target is corrupt (error printed)
3451  *	   - running snapshot in dependent is missing snaplevel (error printed)
3452  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
3453  *	   - couldn't create dependent (permission denied) (error printed)
3454  *	   - couldn't modify dependent pg (permission denied) (error printed)
3455  *   EROFS - couldn't delete dependency pg (repository read-only)
3456  *	   - couldn't create dependent (repository read-only)
3457  *   EACCES - couldn't delete dependency pg (backend access denied)
3458  *	    - couldn't create dependent (backend access denied)
3459  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
3460  *	   - tx's pg was deleted (error printed)
3461  *	   - dependent pg was changed or deleted (error printed)
3462  *   EEXIST - dependency pg already exists in new target (error printed)
3463  */
3464 static int
3465 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
3466     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
3467 {
3468 	pgroup_t pgrp;
3469 	scf_type_t ty;
3470 	pgroup_t *new_dpt_pgroup;
3471 	pgroup_t *old_dpt_pgroup = NULL;
3472 	pgroup_t *current_pg;
3473 	scf_callback_t cbdata;
3474 	int tissvc;
3475 	void *target_ent;
3476 	scf_error_t serr;
3477 	int r;
3478 	scf_transaction_entry_t *ent;
3479 
3480 	const char * const cf_inval = gettext("Conflict upgrading %s "
3481 	    "(dependent \"%s\" has invalid dependents property).\n");
3482 	const char * const cf_missing = gettext("Conflict upgrading %s "
3483 	    "(dependent \"%s\" is missing).\n");
3484 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
3485 	    "(dependent \"%s\" has new dependency property group).\n");
3486 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
3487 	    "(dependent \"%s\" has new target).\n");
3488 	const char * const li_corrupt =
3489 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
3490 	const char * const upgrading =
3491 	    gettext("%s: Upgrading dependent \"%s\".\n");
3492 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
3493 	    "corrupt (missing snaplevel).\n");
3494 
3495 	if (scf_property_type(prop, &ty) != 0) {
3496 		switch (scf_error()) {
3497 		case SCF_ERROR_DELETED:
3498 		case SCF_ERROR_CONNECTION_BROKEN:
3499 			return (scferror2errno(scf_error()));
3500 
3501 		case SCF_ERROR_NOT_BOUND:
3502 		case SCF_ERROR_NOT_SET:
3503 		default:
3504 			bad_error("scf_property_type", scf_error());
3505 		}
3506 	}
3507 
3508 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3509 		warn(li_corrupt, ient->sc_fmri);
3510 		return (EBADF);
3511 	}
3512 
3513 	/*
3514 	 * prop represents a dependent in the old manifest.  It is named after
3515 	 * the dependent.
3516 	 */
3517 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
3518 		switch (scf_error()) {
3519 		case SCF_ERROR_DELETED:
3520 		case SCF_ERROR_CONNECTION_BROKEN:
3521 			return (scferror2errno(scf_error()));
3522 
3523 		case SCF_ERROR_NOT_BOUND:
3524 		case SCF_ERROR_NOT_SET:
3525 		default:
3526 			bad_error("scf_property_get_name", scf_error());
3527 		}
3528 	}
3529 
3530 	/* See if it's in the new manifest. */
3531 	pgrp.sc_pgroup_name = ud_name;
3532 	new_dpt_pgroup =
3533 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
3534 
3535 	/* If it's not, delete it... if it hasn't been customized. */
3536 	if (new_dpt_pgroup == NULL) {
3537 		pgroup_t *dpt;
3538 
3539 		if (!ud_run_dpts_pg_set)
3540 			return (0);
3541 
3542 		if (scf_property_get_value(prop, ud_val) != 0) {
3543 			switch (scf_error()) {
3544 			case SCF_ERROR_NOT_FOUND:
3545 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3546 				warn(li_corrupt, ient->sc_fmri);
3547 				return (EBADF);
3548 
3549 			case SCF_ERROR_DELETED:
3550 			case SCF_ERROR_CONNECTION_BROKEN:
3551 				return (scferror2errno(scf_error()));
3552 
3553 			case SCF_ERROR_HANDLE_MISMATCH:
3554 			case SCF_ERROR_NOT_BOUND:
3555 			case SCF_ERROR_NOT_SET:
3556 			case SCF_ERROR_PERMISSION_DENIED:
3557 			default:
3558 				bad_error("scf_property_get_value",
3559 				    scf_error());
3560 			}
3561 		}
3562 
3563 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
3564 		    max_scf_value_len + 1) < 0)
3565 			bad_error("scf_value_get_as_string", scf_error());
3566 
3567 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
3568 		    0) {
3569 			switch (scf_error()) {
3570 			case SCF_ERROR_NOT_FOUND:
3571 				return (0);
3572 
3573 			case SCF_ERROR_CONNECTION_BROKEN:
3574 				return (scferror2errno(scf_error()));
3575 
3576 			case SCF_ERROR_DELETED:
3577 				warn(emsg_pg_deleted, ient->sc_fmri,
3578 				    "dependents");
3579 				return (EBUSY);
3580 
3581 			case SCF_ERROR_INVALID_ARGUMENT:
3582 			case SCF_ERROR_NOT_BOUND:
3583 			case SCF_ERROR_HANDLE_MISMATCH:
3584 			case SCF_ERROR_NOT_SET:
3585 			default:
3586 				bad_error("scf_pg_get_property", scf_error());
3587 			}
3588 		}
3589 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
3590 			switch (scf_error()) {
3591 			case SCF_ERROR_NOT_FOUND:
3592 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3593 				warn(cf_inval, ient->sc_fmri, ud_name);
3594 				return (0);
3595 
3596 			case SCF_ERROR_DELETED:
3597 			case SCF_ERROR_CONNECTION_BROKEN:
3598 				return (scferror2errno(scf_error()));
3599 
3600 			case SCF_ERROR_HANDLE_MISMATCH:
3601 			case SCF_ERROR_NOT_BOUND:
3602 			case SCF_ERROR_NOT_SET:
3603 			case SCF_ERROR_PERMISSION_DENIED:
3604 			default:
3605 				bad_error("scf_property_get_value",
3606 				    scf_error());
3607 			}
3608 		}
3609 
3610 		ty = scf_value_type(ud_val);
3611 		assert(ty != SCF_TYPE_INVALID);
3612 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3613 			warn(cf_inval, ient->sc_fmri, ud_name);
3614 			return (0);
3615 		}
3616 
3617 		if (scf_value_get_as_string(ud_val, ud_ctarg,
3618 		    max_scf_value_len + 1) < 0)
3619 			bad_error("scf_value_get_as_string", scf_error());
3620 
3621 		r = fmri_equal(ud_ctarg, ud_oldtarg);
3622 		switch (r) {
3623 		case 1:
3624 			break;
3625 
3626 		case 0:
3627 		case -1:	/* warn? */
3628 			warn(cf_newtarg, ient->sc_fmri, ud_name);
3629 			return (0);
3630 
3631 		case -2:
3632 			warn(li_corrupt, ient->sc_fmri);
3633 			return (EBADF);
3634 
3635 		default:
3636 			bad_error("fmri_equal", r);
3637 		}
3638 
3639 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3640 			switch (scf_error()) {
3641 			case SCF_ERROR_NOT_FOUND:
3642 				warn(li_corrupt, ient->sc_fmri);
3643 				return (EBADF);
3644 
3645 			case SCF_ERROR_DELETED:
3646 			case SCF_ERROR_CONNECTION_BROKEN:
3647 				return (scferror2errno(scf_error()));
3648 
3649 			case SCF_ERROR_NOT_BOUND:
3650 			case SCF_ERROR_HANDLE_MISMATCH:
3651 			case SCF_ERROR_INVALID_ARGUMENT:
3652 			case SCF_ERROR_NOT_SET:
3653 			default:
3654 				bad_error("scf_snaplevel_get_pg", scf_error());
3655 			}
3656 		}
3657 
3658 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3659 		    snap_lastimport);
3660 		switch (r) {
3661 		case 0:
3662 			break;
3663 
3664 		case ECANCELED:
3665 		case ECONNABORTED:
3666 		case ENOMEM:
3667 		case EBADF:
3668 			return (r);
3669 
3670 		case EACCES:
3671 		default:
3672 			bad_error("load_pg", r);
3673 		}
3674 
3675 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3676 		switch (serr) {
3677 		case SCF_ERROR_NONE:
3678 			break;
3679 
3680 		case SCF_ERROR_NO_MEMORY:
3681 			internal_pgroup_free(old_dpt_pgroup);
3682 			return (ENOMEM);
3683 
3684 		case SCF_ERROR_NOT_FOUND:
3685 			internal_pgroup_free(old_dpt_pgroup);
3686 			goto delprop;
3687 
3688 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
3689 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
3690 		default:
3691 			bad_error("fmri_to_entity", serr);
3692 		}
3693 
3694 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
3695 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
3696 		switch (r) {
3697 		case 0:
3698 			break;
3699 
3700 		case ECONNABORTED:
3701 			internal_pgroup_free(old_dpt_pgroup);
3702 			return (r);
3703 
3704 		case ECANCELED:
3705 		case ENOENT:
3706 			internal_pgroup_free(old_dpt_pgroup);
3707 			goto delprop;
3708 
3709 		case EBADF:
3710 			warn(r_no_lvl, ud_ctarg);
3711 			internal_pgroup_free(old_dpt_pgroup);
3712 			return (r);
3713 
3714 		case EINVAL:
3715 		default:
3716 			bad_error("entity_get_running_pg", r);
3717 		}
3718 
3719 		/* load it */
3720 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
3721 		switch (r) {
3722 		case 0:
3723 			break;
3724 
3725 		case ECANCELED:
3726 			internal_pgroup_free(old_dpt_pgroup);
3727 			goto delprop;
3728 
3729 		case ECONNABORTED:
3730 		case ENOMEM:
3731 		case EBADF:
3732 			internal_pgroup_free(old_dpt_pgroup);
3733 			return (r);
3734 
3735 		case EACCES:
3736 		default:
3737 			bad_error("load_pg", r);
3738 		}
3739 
3740 		/* compare property groups */
3741 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
3742 			warn(cf_newdpg, ient->sc_fmri, ud_name);
3743 			internal_pgroup_free(old_dpt_pgroup);
3744 			internal_pgroup_free(current_pg);
3745 			return (0);
3746 		}
3747 
3748 		internal_pgroup_free(old_dpt_pgroup);
3749 		internal_pgroup_free(current_pg);
3750 
3751 		if (g_verbose)
3752 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
3753 			    ient->sc_fmri, ud_name);
3754 
3755 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
3756 			switch (scf_error()) {
3757 			case SCF_ERROR_NOT_FOUND:
3758 			case SCF_ERROR_DELETED:
3759 				internal_pgroup_free(old_dpt_pgroup);
3760 				goto delprop;
3761 
3762 			case SCF_ERROR_CONNECTION_BROKEN:
3763 				internal_pgroup_free(old_dpt_pgroup);
3764 				return (ECONNABORTED);
3765 
3766 			case SCF_ERROR_NOT_SET:
3767 			case SCF_ERROR_INVALID_ARGUMENT:
3768 			case SCF_ERROR_HANDLE_MISMATCH:
3769 			case SCF_ERROR_NOT_BOUND:
3770 			default:
3771 				bad_error("entity_get_pg", scf_error());
3772 			}
3773 		}
3774 
3775 		if (scf_pg_delete(ud_pg) != 0) {
3776 			switch (scf_error()) {
3777 			case SCF_ERROR_DELETED:
3778 				break;
3779 
3780 			case SCF_ERROR_CONNECTION_BROKEN:
3781 			case SCF_ERROR_BACKEND_READONLY:
3782 			case SCF_ERROR_BACKEND_ACCESS:
3783 				return (scferror2errno(scf_error()));
3784 
3785 			case SCF_ERROR_PERMISSION_DENIED:
3786 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
3787 				return (scferror2errno(scf_error()));
3788 
3789 			case SCF_ERROR_NOT_SET:
3790 			default:
3791 				bad_error("scf_pg_delete", scf_error());
3792 			}
3793 		}
3794 
3795 		/*
3796 		 * This service was changed, so it must be refreshed.  But
3797 		 * since it's not mentioned in the new manifest, we have to
3798 		 * record its FMRI here for use later.  We record the name
3799 		 * & the entity (via sc_parent) in case we need to print error
3800 		 * messages during the refresh.
3801 		 */
3802 		dpt = internal_pgroup_new();
3803 		if (dpt == NULL)
3804 			return (ENOMEM);
3805 		dpt->sc_pgroup_name = strdup(ud_name);
3806 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
3807 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
3808 			return (ENOMEM);
3809 		dpt->sc_parent = (entity_t *)ient;
3810 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
3811 			uu_die(gettext("libuutil error: %s\n"),
3812 			    uu_strerror(uu_error()));
3813 
3814 delprop:
3815 		if (tx == NULL)
3816 			return (0);
3817 
3818 		ent = scf_entry_create(g_hndl);
3819 		if (ent == NULL)
3820 			return (ENOMEM);
3821 
3822 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
3823 			scf_entry_destroy(ent);
3824 			switch (scf_error()) {
3825 			case SCF_ERROR_DELETED:
3826 				warn(emsg_pg_deleted, ient->sc_fmri,
3827 				    "dependents");
3828 				return (EBUSY);
3829 
3830 			case SCF_ERROR_CONNECTION_BROKEN:
3831 				return (scferror2errno(scf_error()));
3832 
3833 			case SCF_ERROR_NOT_FOUND:
3834 				break;
3835 
3836 			case SCF_ERROR_HANDLE_MISMATCH:
3837 			case SCF_ERROR_NOT_BOUND:
3838 			case SCF_ERROR_INVALID_ARGUMENT:
3839 			case SCF_ERROR_NOT_SET:
3840 			default:
3841 				bad_error("scf_transaction_property_delete",
3842 				    scf_error());
3843 			}
3844 		}
3845 
3846 		return (0);
3847 	}
3848 
3849 	new_dpt_pgroup->sc_pgroup_seen = 1;
3850 
3851 	/*
3852 	 * Decide whether the dependent has changed in the manifest.
3853 	 */
3854 	/* Compare the target. */
3855 	if (scf_property_get_value(prop, ud_val) != 0) {
3856 		switch (scf_error()) {
3857 		case SCF_ERROR_NOT_FOUND:
3858 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3859 			warn(li_corrupt, ient->sc_fmri);
3860 			return (EBADF);
3861 
3862 		case SCF_ERROR_DELETED:
3863 		case SCF_ERROR_CONNECTION_BROKEN:
3864 			return (scferror2errno(scf_error()));
3865 
3866 		case SCF_ERROR_HANDLE_MISMATCH:
3867 		case SCF_ERROR_NOT_BOUND:
3868 		case SCF_ERROR_NOT_SET:
3869 		case SCF_ERROR_PERMISSION_DENIED:
3870 		default:
3871 			bad_error("scf_property_get_value", scf_error());
3872 		}
3873 	}
3874 
3875 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
3876 	    0)
3877 		bad_error("scf_value_get_as_string", scf_error());
3878 
3879 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
3880 	switch (r) {
3881 	case 0:
3882 		break;
3883 
3884 	case 1:
3885 		/* Compare the dependency pgs. */
3886 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3887 			switch (scf_error()) {
3888 			case SCF_ERROR_NOT_FOUND:
3889 				warn(li_corrupt, ient->sc_fmri);
3890 				return (EBADF);
3891 
3892 			case SCF_ERROR_DELETED:
3893 			case SCF_ERROR_CONNECTION_BROKEN:
3894 				return (scferror2errno(scf_error()));
3895 
3896 			case SCF_ERROR_NOT_BOUND:
3897 			case SCF_ERROR_HANDLE_MISMATCH:
3898 			case SCF_ERROR_INVALID_ARGUMENT:
3899 			case SCF_ERROR_NOT_SET:
3900 			default:
3901 				bad_error("scf_snaplevel_get_pg", scf_error());
3902 			}
3903 		}
3904 
3905 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3906 		    snap_lastimport);
3907 		switch (r) {
3908 		case 0:
3909 			break;
3910 
3911 		case ECANCELED:
3912 		case ECONNABORTED:
3913 		case ENOMEM:
3914 		case EBADF:
3915 			return (r);
3916 
3917 		case EACCES:
3918 		default:
3919 			bad_error("load_pg", r);
3920 		}
3921 
3922 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
3923 			/* no change, leave customizations */
3924 			internal_pgroup_free(old_dpt_pgroup);
3925 			return (0);
3926 		}
3927 		break;
3928 
3929 	case -1:
3930 		warn(li_corrupt, ient->sc_fmri);
3931 		return (EBADF);
3932 
3933 	case -2:
3934 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
3935 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
3936 		return (EINVAL);
3937 
3938 	default:
3939 		bad_error("fmri_equal", r);
3940 	}
3941 
3942 	/*
3943 	 * The dependent has changed in the manifest.  Upgrade the current
3944 	 * properties if they haven't been customized.
3945 	 */
3946 
3947 	/*
3948 	 * If new_dpt_pgroup->sc_override, then act as though the property
3949 	 * group hasn't been customized.
3950 	 */
3951 	if (new_dpt_pgroup->sc_pgroup_override)
3952 		goto nocust;
3953 
3954 	if (!ud_run_dpts_pg_set) {
3955 		warn(cf_missing, ient->sc_fmri, ud_name);
3956 		r = 0;
3957 		goto out;
3958 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
3959 		switch (scf_error()) {
3960 		case SCF_ERROR_NOT_FOUND:
3961 			warn(cf_missing, ient->sc_fmri, ud_name);
3962 			r = 0;
3963 			goto out;
3964 
3965 		case SCF_ERROR_CONNECTION_BROKEN:
3966 			r = scferror2errno(scf_error());
3967 			goto out;
3968 
3969 		case SCF_ERROR_DELETED:
3970 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
3971 			r = EBUSY;
3972 			goto out;
3973 
3974 		case SCF_ERROR_INVALID_ARGUMENT:
3975 		case SCF_ERROR_NOT_BOUND:
3976 		case SCF_ERROR_HANDLE_MISMATCH:
3977 		case SCF_ERROR_NOT_SET:
3978 		default:
3979 			bad_error("scf_pg_get_property", scf_error());
3980 		}
3981 	}
3982 
3983 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
3984 		switch (scf_error()) {
3985 		case SCF_ERROR_NOT_FOUND:
3986 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3987 			warn(cf_inval, ient->sc_fmri, ud_name);
3988 			r = 0;
3989 			goto out;
3990 
3991 		case SCF_ERROR_DELETED:
3992 		case SCF_ERROR_CONNECTION_BROKEN:
3993 			r = scferror2errno(scf_error());
3994 			goto out;
3995 
3996 		case SCF_ERROR_HANDLE_MISMATCH:
3997 		case SCF_ERROR_NOT_BOUND:
3998 		case SCF_ERROR_NOT_SET:
3999 		case SCF_ERROR_PERMISSION_DENIED:
4000 		default:
4001 			bad_error("scf_property_get_value", scf_error());
4002 		}
4003 	}
4004 
4005 	ty = scf_value_type(ud_val);
4006 	assert(ty != SCF_TYPE_INVALID);
4007 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4008 		warn(cf_inval, ient->sc_fmri, ud_name);
4009 		r = 0;
4010 		goto out;
4011 	}
4012 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4013 	    0)
4014 		bad_error("scf_value_get_as_string", scf_error());
4015 
4016 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4017 	if (r == -1) {
4018 		warn(cf_inval, ient->sc_fmri, ud_name);
4019 		r = 0;
4020 		goto out;
4021 	} else if (r == -2) {
4022 		warn(li_corrupt, ient->sc_fmri);
4023 		r = EBADF;
4024 		goto out;
4025 	} else if (r == 0) {
4026 		/*
4027 		 * Target has been changed.  Only abort now if it's been
4028 		 * changed to something other than what's in the manifest.
4029 		 */
4030 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4031 		if (r == -1) {
4032 			warn(cf_inval, ient->sc_fmri, ud_name);
4033 			r = 0;
4034 			goto out;
4035 		} else if (r == 0) {
4036 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4037 			r = 0;
4038 			goto out;
4039 		} else if (r != 1) {
4040 			/* invalid sc_pgroup_fmri caught above */
4041 			bad_error("fmri_equal", r);
4042 		}
4043 
4044 		/*
4045 		 * Fetch the current dependency pg.  If it's what the manifest
4046 		 * says, then no problem.
4047 		 */
4048 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4049 		switch (serr) {
4050 		case SCF_ERROR_NONE:
4051 			break;
4052 
4053 		case SCF_ERROR_NOT_FOUND:
4054 			warn(cf_missing, ient->sc_fmri, ud_name);
4055 			r = 0;
4056 			goto out;
4057 
4058 		case SCF_ERROR_NO_MEMORY:
4059 			r = ENOMEM;
4060 			goto out;
4061 
4062 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4063 		case SCF_ERROR_INVALID_ARGUMENT:
4064 		default:
4065 			bad_error("fmri_to_entity", serr);
4066 		}
4067 
4068 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4069 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4070 		switch (r) {
4071 		case 0:
4072 			break;
4073 
4074 		case ECONNABORTED:
4075 			goto out;
4076 
4077 		case ECANCELED:
4078 		case ENOENT:
4079 			warn(cf_missing, ient->sc_fmri, ud_name);
4080 			r = 0;
4081 			goto out;
4082 
4083 		case EBADF:
4084 			warn(r_no_lvl, ud_ctarg);
4085 			goto out;
4086 
4087 		case EINVAL:
4088 		default:
4089 			bad_error("entity_get_running_pg", r);
4090 		}
4091 
4092 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4093 		switch (r) {
4094 		case 0:
4095 			break;
4096 
4097 		case ECANCELED:
4098 			warn(cf_missing, ient->sc_fmri, ud_name);
4099 			r = 0;
4100 			goto out;
4101 
4102 		case ECONNABORTED:
4103 		case ENOMEM:
4104 		case EBADF:
4105 			goto out;
4106 
4107 		case EACCES:
4108 		default:
4109 			bad_error("load_pg", r);
4110 		}
4111 
4112 		if (!pg_equal(current_pg, new_dpt_pgroup))
4113 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4114 		internal_pgroup_free(current_pg);
4115 		r = 0;
4116 		goto out;
4117 	} else if (r != 1) {
4118 		bad_error("fmri_equal", r);
4119 	}
4120 
4121 nocust:
4122 	/*
4123 	 * Target has not been customized.  Check the dependency property
4124 	 * group.
4125 	 */
4126 
4127 	if (old_dpt_pgroup == NULL) {
4128 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4129 		    ud_pg) != 0) {
4130 			switch (scf_error()) {
4131 			case SCF_ERROR_NOT_FOUND:
4132 				warn(li_corrupt, ient->sc_fmri);
4133 				return (EBADF);
4134 
4135 			case SCF_ERROR_DELETED:
4136 			case SCF_ERROR_CONNECTION_BROKEN:
4137 				return (scferror2errno(scf_error()));
4138 
4139 			case SCF_ERROR_NOT_BOUND:
4140 			case SCF_ERROR_HANDLE_MISMATCH:
4141 			case SCF_ERROR_INVALID_ARGUMENT:
4142 			case SCF_ERROR_NOT_SET:
4143 			default:
4144 				bad_error("scf_snaplevel_get_pg", scf_error());
4145 			}
4146 		}
4147 
4148 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4149 		    snap_lastimport);
4150 		switch (r) {
4151 		case 0:
4152 			break;
4153 
4154 		case ECANCELED:
4155 		case ECONNABORTED:
4156 		case ENOMEM:
4157 		case EBADF:
4158 			return (r);
4159 
4160 		case EACCES:
4161 		default:
4162 			bad_error("load_pg", r);
4163 		}
4164 	}
4165 
4166 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4167 	switch (serr) {
4168 	case SCF_ERROR_NONE:
4169 		break;
4170 
4171 	case SCF_ERROR_NOT_FOUND:
4172 		warn(cf_missing, ient->sc_fmri, ud_name);
4173 		r = 0;
4174 		goto out;
4175 
4176 	case SCF_ERROR_NO_MEMORY:
4177 		r = ENOMEM;
4178 		goto out;
4179 
4180 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4181 	case SCF_ERROR_INVALID_ARGUMENT:
4182 	default:
4183 		bad_error("fmri_to_entity", serr);
4184 	}
4185 
4186 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4187 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4188 	switch (r) {
4189 	case 0:
4190 		break;
4191 
4192 	case ECONNABORTED:
4193 		goto out;
4194 
4195 	case ECANCELED:
4196 	case ENOENT:
4197 		warn(cf_missing, ient->sc_fmri, ud_name);
4198 		r = 0;
4199 		goto out;
4200 
4201 	case EBADF:
4202 		warn(r_no_lvl, ud_ctarg);
4203 		goto out;
4204 
4205 	case EINVAL:
4206 	default:
4207 		bad_error("entity_get_running_pg", r);
4208 	}
4209 
4210 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4211 	switch (r) {
4212 	case 0:
4213 		break;
4214 
4215 	case ECANCELED:
4216 		warn(cf_missing, ient->sc_fmri, ud_name);
4217 		goto out;
4218 
4219 	case ECONNABORTED:
4220 	case ENOMEM:
4221 	case EBADF:
4222 		goto out;
4223 
4224 	case EACCES:
4225 	default:
4226 		bad_error("load_pg", r);
4227 	}
4228 
4229 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4230 		if (!pg_equal(current_pg, new_dpt_pgroup))
4231 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4232 		internal_pgroup_free(current_pg);
4233 		r = 0;
4234 		goto out;
4235 	}
4236 
4237 	/* Uncustomized.  Upgrade. */
4238 
4239 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4240 	switch (r) {
4241 	case 1:
4242 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4243 			/* Already upgraded. */
4244 			internal_pgroup_free(current_pg);
4245 			r = 0;
4246 			goto out;
4247 		}
4248 
4249 		internal_pgroup_free(current_pg);
4250 
4251 		/* upgrade current_pg */
4252 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4253 			switch (scf_error()) {
4254 			case SCF_ERROR_CONNECTION_BROKEN:
4255 				r = scferror2errno(scf_error());
4256 				goto out;
4257 
4258 			case SCF_ERROR_DELETED:
4259 				warn(cf_missing, ient->sc_fmri, ud_name);
4260 				r = 0;
4261 				goto out;
4262 
4263 			case SCF_ERROR_NOT_FOUND:
4264 				break;
4265 
4266 			case SCF_ERROR_INVALID_ARGUMENT:
4267 			case SCF_ERROR_NOT_BOUND:
4268 			case SCF_ERROR_NOT_SET:
4269 			case SCF_ERROR_HANDLE_MISMATCH:
4270 			default:
4271 				bad_error("entity_get_pg", scf_error());
4272 			}
4273 
4274 			if (tissvc)
4275 				r = scf_service_add_pg(target_ent, ud_name,
4276 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4277 			else
4278 				r = scf_instance_add_pg(target_ent, ud_name,
4279 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4280 			if (r != 0) {
4281 				switch (scf_error()) {
4282 				case SCF_ERROR_CONNECTION_BROKEN:
4283 				case SCF_ERROR_NO_RESOURCES:
4284 				case SCF_ERROR_BACKEND_READONLY:
4285 				case SCF_ERROR_BACKEND_ACCESS:
4286 					r = scferror2errno(scf_error());
4287 					goto out;
4288 
4289 				case SCF_ERROR_DELETED:
4290 					warn(cf_missing, ient->sc_fmri,
4291 					    ud_name);
4292 					r = 0;
4293 					goto out;
4294 
4295 				case SCF_ERROR_PERMISSION_DENIED:
4296 					warn(emsg_pg_deleted, ud_ctarg,
4297 					    ud_name);
4298 					r = EPERM;
4299 					goto out;
4300 
4301 				case SCF_ERROR_EXISTS:
4302 					warn(emsg_pg_added, ud_ctarg, ud_name);
4303 					r = EBUSY;
4304 					goto out;
4305 
4306 				case SCF_ERROR_NOT_BOUND:
4307 				case SCF_ERROR_HANDLE_MISMATCH:
4308 				case SCF_ERROR_INVALID_ARGUMENT:
4309 				case SCF_ERROR_NOT_SET:
4310 				default:
4311 					bad_error("entity_add_pg", scf_error());
4312 				}
4313 			}
4314 		}
4315 
4316 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4317 		switch (r) {
4318 		case 0:
4319 			break;
4320 
4321 		case ECANCELED:
4322 			warn(cf_missing, ient->sc_fmri, ud_name);
4323 			goto out;
4324 
4325 		case ECONNABORTED:
4326 		case ENOMEM:
4327 		case EBADF:
4328 			goto out;
4329 
4330 		case EACCES:
4331 		default:
4332 			bad_error("load_pg", r);
4333 		}
4334 
4335 		if (g_verbose)
4336 			warn(upgrading, ient->sc_fmri, ud_name);
4337 
4338 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4339 		    new_dpt_pgroup, 0, ient->sc_fmri);
4340 		switch (r) {
4341 		case 0:
4342 			break;
4343 
4344 		case ECANCELED:
4345 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4346 			r = EBUSY;
4347 			goto out;
4348 
4349 		case EPERM:
4350 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4351 			goto out;
4352 
4353 		case EBUSY:
4354 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4355 			goto out;
4356 
4357 		case ECONNABORTED:
4358 		case ENOMEM:
4359 		case ENOSPC:
4360 		case EROFS:
4361 		case EACCES:
4362 		case EINVAL:
4363 			goto out;
4364 
4365 		default:
4366 			bad_error("upgrade_pg", r);
4367 		}
4368 		break;
4369 
4370 	case 0: {
4371 		scf_transaction_entry_t *ent;
4372 		scf_value_t *val;
4373 
4374 		internal_pgroup_free(current_pg);
4375 
4376 		/* delete old pg */
4377 		if (g_verbose)
4378 			warn(upgrading, ient->sc_fmri, ud_name);
4379 
4380 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4381 			switch (scf_error()) {
4382 			case SCF_ERROR_CONNECTION_BROKEN:
4383 				r = scferror2errno(scf_error());
4384 				goto out;
4385 
4386 			case SCF_ERROR_DELETED:
4387 				warn(cf_missing, ient->sc_fmri, ud_name);
4388 				r = 0;
4389 				goto out;
4390 
4391 			case SCF_ERROR_NOT_FOUND:
4392 				break;
4393 
4394 			case SCF_ERROR_INVALID_ARGUMENT:
4395 			case SCF_ERROR_NOT_BOUND:
4396 			case SCF_ERROR_NOT_SET:
4397 			case SCF_ERROR_HANDLE_MISMATCH:
4398 			default:
4399 				bad_error("entity_get_pg", scf_error());
4400 			}
4401 		} else if (scf_pg_delete(ud_pg) != 0) {
4402 			switch (scf_error()) {
4403 			case SCF_ERROR_DELETED:
4404 				break;
4405 
4406 			case SCF_ERROR_CONNECTION_BROKEN:
4407 			case SCF_ERROR_BACKEND_READONLY:
4408 			case SCF_ERROR_BACKEND_ACCESS:
4409 				r = scferror2errno(scf_error());
4410 				goto out;
4411 
4412 			case SCF_ERROR_PERMISSION_DENIED:
4413 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4414 				r = scferror2errno(scf_error());
4415 				goto out;
4416 
4417 			case SCF_ERROR_NOT_SET:
4418 			default:
4419 				bad_error("scf_pg_delete", scf_error());
4420 			}
4421 		}
4422 
4423 		/* import new one */
4424 		cbdata.sc_handle = g_hndl;
4425 		cbdata.sc_trans = NULL;		/* handled below */
4426 
4427 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
4428 		if (r != UU_WALK_NEXT) {
4429 			if (r != UU_WALK_ERROR)
4430 				bad_error("lscf_dependent_import", r);
4431 
4432 			r = cbdata.sc_err;
4433 			goto out;
4434 		}
4435 
4436 		if (tx == NULL)
4437 			break;
4438 
4439 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
4440 		    (val = scf_value_create(g_hndl)) == NULL) {
4441 			if (scf_error() == SCF_ERROR_NO_MEMORY)
4442 				return (ENOMEM);
4443 
4444 			bad_error("scf_entry_create", scf_error());
4445 		}
4446 
4447 		if (scf_transaction_property_change_type(tx, ent, ud_name,
4448 		    SCF_TYPE_FMRI) != 0) {
4449 			switch (scf_error()) {
4450 			case SCF_ERROR_CONNECTION_BROKEN:
4451 				r = scferror2errno(scf_error());
4452 				goto out;
4453 
4454 			case SCF_ERROR_DELETED:
4455 				warn(emsg_pg_deleted, ient->sc_fmri,
4456 				    "dependents");
4457 				r = EBUSY;
4458 				goto out;
4459 
4460 			case SCF_ERROR_NOT_FOUND:
4461 				break;
4462 
4463 			case SCF_ERROR_NOT_BOUND:
4464 			case SCF_ERROR_HANDLE_MISMATCH:
4465 			case SCF_ERROR_INVALID_ARGUMENT:
4466 			case SCF_ERROR_NOT_SET:
4467 			default:
4468 				bad_error("scf_transaction_property_"
4469 				    "change_type", scf_error());
4470 			}
4471 
4472 			if (scf_transaction_property_new(tx, ent, ud_name,
4473 			    SCF_TYPE_FMRI) != 0) {
4474 				switch (scf_error()) {
4475 				case SCF_ERROR_CONNECTION_BROKEN:
4476 					r = scferror2errno(scf_error());
4477 					goto out;
4478 
4479 				case SCF_ERROR_DELETED:
4480 					warn(emsg_pg_deleted, ient->sc_fmri,
4481 					    "dependents");
4482 					r = EBUSY;
4483 					goto out;
4484 
4485 				case SCF_ERROR_EXISTS:
4486 					warn(emsg_pg_changed, ient->sc_fmri,
4487 					    "dependents");
4488 					r = EBUSY;
4489 					goto out;
4490 
4491 				case SCF_ERROR_INVALID_ARGUMENT:
4492 				case SCF_ERROR_HANDLE_MISMATCH:
4493 				case SCF_ERROR_NOT_BOUND:
4494 				case SCF_ERROR_NOT_SET:
4495 				default:
4496 					bad_error("scf_transaction_property_"
4497 					    "new", scf_error());
4498 				}
4499 			}
4500 		}
4501 
4502 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
4503 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
4504 			/* invalid sc_pgroup_fmri caught above */
4505 			bad_error("scf_value_set_from_string",
4506 			    scf_error());
4507 
4508 		if (scf_entry_add_value(ent, val) != 0)
4509 			bad_error("scf_entry_add_value", scf_error());
4510 		break;
4511 	}
4512 
4513 	case -2:
4514 		warn(li_corrupt, ient->sc_fmri);
4515 		internal_pgroup_free(current_pg);
4516 		r = EBADF;
4517 		goto out;
4518 
4519 	case -1:
4520 	default:
4521 		/* invalid sc_pgroup_fmri caught above */
4522 		bad_error("fmri_equal", r);
4523 	}
4524 
4525 	r = 0;
4526 
4527 out:
4528 	if (old_dpt_pgroup != NULL)
4529 		internal_pgroup_free(old_dpt_pgroup);
4530 
4531 	return (r);
4532 }
4533 
4534 /*
4535  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
4536  * would import it, except it seems to exist in the service anyway.  Compare
4537  * the existent dependent with the one we would import, and report any
4538  * differences (if there are none, be silent).  prop is the property which
4539  * represents the existent dependent (in the dependents property group) in the
4540  * entity corresponding to ient.
4541  *
4542  * Returns
4543  *   0 - success (Sort of.  At least, we can continue importing.)
4544  *   ECONNABORTED - repository connection broken
4545  *   EBUSY - ancestor of prop was deleted (error printed)
4546  *   ENOMEM - out of memory
4547  *   EBADF - corrupt property group (error printed)
4548  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
4549  */
4550 static int
4551 handle_dependent_conflict(const entity_t * const ient,
4552     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
4553 {
4554 	int r;
4555 	scf_type_t ty;
4556 	scf_error_t scfe;
4557 	void *tptr;
4558 	int tissvc;
4559 	pgroup_t *pgroup;
4560 
4561 	if (scf_property_get_value(prop, ud_val) != 0) {
4562 		switch (scf_error()) {
4563 		case SCF_ERROR_CONNECTION_BROKEN:
4564 			return (scferror2errno(scf_error()));
4565 
4566 		case SCF_ERROR_DELETED:
4567 			warn(emsg_pg_deleted, ient->sc_fmri,
4568 			    new_dpt_pgroup->sc_pgroup_name);
4569 			return (EBUSY);
4570 
4571 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4572 		case SCF_ERROR_NOT_FOUND:
4573 			warn(gettext("Conflict upgrading %s (not importing "
4574 			    "dependent \"%s\" because it already exists.)  "
4575 			    "Warning: The \"%s/%2$s\" property has more or "
4576 			    "fewer than one value)).\n"), ient->sc_fmri,
4577 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
4578 			return (0);
4579 
4580 		case SCF_ERROR_HANDLE_MISMATCH:
4581 		case SCF_ERROR_NOT_BOUND:
4582 		case SCF_ERROR_NOT_SET:
4583 		case SCF_ERROR_PERMISSION_DENIED:
4584 		default:
4585 			bad_error("scf_property_get_value",
4586 			    scf_error());
4587 		}
4588 	}
4589 
4590 	ty = scf_value_type(ud_val);
4591 	assert(ty != SCF_TYPE_INVALID);
4592 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4593 		warn(gettext("Conflict upgrading %s (not importing dependent "
4594 		    "\"%s\" because it already exists).  Warning: The "
4595 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
4596 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
4597 		    scf_type_to_string(ty), "dependents");
4598 		return (0);
4599 	}
4600 
4601 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4602 	    0)
4603 		bad_error("scf_value_get_as_string", scf_error());
4604 
4605 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4606 	switch (r) {
4607 	case 0:
4608 		warn(gettext("Conflict upgrading %s (not importing dependent "
4609 		    "\"%s\" (target \"%s\") because it already exists with "
4610 		    "target \"%s\").\n"), ient->sc_fmri,
4611 		    new_dpt_pgroup->sc_pgroup_name,
4612 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
4613 		return (0);
4614 
4615 	case 1:
4616 		break;
4617 
4618 	case -1:
4619 		warn(gettext("Conflict upgrading %s (not importing dependent "
4620 		    "\"%s\" because it already exists).  Warning: The current "
4621 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
4622 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4623 		return (0);
4624 
4625 	case -2:
4626 		warn(gettext("Dependent \"%s\" of %s has invalid target "
4627 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
4628 		    new_dpt_pgroup->sc_pgroup_fmri);
4629 		return (EINVAL);
4630 
4631 	default:
4632 		bad_error("fmri_equal", r);
4633 	}
4634 
4635 	/* compare dependency pgs in target */
4636 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
4637 	switch (scfe) {
4638 	case SCF_ERROR_NONE:
4639 		break;
4640 
4641 	case SCF_ERROR_NO_MEMORY:
4642 		return (ENOMEM);
4643 
4644 	case SCF_ERROR_NOT_FOUND:
4645 		warn(emsg_dpt_dangling, ient->sc_fmri,
4646 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4647 		return (0);
4648 
4649 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4650 	case SCF_ERROR_INVALID_ARGUMENT:
4651 	default:
4652 		bad_error("fmri_to_entity", scfe);
4653 	}
4654 
4655 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
4656 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
4657 	switch (r) {
4658 	case 0:
4659 		break;
4660 
4661 	case ECONNABORTED:
4662 		return (r);
4663 
4664 	case ECANCELED:
4665 		warn(emsg_dpt_dangling, ient->sc_fmri,
4666 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4667 		return (0);
4668 
4669 	case EBADF:
4670 		if (tissvc)
4671 			warn(gettext("%s has an instance with a \"%s\" "
4672 			    "snapshot which is missing a snaplevel.\n"),
4673 			    ud_ctarg, "running");
4674 		else
4675 			warn(gettext("%s has a \"%s\" snapshot which is "
4676 			    "missing a snaplevel.\n"), ud_ctarg, "running");
4677 		/* FALLTHROUGH */
4678 
4679 	case ENOENT:
4680 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4681 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4682 		    new_dpt_pgroup->sc_pgroup_name);
4683 		return (0);
4684 
4685 	case EINVAL:
4686 	default:
4687 		bad_error("entity_get_running_pg", r);
4688 	}
4689 
4690 	pgroup = internal_pgroup_new();
4691 	if (pgroup == NULL)
4692 		return (ENOMEM);
4693 
4694 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
4695 	switch (r) {
4696 	case 0:
4697 		break;
4698 
4699 	case ECONNABORTED:
4700 	case EBADF:
4701 	case ENOMEM:
4702 		internal_pgroup_free(pgroup);
4703 		return (r);
4704 
4705 	case ECANCELED:
4706 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4707 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4708 		    new_dpt_pgroup->sc_pgroup_name);
4709 		internal_pgroup_free(pgroup);
4710 		return (0);
4711 
4712 	case EACCES:
4713 	default:
4714 		bad_error("load_pg", r);
4715 	}
4716 
4717 	/* report differences */
4718 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
4719 	internal_pgroup_free(pgroup);
4720 	return (0);
4721 }
4722 
4723 /*
4724  * lipg is a property group in the last-import snapshot of ent, which is an
4725  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
4726  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
4727  * in ents's property groups, compare and upgrade ent appropriately.
4728  *
4729  * Returns
4730  *   0 - success
4731  *   ECONNABORTED - repository connection broken
4732  *   ENOMEM - out of memory
4733  *   ENOSPC - configd is out of resources
4734  *   EINVAL - ient has invalid dependent (error printed)
4735  *	    - ient has invalid pgroup_t (error printed)
4736  *   ECANCELED - ent has been deleted
4737  *   ENODEV - entity containing lipg has been deleted
4738  *	    - entity containing running has been deleted
4739  *   EPERM - could not delete pg (permission denied) (error printed)
4740  *	   - couldn't upgrade dependents (permission denied) (error printed)
4741  *	   - couldn't import pg (permission denied) (error printed)
4742  *	   - couldn't upgrade pg (permission denied) (error printed)
4743  *   EROFS - could not delete pg (repository read-only)
4744  *	   - couldn't upgrade dependents (repository read-only)
4745  *	   - couldn't import pg (repository read-only)
4746  *	   - couldn't upgrade pg (repository read-only)
4747  *   EACCES - could not delete pg (backend access denied)
4748  *	    - couldn't upgrade dependents (backend access denied)
4749  *	    - couldn't import pg (backend access denied)
4750  *	    - couldn't upgrade pg (backend access denied)
4751  *	    - couldn't read property (backend access denied)
4752  *   EBUSY - property group was added (error printed)
4753  *	   - property group was deleted (error printed)
4754  *	   - property group changed (error printed)
4755  *	   - "dependents" pg was added, changed, or deleted (error printed)
4756  *	   - dependent target deleted (error printed)
4757  *	   - dependent pg changed (error printed)
4758  *   EBADF - imp_snpl is corrupt (error printed)
4759  *	   - ent has bad pg (error printed)
4760  *   EEXIST - dependent collision in target service (error printed)
4761  */
4762 static int
4763 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
4764     const scf_snaplevel_t *running)
4765 {
4766 	int r;
4767 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
4768 	scf_callback_t cbdata;
4769 
4770 	const char * const cf_pg_missing =
4771 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
4772 	const char * const deleting =
4773 	    gettext("%s: Deleting property group \"%s\".\n");
4774 
4775 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
4776 
4777 	/* Skip dependent property groups. */
4778 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
4779 		switch (scf_error()) {
4780 		case SCF_ERROR_DELETED:
4781 			return (ENODEV);
4782 
4783 		case SCF_ERROR_CONNECTION_BROKEN:
4784 			return (ECONNABORTED);
4785 
4786 		case SCF_ERROR_NOT_SET:
4787 		case SCF_ERROR_NOT_BOUND:
4788 		default:
4789 			bad_error("scf_pg_get_type", scf_error());
4790 		}
4791 	}
4792 
4793 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
4794 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
4795 			return (0);
4796 
4797 		switch (scf_error()) {
4798 		case SCF_ERROR_NOT_FOUND:
4799 			break;
4800 
4801 		case SCF_ERROR_CONNECTION_BROKEN:
4802 			return (ECONNABORTED);
4803 
4804 		case SCF_ERROR_DELETED:
4805 			return (ENODEV);
4806 
4807 		case SCF_ERROR_INVALID_ARGUMENT:
4808 		case SCF_ERROR_NOT_BOUND:
4809 		case SCF_ERROR_HANDLE_MISMATCH:
4810 		case SCF_ERROR_NOT_SET:
4811 		default:
4812 			bad_error("scf_pg_get_property", scf_error());
4813 		}
4814 	}
4815 
4816 	/* lookup pg in new properties */
4817 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
4818 		switch (scf_error()) {
4819 		case SCF_ERROR_DELETED:
4820 			return (ENODEV);
4821 
4822 		case SCF_ERROR_CONNECTION_BROKEN:
4823 			return (ECONNABORTED);
4824 
4825 		case SCF_ERROR_NOT_SET:
4826 		case SCF_ERROR_NOT_BOUND:
4827 		default:
4828 			bad_error("scf_pg_get_name", scf_error());
4829 		}
4830 	}
4831 
4832 	pgrp.sc_pgroup_name = imp_str;
4833 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
4834 
4835 	if (mpg != NULL)
4836 		mpg->sc_pgroup_seen = 1;
4837 
4838 	/* Special handling for dependents */
4839 	if (strcmp(imp_str, "dependents") == 0)
4840 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
4841 
4842 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
4843 		if ((r = upgrade_manifestfiles(ient, running, ent)) != 0)
4844 			return (r);
4845 
4846 	if (mpg == NULL || mpg->sc_pgroup_delete) {
4847 		/* property group was deleted from manifest */
4848 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4849 			switch (scf_error()) {
4850 			case SCF_ERROR_NOT_FOUND:
4851 				return (0);
4852 
4853 			case SCF_ERROR_DELETED:
4854 			case SCF_ERROR_CONNECTION_BROKEN:
4855 				return (scferror2errno(scf_error()));
4856 
4857 			case SCF_ERROR_INVALID_ARGUMENT:
4858 			case SCF_ERROR_HANDLE_MISMATCH:
4859 			case SCF_ERROR_NOT_BOUND:
4860 			case SCF_ERROR_NOT_SET:
4861 			default:
4862 				bad_error("entity_get_pg", scf_error());
4863 			}
4864 		}
4865 
4866 		if (mpg != NULL && mpg->sc_pgroup_delete) {
4867 			if (g_verbose)
4868 				warn(deleting, ient->sc_fmri, imp_str);
4869 			if (scf_pg_delete(imp_pg2) == 0)
4870 				return (0);
4871 
4872 			switch (scf_error()) {
4873 			case SCF_ERROR_DELETED:
4874 				return (0);
4875 
4876 			case SCF_ERROR_CONNECTION_BROKEN:
4877 			case SCF_ERROR_BACKEND_READONLY:
4878 			case SCF_ERROR_BACKEND_ACCESS:
4879 				return (scferror2errno(scf_error()));
4880 
4881 			case SCF_ERROR_PERMISSION_DENIED:
4882 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
4883 				return (scferror2errno(scf_error()));
4884 
4885 			case SCF_ERROR_NOT_SET:
4886 			default:
4887 				bad_error("scf_pg_delete", scf_error());
4888 			}
4889 		}
4890 
4891 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4892 		switch (r) {
4893 		case 0:
4894 			break;
4895 
4896 		case ECANCELED:
4897 			return (ENODEV);
4898 
4899 		case ECONNABORTED:
4900 		case ENOMEM:
4901 		case EBADF:
4902 		case EACCES:
4903 			return (r);
4904 
4905 		default:
4906 			bad_error("load_pg", r);
4907 		}
4908 
4909 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
4910 		switch (r) {
4911 		case 0:
4912 			break;
4913 
4914 		case ECANCELED:
4915 		case ECONNABORTED:
4916 		case ENOMEM:
4917 		case EBADF:
4918 		case EACCES:
4919 			internal_pgroup_free(lipg_i);
4920 			return (r);
4921 
4922 		default:
4923 			bad_error("load_pg", r);
4924 		}
4925 
4926 		if (pg_equal(lipg_i, curpg_i)) {
4927 			if (g_verbose)
4928 				warn(deleting, ient->sc_fmri, imp_str);
4929 			if (scf_pg_delete(imp_pg2) != 0) {
4930 				switch (scf_error()) {
4931 				case SCF_ERROR_DELETED:
4932 					break;
4933 
4934 				case SCF_ERROR_CONNECTION_BROKEN:
4935 					internal_pgroup_free(lipg_i);
4936 					internal_pgroup_free(curpg_i);
4937 					return (ECONNABORTED);
4938 
4939 				case SCF_ERROR_NOT_SET:
4940 				case SCF_ERROR_NOT_BOUND:
4941 				default:
4942 					bad_error("scf_pg_delete", scf_error());
4943 				}
4944 			}
4945 		} else {
4946 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
4947 		}
4948 
4949 		internal_pgroup_free(lipg_i);
4950 		internal_pgroup_free(curpg_i);
4951 
4952 		return (0);
4953 	}
4954 
4955 	/*
4956 	 * Only dependent pgs can have override set, and we skipped those
4957 	 * above.
4958 	 */
4959 	assert(!mpg->sc_pgroup_override);
4960 
4961 	/* compare */
4962 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4963 	switch (r) {
4964 	case 0:
4965 		break;
4966 
4967 	case ECANCELED:
4968 		return (ENODEV);
4969 
4970 	case ECONNABORTED:
4971 	case EBADF:
4972 	case ENOMEM:
4973 	case EACCES:
4974 		return (r);
4975 
4976 	default:
4977 		bad_error("load_pg", r);
4978 	}
4979 
4980 	if (pg_equal(mpg, lipg_i)) {
4981 		/* The manifest pg has not changed.  Move on. */
4982 		r = 0;
4983 		goto out;
4984 	}
4985 
4986 	/* upgrade current properties according to lipg & mpg */
4987 	if (running != NULL)
4988 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
4989 	else
4990 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
4991 	if (r != 0) {
4992 		switch (scf_error()) {
4993 		case SCF_ERROR_CONNECTION_BROKEN:
4994 			r = scferror2errno(scf_error());
4995 			goto out;
4996 
4997 		case SCF_ERROR_DELETED:
4998 			if (running != NULL)
4999 				r = ENODEV;
5000 			else
5001 				r = ECANCELED;
5002 			goto out;
5003 
5004 		case SCF_ERROR_NOT_FOUND:
5005 			break;
5006 
5007 		case SCF_ERROR_INVALID_ARGUMENT:
5008 		case SCF_ERROR_HANDLE_MISMATCH:
5009 		case SCF_ERROR_NOT_BOUND:
5010 		case SCF_ERROR_NOT_SET:
5011 		default:
5012 			bad_error("entity_get_pg", scf_error());
5013 		}
5014 
5015 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5016 
5017 		r = 0;
5018 		goto out;
5019 	}
5020 
5021 	r = load_pg_attrs(imp_pg2, &curpg_i);
5022 	switch (r) {
5023 	case 0:
5024 		break;
5025 
5026 	case ECANCELED:
5027 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5028 		r = 0;
5029 		goto out;
5030 
5031 	case ECONNABORTED:
5032 	case ENOMEM:
5033 		goto out;
5034 
5035 	default:
5036 		bad_error("load_pg_attrs", r);
5037 	}
5038 
5039 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5040 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5041 		internal_pgroup_free(curpg_i);
5042 		r = 0;
5043 		goto out;
5044 	}
5045 
5046 	internal_pgroup_free(curpg_i);
5047 
5048 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5049 	switch (r) {
5050 	case 0:
5051 		break;
5052 
5053 	case ECANCELED:
5054 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5055 		r = 0;
5056 		goto out;
5057 
5058 	case ECONNABORTED:
5059 	case EBADF:
5060 	case ENOMEM:
5061 	case EACCES:
5062 		goto out;
5063 
5064 	default:
5065 		bad_error("load_pg", r);
5066 	}
5067 
5068 	if (pg_equal(lipg_i, curpg_i) &&
5069 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5070 		int do_delete = 1;
5071 
5072 		if (g_verbose)
5073 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5074 			    ient->sc_fmri, mpg->sc_pgroup_name);
5075 
5076 		internal_pgroup_free(curpg_i);
5077 
5078 		if (running != NULL &&
5079 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5080 			switch (scf_error()) {
5081 			case SCF_ERROR_DELETED:
5082 				r = ECANCELED;
5083 				goto out;
5084 
5085 			case SCF_ERROR_NOT_FOUND:
5086 				do_delete = 0;
5087 				break;
5088 
5089 			case SCF_ERROR_CONNECTION_BROKEN:
5090 				r = scferror2errno(scf_error());
5091 				goto out;
5092 
5093 			case SCF_ERROR_HANDLE_MISMATCH:
5094 			case SCF_ERROR_INVALID_ARGUMENT:
5095 			case SCF_ERROR_NOT_SET:
5096 			case SCF_ERROR_NOT_BOUND:
5097 			default:
5098 				bad_error("entity_get_pg", scf_error());
5099 			}
5100 		}
5101 
5102 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5103 			switch (scf_error()) {
5104 			case SCF_ERROR_DELETED:
5105 				break;
5106 
5107 			case SCF_ERROR_CONNECTION_BROKEN:
5108 			case SCF_ERROR_BACKEND_READONLY:
5109 			case SCF_ERROR_BACKEND_ACCESS:
5110 				r = scferror2errno(scf_error());
5111 				goto out;
5112 
5113 			case SCF_ERROR_PERMISSION_DENIED:
5114 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5115 				    ient->sc_fmri);
5116 				r = scferror2errno(scf_error());
5117 				goto out;
5118 
5119 			case SCF_ERROR_NOT_SET:
5120 			case SCF_ERROR_NOT_BOUND:
5121 			default:
5122 				bad_error("scf_pg_delete", scf_error());
5123 			}
5124 		}
5125 
5126 		cbdata.sc_handle = g_hndl;
5127 		cbdata.sc_parent = ent;
5128 		cbdata.sc_service = issvc;
5129 		cbdata.sc_flags = 0;
5130 		cbdata.sc_source_fmri = ient->sc_fmri;
5131 		cbdata.sc_target_fmri = ient->sc_fmri;
5132 
5133 		r = entity_pgroup_import(mpg, &cbdata);
5134 		switch (r) {
5135 		case UU_WALK_NEXT:
5136 			r = 0;
5137 			goto out;
5138 
5139 		case UU_WALK_ERROR:
5140 			if (cbdata.sc_err == EEXIST) {
5141 				warn(emsg_pg_added, ient->sc_fmri,
5142 				    mpg->sc_pgroup_name);
5143 				r = EBUSY;
5144 			} else {
5145 				r = cbdata.sc_err;
5146 			}
5147 			goto out;
5148 
5149 		default:
5150 			bad_error("entity_pgroup_import", r);
5151 		}
5152 	}
5153 
5154 	if (running != NULL &&
5155 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5156 		switch (scf_error()) {
5157 		case SCF_ERROR_CONNECTION_BROKEN:
5158 		case SCF_ERROR_DELETED:
5159 			r = scferror2errno(scf_error());
5160 			goto out;
5161 
5162 		case SCF_ERROR_NOT_FOUND:
5163 			break;
5164 
5165 		case SCF_ERROR_HANDLE_MISMATCH:
5166 		case SCF_ERROR_INVALID_ARGUMENT:
5167 		case SCF_ERROR_NOT_SET:
5168 		case SCF_ERROR_NOT_BOUND:
5169 		default:
5170 			bad_error("entity_get_pg", scf_error());
5171 		}
5172 
5173 		cbdata.sc_handle = g_hndl;
5174 		cbdata.sc_parent = ent;
5175 		cbdata.sc_service = issvc;
5176 		cbdata.sc_flags = SCI_FORCE;
5177 		cbdata.sc_source_fmri = ient->sc_fmri;
5178 		cbdata.sc_target_fmri = ient->sc_fmri;
5179 
5180 		r = entity_pgroup_import(mpg, &cbdata);
5181 		switch (r) {
5182 		case UU_WALK_NEXT:
5183 			r = 0;
5184 			goto out;
5185 
5186 		case UU_WALK_ERROR:
5187 			if (cbdata.sc_err == EEXIST) {
5188 				warn(emsg_pg_added, ient->sc_fmri,
5189 				    mpg->sc_pgroup_name);
5190 				r = EBUSY;
5191 			} else {
5192 				r = cbdata.sc_err;
5193 			}
5194 			goto out;
5195 
5196 		default:
5197 			bad_error("entity_pgroup_import", r);
5198 		}
5199 	}
5200 
5201 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5202 	internal_pgroup_free(curpg_i);
5203 	switch (r) {
5204 	case 0:
5205 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5206 		break;
5207 
5208 	case ECANCELED:
5209 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5210 		r = EBUSY;
5211 		break;
5212 
5213 	case EPERM:
5214 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5215 		break;
5216 
5217 	case EBUSY:
5218 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5219 		break;
5220 
5221 	case ECONNABORTED:
5222 	case ENOMEM:
5223 	case ENOSPC:
5224 	case EROFS:
5225 	case EACCES:
5226 	case EINVAL:
5227 		break;
5228 
5229 	default:
5230 		bad_error("upgrade_pg", r);
5231 	}
5232 
5233 out:
5234 	internal_pgroup_free(lipg_i);
5235 	return (r);
5236 }
5237 
5238 /*
5239  * Upgrade the properties of ent according to snpl & ient.
5240  *
5241  * Returns
5242  *   0 - success
5243  *   ECONNABORTED - repository connection broken
5244  *   ENOMEM - out of memory
5245  *   ENOSPC - configd is out of resources
5246  *   ECANCELED - ent was deleted
5247  *   ENODEV - entity containing snpl was deleted
5248  *	    - entity containing running was deleted
5249  *   EBADF - imp_snpl is corrupt (error printed)
5250  *	   - ent has corrupt pg (error printed)
5251  *	   - dependent has corrupt pg (error printed)
5252  *	   - dependent target has a corrupt snapshot (error printed)
5253  *   EBUSY - pg was added, changed, or deleted (error printed)
5254  *	   - dependent target was deleted (error printed)
5255  *	   - dependent pg changed (error printed)
5256  *   EINVAL - invalid property group name (error printed)
5257  *	    - invalid property name (error printed)
5258  *	    - invalid value (error printed)
5259  *	    - ient has invalid pgroup or dependent (error printed)
5260  *   EPERM - could not create property group (permission denied) (error printed)
5261  *	   - could not modify property group (permission denied) (error printed)
5262  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5263  *   EROFS - could not create property group (repository read-only)
5264  *	   - couldn't delete, upgrade, or import pg or dependent
5265  *   EACCES - could not create property group (backend access denied)
5266  *	    - couldn't delete, upgrade, or import pg or dependent
5267  *   EEXIST - dependent collision in target service (error printed)
5268  */
5269 static int
5270 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5271     entity_t *ient)
5272 {
5273 	pgroup_t *pg, *rpg;
5274 	int r;
5275 	uu_list_t *pgs = ient->sc_pgroups;
5276 
5277 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5278 
5279 	/* clear sc_sceen for pgs */
5280 	if (uu_list_walk(pgs, clear_int,
5281 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5282 		bad_error("uu_list_walk", uu_error());
5283 
5284 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5285 		switch (scf_error()) {
5286 		case SCF_ERROR_DELETED:
5287 			return (ENODEV);
5288 
5289 		case SCF_ERROR_CONNECTION_BROKEN:
5290 			return (ECONNABORTED);
5291 
5292 		case SCF_ERROR_NOT_SET:
5293 		case SCF_ERROR_NOT_BOUND:
5294 		case SCF_ERROR_HANDLE_MISMATCH:
5295 		default:
5296 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5297 		}
5298 	}
5299 
5300 	for (;;) {
5301 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5302 		if (r == 0)
5303 			break;
5304 		if (r == 1) {
5305 			r = process_old_pg(imp_pg, ient, ent, running);
5306 			switch (r) {
5307 			case 0:
5308 				break;
5309 
5310 			case ECONNABORTED:
5311 			case ENOMEM:
5312 			case ENOSPC:
5313 			case ECANCELED:
5314 			case ENODEV:
5315 			case EPERM:
5316 			case EROFS:
5317 			case EACCES:
5318 			case EBADF:
5319 			case EBUSY:
5320 			case EINVAL:
5321 			case EEXIST:
5322 				return (r);
5323 
5324 			default:
5325 				bad_error("process_old_pg", r);
5326 			}
5327 			continue;
5328 		}
5329 		if (r != -1)
5330 			bad_error("scf_iter_next_pg", r);
5331 
5332 		switch (scf_error()) {
5333 		case SCF_ERROR_DELETED:
5334 			return (ENODEV);
5335 
5336 		case SCF_ERROR_CONNECTION_BROKEN:
5337 			return (ECONNABORTED);
5338 
5339 		case SCF_ERROR_HANDLE_MISMATCH:
5340 		case SCF_ERROR_NOT_BOUND:
5341 		case SCF_ERROR_NOT_SET:
5342 		case SCF_ERROR_INVALID_ARGUMENT:
5343 		default:
5344 			bad_error("scf_iter_next_pg", scf_error());
5345 		}
5346 	}
5347 
5348 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5349 		if (pg->sc_pgroup_seen)
5350 			continue;
5351 
5352 		/* pg is new */
5353 
5354 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5355 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5356 			    ent);
5357 			switch (r) {
5358 			case 0:
5359 				break;
5360 
5361 			case ECONNABORTED:
5362 			case ENOMEM:
5363 			case ENOSPC:
5364 			case ECANCELED:
5365 			case ENODEV:
5366 			case EBADF:
5367 			case EBUSY:
5368 			case EINVAL:
5369 			case EPERM:
5370 			case EROFS:
5371 			case EACCES:
5372 			case EEXIST:
5373 				return (r);
5374 
5375 			default:
5376 				bad_error("upgrade_dependents", r);
5377 			}
5378 			continue;
5379 		}
5380 
5381 		if (running != NULL)
5382 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
5383 			    imp_pg);
5384 		else
5385 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
5386 			    imp_pg);
5387 		if (r != 0) {
5388 			scf_callback_t cbdata;
5389 
5390 			switch (scf_error()) {
5391 			case SCF_ERROR_NOT_FOUND:
5392 				break;
5393 
5394 			case SCF_ERROR_CONNECTION_BROKEN:
5395 				return (scferror2errno(scf_error()));
5396 
5397 			case SCF_ERROR_DELETED:
5398 				if (running != NULL)
5399 					return (ENODEV);
5400 				else
5401 					return (scferror2errno(scf_error()));
5402 
5403 			case SCF_ERROR_INVALID_ARGUMENT:
5404 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
5405 				    pg->sc_pgroup_name);
5406 				return (EINVAL);
5407 
5408 			case SCF_ERROR_NOT_SET:
5409 			case SCF_ERROR_HANDLE_MISMATCH:
5410 			case SCF_ERROR_NOT_BOUND:
5411 			default:
5412 				bad_error("entity_get_pg", scf_error());
5413 			}
5414 
5415 			/* User doesn't have pg, so import it. */
5416 
5417 			cbdata.sc_handle = g_hndl;
5418 			cbdata.sc_parent = ent;
5419 			cbdata.sc_service = issvc;
5420 			cbdata.sc_flags = SCI_FORCE;
5421 			cbdata.sc_source_fmri = ient->sc_fmri;
5422 			cbdata.sc_target_fmri = ient->sc_fmri;
5423 
5424 			r = entity_pgroup_import(pg, &cbdata);
5425 			switch (r) {
5426 			case UU_WALK_NEXT:
5427 				ient->sc_import_state = IMPORT_PROP_BEGUN;
5428 				continue;
5429 
5430 			case UU_WALK_ERROR:
5431 				if (cbdata.sc_err == EEXIST) {
5432 					warn(emsg_pg_added, ient->sc_fmri,
5433 					    pg->sc_pgroup_name);
5434 					return (EBUSY);
5435 				}
5436 				return (cbdata.sc_err);
5437 
5438 			default:
5439 				bad_error("entity_pgroup_import", r);
5440 			}
5441 		}
5442 
5443 		/* report differences between pg & current */
5444 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
5445 		switch (r) {
5446 		case 0:
5447 			break;
5448 
5449 		case ECANCELED:
5450 			warn(emsg_pg_deleted, ient->sc_fmri,
5451 			    pg->sc_pgroup_name);
5452 			return (EBUSY);
5453 
5454 		case ECONNABORTED:
5455 		case EBADF:
5456 		case ENOMEM:
5457 		case EACCES:
5458 			return (r);
5459 
5460 		default:
5461 			bad_error("load_pg", r);
5462 		}
5463 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
5464 		internal_pgroup_free(rpg);
5465 		rpg = NULL;
5466 	}
5467 
5468 	return (0);
5469 }
5470 
5471 /*
5472  * Import an instance.  If it doesn't exist, create it.  If it has
5473  * a last-import snapshot, upgrade its properties.  Finish by updating its
5474  * last-import snapshot.  If it doesn't have a last-import snapshot then it
5475  * could have been created for a dependent tag in another manifest.  Import the
5476  * new properties.  If there's a conflict, don't override, like now?
5477  *
5478  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
5479  * lcbdata->sc_err to
5480  *   ECONNABORTED - repository connection broken
5481  *   ENOMEM - out of memory
5482  *   ENOSPC - svc.configd is out of resources
5483  *   EEXIST - dependency collision in dependent service (error printed)
5484  *   EPERM - couldn't create temporary instance (permission denied)
5485  *	   - couldn't import into temporary instance (permission denied)
5486  *	   - couldn't take snapshot (permission denied)
5487  *	   - couldn't upgrade properties (permission denied)
5488  *	   - couldn't import properties (permission denied)
5489  *	   - couldn't import dependents (permission denied)
5490  *   EROFS - couldn't create temporary instance (repository read-only)
5491  *	   - couldn't import into temporary instance (repository read-only)
5492  *	   - couldn't upgrade properties (repository read-only)
5493  *	   - couldn't import properties (repository read-only)
5494  *	   - couldn't import dependents (repository read-only)
5495  *   EACCES - couldn't create temporary instance (backend access denied)
5496  *	    - couldn't import into temporary instance (backend access denied)
5497  *	    - couldn't upgrade properties (backend access denied)
5498  *	    - couldn't import properties (backend access denied)
5499  *	    - couldn't import dependents (backend access denied)
5500  *   EINVAL - invalid instance name (error printed)
5501  *	    - invalid pgroup_t's (error printed)
5502  *	    - invalid dependents (error printed)
5503  *   EBUSY - temporary service deleted (error printed)
5504  *	   - temporary instance deleted (error printed)
5505  *	   - temporary instance changed (error printed)
5506  *	   - temporary instance already exists (error printed)
5507  *	   - instance deleted (error printed)
5508  *   EBADF - instance has corrupt last-import snapshot (error printed)
5509  *	   - instance is corrupt (error printed)
5510  *	   - dependent has corrupt pg (error printed)
5511  *	   - dependent target has a corrupt snapshot (error printed)
5512  *   -1 - unknown libscf error (error printed)
5513  */
5514 static int
5515 lscf_instance_import(void *v, void *pvt)
5516 {
5517 	entity_t *inst = v;
5518 	scf_callback_t ctx;
5519 	scf_callback_t *lcbdata = pvt;
5520 	scf_service_t *rsvc = lcbdata->sc_parent;
5521 	int r;
5522 	scf_snaplevel_t *running;
5523 	int flags = lcbdata->sc_flags;
5524 
5525 	const char * const emsg_tdel =
5526 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
5527 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
5528 	    "changed unexpectedly.\n");
5529 	const char * const emsg_del = gettext("%s changed unexpectedly "
5530 	    "(instance \"%s\" was deleted.)\n");
5531 	const char * const emsg_badsnap = gettext(
5532 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
5533 
5534 	/*
5535 	 * prepare last-import snapshot:
5536 	 * create temporary instance (service was precreated)
5537 	 * populate with properties from bundle
5538 	 * take snapshot
5539 	 */
5540 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
5541 		switch (scf_error()) {
5542 		case SCF_ERROR_CONNECTION_BROKEN:
5543 		case SCF_ERROR_NO_RESOURCES:
5544 		case SCF_ERROR_BACKEND_READONLY:
5545 		case SCF_ERROR_BACKEND_ACCESS:
5546 			return (stash_scferror(lcbdata));
5547 
5548 		case SCF_ERROR_EXISTS:
5549 			warn(gettext("Temporary service svc:/%s "
5550 			    "changed unexpectedly (instance \"%s\" added).\n"),
5551 			    imp_tsname, inst->sc_name);
5552 			lcbdata->sc_err = EBUSY;
5553 			return (UU_WALK_ERROR);
5554 
5555 		case SCF_ERROR_DELETED:
5556 			warn(gettext("Temporary service svc:/%s "
5557 			    "was deleted unexpectedly.\n"), imp_tsname);
5558 			lcbdata->sc_err = EBUSY;
5559 			return (UU_WALK_ERROR);
5560 
5561 		case SCF_ERROR_INVALID_ARGUMENT:
5562 			warn(gettext("Invalid instance name \"%s\".\n"),
5563 			    inst->sc_name);
5564 			return (stash_scferror(lcbdata));
5565 
5566 		case SCF_ERROR_PERMISSION_DENIED:
5567 			warn(gettext("Could not create temporary instance "
5568 			    "\"%s\" in svc:/%s (permission denied).\n"),
5569 			    inst->sc_name, imp_tsname);
5570 			return (stash_scferror(lcbdata));
5571 
5572 		case SCF_ERROR_HANDLE_MISMATCH:
5573 		case SCF_ERROR_NOT_BOUND:
5574 		case SCF_ERROR_NOT_SET:
5575 		default:
5576 			bad_error("scf_service_add_instance", scf_error());
5577 		}
5578 	}
5579 
5580 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5581 	    inst->sc_name);
5582 	if (r < 0)
5583 		bad_error("snprintf", errno);
5584 
5585 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
5586 	    lcbdata->sc_flags | SCI_NOENABLED);
5587 	switch (r) {
5588 	case 0:
5589 		break;
5590 
5591 	case ECANCELED:
5592 		warn(emsg_tdel, imp_tsname, inst->sc_name);
5593 		lcbdata->sc_err = EBUSY;
5594 		r = UU_WALK_ERROR;
5595 		goto deltemp;
5596 
5597 	case EEXIST:
5598 		warn(emsg_tchg, imp_tsname, inst->sc_name);
5599 		lcbdata->sc_err = EBUSY;
5600 		r = UU_WALK_ERROR;
5601 		goto deltemp;
5602 
5603 	case ECONNABORTED:
5604 		goto connaborted;
5605 
5606 	case ENOMEM:
5607 	case ENOSPC:
5608 	case EPERM:
5609 	case EROFS:
5610 	case EACCES:
5611 	case EINVAL:
5612 	case EBUSY:
5613 		lcbdata->sc_err = r;
5614 		r = UU_WALK_ERROR;
5615 		goto deltemp;
5616 
5617 	default:
5618 		bad_error("lscf_import_instance_pgs", r);
5619 	}
5620 
5621 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5622 	    inst->sc_name);
5623 	if (r < 0)
5624 		bad_error("snprintf", errno);
5625 
5626 	ctx.sc_handle = lcbdata->sc_handle;
5627 	ctx.sc_parent = imp_tinst;
5628 	ctx.sc_service = 0;
5629 	ctx.sc_source_fmri = inst->sc_fmri;
5630 	ctx.sc_target_fmri = imp_str;
5631 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
5632 	    UU_DEFAULT) != 0) {
5633 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5634 			bad_error("uu_list_walk", uu_error());
5635 
5636 		switch (ctx.sc_err) {
5637 		case ECONNABORTED:
5638 			goto connaborted;
5639 
5640 		case ECANCELED:
5641 			warn(emsg_tdel, imp_tsname, inst->sc_name);
5642 			lcbdata->sc_err = EBUSY;
5643 			break;
5644 
5645 		case EEXIST:
5646 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5647 			lcbdata->sc_err = EBUSY;
5648 			break;
5649 
5650 		default:
5651 			lcbdata->sc_err = ctx.sc_err;
5652 		}
5653 		r = UU_WALK_ERROR;
5654 		goto deltemp;
5655 	}
5656 
5657 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
5658 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
5659 		switch (scf_error()) {
5660 		case SCF_ERROR_CONNECTION_BROKEN:
5661 			goto connaborted;
5662 
5663 		case SCF_ERROR_NO_RESOURCES:
5664 			r = stash_scferror(lcbdata);
5665 			goto deltemp;
5666 
5667 		case SCF_ERROR_EXISTS:
5668 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5669 			lcbdata->sc_err = EBUSY;
5670 			r = UU_WALK_ERROR;
5671 			goto deltemp;
5672 
5673 		case SCF_ERROR_PERMISSION_DENIED:
5674 			warn(gettext("Could not take \"%s\" snapshot of %s "
5675 			    "(permission denied).\n"), snap_lastimport,
5676 			    imp_str);
5677 			r = stash_scferror(lcbdata);
5678 			goto deltemp;
5679 
5680 		default:
5681 			scfwarn();
5682 			lcbdata->sc_err = -1;
5683 			r = UU_WALK_ERROR;
5684 			goto deltemp;
5685 
5686 		case SCF_ERROR_HANDLE_MISMATCH:
5687 		case SCF_ERROR_INVALID_ARGUMENT:
5688 		case SCF_ERROR_NOT_SET:
5689 			bad_error("_scf_snapshot_take_new_named", scf_error());
5690 		}
5691 	}
5692 
5693 	if (lcbdata->sc_flags & SCI_FRESH)
5694 		goto fresh;
5695 
5696 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
5697 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
5698 		    imp_lisnap) != 0) {
5699 			switch (scf_error()) {
5700 			case SCF_ERROR_DELETED:
5701 				warn(emsg_del, inst->sc_parent->sc_fmri,
5702 				    inst->sc_name);
5703 				lcbdata->sc_err = EBUSY;
5704 				r = UU_WALK_ERROR;
5705 				goto deltemp;
5706 
5707 			case SCF_ERROR_NOT_FOUND:
5708 				flags |= SCI_FORCE;
5709 				goto nosnap;
5710 
5711 			case SCF_ERROR_CONNECTION_BROKEN:
5712 				goto connaborted;
5713 
5714 			case SCF_ERROR_INVALID_ARGUMENT:
5715 			case SCF_ERROR_HANDLE_MISMATCH:
5716 			case SCF_ERROR_NOT_BOUND:
5717 			case SCF_ERROR_NOT_SET:
5718 			default:
5719 				bad_error("scf_instance_get_snapshot",
5720 				    scf_error());
5721 			}
5722 		}
5723 
5724 		/* upgrade */
5725 
5726 		/*
5727 		 * compare new properties with last-import properties
5728 		 * upgrade current properties
5729 		 */
5730 		/* clear sc_sceen for pgs */
5731 		if (uu_list_walk(inst->sc_pgroups, clear_int,
5732 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
5733 		    0)
5734 			bad_error("uu_list_walk", uu_error());
5735 
5736 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
5737 		switch (r) {
5738 		case 0:
5739 			break;
5740 
5741 		case ECONNABORTED:
5742 			goto connaborted;
5743 
5744 		case ECANCELED:
5745 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5746 			lcbdata->sc_err = EBUSY;
5747 			r = UU_WALK_ERROR;
5748 			goto deltemp;
5749 
5750 		case ENOENT:
5751 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
5752 			lcbdata->sc_err = EBADF;
5753 			r = UU_WALK_ERROR;
5754 			goto deltemp;
5755 
5756 		default:
5757 			bad_error("get_snaplevel", r);
5758 		}
5759 
5760 		if (scf_instance_get_snapshot(imp_inst, snap_running,
5761 		    imp_rsnap) != 0) {
5762 			switch (scf_error()) {
5763 			case SCF_ERROR_DELETED:
5764 				warn(emsg_del, inst->sc_parent->sc_fmri,
5765 				    inst->sc_name);
5766 				lcbdata->sc_err = EBUSY;
5767 				r = UU_WALK_ERROR;
5768 				goto deltemp;
5769 
5770 			case SCF_ERROR_NOT_FOUND:
5771 				break;
5772 
5773 			case SCF_ERROR_CONNECTION_BROKEN:
5774 				goto connaborted;
5775 
5776 			case SCF_ERROR_INVALID_ARGUMENT:
5777 			case SCF_ERROR_HANDLE_MISMATCH:
5778 			case SCF_ERROR_NOT_BOUND:
5779 			case SCF_ERROR_NOT_SET:
5780 			default:
5781 				bad_error("scf_instance_get_snapshot",
5782 				    scf_error());
5783 			}
5784 
5785 			running = NULL;
5786 		} else {
5787 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
5788 			switch (r) {
5789 			case 0:
5790 				running = imp_rsnpl;
5791 				break;
5792 
5793 			case ECONNABORTED:
5794 				goto connaborted;
5795 
5796 			case ECANCELED:
5797 				warn(emsg_del, inst->sc_parent->sc_fmri,
5798 				    inst->sc_name);
5799 				lcbdata->sc_err = EBUSY;
5800 				r = UU_WALK_ERROR;
5801 				goto deltemp;
5802 
5803 			case ENOENT:
5804 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
5805 				lcbdata->sc_err = EBADF;
5806 				r = UU_WALK_ERROR;
5807 				goto deltemp;
5808 
5809 			default:
5810 				bad_error("get_snaplevel", r);
5811 			}
5812 		}
5813 
5814 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
5815 		switch (r) {
5816 		case 0:
5817 			break;
5818 
5819 		case ECANCELED:
5820 		case ENODEV:
5821 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5822 			lcbdata->sc_err = EBUSY;
5823 			r = UU_WALK_ERROR;
5824 			goto deltemp;
5825 
5826 		case ECONNABORTED:
5827 			goto connaborted;
5828 
5829 		case ENOMEM:
5830 		case ENOSPC:
5831 		case EBADF:
5832 		case EBUSY:
5833 		case EINVAL:
5834 		case EPERM:
5835 		case EROFS:
5836 		case EACCES:
5837 		case EEXIST:
5838 			lcbdata->sc_err = r;
5839 			r = UU_WALK_ERROR;
5840 			goto deltemp;
5841 
5842 		default:
5843 			bad_error("upgrade_props", r);
5844 		}
5845 
5846 		inst->sc_import_state = IMPORT_PROP_DONE;
5847 	} else {
5848 		switch (scf_error()) {
5849 		case SCF_ERROR_CONNECTION_BROKEN:
5850 			goto connaborted;
5851 
5852 		case SCF_ERROR_NOT_FOUND:
5853 			break;
5854 
5855 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
5856 		case SCF_ERROR_HANDLE_MISMATCH:
5857 		case SCF_ERROR_NOT_BOUND:
5858 		case SCF_ERROR_NOT_SET:
5859 		default:
5860 			bad_error("scf_service_get_instance", scf_error());
5861 		}
5862 
5863 fresh:
5864 		/* create instance */
5865 		if (scf_service_add_instance(rsvc, inst->sc_name,
5866 		    imp_inst) != 0) {
5867 			switch (scf_error()) {
5868 			case SCF_ERROR_CONNECTION_BROKEN:
5869 				goto connaborted;
5870 
5871 			case SCF_ERROR_NO_RESOURCES:
5872 			case SCF_ERROR_BACKEND_READONLY:
5873 			case SCF_ERROR_BACKEND_ACCESS:
5874 				r = stash_scferror(lcbdata);
5875 				goto deltemp;
5876 
5877 			case SCF_ERROR_EXISTS:
5878 				warn(gettext("%s changed unexpectedly "
5879 				    "(instance \"%s\" added).\n"),
5880 				    inst->sc_parent->sc_fmri, inst->sc_name);
5881 				lcbdata->sc_err = EBUSY;
5882 				r = UU_WALK_ERROR;
5883 				goto deltemp;
5884 
5885 			case SCF_ERROR_PERMISSION_DENIED:
5886 				warn(gettext("Could not create \"%s\" instance "
5887 				    "in %s (permission denied).\n"),
5888 				    inst->sc_name, inst->sc_parent->sc_fmri);
5889 				r = stash_scferror(lcbdata);
5890 				goto deltemp;
5891 
5892 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
5893 			case SCF_ERROR_HANDLE_MISMATCH:
5894 			case SCF_ERROR_NOT_BOUND:
5895 			case SCF_ERROR_NOT_SET:
5896 			default:
5897 				bad_error("scf_service_add_instance",
5898 				    scf_error());
5899 			}
5900 		}
5901 
5902 nosnap:
5903 		/*
5904 		 * Create a last-import snapshot to serve as an attachment
5905 		 * point for the real one from the temporary instance.  Since
5906 		 * the contents is irrelevant, take it now, while the instance
5907 		 * is empty, to minimize svc.configd's work.
5908 		 */
5909 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
5910 		    imp_lisnap) != 0) {
5911 			switch (scf_error()) {
5912 			case SCF_ERROR_CONNECTION_BROKEN:
5913 				goto connaborted;
5914 
5915 			case SCF_ERROR_NO_RESOURCES:
5916 				r = stash_scferror(lcbdata);
5917 				goto deltemp;
5918 
5919 			case SCF_ERROR_EXISTS:
5920 				warn(gettext("%s changed unexpectedly "
5921 				    "(snapshot \"%s\" added).\n"),
5922 				    inst->sc_fmri, snap_lastimport);
5923 				lcbdata->sc_err = EBUSY;
5924 				r = UU_WALK_ERROR;
5925 				goto deltemp;
5926 
5927 			case SCF_ERROR_PERMISSION_DENIED:
5928 				warn(gettext("Could not take \"%s\" snapshot "
5929 				    "of %s (permission denied).\n"),
5930 				    snap_lastimport, inst->sc_fmri);
5931 				r = stash_scferror(lcbdata);
5932 				goto deltemp;
5933 
5934 			default:
5935 				scfwarn();
5936 				lcbdata->sc_err = -1;
5937 				r = UU_WALK_ERROR;
5938 				goto deltemp;
5939 
5940 			case SCF_ERROR_NOT_SET:
5941 			case SCF_ERROR_INTERNAL:
5942 			case SCF_ERROR_INVALID_ARGUMENT:
5943 			case SCF_ERROR_HANDLE_MISMATCH:
5944 				bad_error("_scf_snapshot_take_new",
5945 				    scf_error());
5946 			}
5947 		}
5948 
5949 		if (li_only)
5950 			goto lionly;
5951 
5952 		inst->sc_import_state = IMPORT_PROP_BEGUN;
5953 
5954 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
5955 		    flags);
5956 		switch (r) {
5957 		case 0:
5958 			break;
5959 
5960 		case ECONNABORTED:
5961 			goto connaborted;
5962 
5963 		case ECANCELED:
5964 			warn(gettext("%s changed unexpectedly "
5965 			    "(instance \"%s\" deleted).\n"),
5966 			    inst->sc_parent->sc_fmri, inst->sc_name);
5967 			lcbdata->sc_err = EBUSY;
5968 			r = UU_WALK_ERROR;
5969 			goto deltemp;
5970 
5971 		case EEXIST:
5972 			warn(gettext("%s changed unexpectedly "
5973 			    "(property group added).\n"), inst->sc_fmri);
5974 			lcbdata->sc_err = EBUSY;
5975 			r = UU_WALK_ERROR;
5976 			goto deltemp;
5977 
5978 		default:
5979 			lcbdata->sc_err = r;
5980 			r = UU_WALK_ERROR;
5981 			goto deltemp;
5982 
5983 		case EINVAL:	/* caught above */
5984 			bad_error("lscf_import_instance_pgs", r);
5985 		}
5986 
5987 		ctx.sc_parent = imp_inst;
5988 		ctx.sc_service = 0;
5989 		ctx.sc_trans = NULL;
5990 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
5991 		    &ctx, UU_DEFAULT) != 0) {
5992 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5993 				bad_error("uu_list_walk", uu_error());
5994 
5995 			if (ctx.sc_err == ECONNABORTED)
5996 				goto connaborted;
5997 			lcbdata->sc_err = ctx.sc_err;
5998 			r = UU_WALK_ERROR;
5999 			goto deltemp;
6000 		}
6001 
6002 		inst->sc_import_state = IMPORT_PROP_DONE;
6003 
6004 		if (g_verbose)
6005 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6006 			    snap_initial, inst->sc_fmri);
6007 		r = take_snap(imp_inst, snap_initial, imp_snap);
6008 		switch (r) {
6009 		case 0:
6010 			break;
6011 
6012 		case ECONNABORTED:
6013 			goto connaborted;
6014 
6015 		case ENOSPC:
6016 		case -1:
6017 			lcbdata->sc_err = r;
6018 			r = UU_WALK_ERROR;
6019 			goto deltemp;
6020 
6021 		case ECANCELED:
6022 			warn(gettext("%s changed unexpectedly "
6023 			    "(instance %s deleted).\n"),
6024 			    inst->sc_parent->sc_fmri, inst->sc_name);
6025 			lcbdata->sc_err = r;
6026 			r = UU_WALK_ERROR;
6027 			goto deltemp;
6028 
6029 		case EPERM:
6030 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6031 			lcbdata->sc_err = r;
6032 			r = UU_WALK_ERROR;
6033 			goto deltemp;
6034 
6035 		default:
6036 			bad_error("take_snap", r);
6037 		}
6038 	}
6039 
6040 lionly:
6041 	if (lcbdata->sc_flags & SCI_NOSNAP)
6042 		goto deltemp;
6043 
6044 	/* transfer snapshot from temporary instance */
6045 	if (g_verbose)
6046 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6047 		    snap_lastimport, inst->sc_fmri);
6048 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6049 		switch (scf_error()) {
6050 		case SCF_ERROR_CONNECTION_BROKEN:
6051 			goto connaborted;
6052 
6053 		case SCF_ERROR_NO_RESOURCES:
6054 			r = stash_scferror(lcbdata);
6055 			goto deltemp;
6056 
6057 		case SCF_ERROR_PERMISSION_DENIED:
6058 			warn(gettext("Could not take \"%s\" snapshot for %s "
6059 			    "(permission denied).\n"), snap_lastimport,
6060 			    inst->sc_fmri);
6061 			r = stash_scferror(lcbdata);
6062 			goto deltemp;
6063 
6064 		case SCF_ERROR_NOT_SET:
6065 		case SCF_ERROR_HANDLE_MISMATCH:
6066 		default:
6067 			bad_error("_scf_snapshot_attach", scf_error());
6068 		}
6069 	}
6070 
6071 	inst->sc_import_state = IMPORT_COMPLETE;
6072 
6073 	r = UU_WALK_NEXT;
6074 
6075 deltemp:
6076 	/* delete temporary instance */
6077 	if (scf_instance_delete(imp_tinst) != 0) {
6078 		switch (scf_error()) {
6079 		case SCF_ERROR_DELETED:
6080 			break;
6081 
6082 		case SCF_ERROR_CONNECTION_BROKEN:
6083 			goto connaborted;
6084 
6085 		case SCF_ERROR_NOT_SET:
6086 		case SCF_ERROR_NOT_BOUND:
6087 		default:
6088 			bad_error("scf_instance_delete", scf_error());
6089 		}
6090 	}
6091 
6092 	return (r);
6093 
6094 connaborted:
6095 	warn(gettext("Could not delete svc:/%s:%s "
6096 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6097 	lcbdata->sc_err = ECONNABORTED;
6098 	return (UU_WALK_ERROR);
6099 }
6100 
6101 /*
6102  * If the service is missing, create it, import its properties, and import the
6103  * instances.  Since the service is brand new, it should be empty, and if we
6104  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6105  *
6106  * If the service exists, we want to upgrade its properties and import the
6107  * instances.  Upgrade requires a last-import snapshot, though, which are
6108  * children of instances, so first we'll have to go through the instances
6109  * looking for a last-import snapshot.  If we don't find one then we'll just
6110  * override-import the service properties (but don't delete existing
6111  * properties: another service might have declared us as a dependent).  Before
6112  * we change anything, though, we want to take the previous snapshots.  We
6113  * also give lscf_instance_import() a leg up on taking last-import snapshots
6114  * by importing the manifest's service properties into a temporary service.
6115  *
6116  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6117  * sets lcbdata->sc_err to
6118  *   ECONNABORTED - repository connection broken
6119  *   ENOMEM - out of memory
6120  *   ENOSPC - svc.configd is out of resources
6121  *   EPERM - couldn't create temporary service (error printed)
6122  *	   - couldn't import into temp service (error printed)
6123  *	   - couldn't create service (error printed)
6124  *	   - couldn't import dependent (error printed)
6125  *	   - couldn't take snapshot (error printed)
6126  *	   - couldn't create instance (error printed)
6127  *	   - couldn't create, modify, or delete pg (error printed)
6128  *	   - couldn't create, modify, or delete dependent (error printed)
6129  *	   - couldn't import instance (error printed)
6130  *   EROFS - couldn't create temporary service (repository read-only)
6131  *	   - couldn't import into temporary service (repository read-only)
6132  *	   - couldn't create service (repository read-only)
6133  *	   - couldn't import dependent (repository read-only)
6134  *	   - couldn't create instance (repository read-only)
6135  *	   - couldn't create, modify, or delete pg or dependent
6136  *	   - couldn't import instance (repository read-only)
6137  *   EACCES - couldn't create temporary service (backend access denied)
6138  *	    - couldn't import into temporary service (backend access denied)
6139  *	    - couldn't create service (backend access denied)
6140  *	    - couldn't import dependent (backend access denied)
6141  *	    - couldn't create instance (backend access denied)
6142  *	    - couldn't create, modify, or delete pg or dependent
6143  *	    - couldn't import instance (backend access denied)
6144  *   EINVAL - service name is invalid (error printed)
6145  *	    - service name is too long (error printed)
6146  *	    - s has invalid pgroup (error printed)
6147  *	    - s has invalid dependent (error printed)
6148  *	    - instance name is invalid (error printed)
6149  *	    - instance entity_t is invalid (error printed)
6150  *   EEXIST - couldn't create temporary service (already exists) (error printed)
6151  *	    - couldn't import dependent (dependency pg already exists) (printed)
6152  *	    - dependency collision in dependent service (error printed)
6153  *   EBUSY - temporary service deleted (error printed)
6154  *	   - property group added to temporary service (error printed)
6155  *	   - new property group changed or was deleted (error printed)
6156  *	   - service was added unexpectedly (error printed)
6157  *	   - service was deleted unexpectedly (error printed)
6158  *	   - property group added to new service (error printed)
6159  *	   - instance added unexpectedly (error printed)
6160  *	   - instance deleted unexpectedly (error printed)
6161  *	   - dependent service deleted unexpectedly (error printed)
6162  *	   - pg was added, changed, or deleted (error printed)
6163  *	   - dependent pg changed (error printed)
6164  *	   - temporary instance added, changed, or deleted (error printed)
6165  *   EBADF - a last-import snapshot is corrupt (error printed)
6166  *	   - the service is corrupt (error printed)
6167  *	   - a dependent is corrupt (error printed)
6168  *	   - an instance is corrupt (error printed)
6169  *	   - an instance has a corrupt last-import snapshot (error printed)
6170  *	   - dependent target has a corrupt snapshot (error printed)
6171  *   -1 - unknown libscf error (error printed)
6172  */
6173 static int
6174 lscf_service_import(void *v, void *pvt)
6175 {
6176 	entity_t *s = v;
6177 	scf_callback_t cbdata;
6178 	scf_callback_t *lcbdata = pvt;
6179 	scf_scope_t *scope = lcbdata->sc_parent;
6180 	entity_t *inst, linst;
6181 	int r;
6182 	int fresh = 0;
6183 	scf_snaplevel_t *running;
6184 	int have_ge;
6185 
6186 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
6187 	    "was deleted unexpectedly.\n");
6188 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6189 	    "changed unexpectedly (property group added).\n");
6190 	const char * const s_deleted =
6191 	    gettext("%s was deleted unexpectedly.\n");
6192 	const char * const i_deleted =
6193 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6194 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6195 	    "is corrupt (missing service snaplevel).\n");
6196 
6197 	/* Validate the service name */
6198 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6199 		switch (scf_error()) {
6200 		case SCF_ERROR_CONNECTION_BROKEN:
6201 			return (stash_scferror(lcbdata));
6202 
6203 		case SCF_ERROR_INVALID_ARGUMENT:
6204 			warn(gettext("\"%s\" is an invalid service name.  "
6205 			    "Cannot import.\n"), s->sc_name);
6206 			return (stash_scferror(lcbdata));
6207 
6208 		case SCF_ERROR_NOT_FOUND:
6209 			break;
6210 
6211 		case SCF_ERROR_HANDLE_MISMATCH:
6212 		case SCF_ERROR_NOT_BOUND:
6213 		case SCF_ERROR_NOT_SET:
6214 		default:
6215 			bad_error("scf_scope_get_service", scf_error());
6216 		}
6217 	}
6218 
6219 	/* create temporary service */
6220 	/*
6221 	 * the size of the buffer was reduced to max_scf_name_len to prevent
6222 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6223 	 * should be restored to its original value (max_scf_name_len +1)
6224 	 */
6225 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6226 	if (r < 0)
6227 		bad_error("snprintf", errno);
6228 	if (r > max_scf_name_len) {
6229 		warn(gettext(
6230 		    "Service name \"%s\" is too long.  Cannot import.\n"),
6231 		    s->sc_name);
6232 		lcbdata->sc_err = EINVAL;
6233 		return (UU_WALK_ERROR);
6234 	}
6235 
6236 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6237 		switch (scf_error()) {
6238 		case SCF_ERROR_CONNECTION_BROKEN:
6239 		case SCF_ERROR_NO_RESOURCES:
6240 		case SCF_ERROR_BACKEND_READONLY:
6241 		case SCF_ERROR_BACKEND_ACCESS:
6242 			return (stash_scferror(lcbdata));
6243 
6244 		case SCF_ERROR_EXISTS:
6245 			warn(gettext(
6246 			    "Temporary service \"%s\" must be deleted before "
6247 			    "this manifest can be imported.\n"), imp_tsname);
6248 			return (stash_scferror(lcbdata));
6249 
6250 		case SCF_ERROR_PERMISSION_DENIED:
6251 			warn(gettext("Could not create temporary service "
6252 			    "\"%s\" (permission denied).\n"), imp_tsname);
6253 			return (stash_scferror(lcbdata));
6254 
6255 		case SCF_ERROR_INVALID_ARGUMENT:
6256 		case SCF_ERROR_HANDLE_MISMATCH:
6257 		case SCF_ERROR_NOT_BOUND:
6258 		case SCF_ERROR_NOT_SET:
6259 		default:
6260 			bad_error("scf_scope_add_service", scf_error());
6261 		}
6262 	}
6263 
6264 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6265 	if (r < 0)
6266 		bad_error("snprintf", errno);
6267 
6268 	cbdata.sc_handle = lcbdata->sc_handle;
6269 	cbdata.sc_parent = imp_tsvc;
6270 	cbdata.sc_service = 1;
6271 	cbdata.sc_source_fmri = s->sc_fmri;
6272 	cbdata.sc_target_fmri = imp_str;
6273 	cbdata.sc_flags = 0;
6274 
6275 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6276 	    UU_DEFAULT) != 0) {
6277 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6278 			bad_error("uu_list_walk", uu_error());
6279 
6280 		lcbdata->sc_err = cbdata.sc_err;
6281 		switch (cbdata.sc_err) {
6282 		case ECONNABORTED:
6283 			goto connaborted;
6284 
6285 		case ECANCELED:
6286 			warn(ts_deleted, imp_tsname);
6287 			lcbdata->sc_err = EBUSY;
6288 			return (UU_WALK_ERROR);
6289 
6290 		case EEXIST:
6291 			warn(ts_pg_added, imp_tsname);
6292 			lcbdata->sc_err = EBUSY;
6293 			return (UU_WALK_ERROR);
6294 		}
6295 
6296 		r = UU_WALK_ERROR;
6297 		goto deltemp;
6298 	}
6299 
6300 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6301 	    UU_DEFAULT) != 0) {
6302 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6303 			bad_error("uu_list_walk", uu_error());
6304 
6305 		lcbdata->sc_err = cbdata.sc_err;
6306 		switch (cbdata.sc_err) {
6307 		case ECONNABORTED:
6308 			goto connaborted;
6309 
6310 		case ECANCELED:
6311 			warn(ts_deleted, imp_tsname);
6312 			lcbdata->sc_err = EBUSY;
6313 			return (UU_WALK_ERROR);
6314 
6315 		case EEXIST:
6316 			warn(ts_pg_added, imp_tsname);
6317 			lcbdata->sc_err = EBUSY;
6318 			return (UU_WALK_ERROR);
6319 		}
6320 
6321 		r = UU_WALK_ERROR;
6322 		goto deltemp;
6323 	}
6324 
6325 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6326 		switch (scf_error()) {
6327 		case SCF_ERROR_NOT_FOUND:
6328 			break;
6329 
6330 		case SCF_ERROR_CONNECTION_BROKEN:
6331 			goto connaborted;
6332 
6333 		case SCF_ERROR_INVALID_ARGUMENT:
6334 		case SCF_ERROR_HANDLE_MISMATCH:
6335 		case SCF_ERROR_NOT_BOUND:
6336 		case SCF_ERROR_NOT_SET:
6337 		default:
6338 			bad_error("scf_scope_get_service", scf_error());
6339 		}
6340 
6341 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6342 			switch (scf_error()) {
6343 			case SCF_ERROR_CONNECTION_BROKEN:
6344 				goto connaborted;
6345 
6346 			case SCF_ERROR_NO_RESOURCES:
6347 			case SCF_ERROR_BACKEND_READONLY:
6348 			case SCF_ERROR_BACKEND_ACCESS:
6349 				r = stash_scferror(lcbdata);
6350 				goto deltemp;
6351 
6352 			case SCF_ERROR_EXISTS:
6353 				warn(gettext("Scope \"%s\" changed unexpectedly"
6354 				    " (service \"%s\" added).\n"),
6355 				    SCF_SCOPE_LOCAL, s->sc_name);
6356 				lcbdata->sc_err = EBUSY;
6357 				goto deltemp;
6358 
6359 			case SCF_ERROR_PERMISSION_DENIED:
6360 				warn(gettext("Could not create service \"%s\" "
6361 				    "(permission denied).\n"), s->sc_name);
6362 				goto deltemp;
6363 
6364 			case SCF_ERROR_INVALID_ARGUMENT:
6365 			case SCF_ERROR_HANDLE_MISMATCH:
6366 			case SCF_ERROR_NOT_BOUND:
6367 			case SCF_ERROR_NOT_SET:
6368 			default:
6369 				bad_error("scf_scope_add_service", scf_error());
6370 			}
6371 		}
6372 
6373 		s->sc_import_state = IMPORT_PROP_BEGUN;
6374 
6375 		/* import service properties */
6376 		cbdata.sc_handle = lcbdata->sc_handle;
6377 		cbdata.sc_parent = imp_svc;
6378 		cbdata.sc_service = 1;
6379 		cbdata.sc_flags = lcbdata->sc_flags;
6380 		cbdata.sc_source_fmri = s->sc_fmri;
6381 		cbdata.sc_target_fmri = s->sc_fmri;
6382 
6383 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6384 		    &cbdata, UU_DEFAULT) != 0) {
6385 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6386 				bad_error("uu_list_walk", uu_error());
6387 
6388 			lcbdata->sc_err = cbdata.sc_err;
6389 			switch (cbdata.sc_err) {
6390 			case ECONNABORTED:
6391 				goto connaborted;
6392 
6393 			case ECANCELED:
6394 				warn(s_deleted, s->sc_fmri);
6395 				lcbdata->sc_err = EBUSY;
6396 				return (UU_WALK_ERROR);
6397 
6398 			case EEXIST:
6399 				warn(gettext("%s changed unexpectedly "
6400 				    "(property group added).\n"), s->sc_fmri);
6401 				lcbdata->sc_err = EBUSY;
6402 				return (UU_WALK_ERROR);
6403 
6404 			case EINVAL:
6405 				/* caught above */
6406 				bad_error("entity_pgroup_import",
6407 				    cbdata.sc_err);
6408 			}
6409 
6410 			r = UU_WALK_ERROR;
6411 			goto deltemp;
6412 		}
6413 
6414 		cbdata.sc_trans = NULL;
6415 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
6416 		    &cbdata, UU_DEFAULT) != 0) {
6417 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6418 				bad_error("uu_list_walk", uu_error());
6419 
6420 			lcbdata->sc_err = cbdata.sc_err;
6421 			if (cbdata.sc_err == ECONNABORTED)
6422 				goto connaborted;
6423 			r = UU_WALK_ERROR;
6424 			goto deltemp;
6425 		}
6426 
6427 		s->sc_import_state = IMPORT_PROP_DONE;
6428 
6429 		/*
6430 		 * This is a new service, so we can't take previous snapshots
6431 		 * or upgrade service properties.
6432 		 */
6433 		fresh = 1;
6434 		goto instances;
6435 	}
6436 
6437 	/* Clear sc_seen for the instances. */
6438 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
6439 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
6440 		bad_error("uu_list_walk", uu_error());
6441 
6442 	/*
6443 	 * Take previous snapshots for all instances.  Even for ones not
6444 	 * mentioned in the bundle, since we might change their service
6445 	 * properties.
6446 	 */
6447 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6448 		switch (scf_error()) {
6449 		case SCF_ERROR_CONNECTION_BROKEN:
6450 			goto connaborted;
6451 
6452 		case SCF_ERROR_DELETED:
6453 			warn(s_deleted, s->sc_fmri);
6454 			lcbdata->sc_err = EBUSY;
6455 			r = UU_WALK_ERROR;
6456 			goto deltemp;
6457 
6458 		case SCF_ERROR_HANDLE_MISMATCH:
6459 		case SCF_ERROR_NOT_BOUND:
6460 		case SCF_ERROR_NOT_SET:
6461 		default:
6462 			bad_error("scf_iter_service_instances", scf_error());
6463 		}
6464 	}
6465 
6466 	for (;;) {
6467 		r = scf_iter_next_instance(imp_iter, imp_inst);
6468 		if (r == 0)
6469 			break;
6470 		if (r != 1) {
6471 			switch (scf_error()) {
6472 			case SCF_ERROR_DELETED:
6473 				warn(s_deleted, s->sc_fmri);
6474 				lcbdata->sc_err = EBUSY;
6475 				r = UU_WALK_ERROR;
6476 				goto deltemp;
6477 
6478 			case SCF_ERROR_CONNECTION_BROKEN:
6479 				goto connaborted;
6480 
6481 			case SCF_ERROR_NOT_BOUND:
6482 			case SCF_ERROR_HANDLE_MISMATCH:
6483 			case SCF_ERROR_INVALID_ARGUMENT:
6484 			case SCF_ERROR_NOT_SET:
6485 			default:
6486 				bad_error("scf_iter_next_instance",
6487 				    scf_error());
6488 			}
6489 		}
6490 
6491 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
6492 			switch (scf_error()) {
6493 			case SCF_ERROR_DELETED:
6494 				continue;
6495 
6496 			case SCF_ERROR_CONNECTION_BROKEN:
6497 				goto connaborted;
6498 
6499 			case SCF_ERROR_NOT_SET:
6500 			case SCF_ERROR_NOT_BOUND:
6501 			default:
6502 				bad_error("scf_instance_get_name", scf_error());
6503 			}
6504 		}
6505 
6506 		if (g_verbose)
6507 			warn(gettext(
6508 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
6509 			    snap_previous, s->sc_name, imp_str);
6510 
6511 		r = take_snap(imp_inst, snap_previous, imp_snap);
6512 		switch (r) {
6513 		case 0:
6514 			break;
6515 
6516 		case ECANCELED:
6517 			continue;
6518 
6519 		case ECONNABORTED:
6520 			goto connaborted;
6521 
6522 		case EPERM:
6523 			warn(gettext("Could not take \"%s\" snapshot of "
6524 			    "svc:/%s:%s (permission denied).\n"),
6525 			    snap_previous, s->sc_name, imp_str);
6526 			lcbdata->sc_err = r;
6527 			return (UU_WALK_ERROR);
6528 
6529 		case ENOSPC:
6530 		case -1:
6531 			lcbdata->sc_err = r;
6532 			r = UU_WALK_ERROR;
6533 			goto deltemp;
6534 
6535 		default:
6536 			bad_error("take_snap", r);
6537 		}
6538 
6539 		linst.sc_name = imp_str;
6540 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
6541 		    &linst, NULL, NULL);
6542 		if (inst != NULL) {
6543 			inst->sc_import_state = IMPORT_PREVIOUS;
6544 			inst->sc_seen = 1;
6545 		}
6546 	}
6547 
6548 	/*
6549 	 * Create the new instances and take previous snapshots of
6550 	 * them.  This is not necessary, but it maximizes data preservation.
6551 	 */
6552 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
6553 	    inst != NULL;
6554 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
6555 	    inst)) {
6556 		if (inst->sc_seen)
6557 			continue;
6558 
6559 		if (scf_service_add_instance(imp_svc, inst->sc_name,
6560 		    imp_inst) != 0) {
6561 			switch (scf_error()) {
6562 			case SCF_ERROR_CONNECTION_BROKEN:
6563 				goto connaborted;
6564 
6565 			case SCF_ERROR_BACKEND_READONLY:
6566 			case SCF_ERROR_BACKEND_ACCESS:
6567 			case SCF_ERROR_NO_RESOURCES:
6568 				r = stash_scferror(lcbdata);
6569 				goto deltemp;
6570 
6571 			case SCF_ERROR_EXISTS:
6572 				warn(gettext("%s changed unexpectedly "
6573 				    "(instance \"%s\" added).\n"), s->sc_fmri,
6574 				    inst->sc_name);
6575 				lcbdata->sc_err = EBUSY;
6576 				r = UU_WALK_ERROR;
6577 				goto deltemp;
6578 
6579 			case SCF_ERROR_INVALID_ARGUMENT:
6580 				warn(gettext("Service \"%s\" has instance with "
6581 				    "invalid name \"%s\".\n"), s->sc_name,
6582 				    inst->sc_name);
6583 				r = stash_scferror(lcbdata);
6584 				goto deltemp;
6585 
6586 			case SCF_ERROR_PERMISSION_DENIED:
6587 				warn(gettext("Could not create instance \"%s\" "
6588 				    "in %s (permission denied).\n"),
6589 				    inst->sc_name, s->sc_fmri);
6590 				r = stash_scferror(lcbdata);
6591 				goto deltemp;
6592 
6593 			case SCF_ERROR_HANDLE_MISMATCH:
6594 			case SCF_ERROR_NOT_BOUND:
6595 			case SCF_ERROR_NOT_SET:
6596 			default:
6597 				bad_error("scf_service_add_instance",
6598 				    scf_error());
6599 			}
6600 		}
6601 
6602 		if (g_verbose)
6603 			warn(gettext("Taking \"%s\" snapshot for "
6604 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
6605 		r = take_snap(imp_inst, snap_previous, imp_snap);
6606 		switch (r) {
6607 		case 0:
6608 			break;
6609 
6610 		case ECANCELED:
6611 			warn(i_deleted, s->sc_fmri, inst->sc_name);
6612 			lcbdata->sc_err = EBUSY;
6613 			r = UU_WALK_ERROR;
6614 			goto deltemp;
6615 
6616 		case ECONNABORTED:
6617 			goto connaborted;
6618 
6619 		case EPERM:
6620 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
6621 			lcbdata->sc_err = r;
6622 			r = UU_WALK_ERROR;
6623 			goto deltemp;
6624 
6625 		case ENOSPC:
6626 		case -1:
6627 			r = UU_WALK_ERROR;
6628 			goto deltemp;
6629 
6630 		default:
6631 			bad_error("take_snap", r);
6632 		}
6633 	}
6634 
6635 	s->sc_import_state = IMPORT_PREVIOUS;
6636 
6637 	/*
6638 	 * Upgrade service properties, if we can find a last-import snapshot.
6639 	 * Any will do because we don't support different service properties
6640 	 * in different manifests, so all snaplevels of the service in all of
6641 	 * the last-import snapshots of the instances should be the same.
6642 	 */
6643 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6644 		switch (scf_error()) {
6645 		case SCF_ERROR_CONNECTION_BROKEN:
6646 			goto connaborted;
6647 
6648 		case SCF_ERROR_DELETED:
6649 			warn(s_deleted, s->sc_fmri);
6650 			lcbdata->sc_err = EBUSY;
6651 			r = UU_WALK_ERROR;
6652 			goto deltemp;
6653 
6654 		case SCF_ERROR_HANDLE_MISMATCH:
6655 		case SCF_ERROR_NOT_BOUND:
6656 		case SCF_ERROR_NOT_SET:
6657 		default:
6658 			bad_error("scf_iter_service_instances", scf_error());
6659 		}
6660 	}
6661 
6662 	have_ge = 0;
6663 	li_only = 0;
6664 
6665 	for (;;) {
6666 		r = scf_iter_next_instance(imp_iter, imp_inst);
6667 		if (r == -1) {
6668 			switch (scf_error()) {
6669 			case SCF_ERROR_DELETED:
6670 				warn(s_deleted, s->sc_fmri);
6671 				lcbdata->sc_err = EBUSY;
6672 				r = UU_WALK_ERROR;
6673 				goto deltemp;
6674 
6675 			case SCF_ERROR_CONNECTION_BROKEN:
6676 				goto connaborted;
6677 
6678 			case SCF_ERROR_NOT_BOUND:
6679 			case SCF_ERROR_HANDLE_MISMATCH:
6680 			case SCF_ERROR_INVALID_ARGUMENT:
6681 			case SCF_ERROR_NOT_SET:
6682 			default:
6683 				bad_error("scf_iter_next_instance",
6684 				    scf_error());
6685 			}
6686 		}
6687 
6688 		if (r == 0) {
6689 			/*
6690 			 * Didn't find any last-import snapshots.  Override-
6691 			 * import the properties.  Unless one of the instances
6692 			 * has a general/enabled property, in which case we're
6693 			 * probably running a last-import-capable svccfg for
6694 			 * the first time, and we should only take the
6695 			 * last-import snapshot.
6696 			 */
6697 			if (have_ge) {
6698 				li_only = 1;
6699 				no_refresh = 1;
6700 				break;
6701 			}
6702 
6703 			s->sc_import_state = IMPORT_PROP_BEGUN;
6704 
6705 			cbdata.sc_handle = g_hndl;
6706 			cbdata.sc_parent = imp_svc;
6707 			cbdata.sc_service = 1;
6708 			cbdata.sc_flags = SCI_FORCE;
6709 			cbdata.sc_source_fmri = s->sc_fmri;
6710 			cbdata.sc_target_fmri = s->sc_fmri;
6711 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6712 			    &cbdata, UU_DEFAULT) != 0) {
6713 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6714 					bad_error("uu_list_walk", uu_error());
6715 				lcbdata->sc_err = cbdata.sc_err;
6716 				switch (cbdata.sc_err) {
6717 				case ECONNABORTED:
6718 					goto connaborted;
6719 
6720 				case ECANCELED:
6721 					warn(s_deleted, s->sc_fmri);
6722 					lcbdata->sc_err = EBUSY;
6723 					break;
6724 
6725 				case EINVAL:	/* caught above */
6726 				case EEXIST:
6727 					bad_error("entity_pgroup_import",
6728 					    cbdata.sc_err);
6729 				}
6730 
6731 				r = UU_WALK_ERROR;
6732 				goto deltemp;
6733 			}
6734 
6735 			cbdata.sc_trans = NULL;
6736 			if (uu_list_walk(s->sc_dependents,
6737 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
6738 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6739 					bad_error("uu_list_walk", uu_error());
6740 				lcbdata->sc_err = cbdata.sc_err;
6741 				if (cbdata.sc_err == ECONNABORTED)
6742 					goto connaborted;
6743 				r = UU_WALK_ERROR;
6744 				goto deltemp;
6745 			}
6746 			break;
6747 		}
6748 
6749 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6750 		    imp_snap) != 0) {
6751 			switch (scf_error()) {
6752 			case SCF_ERROR_DELETED:
6753 				continue;
6754 
6755 			case SCF_ERROR_NOT_FOUND:
6756 				break;
6757 
6758 			case SCF_ERROR_CONNECTION_BROKEN:
6759 				goto connaborted;
6760 
6761 			case SCF_ERROR_HANDLE_MISMATCH:
6762 			case SCF_ERROR_NOT_BOUND:
6763 			case SCF_ERROR_INVALID_ARGUMENT:
6764 			case SCF_ERROR_NOT_SET:
6765 			default:
6766 				bad_error("scf_instance_get_snapshot",
6767 				    scf_error());
6768 			}
6769 
6770 			if (have_ge)
6771 				continue;
6772 
6773 			/*
6774 			 * Check for a general/enabled property.  This is how
6775 			 * we tell whether to import if there turn out to be
6776 			 * no last-import snapshots.
6777 			 */
6778 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
6779 			    imp_pg) == 0) {
6780 				if (scf_pg_get_property(imp_pg,
6781 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
6782 					have_ge = 1;
6783 				} else {
6784 					switch (scf_error()) {
6785 					case SCF_ERROR_DELETED:
6786 					case SCF_ERROR_NOT_FOUND:
6787 						continue;
6788 
6789 					case SCF_ERROR_INVALID_ARGUMENT:
6790 					case SCF_ERROR_HANDLE_MISMATCH:
6791 					case SCF_ERROR_CONNECTION_BROKEN:
6792 					case SCF_ERROR_NOT_BOUND:
6793 					case SCF_ERROR_NOT_SET:
6794 					default:
6795 						bad_error("scf_pg_get_property",
6796 						    scf_error());
6797 					}
6798 				}
6799 			} else {
6800 				switch (scf_error()) {
6801 				case SCF_ERROR_DELETED:
6802 				case SCF_ERROR_NOT_FOUND:
6803 					continue;
6804 
6805 				case SCF_ERROR_CONNECTION_BROKEN:
6806 					goto connaborted;
6807 
6808 				case SCF_ERROR_NOT_BOUND:
6809 				case SCF_ERROR_NOT_SET:
6810 				case SCF_ERROR_INVALID_ARGUMENT:
6811 				case SCF_ERROR_HANDLE_MISMATCH:
6812 				default:
6813 					bad_error("scf_instance_get_pg",
6814 					    scf_error());
6815 				}
6816 			}
6817 			continue;
6818 		}
6819 
6820 		/* find service snaplevel */
6821 		r = get_snaplevel(imp_snap, 1, imp_snpl);
6822 		switch (r) {
6823 		case 0:
6824 			break;
6825 
6826 		case ECONNABORTED:
6827 			goto connaborted;
6828 
6829 		case ECANCELED:
6830 			continue;
6831 
6832 		case ENOENT:
6833 			if (scf_instance_get_name(imp_inst, imp_str,
6834 			    imp_str_sz) < 0)
6835 				(void) strcpy(imp_str, "?");
6836 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
6837 			lcbdata->sc_err = EBADF;
6838 			r = UU_WALK_ERROR;
6839 			goto deltemp;
6840 
6841 		default:
6842 			bad_error("get_snaplevel", r);
6843 		}
6844 
6845 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6846 		    imp_rsnap) != 0) {
6847 			switch (scf_error()) {
6848 			case SCF_ERROR_DELETED:
6849 				continue;
6850 
6851 			case SCF_ERROR_NOT_FOUND:
6852 				break;
6853 
6854 			case SCF_ERROR_CONNECTION_BROKEN:
6855 				goto connaborted;
6856 
6857 			case SCF_ERROR_INVALID_ARGUMENT:
6858 			case SCF_ERROR_HANDLE_MISMATCH:
6859 			case SCF_ERROR_NOT_BOUND:
6860 			case SCF_ERROR_NOT_SET:
6861 			default:
6862 				bad_error("scf_instance_get_snapshot",
6863 				    scf_error());
6864 			}
6865 			running = NULL;
6866 		} else {
6867 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
6868 			switch (r) {
6869 			case 0:
6870 				running = imp_rsnpl;
6871 				break;
6872 
6873 			case ECONNABORTED:
6874 				goto connaborted;
6875 
6876 			case ECANCELED:
6877 				continue;
6878 
6879 			case ENOENT:
6880 				if (scf_instance_get_name(imp_inst, imp_str,
6881 				    imp_str_sz) < 0)
6882 					(void) strcpy(imp_str, "?");
6883 				warn(badsnap, snap_running, s->sc_name,
6884 				    imp_str);
6885 				lcbdata->sc_err = EBADF;
6886 				r = UU_WALK_ERROR;
6887 				goto deltemp;
6888 
6889 			default:
6890 				bad_error("get_snaplevel", r);
6891 			}
6892 		}
6893 
6894 		if (g_verbose) {
6895 			if (scf_instance_get_name(imp_inst, imp_str,
6896 			    imp_str_sz) < 0)
6897 				(void) strcpy(imp_str, "?");
6898 			warn(gettext("Upgrading properties of %s according to "
6899 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
6900 		}
6901 
6902 		/* upgrade service properties */
6903 		r = upgrade_props(imp_svc, running, imp_snpl, s);
6904 		if (r == 0)
6905 			break;
6906 
6907 		switch (r) {
6908 		case ECONNABORTED:
6909 			goto connaborted;
6910 
6911 		case ECANCELED:
6912 			warn(s_deleted, s->sc_fmri);
6913 			lcbdata->sc_err = EBUSY;
6914 			break;
6915 
6916 		case ENODEV:
6917 			if (scf_instance_get_name(imp_inst, imp_str,
6918 			    imp_str_sz) < 0)
6919 				(void) strcpy(imp_str, "?");
6920 			warn(i_deleted, s->sc_fmri, imp_str);
6921 			lcbdata->sc_err = EBUSY;
6922 			break;
6923 
6924 		default:
6925 			lcbdata->sc_err = r;
6926 		}
6927 
6928 		r = UU_WALK_ERROR;
6929 		goto deltemp;
6930 	}
6931 
6932 	s->sc_import_state = IMPORT_PROP_DONE;
6933 
6934 instances:
6935 	/* import instances */
6936 	cbdata.sc_handle = lcbdata->sc_handle;
6937 	cbdata.sc_parent = imp_svc;
6938 	cbdata.sc_service = 1;
6939 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
6940 	cbdata.sc_general = NULL;
6941 
6942 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
6943 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
6944 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6945 			bad_error("uu_list_walk", uu_error());
6946 
6947 		lcbdata->sc_err = cbdata.sc_err;
6948 		if (cbdata.sc_err == ECONNABORTED)
6949 			goto connaborted;
6950 		r = UU_WALK_ERROR;
6951 		goto deltemp;
6952 	}
6953 
6954 	s->sc_import_state = IMPORT_COMPLETE;
6955 	r = UU_WALK_NEXT;
6956 
6957 deltemp:
6958 	/* delete temporary service */
6959 	if (scf_service_delete(imp_tsvc) != 0) {
6960 		switch (scf_error()) {
6961 		case SCF_ERROR_DELETED:
6962 			break;
6963 
6964 		case SCF_ERROR_CONNECTION_BROKEN:
6965 			goto connaborted;
6966 
6967 		case SCF_ERROR_EXISTS:
6968 			warn(gettext(
6969 			    "Could not delete svc:/%s (instances exist).\n"),
6970 			    imp_tsname);
6971 			break;
6972 
6973 		case SCF_ERROR_NOT_SET:
6974 		case SCF_ERROR_NOT_BOUND:
6975 		default:
6976 			bad_error("scf_service_delete", scf_error());
6977 		}
6978 	}
6979 
6980 	return (r);
6981 
6982 connaborted:
6983 	warn(gettext("Could not delete svc:/%s "
6984 	    "(repository connection broken).\n"), imp_tsname);
6985 	lcbdata->sc_err = ECONNABORTED;
6986 	return (UU_WALK_ERROR);
6987 }
6988 
6989 static const char *
6990 import_progress(int st)
6991 {
6992 	switch (st) {
6993 	case 0:
6994 		return (gettext("not reached."));
6995 
6996 	case IMPORT_PREVIOUS:
6997 		return (gettext("previous snapshot taken."));
6998 
6999 	case IMPORT_PROP_BEGUN:
7000 		return (gettext("some properties imported."));
7001 
7002 	case IMPORT_PROP_DONE:
7003 		return (gettext("properties imported."));
7004 
7005 	case IMPORT_COMPLETE:
7006 		return (gettext("imported."));
7007 
7008 	case IMPORT_REFRESHED:
7009 		return (gettext("refresh requested."));
7010 
7011 	default:
7012 #ifndef NDEBUG
7013 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7014 		    __FILE__, __LINE__, st);
7015 #endif
7016 		abort();
7017 		/* NOTREACHED */
7018 	}
7019 }
7020 
7021 /*
7022  * Returns
7023  *   0 - success
7024  *     - fmri wasn't found (error printed)
7025  *     - entity was deleted (error printed)
7026  *     - backend denied access (error printed)
7027  *   ENOMEM - out of memory (error printed)
7028  *   ECONNABORTED - repository connection broken (error printed)
7029  *   EPERM - permission denied (error printed)
7030  *   -1 - unknown libscf error (error printed)
7031  */
7032 static int
7033 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7034 {
7035 	scf_error_t serr;
7036 	void *ent;
7037 	int issvc;
7038 	int r;
7039 
7040 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7041 	const char *dpt_deleted = gettext("Could not refresh %s "
7042 	    "(dependent \"%s\" of %s) (deleted).\n");
7043 
7044 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7045 	switch (serr) {
7046 	case SCF_ERROR_NONE:
7047 		break;
7048 
7049 	case SCF_ERROR_NO_MEMORY:
7050 		if (name == NULL)
7051 			warn(gettext("Could not refresh %s (out of memory).\n"),
7052 			    fmri);
7053 		else
7054 			warn(gettext("Could not refresh %s "
7055 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7056 			    fmri, name, d_fmri);
7057 		return (ENOMEM);
7058 
7059 	case SCF_ERROR_NOT_FOUND:
7060 		if (name == NULL)
7061 			warn(deleted, fmri);
7062 		else
7063 			warn(dpt_deleted, fmri, name, d_fmri);
7064 		return (0);
7065 
7066 	case SCF_ERROR_INVALID_ARGUMENT:
7067 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7068 	default:
7069 		bad_error("fmri_to_entity", serr);
7070 	}
7071 
7072 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7073 	switch (r) {
7074 	case 0:
7075 		break;
7076 
7077 	case ECONNABORTED:
7078 		if (name != NULL)
7079 			warn(gettext("Could not refresh %s "
7080 			    "(dependent \"%s\" of %s) "
7081 			    "(repository connection broken).\n"), fmri, name,
7082 			    d_fmri);
7083 		return (r);
7084 
7085 	case ECANCELED:
7086 		if (name == NULL)
7087 			warn(deleted, fmri);
7088 		else
7089 			warn(dpt_deleted, fmri, name, d_fmri);
7090 		return (0);
7091 
7092 	case EACCES:
7093 		if (!g_verbose)
7094 			return (0);
7095 		if (name == NULL)
7096 			warn(gettext("Could not refresh %s "
7097 			    "(backend access denied).\n"), fmri);
7098 		else
7099 			warn(gettext("Could not refresh %s "
7100 			    "(dependent \"%s\" of %s) "
7101 			    "(backend access denied).\n"), fmri, name, d_fmri);
7102 		return (0);
7103 
7104 	case EPERM:
7105 		if (name == NULL)
7106 			warn(gettext("Could not refresh %s "
7107 			    "(permission denied).\n"), fmri);
7108 		else
7109 			warn(gettext("Could not refresh %s "
7110 			    "(dependent \"%s\" of %s) "
7111 			    "(permission denied).\n"), fmri, name, d_fmri);
7112 		return (r);
7113 
7114 	case ENOSPC:
7115 		if (name == NULL)
7116 			warn(gettext("Could not refresh %s "
7117 			    "(repository server out of resources).\n"),
7118 			    fmri);
7119 		else
7120 			warn(gettext("Could not refresh %s "
7121 			    "(dependent \"%s\" of %s) "
7122 			    "(repository server out of resources).\n"),
7123 			    fmri, name, d_fmri);
7124 		return (r);
7125 
7126 	case -1:
7127 		scfwarn();
7128 		return (r);
7129 
7130 	default:
7131 		bad_error("refresh_entity", r);
7132 	}
7133 
7134 	if (issvc)
7135 		scf_service_destroy(ent);
7136 	else
7137 		scf_instance_destroy(ent);
7138 
7139 	return (0);
7140 }
7141 
7142 int
7143 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7144 {
7145 	scf_callback_t cbdata;
7146 	int result = 0;
7147 	entity_t *svc, *inst;
7148 	uu_list_t *insts;
7149 	int r;
7150 	pgroup_t *old_dpt;
7151 	void *cookie;
7152 	int annotation_set = 0;
7153 
7154 	const char * const emsg_nomem = gettext("Out of memory.\n");
7155 	const char * const emsg_nores =
7156 	    gettext("svc.configd is out of resources.\n");
7157 
7158 	lscf_prep_hndl();
7159 
7160 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7161 	    max_scf_name_len : max_scf_fmri_len) + 1;
7162 
7163 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7164 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
7165 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7166 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7167 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7168 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7169 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7170 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7171 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7172 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7173 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7174 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7175 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7176 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7177 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7178 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7179 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7180 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7181 	    (imp_str = malloc(imp_str_sz)) == NULL ||
7182 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7183 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7184 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7185 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7186 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7187 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7188 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7189 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7190 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7191 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7192 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7193 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7194 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7195 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7196 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7197 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7198 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7199 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7200 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7201 			warn(emsg_nores);
7202 		else
7203 			warn(emsg_nomem);
7204 		result = -1;
7205 		goto out;
7206 	}
7207 
7208 	r = load_init();
7209 	switch (r) {
7210 	case 0:
7211 		break;
7212 
7213 	case ENOMEM:
7214 		warn(emsg_nomem);
7215 		result = -1;
7216 		goto out;
7217 
7218 	default:
7219 		bad_error("load_init", r);
7220 	}
7221 
7222 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7223 		switch (scf_error()) {
7224 		case SCF_ERROR_CONNECTION_BROKEN:
7225 			warn(gettext("Repository connection broken.\n"));
7226 			repository_teardown();
7227 			result = -1;
7228 			goto out;
7229 
7230 		case SCF_ERROR_NOT_FOUND:
7231 		case SCF_ERROR_INVALID_ARGUMENT:
7232 		case SCF_ERROR_NOT_BOUND:
7233 		case SCF_ERROR_HANDLE_MISMATCH:
7234 		default:
7235 			bad_error("scf_handle_get_scope", scf_error());
7236 		}
7237 	}
7238 
7239 	/* Set up the auditing annotation. */
7240 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7241 		annotation_set = 1;
7242 	} else {
7243 		switch (scf_error()) {
7244 		case SCF_ERROR_CONNECTION_BROKEN:
7245 			warn(gettext("Repository connection broken.\n"));
7246 			repository_teardown();
7247 			result = -1;
7248 			goto out;
7249 
7250 		case SCF_ERROR_INVALID_ARGUMENT:
7251 		case SCF_ERROR_NOT_BOUND:
7252 		case SCF_ERROR_NO_RESOURCES:
7253 		case SCF_ERROR_INTERNAL:
7254 			bad_error("_scf_set_annotation", scf_error());
7255 			/* NOTREACHED */
7256 
7257 		default:
7258 			/*
7259 			 * Do not terminate import because of inability to
7260 			 * generate annotation audit event.
7261 			 */
7262 			warn(gettext("_scf_set_annotation() unexpectedly "
7263 			    "failed with return code of %d\n"), scf_error());
7264 			break;
7265 		}
7266 	}
7267 
7268 	/*
7269 	 * Clear the sc_import_state's of all services & instances so we can
7270 	 * report how far we got if we fail.
7271 	 */
7272 	for (svc = uu_list_first(bndl->sc_bundle_services);
7273 	    svc != NULL;
7274 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7275 		svc->sc_import_state = 0;
7276 
7277 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
7278 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
7279 		    UU_DEFAULT) != 0)
7280 			bad_error("uu_list_walk", uu_error());
7281 	}
7282 
7283 	cbdata.sc_handle = g_hndl;
7284 	cbdata.sc_parent = imp_scope;
7285 	cbdata.sc_flags = flags;
7286 	cbdata.sc_general = NULL;
7287 
7288 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
7289 	    &cbdata, UU_DEFAULT) == 0) {
7290 		/* Success.  Refresh everything. */
7291 
7292 		if (flags & SCI_NOREFRESH || no_refresh) {
7293 			result = 0;
7294 			goto out;
7295 		}
7296 
7297 		for (svc = uu_list_first(bndl->sc_bundle_services);
7298 		    svc != NULL;
7299 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7300 			pgroup_t *dpt;
7301 
7302 			insts = svc->sc_u.sc_service.sc_service_instances;
7303 
7304 			for (inst = uu_list_first(insts);
7305 			    inst != NULL;
7306 			    inst = uu_list_next(insts, inst)) {
7307 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
7308 				switch (r) {
7309 				case 0:
7310 					break;
7311 
7312 				case ENOMEM:
7313 				case ECONNABORTED:
7314 				case EPERM:
7315 				case -1:
7316 					goto progress;
7317 
7318 				default:
7319 					bad_error("imp_refresh_fmri", r);
7320 				}
7321 
7322 				inst->sc_import_state = IMPORT_REFRESHED;
7323 
7324 				for (dpt = uu_list_first(inst->sc_dependents);
7325 				    dpt != NULL;
7326 				    dpt = uu_list_next(inst->sc_dependents,
7327 				    dpt))
7328 					if (imp_refresh_fmri(
7329 					    dpt->sc_pgroup_fmri,
7330 					    dpt->sc_pgroup_name,
7331 					    inst->sc_fmri) != 0)
7332 						goto progress;
7333 			}
7334 
7335 			for (dpt = uu_list_first(svc->sc_dependents);
7336 			    dpt != NULL;
7337 			    dpt = uu_list_next(svc->sc_dependents, dpt))
7338 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
7339 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
7340 					goto progress;
7341 		}
7342 
7343 		for (old_dpt = uu_list_first(imp_deleted_dpts);
7344 		    old_dpt != NULL;
7345 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
7346 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
7347 			    old_dpt->sc_pgroup_name,
7348 			    old_dpt->sc_parent->sc_fmri) != 0)
7349 				goto progress;
7350 
7351 		result = 0;
7352 		goto out;
7353 	}
7354 
7355 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7356 		bad_error("uu_list_walk", uu_error());
7357 
7358 printerr:
7359 	/* If the error hasn't been printed yet, do so here. */
7360 	switch (cbdata.sc_err) {
7361 	case ECONNABORTED:
7362 		warn(gettext("Repository connection broken.\n"));
7363 		break;
7364 
7365 	case ENOMEM:
7366 		warn(emsg_nomem);
7367 		break;
7368 
7369 	case ENOSPC:
7370 		warn(emsg_nores);
7371 		break;
7372 
7373 	case EROFS:
7374 		warn(gettext("Repository is read-only.\n"));
7375 		break;
7376 
7377 	case EACCES:
7378 		warn(gettext("Repository backend denied access.\n"));
7379 		break;
7380 
7381 	case EPERM:
7382 	case EINVAL:
7383 	case EEXIST:
7384 	case EBUSY:
7385 	case EBADF:
7386 	case -1:
7387 		break;
7388 
7389 	default:
7390 		bad_error("lscf_service_import", cbdata.sc_err);
7391 	}
7392 
7393 progress:
7394 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
7395 
7396 	for (svc = uu_list_first(bndl->sc_bundle_services);
7397 	    svc != NULL;
7398 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7399 		insts = svc->sc_u.sc_service.sc_service_instances;
7400 
7401 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
7402 		    import_progress(svc->sc_import_state));
7403 
7404 		for (inst = uu_list_first(insts);
7405 		    inst != NULL;
7406 		    inst = uu_list_next(insts, inst))
7407 			warn(gettext("    Instance \"%s\": %s\n"),
7408 			    inst->sc_name,
7409 			    import_progress(inst->sc_import_state));
7410 	}
7411 
7412 	if (cbdata.sc_err == ECONNABORTED)
7413 		repository_teardown();
7414 
7415 
7416 	result = -1;
7417 
7418 out:
7419 	if (annotation_set != 0) {
7420 		/* Turn off annotation.  It is no longer needed. */
7421 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7422 	}
7423 	load_fini();
7424 
7425 	free(ud_ctarg);
7426 	free(ud_oldtarg);
7427 	free(ud_name);
7428 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7429 
7430 	scf_transaction_destroy(ud_tx);
7431 	ud_tx = NULL;
7432 	scf_iter_destroy(ud_iter);
7433 	scf_iter_destroy(ud_iter2);
7434 	ud_iter = ud_iter2 = NULL;
7435 	scf_value_destroy(ud_val);
7436 	ud_val = NULL;
7437 	scf_property_destroy(ud_prop);
7438 	scf_property_destroy(ud_dpt_prop);
7439 	ud_prop = ud_dpt_prop = NULL;
7440 	scf_pg_destroy(ud_pg);
7441 	scf_pg_destroy(ud_cur_depts_pg);
7442 	scf_pg_destroy(ud_run_dpts_pg);
7443 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7444 	scf_snaplevel_destroy(ud_snpl);
7445 	ud_snpl = NULL;
7446 	scf_instance_destroy(ud_inst);
7447 	ud_inst = NULL;
7448 
7449 	free(imp_str);
7450 	free(imp_tsname);
7451 	free(imp_fe1);
7452 	free(imp_fe2);
7453 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7454 
7455 	cookie = NULL;
7456 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7457 	    NULL) {
7458 		free((char *)old_dpt->sc_pgroup_name);
7459 		free((char *)old_dpt->sc_pgroup_fmri);
7460 		internal_pgroup_free(old_dpt);
7461 	}
7462 	uu_list_destroy(imp_deleted_dpts);
7463 
7464 	scf_transaction_destroy(imp_tx);
7465 	imp_tx = NULL;
7466 	scf_iter_destroy(imp_iter);
7467 	scf_iter_destroy(imp_rpg_iter);
7468 	scf_iter_destroy(imp_up_iter);
7469 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7470 	scf_property_destroy(imp_prop);
7471 	imp_prop = NULL;
7472 	scf_pg_destroy(imp_pg);
7473 	scf_pg_destroy(imp_pg2);
7474 	imp_pg = imp_pg2 = NULL;
7475 	scf_snaplevel_destroy(imp_snpl);
7476 	scf_snaplevel_destroy(imp_rsnpl);
7477 	imp_snpl = imp_rsnpl = NULL;
7478 	scf_snapshot_destroy(imp_snap);
7479 	scf_snapshot_destroy(imp_lisnap);
7480 	scf_snapshot_destroy(imp_tlisnap);
7481 	scf_snapshot_destroy(imp_rsnap);
7482 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7483 	scf_instance_destroy(imp_inst);
7484 	scf_instance_destroy(imp_tinst);
7485 	imp_inst = imp_tinst = NULL;
7486 	scf_service_destroy(imp_svc);
7487 	scf_service_destroy(imp_tsvc);
7488 	imp_svc = imp_tsvc = NULL;
7489 	scf_scope_destroy(imp_scope);
7490 	imp_scope = NULL;
7491 
7492 	return (result);
7493 }
7494 
7495 /*
7496  * _lscf_import_err() summarize the error handling returned by
7497  * lscf_import_{instance | service}_pgs
7498  * Return values are:
7499  * IMPORT_NEXT
7500  * IMPORT_OUT
7501  * IMPORT_BAD
7502  */
7503 
7504 #define	IMPORT_BAD	-1
7505 #define	IMPORT_NEXT	0
7506 #define	IMPORT_OUT	1
7507 
7508 static int
7509 _lscf_import_err(int err, const char *fmri)
7510 {
7511 	switch (err) {
7512 	case 0:
7513 		if (g_verbose)
7514 			warn(gettext("%s updated.\n"), fmri);
7515 		return (IMPORT_NEXT);
7516 
7517 	case ECONNABORTED:
7518 		warn(gettext("Could not update %s "
7519 		    "(repository connection broken).\n"), fmri);
7520 		return (IMPORT_OUT);
7521 
7522 	case ENOMEM:
7523 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
7524 		return (IMPORT_OUT);
7525 
7526 	case ENOSPC:
7527 		warn(gettext("Could not update %s "
7528 		    "(repository server out of resources).\n"), fmri);
7529 		return (IMPORT_OUT);
7530 
7531 	case ECANCELED:
7532 		warn(gettext(
7533 		    "Could not update %s (deleted).\n"), fmri);
7534 		return (IMPORT_NEXT);
7535 
7536 	case EPERM:
7537 	case EINVAL:
7538 	case EBUSY:
7539 		return (IMPORT_NEXT);
7540 
7541 	case EROFS:
7542 		warn(gettext("Could not update %s (repository read-only).\n"),
7543 		    fmri);
7544 		return (IMPORT_OUT);
7545 
7546 	case EACCES:
7547 		warn(gettext("Could not update %s "
7548 		    "(backend access denied).\n"), fmri);
7549 		return (IMPORT_NEXT);
7550 
7551 	case EEXIST:
7552 	default:
7553 		return (IMPORT_BAD);
7554 	}
7555 
7556 	/*NOTREACHED*/
7557 }
7558 
7559 /*
7560  * Returns
7561  *   0 - success
7562  *   -1 - lscf_import_instance_pgs() failed.
7563  */
7564 int
7565 lscf_bundle_apply(bundle_t *bndl, const char *file)
7566 {
7567 	entity_t *svc, *inst;
7568 	scf_scope_t *rscope;
7569 	scf_service_t *rsvc;
7570 	scf_instance_t *rinst;
7571 	scf_iter_t *iter;
7572 	int annotation_set = 0;
7573 	int r;
7574 
7575 	lscf_prep_hndl();
7576 
7577 	if ((rscope = scf_scope_create(g_hndl)) == NULL ||
7578 	    (rsvc = scf_service_create(g_hndl)) == NULL ||
7579 	    (rinst = scf_instance_create(g_hndl)) == NULL ||
7580 	    (iter = scf_iter_create(g_hndl)) == NULL ||
7581 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7582 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL)
7583 		scfdie();
7584 
7585 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0)
7586 		scfdie();
7587 
7588 	/*
7589 	 * Set the strings to be used for the security audit annotation
7590 	 * event.
7591 	 */
7592 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
7593 		annotation_set = 1;
7594 	} else {
7595 		switch (scf_error()) {
7596 		case SCF_ERROR_CONNECTION_BROKEN:
7597 			warn(gettext("Repository connection broken.\n"));
7598 			goto out;
7599 
7600 		case SCF_ERROR_INVALID_ARGUMENT:
7601 		case SCF_ERROR_NOT_BOUND:
7602 		case SCF_ERROR_NO_RESOURCES:
7603 		case SCF_ERROR_INTERNAL:
7604 			bad_error("_scf_set_annotation", scf_error());
7605 			/* NOTREACHED */
7606 
7607 		default:
7608 			/*
7609 			 * Do not abort apply operation because of
7610 			 * inability to create annotation audit event.
7611 			 */
7612 			warn(gettext("_scf_set_annotation() unexpectedly "
7613 			    "failed with return code of %d\n"), scf_error());
7614 			break;
7615 		}
7616 	}
7617 
7618 	for (svc = uu_list_first(bndl->sc_bundle_services);
7619 	    svc != NULL;
7620 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7621 		int refresh = 0;
7622 
7623 		if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) {
7624 			switch (scf_error()) {
7625 			case SCF_ERROR_NOT_FOUND:
7626 				if (g_verbose)
7627 					warn(gettext("Ignoring nonexistent "
7628 					    "service %s.\n"), svc->sc_name);
7629 				continue;
7630 
7631 			default:
7632 				scfdie();
7633 			}
7634 		}
7635 
7636 		/*
7637 		 * if we have pgs in the profile, we need to refresh ALL
7638 		 * instances of the service
7639 		 */
7640 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
7641 			refresh = 1;
7642 			r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc,
7643 			    SCI_FORCE | SCI_KEEP);
7644 			switch (_lscf_import_err(r, svc->sc_fmri)) {
7645 			case IMPORT_NEXT:
7646 				break;
7647 
7648 			case IMPORT_OUT:
7649 				goto out;
7650 
7651 			case IMPORT_BAD:
7652 			default:
7653 				bad_error("lscf_import_service_pgs", r);
7654 			}
7655 		}
7656 
7657 		for (inst = uu_list_first(
7658 		    svc->sc_u.sc_service.sc_service_instances);
7659 		    inst != NULL;
7660 		    inst = uu_list_next(
7661 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
7662 			if (scf_service_get_instance(rsvc, inst->sc_name,
7663 			    rinst) != 0) {
7664 				switch (scf_error()) {
7665 				case SCF_ERROR_NOT_FOUND:
7666 					if (g_verbose)
7667 						warn(gettext("Ignoring "
7668 						    "nonexistant instance "
7669 						    "%s:%s.\n"),
7670 						    inst->sc_parent->sc_name,
7671 						    inst->sc_name);
7672 					continue;
7673 
7674 				default:
7675 					scfdie();
7676 				}
7677 			}
7678 
7679 			r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst,
7680 			    SCI_FORCE | SCI_KEEP);
7681 			switch (_lscf_import_err(r, inst->sc_fmri)) {
7682 			case IMPORT_NEXT:
7683 				break;
7684 
7685 			case IMPORT_OUT:
7686 				goto out;
7687 
7688 			case IMPORT_BAD:
7689 			default:
7690 				bad_error("lscf_import_instance_pgs", r);
7691 			}
7692 
7693 			/* refresh only if there is no pgs in the service */
7694 			if (refresh == 0)
7695 				(void) refresh_entity(0, rinst, inst->sc_fmri,
7696 				    NULL, NULL, NULL);
7697 		}
7698 
7699 		if (refresh == 1) {
7700 			char *name_buf = safe_malloc(max_scf_name_len + 1);
7701 
7702 			(void) refresh_entity(1, rsvc, svc->sc_name, rinst,
7703 			    iter, name_buf);
7704 			free(name_buf);
7705 		}
7706 	}
7707 
7708 out:
7709 	if (annotation_set) {
7710 		/* Remove security audit annotation strings. */
7711 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7712 	}
7713 
7714 	scf_transaction_destroy(imp_tx);
7715 	imp_tx = NULL;
7716 	scf_pg_destroy(imp_pg);
7717 	imp_pg = NULL;
7718 
7719 	scf_iter_destroy(iter);
7720 	scf_instance_destroy(rinst);
7721 	scf_service_destroy(rsvc);
7722 	scf_scope_destroy(rscope);
7723 	return (0);
7724 }
7725 
7726 
7727 /*
7728  * Export.  These functions create and output an XML tree of a service
7729  * description from the repository.  This is largely the inverse of
7730  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
7731  *
7732  * - We must include any properties which are not represented specifically by
7733  *   a service manifest, e.g., properties created by an admin post-import.  To
7734  *   do so we'll iterate through all properties and deal with each
7735  *   apropriately.
7736  *
7737  * - Children of services and instances must must be in the order set by the
7738  *   DTD, but we iterate over the properties in undefined order.  The elements
7739  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
7740  *   number of classes of them, however, we'll keep the classes separate and
7741  *   assemble them in order.
7742  */
7743 
7744 /*
7745  * Convenience function to handle xmlSetProp errors (and type casting).
7746  */
7747 static void
7748 safe_setprop(xmlNodePtr n, const char *name, const char *val)
7749 {
7750 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
7751 		uu_die(gettext("Could not set XML property.\n"));
7752 }
7753 
7754 /*
7755  * Convenience function to set an XML attribute to the single value of an
7756  * astring property.  If the value happens to be the default, don't set the
7757  * attribute.  "dval" should be the default value supplied by the DTD, or
7758  * NULL for no default.
7759  */
7760 static int
7761 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
7762     const char *name, const char *dval)
7763 {
7764 	scf_value_t *val;
7765 	ssize_t len;
7766 	char *str;
7767 
7768 	val = scf_value_create(g_hndl);
7769 	if (val == NULL)
7770 		scfdie();
7771 
7772 	if (prop_get_val(prop, val) != 0) {
7773 		scf_value_destroy(val);
7774 		return (-1);
7775 	}
7776 
7777 	len = scf_value_get_as_string(val, NULL, 0);
7778 	if (len < 0)
7779 		scfdie();
7780 
7781 	str = safe_malloc(len + 1);
7782 
7783 	if (scf_value_get_as_string(val, str, len + 1) < 0)
7784 		scfdie();
7785 
7786 	scf_value_destroy(val);
7787 
7788 	if (dval == NULL || strcmp(str, dval) != 0)
7789 		safe_setprop(n, name, str);
7790 
7791 	free(str);
7792 
7793 	return (0);
7794 }
7795 
7796 /*
7797  * As above, but the attribute is always set.
7798  */
7799 static int
7800 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
7801 {
7802 	return (set_attr_from_prop_default(prop, n, name, NULL));
7803 }
7804 
7805 /*
7806  * Dump the given document onto f, with "'s replaced by ''s.
7807  */
7808 static int
7809 write_service_bundle(xmlDocPtr doc, FILE *f)
7810 {
7811 	xmlChar *mem;
7812 	int sz, i;
7813 
7814 	mem = NULL;
7815 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
7816 
7817 	if (mem == NULL) {
7818 		semerr(gettext("Could not dump XML tree.\n"));
7819 		return (-1);
7820 	}
7821 
7822 	/*
7823 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
7824 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
7825 	 * &apos; code?!
7826 	 */
7827 	for (i = 0; i < sz; ++i) {
7828 		char c = (char)mem[i];
7829 
7830 		if (c == '"')
7831 			(void) fputc('\'', f);
7832 		else if (c == '\'')
7833 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
7834 		else
7835 			(void) fputc(c, f);
7836 	}
7837 
7838 	return (0);
7839 }
7840 
7841 /*
7842  * Create the DOM elements in elts necessary to (generically) represent prop
7843  * (i.e., a property or propval element).  If the name of the property is
7844  * known, it should be passed as name_arg.  Otherwise, pass NULL.
7845  */
7846 static void
7847 export_property(scf_property_t *prop, const char *name_arg,
7848     struct pg_elts *elts, int flags)
7849 {
7850 	const char *type;
7851 	scf_error_t err = 0;
7852 	xmlNodePtr pnode, lnode;
7853 	char *lnname;
7854 	int ret;
7855 
7856 	/* name */
7857 	if (name_arg != NULL) {
7858 		(void) strcpy(exp_str, name_arg);
7859 	} else {
7860 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
7861 			scfdie();
7862 	}
7863 
7864 	/* type */
7865 	type = prop_to_typestr(prop);
7866 	if (type == NULL)
7867 		uu_die(gettext("Can't export property %s: unknown type.\n"),
7868 		    exp_str);
7869 
7870 	/* If we're exporting values, and there's just one, export it here. */
7871 	if (!(flags & SCE_ALL_VALUES))
7872 		goto empty;
7873 
7874 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
7875 		xmlNodePtr n;
7876 
7877 		/* Single value, so use propval */
7878 		n = xmlNewNode(NULL, (xmlChar *)"propval");
7879 		if (n == NULL)
7880 			uu_die(emsg_create_xml);
7881 
7882 		safe_setprop(n, name_attr, exp_str);
7883 		safe_setprop(n, type_attr, type);
7884 
7885 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
7886 			scfdie();
7887 		safe_setprop(n, value_attr, exp_str);
7888 
7889 		if (elts->propvals == NULL)
7890 			elts->propvals = n;
7891 		else
7892 			(void) xmlAddSibling(elts->propvals, n);
7893 
7894 		return;
7895 	}
7896 
7897 	err = scf_error();
7898 
7899 	if (err == SCF_ERROR_PERMISSION_DENIED) {
7900 		semerr(emsg_permission_denied);
7901 		return;
7902 	}
7903 
7904 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
7905 	    err != SCF_ERROR_NOT_FOUND &&
7906 	    err != SCF_ERROR_PERMISSION_DENIED)
7907 		scfdie();
7908 
7909 empty:
7910 	/* Multiple (or no) values, so use property */
7911 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
7912 	if (pnode == NULL)
7913 		uu_die(emsg_create_xml);
7914 
7915 	safe_setprop(pnode, name_attr, exp_str);
7916 	safe_setprop(pnode, type_attr, type);
7917 
7918 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
7919 		lnname = uu_msprintf("%s_list", type);
7920 		if (lnname == NULL)
7921 			uu_die(gettext("Could not create string"));
7922 
7923 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
7924 		if (lnode == NULL)
7925 			uu_die(emsg_create_xml);
7926 
7927 		uu_free(lnname);
7928 
7929 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
7930 			scfdie();
7931 
7932 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
7933 		    1) {
7934 			xmlNodePtr vn;
7935 
7936 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
7937 			    NULL);
7938 			if (vn == NULL)
7939 				uu_die(emsg_create_xml);
7940 
7941 			if (scf_value_get_as_string(exp_val, exp_str,
7942 			    exp_str_sz) < 0)
7943 				scfdie();
7944 			safe_setprop(vn, value_attr, exp_str);
7945 		}
7946 		if (ret != 0)
7947 			scfdie();
7948 	}
7949 
7950 	if (elts->properties == NULL)
7951 		elts->properties = pnode;
7952 	else
7953 		(void) xmlAddSibling(elts->properties, pnode);
7954 }
7955 
7956 /*
7957  * Add a property_group element for this property group to elts.
7958  */
7959 static void
7960 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
7961 {
7962 	xmlNodePtr n;
7963 	struct pg_elts elts;
7964 	int ret;
7965 	boolean_t read_protected;
7966 
7967 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
7968 
7969 	/* name */
7970 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
7971 		scfdie();
7972 	safe_setprop(n, name_attr, exp_str);
7973 
7974 	/* type */
7975 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
7976 		scfdie();
7977 	safe_setprop(n, type_attr, exp_str);
7978 
7979 	/* properties */
7980 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
7981 		scfdie();
7982 
7983 	(void) memset(&elts, 0, sizeof (elts));
7984 
7985 	/*
7986 	 * If this property group is not read protected, we always want to
7987 	 * output all the values.  Otherwise, we only output the values if the
7988 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
7989 	 */
7990 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
7991 		scfdie();
7992 
7993 	if (!read_protected)
7994 		flags |= SCE_ALL_VALUES;
7995 
7996 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
7997 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
7998 			scfdie();
7999 
8000 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8001 			xmlNodePtr m;
8002 
8003 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8004 			if (m == NULL)
8005 				uu_die(emsg_create_xml);
8006 
8007 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8008 				elts.stability = m;
8009 				continue;
8010 			}
8011 
8012 			xmlFreeNode(m);
8013 		}
8014 
8015 		export_property(exp_prop, NULL, &elts, flags);
8016 	}
8017 	if (ret == -1)
8018 		scfdie();
8019 
8020 	(void) xmlAddChild(n, elts.stability);
8021 	(void) xmlAddChildList(n, elts.propvals);
8022 	(void) xmlAddChildList(n, elts.properties);
8023 
8024 	if (eelts->property_groups == NULL)
8025 		eelts->property_groups = n;
8026 	else
8027 		(void) xmlAddSibling(eelts->property_groups, n);
8028 }
8029 
8030 /*
8031  * Create an XML node representing the dependency described by the given
8032  * property group and put it in eelts.  Unless the dependency is not valid, in
8033  * which case create a generic property_group element which represents it and
8034  * put it in eelts.
8035  */
8036 static void
8037 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8038 {
8039 	xmlNodePtr n;
8040 	int err = 0, ret;
8041 	struct pg_elts elts;
8042 
8043 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
8044 	if (n == NULL)
8045 		uu_die(emsg_create_xml);
8046 
8047 	/*
8048 	 * If the external flag is present, skip this dependency because it
8049 	 * should have been created by another manifest.
8050 	 */
8051 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
8052 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8053 		    prop_get_val(exp_prop, exp_val) == 0) {
8054 			uint8_t b;
8055 
8056 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
8057 				scfdie();
8058 
8059 			if (b)
8060 				return;
8061 		}
8062 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
8063 		scfdie();
8064 
8065 	/* Get the required attributes. */
8066 
8067 	/* name */
8068 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8069 		scfdie();
8070 	safe_setprop(n, name_attr, exp_str);
8071 
8072 	/* grouping */
8073 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8074 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8075 		err = 1;
8076 
8077 	/* restart_on */
8078 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8079 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8080 		err = 1;
8081 
8082 	/* type */
8083 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8084 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8085 		err = 1;
8086 
8087 	/*
8088 	 * entities: Not required, but if we create no children, it will be
8089 	 * created as empty on import, so fail if it's missing.
8090 	 */
8091 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8092 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
8093 		scf_iter_t *eiter;
8094 		int ret2;
8095 
8096 		eiter = scf_iter_create(g_hndl);
8097 		if (eiter == NULL)
8098 			scfdie();
8099 
8100 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
8101 			scfdie();
8102 
8103 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
8104 			xmlNodePtr ch;
8105 
8106 			if (scf_value_get_astring(exp_val, exp_str,
8107 			    exp_str_sz) < 0)
8108 				scfdie();
8109 
8110 			/*
8111 			 * service_fmri's must be first, so we can add them
8112 			 * here.
8113 			 */
8114 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
8115 			    NULL);
8116 			if (ch == NULL)
8117 				uu_die(emsg_create_xml);
8118 
8119 			safe_setprop(ch, value_attr, exp_str);
8120 		}
8121 		if (ret2 == -1)
8122 			scfdie();
8123 
8124 		scf_iter_destroy(eiter);
8125 	} else
8126 		err = 1;
8127 
8128 	if (err) {
8129 		xmlFreeNode(n);
8130 
8131 		export_pg(pg, eelts, 0);
8132 
8133 		return;
8134 	}
8135 
8136 	/* Iterate through the properties & handle each. */
8137 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8138 		scfdie();
8139 
8140 	(void) memset(&elts, 0, sizeof (elts));
8141 
8142 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8143 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8144 			scfdie();
8145 
8146 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8147 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8148 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8149 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8150 			continue;
8151 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8152 			xmlNodePtr m;
8153 
8154 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8155 			if (m == NULL)
8156 				uu_die(emsg_create_xml);
8157 
8158 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8159 				elts.stability = m;
8160 				continue;
8161 			}
8162 
8163 			xmlFreeNode(m);
8164 		}
8165 
8166 		export_property(exp_prop, exp_str, &elts, 0);
8167 	}
8168 	if (ret == -1)
8169 		scfdie();
8170 
8171 	(void) xmlAddChild(n, elts.stability);
8172 	(void) xmlAddChildList(n, elts.propvals);
8173 	(void) xmlAddChildList(n, elts.properties);
8174 
8175 	if (eelts->dependencies == NULL)
8176 		eelts->dependencies = n;
8177 	else
8178 		(void) xmlAddSibling(eelts->dependencies, n);
8179 }
8180 
8181 static xmlNodePtr
8182 export_method_environment(scf_propertygroup_t *pg)
8183 {
8184 	xmlNodePtr env;
8185 	int ret;
8186 	int children = 0;
8187 
8188 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
8189 		return (NULL);
8190 
8191 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
8192 	if (env == NULL)
8193 		uu_die(emsg_create_xml);
8194 
8195 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
8196 		scfdie();
8197 
8198 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
8199 		scfdie();
8200 
8201 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
8202 		xmlNodePtr ev;
8203 		char *cp;
8204 
8205 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8206 			scfdie();
8207 
8208 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
8209 			warn(gettext("Invalid environment variable \"%s\".\n"),
8210 			    exp_str);
8211 			continue;
8212 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
8213 			warn(gettext("Invalid environment variable \"%s\"; "
8214 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
8215 			continue;
8216 		}
8217 
8218 		*cp = '\0';
8219 		cp++;
8220 
8221 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
8222 		if (ev == NULL)
8223 			uu_die(emsg_create_xml);
8224 
8225 		safe_setprop(ev, name_attr, exp_str);
8226 		safe_setprop(ev, value_attr, cp);
8227 		children++;
8228 	}
8229 
8230 	if (ret != 0)
8231 		scfdie();
8232 
8233 	if (children == 0) {
8234 		xmlFreeNode(env);
8235 		return (NULL);
8236 	}
8237 
8238 	return (env);
8239 }
8240 
8241 /*
8242  * As above, but for a method property group.
8243  */
8244 static void
8245 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
8246 {
8247 	xmlNodePtr n, env;
8248 	char *str;
8249 	int err = 0, nonenv, ret;
8250 	uint8_t use_profile;
8251 	struct pg_elts elts;
8252 	xmlNodePtr ctxt = NULL;
8253 
8254 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
8255 
8256 	/* Get the required attributes. */
8257 
8258 	/* name */
8259 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8260 		scfdie();
8261 	safe_setprop(n, name_attr, exp_str);
8262 
8263 	/* type */
8264 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8265 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8266 		err = 1;
8267 
8268 	/* exec */
8269 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
8270 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
8271 		err = 1;
8272 
8273 	/* timeout */
8274 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
8275 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
8276 	    prop_get_val(exp_prop, exp_val) == 0) {
8277 		uint64_t c;
8278 
8279 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
8280 			scfdie();
8281 
8282 		str = uu_msprintf("%llu", c);
8283 		if (str == NULL)
8284 			uu_die(gettext("Could not create string"));
8285 
8286 		safe_setprop(n, "timeout_seconds", str);
8287 		free(str);
8288 	} else
8289 		err = 1;
8290 
8291 	if (err) {
8292 		xmlFreeNode(n);
8293 
8294 		export_pg(pg, eelts, 0);
8295 
8296 		return;
8297 	}
8298 
8299 
8300 	/*
8301 	 * If we're going to have a method_context child, we need to know
8302 	 * before we iterate through the properties.  Since method_context's
8303 	 * are optional, we don't want to complain about any properties
8304 	 * missing if none of them are there.  Thus we can't use the
8305 	 * convenience functions.
8306 	 */
8307 	nonenv =
8308 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
8309 	    SCF_SUCCESS ||
8310 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
8311 	    SCF_SUCCESS ||
8312 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
8313 	    SCF_SUCCESS ||
8314 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
8315 	    SCF_SUCCESS;
8316 
8317 	if (nonenv) {
8318 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8319 		if (ctxt == NULL)
8320 			uu_die(emsg_create_xml);
8321 
8322 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
8323 		    0 &&
8324 		    set_attr_from_prop_default(exp_prop, ctxt,
8325 		    "working_directory", ":default") != 0)
8326 			err = 1;
8327 
8328 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
8329 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
8330 		    ":default") != 0)
8331 			err = 1;
8332 
8333 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
8334 		    0 &&
8335 		    set_attr_from_prop_default(exp_prop, ctxt,
8336 		    "resource_pool", ":default") != 0)
8337 			err = 1;
8338 		/*
8339 		 * We only want to complain about profile or credential
8340 		 * properties if we will use them.  To determine that we must
8341 		 * examine USE_PROFILE.
8342 		 */
8343 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8344 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8345 		    prop_get_val(exp_prop, exp_val) == 0) {
8346 			if (scf_value_get_boolean(exp_val, &use_profile) !=
8347 			    SCF_SUCCESS) {
8348 				scfdie();
8349 			}
8350 
8351 			if (use_profile) {
8352 				xmlNodePtr prof;
8353 
8354 				prof = xmlNewChild(ctxt, NULL,
8355 				    (xmlChar *)"method_profile", NULL);
8356 				if (prof == NULL)
8357 					uu_die(emsg_create_xml);
8358 
8359 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
8360 				    exp_prop) != 0 ||
8361 				    set_attr_from_prop(exp_prop, prof,
8362 				    name_attr) != 0)
8363 					err = 1;
8364 			} else {
8365 				xmlNodePtr cred;
8366 
8367 				cred = xmlNewChild(ctxt, NULL,
8368 				    (xmlChar *)"method_credential", NULL);
8369 				if (cred == NULL)
8370 					uu_die(emsg_create_xml);
8371 
8372 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
8373 				    exp_prop) != 0 ||
8374 				    set_attr_from_prop(exp_prop, cred,
8375 				    "user") != 0) {
8376 					err = 1;
8377 				}
8378 
8379 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
8380 				    exp_prop) == 0 &&
8381 				    set_attr_from_prop_default(exp_prop, cred,
8382 				    "group", ":default") != 0)
8383 					err = 1;
8384 
8385 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
8386 				    exp_prop) == 0 &&
8387 				    set_attr_from_prop_default(exp_prop, cred,
8388 				    "supp_groups", ":default") != 0)
8389 					err = 1;
8390 
8391 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
8392 				    exp_prop) == 0 &&
8393 				    set_attr_from_prop_default(exp_prop, cred,
8394 				    "privileges", ":default") != 0)
8395 					err = 1;
8396 
8397 				if (pg_get_prop(pg,
8398 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
8399 				    exp_prop) == 0 &&
8400 				    set_attr_from_prop_default(exp_prop, cred,
8401 				    "limit_privileges", ":default") != 0)
8402 					err = 1;
8403 			}
8404 		}
8405 	}
8406 
8407 	if ((env = export_method_environment(pg)) != NULL) {
8408 		if (ctxt == NULL) {
8409 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8410 			if (ctxt == NULL)
8411 				uu_die(emsg_create_xml);
8412 		}
8413 		(void) xmlAddChild(ctxt, env);
8414 	}
8415 
8416 	if (env != NULL || (nonenv && err == 0))
8417 		(void) xmlAddChild(n, ctxt);
8418 	else
8419 		xmlFreeNode(ctxt);
8420 
8421 	nonenv = (err == 0);
8422 
8423 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8424 		scfdie();
8425 
8426 	(void) memset(&elts, 0, sizeof (elts));
8427 
8428 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8429 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8430 			scfdie();
8431 
8432 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8433 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
8434 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
8435 			continue;
8436 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8437 			xmlNodePtr m;
8438 
8439 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8440 			if (m == NULL)
8441 				uu_die(emsg_create_xml);
8442 
8443 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8444 				elts.stability = m;
8445 				continue;
8446 			}
8447 
8448 			xmlFreeNode(m);
8449 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
8450 		    0 ||
8451 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
8452 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
8453 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8454 			if (nonenv)
8455 				continue;
8456 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
8457 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
8458 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
8459 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
8460 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
8461 			if (nonenv && !use_profile)
8462 				continue;
8463 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8464 			if (nonenv && use_profile)
8465 				continue;
8466 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
8467 			if (env != NULL)
8468 				continue;
8469 		}
8470 
8471 		export_property(exp_prop, exp_str, &elts, 0);
8472 	}
8473 	if (ret == -1)
8474 		scfdie();
8475 
8476 	(void) xmlAddChild(n, elts.stability);
8477 	(void) xmlAddChildList(n, elts.propvals);
8478 	(void) xmlAddChildList(n, elts.properties);
8479 
8480 	if (eelts->exec_methods == NULL)
8481 		eelts->exec_methods = n;
8482 	else
8483 		(void) xmlAddSibling(eelts->exec_methods, n);
8484 }
8485 
8486 static void
8487 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
8488     struct entity_elts *eelts)
8489 {
8490 	xmlNodePtr pgnode;
8491 
8492 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
8493 	if (pgnode == NULL)
8494 		uu_die(emsg_create_xml);
8495 
8496 	safe_setprop(pgnode, name_attr, name);
8497 	safe_setprop(pgnode, type_attr, type);
8498 
8499 	(void) xmlAddChildList(pgnode, elts->propvals);
8500 	(void) xmlAddChildList(pgnode, elts->properties);
8501 
8502 	if (eelts->property_groups == NULL)
8503 		eelts->property_groups = pgnode;
8504 	else
8505 		(void) xmlAddSibling(eelts->property_groups, pgnode);
8506 }
8507 
8508 /*
8509  * Process the general property group for a service.  This is the one with the
8510  * goodies.
8511  */
8512 static void
8513 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
8514 {
8515 	struct pg_elts elts;
8516 	int ret;
8517 
8518 	/*
8519 	 * In case there are properties which don't correspond to child
8520 	 * entities of the service entity, we'll set up a pg_elts structure to
8521 	 * put them in.
8522 	 */
8523 	(void) memset(&elts, 0, sizeof (elts));
8524 
8525 	/* Walk the properties, looking for special ones. */
8526 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8527 		scfdie();
8528 
8529 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8530 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8531 			scfdie();
8532 
8533 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
8534 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8535 			    prop_get_val(exp_prop, exp_val) == 0) {
8536 				uint8_t b;
8537 
8538 				if (scf_value_get_boolean(exp_val, &b) !=
8539 				    SCF_SUCCESS)
8540 					scfdie();
8541 
8542 				if (b) {
8543 					selts->single_instance =
8544 					    xmlNewNode(NULL,
8545 					    (xmlChar *)"single_instance");
8546 					if (selts->single_instance == NULL)
8547 						uu_die(emsg_create_xml);
8548 				}
8549 
8550 				continue;
8551 			}
8552 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8553 			xmlNodePtr rnode, sfnode;
8554 
8555 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8556 			if (rnode == NULL)
8557 				uu_die(emsg_create_xml);
8558 
8559 			sfnode = xmlNewChild(rnode, NULL,
8560 			    (xmlChar *)"service_fmri", NULL);
8561 			if (sfnode == NULL)
8562 				uu_die(emsg_create_xml);
8563 
8564 			if (set_attr_from_prop(exp_prop, sfnode,
8565 			    value_attr) == 0) {
8566 				selts->restarter = rnode;
8567 				continue;
8568 			}
8569 
8570 			xmlFreeNode(rnode);
8571 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
8572 		    0) {
8573 			xmlNodePtr s;
8574 
8575 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8576 			if (s == NULL)
8577 				uu_die(emsg_create_xml);
8578 
8579 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8580 				selts->stability = s;
8581 				continue;
8582 			}
8583 
8584 			xmlFreeNode(s);
8585 		}
8586 
8587 		export_property(exp_prop, exp_str, &elts, 0);
8588 	}
8589 	if (ret == -1)
8590 		scfdie();
8591 
8592 	if (elts.propvals != NULL || elts.properties != NULL)
8593 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
8594 		    selts);
8595 }
8596 
8597 static void
8598 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
8599 {
8600 	xmlNodePtr n, prof, cred, env;
8601 	uint8_t use_profile;
8602 	int ret, err = 0;
8603 
8604 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
8605 
8606 	env = export_method_environment(pg);
8607 
8608 	/* Need to know whether we'll use a profile or not. */
8609 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8610 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8611 	    prop_get_val(exp_prop, exp_val) == 0) {
8612 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
8613 			scfdie();
8614 
8615 		if (use_profile)
8616 			prof =
8617 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
8618 			    NULL);
8619 		else
8620 			cred =
8621 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
8622 			    NULL);
8623 	}
8624 
8625 	if (env != NULL)
8626 		(void) xmlAddChild(n, env);
8627 
8628 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8629 		scfdie();
8630 
8631 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8632 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8633 			scfdie();
8634 
8635 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
8636 			if (set_attr_from_prop(exp_prop, n,
8637 			    "working_directory") != 0)
8638 				err = 1;
8639 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
8640 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
8641 				err = 1;
8642 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
8643 			if (set_attr_from_prop(exp_prop, n,
8644 			    "resource_pool") != 0)
8645 				err = 1;
8646 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8647 			/* EMPTY */
8648 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
8649 			if (use_profile ||
8650 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
8651 				err = 1;
8652 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
8653 			if (use_profile ||
8654 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
8655 				err = 1;
8656 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
8657 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8658 			    "supp_groups") != 0)
8659 				err = 1;
8660 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
8661 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8662 			    "privileges") != 0)
8663 				err = 1;
8664 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
8665 		    0) {
8666 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8667 			    "limit_privileges") != 0)
8668 				err = 1;
8669 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8670 			if (!use_profile || set_attr_from_prop(exp_prop,
8671 			    prof, name_attr) != 0)
8672 				err = 1;
8673 		} else {
8674 			/* Can't have generic properties in method_context's */
8675 			err = 1;
8676 		}
8677 	}
8678 	if (ret == -1)
8679 		scfdie();
8680 
8681 	if (err && env == NULL) {
8682 		xmlFreeNode(n);
8683 		export_pg(pg, elts, 0);
8684 		return;
8685 	}
8686 
8687 	elts->method_context = n;
8688 }
8689 
8690 /*
8691  * Given a dependency property group in the tfmri entity (target fmri), return
8692  * a dependent element which represents it.
8693  */
8694 static xmlNodePtr
8695 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
8696 {
8697 	uint8_t b;
8698 	xmlNodePtr n, sf;
8699 	int err = 0, ret;
8700 	struct pg_elts pgelts;
8701 
8702 	/*
8703 	 * If external isn't set to true then exporting the service will
8704 	 * export this as a normal dependency, so we should stop to avoid
8705 	 * duplication.
8706 	 */
8707 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
8708 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
8709 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
8710 		if (g_verbose) {
8711 			warn(gettext("Dependent \"%s\" cannot be exported "
8712 			    "properly because the \"%s\" property of the "
8713 			    "\"%s\" dependency of %s is not set to true.\n"),
8714 			    name, scf_property_external, name, tfmri);
8715 		}
8716 
8717 		return (NULL);
8718 	}
8719 
8720 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
8721 	if (n == NULL)
8722 		uu_die(emsg_create_xml);
8723 
8724 	safe_setprop(n, name_attr, name);
8725 
8726 	/* Get the required attributes */
8727 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8728 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8729 		err = 1;
8730 
8731 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8732 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8733 		err = 1;
8734 
8735 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8736 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
8737 	    prop_get_val(exp_prop, exp_val) == 0) {
8738 		/* EMPTY */
8739 	} else
8740 		err = 1;
8741 
8742 	if (err) {
8743 		xmlFreeNode(n);
8744 		return (NULL);
8745 	}
8746 
8747 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
8748 	if (sf == NULL)
8749 		uu_die(emsg_create_xml);
8750 
8751 	safe_setprop(sf, value_attr, tfmri);
8752 
8753 	/*
8754 	 * Now add elements for the other properties.
8755 	 */
8756 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8757 		scfdie();
8758 
8759 	(void) memset(&pgelts, 0, sizeof (pgelts));
8760 
8761 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8762 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8763 			scfdie();
8764 
8765 		if (strcmp(exp_str, scf_property_external) == 0 ||
8766 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8767 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8768 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8769 			continue;
8770 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
8771 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
8772 			    prop_get_val(exp_prop, exp_val) == 0) {
8773 				char type[sizeof ("service") + 1];
8774 
8775 				if (scf_value_get_astring(exp_val, type,
8776 				    sizeof (type)) < 0)
8777 					scfdie();
8778 
8779 				if (strcmp(type, "service") == 0)
8780 					continue;
8781 			}
8782 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8783 			xmlNodePtr s;
8784 
8785 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8786 			if (s == NULL)
8787 				uu_die(emsg_create_xml);
8788 
8789 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8790 				pgelts.stability = s;
8791 				continue;
8792 			}
8793 
8794 			xmlFreeNode(s);
8795 		}
8796 
8797 		export_property(exp_prop, exp_str, &pgelts, 0);
8798 	}
8799 	if (ret == -1)
8800 		scfdie();
8801 
8802 	(void) xmlAddChild(n, pgelts.stability);
8803 	(void) xmlAddChildList(n, pgelts.propvals);
8804 	(void) xmlAddChildList(n, pgelts.properties);
8805 
8806 	return (n);
8807 }
8808 
8809 static void
8810 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
8811 {
8812 	scf_propertygroup_t *opg;
8813 	scf_iter_t *iter;
8814 	char *type, *fmri;
8815 	int ret;
8816 	struct pg_elts pgelts;
8817 	xmlNodePtr n;
8818 	scf_error_t serr;
8819 
8820 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
8821 	    (iter = scf_iter_create(g_hndl)) == NULL)
8822 		scfdie();
8823 
8824 	/* Can't use exp_prop_iter due to export_dependent(). */
8825 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
8826 		scfdie();
8827 
8828 	type = safe_malloc(max_scf_pg_type_len + 1);
8829 
8830 	/* Get an extra byte so we can tell if values are too long. */
8831 	fmri = safe_malloc(max_scf_fmri_len + 2);
8832 
8833 	(void) memset(&pgelts, 0, sizeof (pgelts));
8834 
8835 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
8836 		void *entity;
8837 		int isservice;
8838 		scf_type_t ty;
8839 
8840 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
8841 			scfdie();
8842 
8843 		if ((ty != SCF_TYPE_ASTRING &&
8844 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
8845 		    prop_get_val(exp_prop, exp_val) != 0) {
8846 			export_property(exp_prop, NULL, &pgelts, 0);
8847 			continue;
8848 		}
8849 
8850 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8851 			scfdie();
8852 
8853 		if (scf_value_get_astring(exp_val, fmri,
8854 		    max_scf_fmri_len + 2) < 0)
8855 			scfdie();
8856 
8857 		/* Look for a dependency group in the target fmri. */
8858 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
8859 		switch (serr) {
8860 		case SCF_ERROR_NONE:
8861 			break;
8862 
8863 		case SCF_ERROR_NO_MEMORY:
8864 			uu_die(gettext("Out of memory.\n"));
8865 			/* NOTREACHED */
8866 
8867 		case SCF_ERROR_INVALID_ARGUMENT:
8868 			if (g_verbose) {
8869 				if (scf_property_to_fmri(exp_prop, fmri,
8870 				    max_scf_fmri_len + 2) < 0)
8871 					scfdie();
8872 
8873 				warn(gettext("The value of %s is not a valid "
8874 				    "FMRI.\n"), fmri);
8875 			}
8876 
8877 			export_property(exp_prop, exp_str, &pgelts, 0);
8878 			continue;
8879 
8880 		case SCF_ERROR_CONSTRAINT_VIOLATED:
8881 			if (g_verbose) {
8882 				if (scf_property_to_fmri(exp_prop, fmri,
8883 				    max_scf_fmri_len + 2) < 0)
8884 					scfdie();
8885 
8886 				warn(gettext("The value of %s does not specify "
8887 				    "a service or an instance.\n"), fmri);
8888 			}
8889 
8890 			export_property(exp_prop, exp_str, &pgelts, 0);
8891 			continue;
8892 
8893 		case SCF_ERROR_NOT_FOUND:
8894 			if (g_verbose) {
8895 				if (scf_property_to_fmri(exp_prop, fmri,
8896 				    max_scf_fmri_len + 2) < 0)
8897 					scfdie();
8898 
8899 				warn(gettext("The entity specified by %s does "
8900 				    "not exist.\n"), fmri);
8901 			}
8902 
8903 			export_property(exp_prop, exp_str, &pgelts, 0);
8904 			continue;
8905 
8906 		default:
8907 #ifndef NDEBUG
8908 			(void) fprintf(stderr, "%s:%d: %s() failed with "
8909 			    "unexpected error %d.\n", __FILE__, __LINE__,
8910 			    "fmri_to_entity", serr);
8911 #endif
8912 			abort();
8913 		}
8914 
8915 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
8916 			if (scf_error() != SCF_ERROR_NOT_FOUND)
8917 				scfdie();
8918 
8919 			warn(gettext("Entity %s is missing dependency property "
8920 			    "group %s.\n"), fmri, exp_str);
8921 
8922 			export_property(exp_prop, NULL, &pgelts, 0);
8923 			continue;
8924 		}
8925 
8926 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
8927 			scfdie();
8928 
8929 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
8930 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
8931 				scfdie();
8932 
8933 			warn(gettext("Property group %s is not of "
8934 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
8935 
8936 			export_property(exp_prop, NULL, &pgelts, 0);
8937 			continue;
8938 		}
8939 
8940 		n = export_dependent(opg, exp_str, fmri);
8941 		if (n == NULL)
8942 			export_property(exp_prop, exp_str, &pgelts, 0);
8943 		else {
8944 			if (eelts->dependents == NULL)
8945 				eelts->dependents = n;
8946 			else
8947 				(void) xmlAddSibling(eelts->dependents,
8948 				    n);
8949 		}
8950 	}
8951 	if (ret == -1)
8952 		scfdie();
8953 
8954 	free(fmri);
8955 	free(type);
8956 
8957 	scf_iter_destroy(iter);
8958 	scf_pg_destroy(opg);
8959 
8960 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
8961 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
8962 		    eelts);
8963 }
8964 
8965 static void
8966 make_node(xmlNodePtr *nodep, const char *name)
8967 {
8968 	if (*nodep == NULL) {
8969 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
8970 		if (*nodep == NULL)
8971 			uu_die(emsg_create_xml);
8972 	}
8973 }
8974 
8975 static xmlNodePtr
8976 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
8977 {
8978 	int ret;
8979 	xmlNodePtr parent = NULL;
8980 	xmlNodePtr loctext = NULL;
8981 
8982 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8983 		scfdie();
8984 
8985 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8986 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
8987 		    prop_get_val(exp_prop, exp_val) != 0)
8988 			continue;
8989 
8990 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
8991 			scfdie();
8992 
8993 		make_node(&parent, parname);
8994 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
8995 		    (xmlChar *)exp_str);
8996 		if (loctext == NULL)
8997 			uu_die(emsg_create_xml);
8998 
8999 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9000 			scfdie();
9001 
9002 		safe_setprop(loctext, "xml:lang", exp_str);
9003 	}
9004 
9005 	if (ret == -1)
9006 		scfdie();
9007 
9008 	return (parent);
9009 }
9010 
9011 static xmlNodePtr
9012 export_tm_manpage(scf_propertygroup_t *pg)
9013 {
9014 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9015 	if (manpage == NULL)
9016 		uu_die(emsg_create_xml);
9017 
9018 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9019 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9020 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9021 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9022 		xmlFreeNode(manpage);
9023 		return (NULL);
9024 	}
9025 
9026 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9027 		(void) set_attr_from_prop_default(exp_prop,
9028 		    manpage, "manpath", ":default");
9029 
9030 	return (manpage);
9031 }
9032 
9033 static xmlNodePtr
9034 export_tm_doc_link(scf_propertygroup_t *pg)
9035 {
9036 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9037 	if (doc_link == NULL)
9038 		uu_die(emsg_create_xml);
9039 
9040 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9041 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9042 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9043 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9044 		xmlFreeNode(doc_link);
9045 		return (NULL);
9046 	}
9047 	return (doc_link);
9048 }
9049 
9050 /*
9051  * Process template information for a service or instances.
9052  */
9053 static void
9054 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
9055     struct template_elts *telts)
9056 {
9057 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
9058 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
9059 	xmlNodePtr child = NULL;
9060 
9061 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
9062 		scfdie();
9063 
9064 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
9065 		telts->common_name = export_tm_loctext(pg, "common_name");
9066 		if (telts->common_name == NULL)
9067 			export_pg(pg, elts, 0);
9068 		return;
9069 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
9070 		telts->description = export_tm_loctext(pg, "description");
9071 		if (telts->description == NULL)
9072 			export_pg(pg, elts, 0);
9073 		return;
9074 	}
9075 
9076 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
9077 		child = export_tm_manpage(pg);
9078 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
9079 		child = export_tm_doc_link(pg);
9080 	}
9081 
9082 	if (child != NULL) {
9083 		make_node(&telts->documentation, "documentation");
9084 		(void) xmlAddChild(telts->documentation, child);
9085 	} else {
9086 		export_pg(pg, elts, 0);
9087 	}
9088 }
9089 
9090 /*
9091  * Process the general property group for an instance.
9092  */
9093 static void
9094 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
9095     struct entity_elts *elts)
9096 {
9097 	uint8_t enabled;
9098 	struct pg_elts pgelts;
9099 	int ret;
9100 
9101 	/* enabled */
9102 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
9103 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9104 	    prop_get_val(exp_prop, exp_val) == 0) {
9105 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
9106 			scfdie();
9107 	} else {
9108 		enabled = 0;
9109 	}
9110 
9111 	safe_setprop(inode, enabled_attr, enabled ? true : false);
9112 
9113 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9114 		scfdie();
9115 
9116 	(void) memset(&pgelts, 0, sizeof (pgelts));
9117 
9118 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9119 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9120 			scfdie();
9121 
9122 		if (strcmp(exp_str, scf_property_enabled) == 0) {
9123 			continue;
9124 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9125 			xmlNodePtr rnode, sfnode;
9126 
9127 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9128 			if (rnode == NULL)
9129 				uu_die(emsg_create_xml);
9130 
9131 			sfnode = xmlNewChild(rnode, NULL,
9132 			    (xmlChar *)"service_fmri", NULL);
9133 			if (sfnode == NULL)
9134 				uu_die(emsg_create_xml);
9135 
9136 			if (set_attr_from_prop(exp_prop, sfnode,
9137 			    value_attr) == 0) {
9138 				elts->restarter = rnode;
9139 				continue;
9140 			}
9141 
9142 			xmlFreeNode(rnode);
9143 		}
9144 
9145 		export_property(exp_prop, exp_str, &pgelts, 0);
9146 	}
9147 	if (ret == -1)
9148 		scfdie();
9149 
9150 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9151 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
9152 		    elts);
9153 }
9154 
9155 /*
9156  * Put an instance element for the given instance into selts.
9157  */
9158 static void
9159 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
9160 {
9161 	xmlNodePtr n;
9162 	boolean_t isdefault;
9163 	struct entity_elts elts;
9164 	struct template_elts template_elts;
9165 	int ret;
9166 
9167 	n = xmlNewNode(NULL, (xmlChar *)"instance");
9168 	if (n == NULL)
9169 		uu_die(emsg_create_xml);
9170 
9171 	/* name */
9172 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
9173 		scfdie();
9174 	safe_setprop(n, name_attr, exp_str);
9175 	isdefault = strcmp(exp_str, "default") == 0;
9176 
9177 	/* check existance of general pg (since general/enabled is required) */
9178 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
9179 		if (scf_error() != SCF_ERROR_NOT_FOUND)
9180 			scfdie();
9181 
9182 		if (g_verbose) {
9183 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
9184 				scfdie();
9185 
9186 			warn(gettext("Instance %s has no general property "
9187 			    "group; it will be marked disabled.\n"), exp_str);
9188 		}
9189 
9190 		safe_setprop(n, enabled_attr, false);
9191 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
9192 	    strcmp(exp_str, scf_group_framework) != 0) {
9193 		if (g_verbose) {
9194 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
9195 				scfdie();
9196 
9197 			warn(gettext("Property group %s is not of type "
9198 			    "framework; the instance will be marked "
9199 			    "disabled.\n"), exp_str);
9200 		}
9201 
9202 		safe_setprop(n, enabled_attr, false);
9203 	}
9204 
9205 	/* property groups */
9206 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
9207 		scfdie();
9208 
9209 	(void) memset(&elts, 0, sizeof (elts));
9210 	(void) memset(&template_elts, 0, sizeof (template_elts));
9211 
9212 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9213 		uint32_t pgflags;
9214 
9215 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9216 			scfdie();
9217 
9218 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9219 			continue;
9220 
9221 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9222 			scfdie();
9223 
9224 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9225 			export_dependency(exp_pg, &elts);
9226 			continue;
9227 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9228 			export_method(exp_pg, &elts);
9229 			continue;
9230 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9231 			if (scf_pg_get_name(exp_pg, exp_str,
9232 			    max_scf_name_len + 1) < 0)
9233 				scfdie();
9234 
9235 			if (strcmp(exp_str, scf_pg_general) == 0) {
9236 				export_inst_general(exp_pg, n, &elts);
9237 				continue;
9238 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9239 			    0) {
9240 				export_method_context(exp_pg, &elts);
9241 				continue;
9242 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9243 				export_dependents(exp_pg, &elts);
9244 				continue;
9245 			}
9246 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9247 			export_template(exp_pg, &elts, &template_elts);
9248 			continue;
9249 		}
9250 
9251 		/* Ordinary pg. */
9252 		export_pg(exp_pg, &elts, flags);
9253 	}
9254 	if (ret == -1)
9255 		scfdie();
9256 
9257 	if (template_elts.common_name != NULL) {
9258 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9259 		(void) xmlAddChild(elts.template, template_elts.common_name);
9260 		(void) xmlAddChild(elts.template, template_elts.description);
9261 		(void) xmlAddChild(elts.template, template_elts.documentation);
9262 	} else {
9263 		xmlFreeNode(template_elts.description);
9264 		xmlFreeNode(template_elts.documentation);
9265 	}
9266 
9267 	if (isdefault && elts.restarter == NULL &&
9268 	    elts.dependencies == NULL && elts.method_context == NULL &&
9269 	    elts.exec_methods == NULL && elts.property_groups == NULL &&
9270 	    elts.template == NULL) {
9271 		xmlChar *eval;
9272 
9273 		/* This is a default instance */
9274 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
9275 
9276 		xmlFreeNode(n);
9277 
9278 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
9279 		if (n == NULL)
9280 			uu_die(emsg_create_xml);
9281 
9282 		safe_setprop(n, enabled_attr, (char *)eval);
9283 		xmlFree(eval);
9284 
9285 		selts->create_default_instance = n;
9286 	} else {
9287 		/* Assemble the children in order. */
9288 		(void) xmlAddChild(n, elts.restarter);
9289 		(void) xmlAddChildList(n, elts.dependencies);
9290 		(void) xmlAddChildList(n, elts.dependents);
9291 		(void) xmlAddChild(n, elts.method_context);
9292 		(void) xmlAddChildList(n, elts.exec_methods);
9293 		(void) xmlAddChildList(n, elts.property_groups);
9294 		(void) xmlAddChild(n, elts.template);
9295 
9296 		if (selts->instances == NULL)
9297 			selts->instances = n;
9298 		else
9299 			(void) xmlAddSibling(selts->instances, n);
9300 	}
9301 }
9302 
9303 /*
9304  * Return a service element for the given service.
9305  */
9306 static xmlNodePtr
9307 export_service(scf_service_t *svc, int flags)
9308 {
9309 	xmlNodePtr snode;
9310 	struct entity_elts elts;
9311 	struct template_elts template_elts;
9312 	int ret;
9313 
9314 	snode = xmlNewNode(NULL, (xmlChar *)"service");
9315 	if (snode == NULL)
9316 		uu_die(emsg_create_xml);
9317 
9318 	/* Get & set name attribute */
9319 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
9320 		scfdie();
9321 	safe_setprop(snode, name_attr, exp_str);
9322 
9323 	safe_setprop(snode, type_attr, "service");
9324 	safe_setprop(snode, "version", "0");
9325 
9326 	/* Acquire child elements. */
9327 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
9328 		scfdie();
9329 
9330 	(void) memset(&elts, 0, sizeof (elts));
9331 	(void) memset(&template_elts, 0, sizeof (template_elts));
9332 
9333 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9334 		uint32_t pgflags;
9335 
9336 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9337 			scfdie();
9338 
9339 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9340 			continue;
9341 
9342 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9343 			scfdie();
9344 
9345 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9346 			export_dependency(exp_pg, &elts);
9347 			continue;
9348 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9349 			export_method(exp_pg, &elts);
9350 			continue;
9351 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9352 			if (scf_pg_get_name(exp_pg, exp_str,
9353 			    max_scf_name_len + 1) < 0)
9354 				scfdie();
9355 
9356 			if (strcmp(exp_str, scf_pg_general) == 0) {
9357 				export_svc_general(exp_pg, &elts);
9358 				continue;
9359 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9360 			    0) {
9361 				export_method_context(exp_pg, &elts);
9362 				continue;
9363 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9364 				export_dependents(exp_pg, &elts);
9365 				continue;
9366 			}
9367 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9368 			export_template(exp_pg, &elts, &template_elts);
9369 			continue;
9370 		}
9371 
9372 		export_pg(exp_pg, &elts, flags);
9373 	}
9374 	if (ret == -1)
9375 		scfdie();
9376 
9377 	if (template_elts.common_name != NULL) {
9378 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9379 		(void) xmlAddChild(elts.template, template_elts.common_name);
9380 		(void) xmlAddChild(elts.template, template_elts.description);
9381 		(void) xmlAddChild(elts.template, template_elts.documentation);
9382 	} else {
9383 		xmlFreeNode(template_elts.description);
9384 		xmlFreeNode(template_elts.documentation);
9385 	}
9386 
9387 	/* Iterate instances */
9388 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
9389 		scfdie();
9390 
9391 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
9392 		export_instance(exp_inst, &elts, flags);
9393 	if (ret == -1)
9394 		scfdie();
9395 
9396 	/* Now add all of the accumulated elements in order. */
9397 	(void) xmlAddChild(snode, elts.create_default_instance);
9398 	(void) xmlAddChild(snode, elts.single_instance);
9399 	(void) xmlAddChild(snode, elts.restarter);
9400 	(void) xmlAddChildList(snode, elts.dependencies);
9401 	(void) xmlAddChildList(snode, elts.dependents);
9402 	(void) xmlAddChild(snode, elts.method_context);
9403 	(void) xmlAddChildList(snode, elts.exec_methods);
9404 	(void) xmlAddChildList(snode, elts.property_groups);
9405 	(void) xmlAddChildList(snode, elts.instances);
9406 	(void) xmlAddChild(snode, elts.stability);
9407 	(void) xmlAddChild(snode, elts.template);
9408 
9409 	return (snode);
9410 }
9411 
9412 static int
9413 export_callback(void *data, scf_walkinfo_t *wip)
9414 {
9415 	FILE *f;
9416 	xmlDocPtr doc;
9417 	xmlNodePtr sb;
9418 	int result;
9419 	struct export_args *argsp = (struct export_args *)data;
9420 
9421 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
9422 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9423 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9424 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9425 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9426 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9427 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9428 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9429 		scfdie();
9430 
9431 	exp_str_sz = max_scf_len + 1;
9432 	exp_str = safe_malloc(exp_str_sz);
9433 
9434 	if (argsp->filename != NULL) {
9435 		errno = 0;
9436 		f = fopen(argsp->filename, "wb");
9437 		if (f == NULL) {
9438 			if (errno == 0)
9439 				uu_die(gettext("Could not open \"%s\": no free "
9440 				    "stdio streams.\n"), argsp->filename);
9441 			else
9442 				uu_die(gettext("Could not open \"%s\""),
9443 				    argsp->filename);
9444 		}
9445 	} else
9446 		f = stdout;
9447 
9448 	doc = xmlNewDoc((xmlChar *)"1.0");
9449 	if (doc == NULL)
9450 		uu_die(gettext("Could not create XML document.\n"));
9451 
9452 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9453 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9454 		uu_die(emsg_create_xml);
9455 
9456 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9457 	if (sb == NULL)
9458 		uu_die(emsg_create_xml);
9459 	safe_setprop(sb, type_attr, "manifest");
9460 	safe_setprop(sb, name_attr, "export");
9461 	(void) xmlAddSibling(doc->children, sb);
9462 
9463 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
9464 
9465 	result = write_service_bundle(doc, f);
9466 
9467 	free(exp_str);
9468 	scf_iter_destroy(exp_val_iter);
9469 	scf_iter_destroy(exp_prop_iter);
9470 	scf_iter_destroy(exp_pg_iter);
9471 	scf_iter_destroy(exp_inst_iter);
9472 	scf_value_destroy(exp_val);
9473 	scf_property_destroy(exp_prop);
9474 	scf_pg_destroy(exp_pg);
9475 	scf_instance_destroy(exp_inst);
9476 
9477 	xmlFreeDoc(doc);
9478 
9479 	if (f != stdout)
9480 		(void) fclose(f);
9481 
9482 	return (result);
9483 }
9484 
9485 /*
9486  * Get the service named by fmri, build an XML tree which represents it, and
9487  * dump it into filename (or stdout if filename is NULL).
9488  */
9489 int
9490 lscf_service_export(char *fmri, const char *filename, int flags)
9491 {
9492 	struct export_args args;
9493 	int ret, err;
9494 
9495 	lscf_prep_hndl();
9496 
9497 	bzero(&args, sizeof (args));
9498 	args.filename = filename;
9499 	args.flags = flags;
9500 
9501 	err = 0;
9502 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
9503 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
9504 	    &args, &err, semerr)) != 0) {
9505 		if (ret != -1)
9506 			semerr(gettext("Failed to walk instances: %s\n"),
9507 			    scf_strerror(ret));
9508 		return (-1);
9509 	}
9510 
9511 	/*
9512 	 * Error message has already been printed.
9513 	 */
9514 	if (err != 0)
9515 		return (-1);
9516 
9517 	return (0);
9518 }
9519 
9520 
9521 /*
9522  * Archive
9523  */
9524 
9525 static xmlNodePtr
9526 make_archive(int flags)
9527 {
9528 	xmlNodePtr sb;
9529 	scf_scope_t *scope;
9530 	scf_service_t *svc;
9531 	scf_iter_t *iter;
9532 	int r;
9533 
9534 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9535 	    (svc = scf_service_create(g_hndl)) == NULL ||
9536 	    (iter = scf_iter_create(g_hndl)) == NULL ||
9537 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
9538 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9539 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9540 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9541 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9542 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9543 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9544 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9545 		scfdie();
9546 
9547 	exp_str_sz = max_scf_len + 1;
9548 	exp_str = safe_malloc(exp_str_sz);
9549 
9550 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9551 	if (sb == NULL)
9552 		uu_die(emsg_create_xml);
9553 	safe_setprop(sb, type_attr, "archive");
9554 	safe_setprop(sb, name_attr, "none");
9555 
9556 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
9557 		scfdie();
9558 	if (scf_iter_scope_services(iter, scope) != 0)
9559 		scfdie();
9560 
9561 	for (;;) {
9562 		r = scf_iter_next_service(iter, svc);
9563 		if (r == 0)
9564 			break;
9565 		if (r != 1)
9566 			scfdie();
9567 
9568 		if (scf_service_get_name(svc, exp_str,
9569 		    max_scf_name_len + 1) < 0)
9570 			scfdie();
9571 
9572 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
9573 			continue;
9574 
9575 		xmlAddChild(sb, export_service(svc, flags));
9576 	}
9577 
9578 	free(exp_str);
9579 
9580 	scf_iter_destroy(exp_val_iter);
9581 	scf_iter_destroy(exp_prop_iter);
9582 	scf_iter_destroy(exp_pg_iter);
9583 	scf_iter_destroy(exp_inst_iter);
9584 	scf_value_destroy(exp_val);
9585 	scf_property_destroy(exp_prop);
9586 	scf_pg_destroy(exp_pg);
9587 	scf_instance_destroy(exp_inst);
9588 	scf_iter_destroy(iter);
9589 	scf_service_destroy(svc);
9590 	scf_scope_destroy(scope);
9591 
9592 	return (sb);
9593 }
9594 
9595 int
9596 lscf_archive(const char *filename, int flags)
9597 {
9598 	FILE *f;
9599 	xmlDocPtr doc;
9600 	int result;
9601 
9602 	lscf_prep_hndl();
9603 
9604 	if (filename != NULL) {
9605 		errno = 0;
9606 		f = fopen(filename, "wb");
9607 		if (f == NULL) {
9608 			if (errno == 0)
9609 				uu_die(gettext("Could not open \"%s\": no free "
9610 				    "stdio streams.\n"), filename);
9611 			else
9612 				uu_die(gettext("Could not open \"%s\""),
9613 				    filename);
9614 		}
9615 	} else
9616 		f = stdout;
9617 
9618 	doc = xmlNewDoc((xmlChar *)"1.0");
9619 	if (doc == NULL)
9620 		uu_die(gettext("Could not create XML document.\n"));
9621 
9622 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9623 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9624 		uu_die(emsg_create_xml);
9625 
9626 	(void) xmlAddSibling(doc->children, make_archive(flags));
9627 
9628 	result = write_service_bundle(doc, f);
9629 
9630 	xmlFreeDoc(doc);
9631 
9632 	if (f != stdout)
9633 		(void) fclose(f);
9634 
9635 	return (result);
9636 }
9637 
9638 
9639 /*
9640  * "Extract" a profile.
9641  */
9642 int
9643 lscf_profile_extract(const char *filename)
9644 {
9645 	FILE *f;
9646 	xmlDocPtr doc;
9647 	xmlNodePtr sb, snode, inode;
9648 	scf_scope_t *scope;
9649 	scf_service_t *svc;
9650 	scf_instance_t *inst;
9651 	scf_propertygroup_t *pg;
9652 	scf_property_t *prop;
9653 	scf_value_t *val;
9654 	scf_iter_t *siter, *iiter;
9655 	int r, s;
9656 	char *namebuf;
9657 	uint8_t b;
9658 	int result;
9659 
9660 	lscf_prep_hndl();
9661 
9662 	if (filename != NULL) {
9663 		errno = 0;
9664 		f = fopen(filename, "wb");
9665 		if (f == NULL) {
9666 			if (errno == 0)
9667 				uu_die(gettext("Could not open \"%s\": no "
9668 				    "free stdio streams.\n"), filename);
9669 			else
9670 				uu_die(gettext("Could not open \"%s\""),
9671 				    filename);
9672 		}
9673 	} else
9674 		f = stdout;
9675 
9676 	doc = xmlNewDoc((xmlChar *)"1.0");
9677 	if (doc == NULL)
9678 		uu_die(gettext("Could not create XML document.\n"));
9679 
9680 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9681 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9682 		uu_die(emsg_create_xml);
9683 
9684 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9685 	if (sb == NULL)
9686 		uu_die(emsg_create_xml);
9687 	safe_setprop(sb, type_attr, "profile");
9688 	safe_setprop(sb, name_attr, "extract");
9689 	(void) xmlAddSibling(doc->children, sb);
9690 
9691 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9692 	    (svc = scf_service_create(g_hndl)) == NULL ||
9693 	    (inst = scf_instance_create(g_hndl)) == NULL ||
9694 	    (pg = scf_pg_create(g_hndl)) == NULL ||
9695 	    (prop = scf_property_create(g_hndl)) == NULL ||
9696 	    (val = scf_value_create(g_hndl)) == NULL ||
9697 	    (siter = scf_iter_create(g_hndl)) == NULL ||
9698 	    (iiter = scf_iter_create(g_hndl)) == NULL)
9699 		scfdie();
9700 
9701 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
9702 		scfdie();
9703 
9704 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
9705 		scfdie();
9706 
9707 	namebuf = safe_malloc(max_scf_name_len + 1);
9708 
9709 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
9710 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
9711 			scfdie();
9712 
9713 		snode = xmlNewNode(NULL, (xmlChar *)"service");
9714 		if (snode == NULL)
9715 			uu_die(emsg_create_xml);
9716 
9717 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
9718 		    0)
9719 			scfdie();
9720 
9721 		safe_setprop(snode, name_attr, namebuf);
9722 
9723 		safe_setprop(snode, type_attr, "service");
9724 		safe_setprop(snode, "version", "0");
9725 
9726 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
9727 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
9728 			    SCF_SUCCESS) {
9729 				if (scf_error() != SCF_ERROR_NOT_FOUND)
9730 					scfdie();
9731 
9732 				if (g_verbose) {
9733 					ssize_t len;
9734 					char *fmri;
9735 
9736 					len =
9737 					    scf_instance_to_fmri(inst, NULL, 0);
9738 					if (len < 0)
9739 						scfdie();
9740 
9741 					fmri = safe_malloc(len + 1);
9742 
9743 					if (scf_instance_to_fmri(inst, fmri,
9744 					    len + 1) < 0)
9745 						scfdie();
9746 
9747 					warn("Instance %s has no \"%s\" "
9748 					    "property group.\n", fmri,
9749 					    scf_pg_general);
9750 
9751 					free(fmri);
9752 				}
9753 
9754 				continue;
9755 			}
9756 
9757 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
9758 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
9759 			    prop_get_val(prop, val) != 0)
9760 				continue;
9761 
9762 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
9763 			    NULL);
9764 			if (inode == NULL)
9765 				uu_die(emsg_create_xml);
9766 
9767 			if (scf_instance_get_name(inst, namebuf,
9768 			    max_scf_name_len + 1) < 0)
9769 				scfdie();
9770 
9771 			safe_setprop(inode, name_attr, namebuf);
9772 
9773 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
9774 				scfdie();
9775 
9776 			safe_setprop(inode, enabled_attr, b ? true : false);
9777 		}
9778 		if (s < 0)
9779 			scfdie();
9780 
9781 		if (snode->children != NULL)
9782 			xmlAddChild(sb, snode);
9783 		else
9784 			xmlFreeNode(snode);
9785 	}
9786 	if (r < 0)
9787 		scfdie();
9788 
9789 	free(namebuf);
9790 
9791 	result = write_service_bundle(doc, f);
9792 
9793 	xmlFreeDoc(doc);
9794 
9795 	if (f != stdout)
9796 		(void) fclose(f);
9797 
9798 	return (result);
9799 }
9800 
9801 
9802 /*
9803  * Entity manipulation commands
9804  */
9805 
9806 /*
9807  * Entity selection.  If no entity is selected, then the current scope is in
9808  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
9809  * only cur_inst is NULL, and when an instance is selected, none are NULL.
9810  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
9811  * cur_inst will be non-NULL.
9812  */
9813 
9814 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
9815 static int
9816 select_inst(const char *name)
9817 {
9818 	scf_instance_t *inst;
9819 	scf_error_t err;
9820 
9821 	assert(cur_svc != NULL);
9822 
9823 	inst = scf_instance_create(g_hndl);
9824 	if (inst == NULL)
9825 		scfdie();
9826 
9827 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
9828 		cur_inst = inst;
9829 		return (0);
9830 	}
9831 
9832 	err = scf_error();
9833 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9834 		scfdie();
9835 
9836 	scf_instance_destroy(inst);
9837 	return (1);
9838 }
9839 
9840 /* Returns as above. */
9841 static int
9842 select_svc(const char *name)
9843 {
9844 	scf_service_t *svc;
9845 	scf_error_t err;
9846 
9847 	assert(cur_scope != NULL);
9848 
9849 	svc = scf_service_create(g_hndl);
9850 	if (svc == NULL)
9851 		scfdie();
9852 
9853 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
9854 		cur_svc = svc;
9855 		return (0);
9856 	}
9857 
9858 	err = scf_error();
9859 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9860 		scfdie();
9861 
9862 	scf_service_destroy(svc);
9863 	return (1);
9864 }
9865 
9866 /* ARGSUSED */
9867 static int
9868 select_callback(void *unused, scf_walkinfo_t *wip)
9869 {
9870 	scf_instance_t *inst;
9871 	scf_service_t *svc;
9872 	scf_scope_t *scope;
9873 
9874 	if (wip->inst != NULL) {
9875 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9876 		    (svc = scf_service_create(g_hndl)) == NULL ||
9877 		    (inst = scf_instance_create(g_hndl)) == NULL)
9878 			scfdie();
9879 
9880 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9881 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9882 			scfdie();
9883 	} else {
9884 		assert(wip->svc != NULL);
9885 
9886 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9887 		    (svc = scf_service_create(g_hndl)) == NULL)
9888 			scfdie();
9889 
9890 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9891 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9892 			scfdie();
9893 
9894 		inst = NULL;
9895 	}
9896 
9897 	/* Clear out the current selection */
9898 	assert(cur_scope != NULL);
9899 	scf_scope_destroy(cur_scope);
9900 	scf_service_destroy(cur_svc);
9901 	scf_instance_destroy(cur_inst);
9902 
9903 	cur_scope = scope;
9904 	cur_svc = svc;
9905 	cur_inst = inst;
9906 
9907 	return (0);
9908 }
9909 
9910 static int
9911 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
9912 {
9913 	char **fmri = fmri_p;
9914 
9915 	*fmri = strdup(wip->fmri);
9916 	if (*fmri == NULL)
9917 		uu_die(gettext("Out of memory.\n"));
9918 
9919 	return (0);
9920 }
9921 
9922 /*
9923  * validate [fmri]
9924  * Perform the validation of an FMRI instance.
9925  */
9926 void
9927 lscf_validate_fmri(const char *fmri)
9928 {
9929 	int ret = 0;
9930 	size_t inst_sz;
9931 	char *inst_fmri = NULL;
9932 	scf_tmpl_errors_t *errs = NULL;
9933 	char *snapbuf = NULL;
9934 
9935 	lscf_prep_hndl();
9936 
9937 	if (fmri == NULL) {
9938 		inst_sz = max_scf_fmri_len + 1;
9939 		inst_fmri = safe_malloc(inst_sz);
9940 
9941 		if (cur_snap != NULL) {
9942 			snapbuf = safe_malloc(max_scf_name_len + 1);
9943 			if (scf_snapshot_get_name(cur_snap, snapbuf,
9944 			    max_scf_name_len + 1) < 0)
9945 				scfdie();
9946 		}
9947 		if (cur_inst == NULL) {
9948 			semerr(gettext("No instance selected\n"));
9949 			goto cleanup;
9950 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
9951 		    inst_sz) >= inst_sz) {
9952 			/* sanity check. Should never get here */
9953 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
9954 			    __FILE__, __LINE__);
9955 		}
9956 	} else {
9957 		scf_error_t scf_err;
9958 		int err = 0;
9959 
9960 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
9961 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
9962 			uu_warn("Failed to walk instances: %s\n",
9963 			    scf_strerror(scf_err));
9964 			goto cleanup;
9965 		}
9966 		if (err != 0) {
9967 			/* error message displayed by scf_walk_fmri */
9968 			goto cleanup;
9969 		}
9970 	}
9971 
9972 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
9973 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
9974 	if (ret == -1) {
9975 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
9976 			warn(gettext("Template data for %s is invalid. "
9977 			    "Consider reverting to a previous snapshot or "
9978 			    "restoring original configuration.\n"), inst_fmri);
9979 		} else {
9980 			uu_warn("%s: %s\n",
9981 			    gettext("Error validating the instance"),
9982 			    scf_strerror(scf_error()));
9983 		}
9984 	} else if (ret == 1 && errs != NULL) {
9985 		scf_tmpl_error_t *err = NULL;
9986 		char *msg;
9987 		size_t len = 256;	/* initial error buffer size */
9988 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
9989 		    SCF_TMPL_STRERROR_HUMAN : 0;
9990 
9991 		msg = safe_malloc(len);
9992 
9993 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
9994 			int ret;
9995 
9996 			if ((ret = scf_tmpl_strerror(err, msg, len,
9997 			    flag)) >= len) {
9998 				len = ret + 1;
9999 				msg = realloc(msg, len);
10000 				if (msg == NULL)
10001 					uu_die(gettext(
10002 					    "Out of memory.\n"));
10003 				(void) scf_tmpl_strerror(err, msg, len,
10004 				    flag);
10005 			}
10006 			(void) fprintf(stderr, "%s\n", msg);
10007 		}
10008 		if (msg != NULL)
10009 			free(msg);
10010 	}
10011 	if (errs != NULL)
10012 		scf_tmpl_errors_destroy(errs);
10013 
10014 cleanup:
10015 	free(inst_fmri);
10016 	free(snapbuf);
10017 }
10018 
10019 static void
10020 lscf_validate_file(const char *filename)
10021 {
10022 	tmpl_errors_t *errs;
10023 
10024 	bundle_t *b = internal_bundle_new();
10025 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
10026 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
10027 			tmpl_errors_print(stderr, errs, "");
10028 			semerr(gettext("Validation failed.\n"));
10029 		}
10030 		tmpl_errors_destroy(errs);
10031 	}
10032 	(void) internal_bundle_free(b);
10033 }
10034 
10035 /*
10036  * validate [fmri|file]
10037  */
10038 void
10039 lscf_validate(const char *arg)
10040 {
10041 	const char *str;
10042 
10043 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
10044 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
10045 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
10046 		lscf_validate_file(str);
10047 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
10048 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
10049 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
10050 		lscf_validate_fmri(str);
10051 	} else if (access(arg, R_OK | F_OK) == 0) {
10052 		lscf_validate_file(arg);
10053 	} else {
10054 		lscf_validate_fmri(arg);
10055 	}
10056 }
10057 
10058 void
10059 lscf_select(const char *fmri)
10060 {
10061 	int ret, err;
10062 
10063 	lscf_prep_hndl();
10064 
10065 	if (cur_snap != NULL) {
10066 		struct snaplevel *elt;
10067 		char *buf;
10068 
10069 		/* Error unless name is that of the next level. */
10070 		elt = uu_list_next(cur_levels, cur_elt);
10071 		if (elt == NULL) {
10072 			semerr(gettext("No children.\n"));
10073 			return;
10074 		}
10075 
10076 		buf = safe_malloc(max_scf_name_len + 1);
10077 
10078 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10079 		    max_scf_name_len + 1) < 0)
10080 			scfdie();
10081 
10082 		if (strcmp(buf, fmri) != 0) {
10083 			semerr(gettext("No such child.\n"));
10084 			free(buf);
10085 			return;
10086 		}
10087 
10088 		free(buf);
10089 
10090 		cur_elt = elt;
10091 		cur_level = elt->sl;
10092 		return;
10093 	}
10094 
10095 	/*
10096 	 * Special case for 'svc:', which takes the user to the scope level.
10097 	 */
10098 	if (strcmp(fmri, "svc:") == 0) {
10099 		scf_instance_destroy(cur_inst);
10100 		scf_service_destroy(cur_svc);
10101 		cur_inst = NULL;
10102 		cur_svc = NULL;
10103 		return;
10104 	}
10105 
10106 	/*
10107 	 * Special case for ':properties'.  This appears as part of 'list' but
10108 	 * can't be selected.  Give a more helpful error message in this case.
10109 	 */
10110 	if (strcmp(fmri, ":properties") == 0) {
10111 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
10112 		    "to list properties.\n"));
10113 		return;
10114 	}
10115 
10116 	/*
10117 	 * First try the argument as relative to the current selection.
10118 	 */
10119 	if (cur_inst != NULL) {
10120 		/* EMPTY */;
10121 	} else if (cur_svc != NULL) {
10122 		if (select_inst(fmri) != 1)
10123 			return;
10124 	} else {
10125 		if (select_svc(fmri) != 1)
10126 			return;
10127 	}
10128 
10129 	err = 0;
10130 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
10131 	    select_callback, NULL, &err, semerr)) != 0) {
10132 		semerr(gettext("Failed to walk instances: %s\n"),
10133 		    scf_strerror(ret));
10134 	}
10135 }
10136 
10137 void
10138 lscf_unselect(void)
10139 {
10140 	lscf_prep_hndl();
10141 
10142 	if (cur_snap != NULL) {
10143 		struct snaplevel *elt;
10144 
10145 		elt = uu_list_prev(cur_levels, cur_elt);
10146 		if (elt == NULL) {
10147 			semerr(gettext("No parent levels.\n"));
10148 		} else {
10149 			cur_elt = elt;
10150 			cur_level = elt->sl;
10151 		}
10152 	} else if (cur_inst != NULL) {
10153 		scf_instance_destroy(cur_inst);
10154 		cur_inst = NULL;
10155 	} else if (cur_svc != NULL) {
10156 		scf_service_destroy(cur_svc);
10157 		cur_svc = NULL;
10158 	} else {
10159 		semerr(gettext("Cannot unselect at scope level.\n"));
10160 	}
10161 }
10162 
10163 /*
10164  * Return the FMRI of the current selection, for the prompt.
10165  */
10166 void
10167 lscf_get_selection_str(char *buf, size_t bufsz)
10168 {
10169 	char *cp;
10170 	ssize_t fmrilen, szret;
10171 	boolean_t deleted = B_FALSE;
10172 
10173 	if (g_hndl == NULL) {
10174 		(void) strlcpy(buf, "svc:", bufsz);
10175 		return;
10176 	}
10177 
10178 	if (cur_level != NULL) {
10179 		assert(cur_snap != NULL);
10180 
10181 		/* [ snapshot ] FMRI [: instance ] */
10182 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
10183 		    + 2 + max_scf_name_len + 1 + 1);
10184 
10185 		buf[0] = '[';
10186 
10187 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
10188 		    max_scf_name_len + 1);
10189 		if (szret < 0) {
10190 			if (scf_error() != SCF_ERROR_DELETED)
10191 				scfdie();
10192 
10193 			goto snap_deleted;
10194 		}
10195 
10196 		(void) strcat(buf, "]svc:/");
10197 
10198 		cp = strchr(buf, '\0');
10199 
10200 		szret = scf_snaplevel_get_service_name(cur_level, cp,
10201 		    max_scf_name_len + 1);
10202 		if (szret < 0) {
10203 			if (scf_error() != SCF_ERROR_DELETED)
10204 				scfdie();
10205 
10206 			goto snap_deleted;
10207 		}
10208 
10209 		cp = strchr(cp, '\0');
10210 
10211 		if (snaplevel_is_instance(cur_level)) {
10212 			*cp++ = ':';
10213 
10214 			if (scf_snaplevel_get_instance_name(cur_level, cp,
10215 			    max_scf_name_len + 1) < 0) {
10216 				if (scf_error() != SCF_ERROR_DELETED)
10217 					scfdie();
10218 
10219 				goto snap_deleted;
10220 			}
10221 		} else {
10222 			*cp++ = '[';
10223 			*cp++ = ':';
10224 
10225 			if (scf_instance_get_name(cur_inst, cp,
10226 			    max_scf_name_len + 1) < 0) {
10227 				if (scf_error() != SCF_ERROR_DELETED)
10228 					scfdie();
10229 
10230 				goto snap_deleted;
10231 			}
10232 
10233 			(void) strcat(buf, "]");
10234 		}
10235 
10236 		return;
10237 
10238 snap_deleted:
10239 		deleted = B_TRUE;
10240 		free(buf);
10241 		unselect_cursnap();
10242 	}
10243 
10244 	assert(cur_snap == NULL);
10245 
10246 	if (cur_inst != NULL) {
10247 		assert(cur_svc != NULL);
10248 		assert(cur_scope != NULL);
10249 
10250 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
10251 		if (fmrilen >= 0) {
10252 			assert(fmrilen < bufsz);
10253 			if (deleted)
10254 				warn(emsg_deleted);
10255 			return;
10256 		}
10257 
10258 		if (scf_error() != SCF_ERROR_DELETED)
10259 			scfdie();
10260 
10261 		deleted = B_TRUE;
10262 
10263 		scf_instance_destroy(cur_inst);
10264 		cur_inst = NULL;
10265 	}
10266 
10267 	if (cur_svc != NULL) {
10268 		assert(cur_scope != NULL);
10269 
10270 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
10271 		if (szret >= 0) {
10272 			assert(szret < bufsz);
10273 			if (deleted)
10274 				warn(emsg_deleted);
10275 			return;
10276 		}
10277 
10278 		if (scf_error() != SCF_ERROR_DELETED)
10279 			scfdie();
10280 
10281 		deleted = B_TRUE;
10282 		scf_service_destroy(cur_svc);
10283 		cur_svc = NULL;
10284 	}
10285 
10286 	assert(cur_scope != NULL);
10287 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
10288 
10289 	if (fmrilen < 0)
10290 		scfdie();
10291 
10292 	assert(fmrilen < bufsz);
10293 	if (deleted)
10294 		warn(emsg_deleted);
10295 }
10296 
10297 /*
10298  * Entity listing.  Entities and colon namespaces (e.g., :properties and
10299  * :statistics) are listed for the current selection.
10300  */
10301 void
10302 lscf_list(const char *pattern)
10303 {
10304 	scf_iter_t *iter;
10305 	char *buf;
10306 	int ret;
10307 
10308 	lscf_prep_hndl();
10309 
10310 	if (cur_level != NULL) {
10311 		struct snaplevel *elt;
10312 
10313 		(void) fputs(COLON_NAMESPACES, stdout);
10314 
10315 		elt = uu_list_next(cur_levels, cur_elt);
10316 		if (elt == NULL)
10317 			return;
10318 
10319 		/*
10320 		 * For now, we know that the next level is an instance.  But
10321 		 * if we ever have multiple scopes, this could be complicated.
10322 		 */
10323 		buf = safe_malloc(max_scf_name_len + 1);
10324 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10325 		    max_scf_name_len + 1) >= 0) {
10326 			(void) puts(buf);
10327 		} else {
10328 			if (scf_error() != SCF_ERROR_DELETED)
10329 				scfdie();
10330 		}
10331 
10332 		free(buf);
10333 
10334 		return;
10335 	}
10336 
10337 	if (cur_inst != NULL) {
10338 		(void) fputs(COLON_NAMESPACES, stdout);
10339 		return;
10340 	}
10341 
10342 	iter = scf_iter_create(g_hndl);
10343 	if (iter == NULL)
10344 		scfdie();
10345 
10346 	buf = safe_malloc(max_scf_name_len + 1);
10347 
10348 	if (cur_svc != NULL) {
10349 		/* List the instances in this service. */
10350 		scf_instance_t *inst;
10351 
10352 		inst = scf_instance_create(g_hndl);
10353 		if (inst == NULL)
10354 			scfdie();
10355 
10356 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
10357 			safe_printf(COLON_NAMESPACES);
10358 
10359 			for (;;) {
10360 				ret = scf_iter_next_instance(iter, inst);
10361 				if (ret == 0)
10362 					break;
10363 				if (ret != 1) {
10364 					if (scf_error() != SCF_ERROR_DELETED)
10365 						scfdie();
10366 
10367 					break;
10368 				}
10369 
10370 				if (scf_instance_get_name(inst, buf,
10371 				    max_scf_name_len + 1) >= 0) {
10372 					if (pattern == NULL ||
10373 					    fnmatch(pattern, buf, 0) == 0)
10374 						(void) puts(buf);
10375 				} else {
10376 					if (scf_error() != SCF_ERROR_DELETED)
10377 						scfdie();
10378 				}
10379 			}
10380 		} else {
10381 			if (scf_error() != SCF_ERROR_DELETED)
10382 				scfdie();
10383 		}
10384 
10385 		scf_instance_destroy(inst);
10386 	} else {
10387 		/* List the services in this scope. */
10388 		scf_service_t *svc;
10389 
10390 		assert(cur_scope != NULL);
10391 
10392 		svc = scf_service_create(g_hndl);
10393 		if (svc == NULL)
10394 			scfdie();
10395 
10396 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
10397 			scfdie();
10398 
10399 		for (;;) {
10400 			ret = scf_iter_next_service(iter, svc);
10401 			if (ret == 0)
10402 				break;
10403 			if (ret != 1)
10404 				scfdie();
10405 
10406 			if (scf_service_get_name(svc, buf,
10407 			    max_scf_name_len + 1) >= 0) {
10408 				if (pattern == NULL ||
10409 				    fnmatch(pattern, buf, 0) == 0)
10410 					safe_printf("%s\n", buf);
10411 			} else {
10412 				if (scf_error() != SCF_ERROR_DELETED)
10413 					scfdie();
10414 			}
10415 		}
10416 
10417 		scf_service_destroy(svc);
10418 	}
10419 
10420 	free(buf);
10421 	scf_iter_destroy(iter);
10422 }
10423 
10424 /*
10425  * Entity addition.  Creates an empty entity in the current selection.
10426  */
10427 void
10428 lscf_add(const char *name)
10429 {
10430 	lscf_prep_hndl();
10431 
10432 	if (cur_snap != NULL) {
10433 		semerr(emsg_cant_modify_snapshots);
10434 	} else if (cur_inst != NULL) {
10435 		semerr(gettext("Cannot add entities to an instance.\n"));
10436 	} else if (cur_svc != NULL) {
10437 
10438 		if (scf_service_add_instance(cur_svc, name, NULL) !=
10439 		    SCF_SUCCESS) {
10440 			switch (scf_error()) {
10441 			case SCF_ERROR_INVALID_ARGUMENT:
10442 				semerr(gettext("Invalid name.\n"));
10443 				break;
10444 
10445 			case SCF_ERROR_EXISTS:
10446 				semerr(gettext("Instance already exists.\n"));
10447 				break;
10448 
10449 			case SCF_ERROR_PERMISSION_DENIED:
10450 				semerr(emsg_permission_denied);
10451 				break;
10452 
10453 			default:
10454 				scfdie();
10455 			}
10456 		}
10457 	} else {
10458 		assert(cur_scope != NULL);
10459 
10460 		if (scf_scope_add_service(cur_scope, name, NULL) !=
10461 		    SCF_SUCCESS) {
10462 			switch (scf_error()) {
10463 			case SCF_ERROR_INVALID_ARGUMENT:
10464 				semerr(gettext("Invalid name.\n"));
10465 				break;
10466 
10467 			case SCF_ERROR_EXISTS:
10468 				semerr(gettext("Service already exists.\n"));
10469 				break;
10470 
10471 			case SCF_ERROR_PERMISSION_DENIED:
10472 				semerr(emsg_permission_denied);
10473 				break;
10474 
10475 			case SCF_ERROR_BACKEND_READONLY:
10476 				semerr(emsg_read_only);
10477 				break;
10478 
10479 			default:
10480 				scfdie();
10481 			}
10482 		}
10483 	}
10484 }
10485 
10486 /* return 1 if the entity has no persistent pgs, else return 0 */
10487 static int
10488 entity_has_no_pgs(void *ent, int isservice)
10489 {
10490 	scf_iter_t *iter = NULL;
10491 	scf_propertygroup_t *pg = NULL;
10492 	uint32_t flags;
10493 	int err;
10494 	int ret = 1;
10495 
10496 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10497 	    (pg = scf_pg_create(g_hndl)) == NULL)
10498 		scfdie();
10499 
10500 	if (isservice) {
10501 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
10502 			scfdie();
10503 	} else {
10504 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
10505 			scfdie();
10506 	}
10507 
10508 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10509 		if (scf_pg_get_flags(pg, &flags) != 0)
10510 			scfdie();
10511 
10512 		/* skip nonpersistent pgs */
10513 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
10514 			continue;
10515 
10516 		ret = 0;
10517 		break;
10518 	}
10519 
10520 	if (err == -1)
10521 		scfdie();
10522 
10523 	scf_pg_destroy(pg);
10524 	scf_iter_destroy(iter);
10525 
10526 	return (ret);
10527 }
10528 
10529 /* return 1 if the service has no instances, else return 0 */
10530 static int
10531 svc_has_no_insts(scf_service_t *svc)
10532 {
10533 	scf_instance_t *inst;
10534 	scf_iter_t *iter;
10535 	int r;
10536 	int ret = 1;
10537 
10538 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10539 	    (iter = scf_iter_create(g_hndl)) == NULL)
10540 		scfdie();
10541 
10542 	if (scf_iter_service_instances(iter, svc) != 0)
10543 		scfdie();
10544 
10545 	r = scf_iter_next_instance(iter, inst);
10546 	if (r == 1) {
10547 		ret = 0;
10548 	} else if (r == 0) {
10549 		ret = 1;
10550 	} else if (r == -1) {
10551 		scfdie();
10552 	} else {
10553 		bad_error("scf_iter_next_instance", r);
10554 	}
10555 
10556 	scf_iter_destroy(iter);
10557 	scf_instance_destroy(inst);
10558 
10559 	return (ret);
10560 }
10561 
10562 /*
10563  * Entity deletion.
10564  */
10565 
10566 /*
10567  * Delete the property group <fmri>/:properties/<name>.  Returns
10568  * SCF_ERROR_NONE on success (or if the entity is not found),
10569  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
10570  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
10571  * denied.
10572  */
10573 static scf_error_t
10574 delete_dependency_pg(const char *fmri, const char *name)
10575 {
10576 	void *entity = NULL;
10577 	int isservice;
10578 	scf_propertygroup_t *pg = NULL;
10579 	scf_error_t result;
10580 	char *pgty;
10581 	scf_service_t *svc = NULL;
10582 	scf_instance_t *inst = NULL;
10583 	scf_iter_t *iter = NULL;
10584 	char *name_buf = NULL;
10585 
10586 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10587 	switch (result) {
10588 	case SCF_ERROR_NONE:
10589 		break;
10590 
10591 	case SCF_ERROR_NO_MEMORY:
10592 		uu_die(gettext("Out of memory.\n"));
10593 		/* NOTREACHED */
10594 
10595 	case SCF_ERROR_INVALID_ARGUMENT:
10596 	case SCF_ERROR_CONSTRAINT_VIOLATED:
10597 		return (SCF_ERROR_INVALID_ARGUMENT);
10598 
10599 	case SCF_ERROR_NOT_FOUND:
10600 		result = SCF_ERROR_NONE;
10601 		goto out;
10602 
10603 	default:
10604 		bad_error("fmri_to_entity", result);
10605 	}
10606 
10607 	pg = scf_pg_create(g_hndl);
10608 	if (pg == NULL)
10609 		scfdie();
10610 
10611 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
10612 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10613 			scfdie();
10614 
10615 		result = SCF_ERROR_NONE;
10616 		goto out;
10617 	}
10618 
10619 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10620 
10621 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10622 		scfdie();
10623 
10624 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
10625 		result = SCF_ERROR_TYPE_MISMATCH;
10626 		free(pgty);
10627 		goto out;
10628 	}
10629 
10630 	free(pgty);
10631 
10632 	if (scf_pg_delete(pg) != 0) {
10633 		result = scf_error();
10634 		if (result != SCF_ERROR_PERMISSION_DENIED)
10635 			scfdie();
10636 		goto out;
10637 	}
10638 
10639 	/*
10640 	 * We have to handle the case where we've just deleted the last
10641 	 * property group of a "dummy" entity (instance or service).
10642 	 * A "dummy" entity is an entity only present to hold an
10643 	 * external dependency.
10644 	 * So, in the case we deleted the last property group then we
10645 	 * can also delete the entity. If the entity is an instance then
10646 	 * we must verify if this was the last instance for the service
10647 	 * and if it is, we can also delete the service if it doesn't
10648 	 * have any property group either.
10649 	 */
10650 
10651 	result = SCF_ERROR_NONE;
10652 
10653 	if (isservice) {
10654 		svc = (scf_service_t *)entity;
10655 
10656 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
10657 		    (iter = scf_iter_create(g_hndl)) == NULL)
10658 			scfdie();
10659 
10660 		name_buf = safe_malloc(max_scf_name_len + 1);
10661 	} else {
10662 		inst = (scf_instance_t *)entity;
10663 	}
10664 
10665 	/*
10666 	 * If the entity is an instance and we've just deleted its last
10667 	 * property group then we should delete it.
10668 	 */
10669 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
10670 		/* find the service before deleting the inst. - needed later */
10671 		if ((svc = scf_service_create(g_hndl)) == NULL)
10672 			scfdie();
10673 
10674 		if (scf_instance_get_parent(inst, svc) != 0)
10675 			scfdie();
10676 
10677 		/* delete the instance */
10678 		if (scf_instance_delete(inst) != 0) {
10679 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10680 				scfdie();
10681 
10682 			result = SCF_ERROR_PERMISSION_DENIED;
10683 			goto out;
10684 		}
10685 		/* no need to refresh the instance */
10686 		inst = NULL;
10687 	}
10688 
10689 	/*
10690 	 * If the service has no more instances and pgs or we just deleted the
10691 	 * last instance and the service doesn't have anymore propery groups
10692 	 * then the service should be deleted.
10693 	 */
10694 	if (svc != NULL &&
10695 	    svc_has_no_insts(svc) &&
10696 	    entity_has_no_pgs((void *)svc, 1)) {
10697 		if (scf_service_delete(svc) == 0) {
10698 			if (isservice) {
10699 				/* no need to refresh the service */
10700 				svc = NULL;
10701 			}
10702 
10703 			goto out;
10704 		}
10705 
10706 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10707 			scfdie();
10708 
10709 		result = SCF_ERROR_PERMISSION_DENIED;
10710 	}
10711 
10712 	/* if the entity has not been deleted, refresh it */
10713 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
10714 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
10715 		    name_buf);
10716 	}
10717 
10718 out:
10719 	if (isservice && (inst != NULL && iter != NULL)) {
10720 		free(name_buf);
10721 		scf_iter_destroy(iter);
10722 		scf_instance_destroy(inst);
10723 	}
10724 
10725 	if (!isservice && svc != NULL) {
10726 		scf_service_destroy(svc);
10727 	}
10728 
10729 	scf_pg_destroy(pg);
10730 	if (entity != NULL)
10731 		entity_destroy(entity, isservice);
10732 
10733 	return (result);
10734 }
10735 
10736 static int
10737 delete_dependents(scf_propertygroup_t *pg)
10738 {
10739 	char *pgty, *name, *fmri;
10740 	scf_property_t *prop;
10741 	scf_value_t *val;
10742 	scf_iter_t *iter;
10743 	int r;
10744 	scf_error_t err;
10745 
10746 	/* Verify that the pg has the correct type. */
10747 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10748 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10749 		scfdie();
10750 
10751 	if (strcmp(pgty, scf_group_framework) != 0) {
10752 		if (g_verbose) {
10753 			fmri = safe_malloc(max_scf_fmri_len + 1);
10754 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
10755 				scfdie();
10756 
10757 			warn(gettext("Property group %s is not of expected "
10758 			    "type %s.\n"), fmri, scf_group_framework);
10759 
10760 			free(fmri);
10761 		}
10762 
10763 		free(pgty);
10764 		return (-1);
10765 	}
10766 
10767 	free(pgty);
10768 
10769 	/* map delete_dependency_pg onto the properties. */
10770 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10771 	    (val = scf_value_create(g_hndl)) == NULL ||
10772 	    (iter = scf_iter_create(g_hndl)) == NULL)
10773 		scfdie();
10774 
10775 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10776 		scfdie();
10777 
10778 	name = safe_malloc(max_scf_name_len + 1);
10779 	fmri = safe_malloc(max_scf_fmri_len + 2);
10780 
10781 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
10782 		scf_type_t ty;
10783 
10784 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
10785 			scfdie();
10786 
10787 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
10788 			scfdie();
10789 
10790 		if ((ty != SCF_TYPE_ASTRING &&
10791 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
10792 		    prop_get_val(prop, val) != 0)
10793 			continue;
10794 
10795 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
10796 			scfdie();
10797 
10798 		err = delete_dependency_pg(fmri, name);
10799 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
10800 			if (scf_property_to_fmri(prop, fmri,
10801 			    max_scf_fmri_len + 2) < 0)
10802 				scfdie();
10803 
10804 			warn(gettext("Value of %s is not a valid FMRI.\n"),
10805 			    fmri);
10806 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
10807 			warn(gettext("Property group \"%s\" of entity \"%s\" "
10808 			    "does not have dependency type.\n"), name, fmri);
10809 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
10810 			warn(gettext("Could not delete property group \"%s\" "
10811 			    "of entity \"%s\" (permission denied).\n"), name,
10812 			    fmri);
10813 		}
10814 	}
10815 	if (r == -1)
10816 		scfdie();
10817 
10818 	scf_value_destroy(val);
10819 	scf_property_destroy(prop);
10820 
10821 	return (0);
10822 }
10823 
10824 /*
10825  * Returns 1 if the instance may be running, and 0 otherwise.
10826  */
10827 static int
10828 inst_is_running(scf_instance_t *inst)
10829 {
10830 	scf_propertygroup_t *pg;
10831 	scf_property_t *prop;
10832 	scf_value_t *val;
10833 	char buf[MAX_SCF_STATE_STRING_SZ];
10834 	int ret = 0;
10835 	ssize_t szret;
10836 
10837 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10838 	    (prop = scf_property_create(g_hndl)) == NULL ||
10839 	    (val = scf_value_create(g_hndl)) == NULL)
10840 		scfdie();
10841 
10842 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
10843 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10844 			scfdie();
10845 		goto out;
10846 	}
10847 
10848 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
10849 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
10850 	    prop_get_val(prop, val) != 0)
10851 		goto out;
10852 
10853 	szret = scf_value_get_astring(val, buf, sizeof (buf));
10854 	assert(szret >= 0);
10855 
10856 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
10857 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
10858 
10859 out:
10860 	scf_value_destroy(val);
10861 	scf_property_destroy(prop);
10862 	scf_pg_destroy(pg);
10863 	return (ret);
10864 }
10865 
10866 static uint8_t
10867 pg_is_external_dependency(scf_propertygroup_t *pg)
10868 {
10869 	char *type;
10870 	scf_value_t *val;
10871 	scf_property_t *prop;
10872 	uint8_t b = B_FALSE;
10873 
10874 	type = safe_malloc(max_scf_pg_type_len + 1);
10875 
10876 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
10877 		scfdie();
10878 
10879 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10880 	    (val = scf_value_create(g_hndl)) == NULL)
10881 		scfdie();
10882 
10883 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
10884 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
10885 			if (scf_property_get_value(prop, val) != 0)
10886 				scfdie();
10887 			if (scf_value_get_boolean(val, &b) != 0)
10888 				scfdie();
10889 		}
10890 	}
10891 
10892 	free(type);
10893 	(void) scf_value_destroy(val);
10894 	(void) scf_property_destroy(prop);
10895 
10896 	return (b);
10897 }
10898 
10899 #define	DELETE_FAILURE			-1
10900 #define	DELETE_SUCCESS_NOEXTDEPS	0
10901 #define	DELETE_SUCCESS_EXTDEPS		1
10902 
10903 /*
10904  * lscf_instance_delete() deletes an instance.  Before calling
10905  * scf_instance_delete(), though, we make sure the instance isn't
10906  * running and delete dependencies in other entities which the instance
10907  * declared as "dependents".  If there are dependencies which were
10908  * created for other entities, then instead of deleting the instance we
10909  * make it "empty" by deleting all other property groups and all
10910  * snapshots.
10911  *
10912  * lscf_instance_delete() verifies that there is no external dependency pgs
10913  * before suppressing the instance. If there is, then we must not remove them
10914  * now in case the instance is re-created otherwise the dependencies would be
10915  * lost. The external dependency pgs will be removed if the dependencies are
10916  * removed.
10917  *
10918  * Returns:
10919  *  DELETE_FAILURE		on failure
10920  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
10921  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
10922  */
10923 static int
10924 lscf_instance_delete(scf_instance_t *inst, int force)
10925 {
10926 	scf_propertygroup_t *pg;
10927 	scf_snapshot_t *snap;
10928 	scf_iter_t *iter;
10929 	int err;
10930 	int external = 0;
10931 
10932 	/* If we're not forcing and the instance is running, refuse. */
10933 	if (!force && inst_is_running(inst)) {
10934 		char *fmri;
10935 
10936 		fmri = safe_malloc(max_scf_fmri_len + 1);
10937 
10938 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
10939 			scfdie();
10940 
10941 		semerr(gettext("Instance %s may be running.  "
10942 		    "Use delete -f if it is not.\n"), fmri);
10943 
10944 		free(fmri);
10945 		return (DELETE_FAILURE);
10946 	}
10947 
10948 	pg = scf_pg_create(g_hndl);
10949 	if (pg == NULL)
10950 		scfdie();
10951 
10952 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
10953 		(void) delete_dependents(pg);
10954 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
10955 		scfdie();
10956 
10957 	scf_pg_destroy(pg);
10958 
10959 	/*
10960 	 * If the instance has some external dependencies then we must
10961 	 * keep them in case the instance is reimported otherwise the
10962 	 * dependencies would be lost on reimport.
10963 	 */
10964 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10965 	    (pg = scf_pg_create(g_hndl)) == NULL)
10966 		scfdie();
10967 
10968 	if (scf_iter_instance_pgs(iter, inst) < 0)
10969 		scfdie();
10970 
10971 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10972 		if (pg_is_external_dependency(pg)) {
10973 			external = 1;
10974 			continue;
10975 		}
10976 
10977 		if (scf_pg_delete(pg) != 0) {
10978 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10979 				scfdie();
10980 			else {
10981 				semerr(emsg_permission_denied);
10982 
10983 				(void) scf_iter_destroy(iter);
10984 				(void) scf_pg_destroy(pg);
10985 				return (DELETE_FAILURE);
10986 			}
10987 		}
10988 	}
10989 
10990 	if (err == -1)
10991 		scfdie();
10992 
10993 	(void) scf_iter_destroy(iter);
10994 	(void) scf_pg_destroy(pg);
10995 
10996 	if (external) {
10997 		/*
10998 		 * All the pgs have been deleted for the instance except
10999 		 * the ones holding the external dependencies.
11000 		 * For the job to be complete, we must also delete the
11001 		 * snapshots associated with the instance.
11002 		 */
11003 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
11004 		    NULL)
11005 			scfdie();
11006 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
11007 			scfdie();
11008 
11009 		if (scf_iter_instance_snapshots(iter, inst) == -1)
11010 			scfdie();
11011 
11012 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
11013 			if (_scf_snapshot_delete(snap) != 0) {
11014 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11015 					scfdie();
11016 
11017 				semerr(emsg_permission_denied);
11018 
11019 				(void) scf_iter_destroy(iter);
11020 				(void) scf_snapshot_destroy(snap);
11021 				return (DELETE_FAILURE);
11022 			}
11023 		}
11024 
11025 		if (err == -1)
11026 			scfdie();
11027 
11028 		(void) scf_iter_destroy(iter);
11029 		(void) scf_snapshot_destroy(snap);
11030 		return (DELETE_SUCCESS_EXTDEPS);
11031 	}
11032 
11033 	if (scf_instance_delete(inst) != 0) {
11034 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11035 			scfdie();
11036 
11037 		semerr(emsg_permission_denied);
11038 
11039 		return (DELETE_FAILURE);
11040 	}
11041 
11042 	return (DELETE_SUCCESS_NOEXTDEPS);
11043 }
11044 
11045 /*
11046  * lscf_service_delete() deletes a service.  Before calling
11047  * scf_service_delete(), though, we call lscf_instance_delete() for
11048  * each of the instances and delete dependencies in other entities
11049  * which were created as "dependents" of this service.  If there are
11050  * dependencies which were created for other entities, then we delete
11051  * all other property groups in the service and leave it as "empty".
11052  *
11053  * lscf_service_delete() verifies that there is no external dependency
11054  * pgs at the instance & service level before suppressing the service.
11055  * If there is, then we must not remove them now in case the service
11056  * is re-imported otherwise the dependencies would be lost. The external
11057  * dependency pgs will be removed if the dependencies are removed.
11058  *
11059  * Returns:
11060  *   DELETE_FAILURE		on failure
11061  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11062  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11063  */
11064 static int
11065 lscf_service_delete(scf_service_t *svc, int force)
11066 {
11067 	int r;
11068 	scf_instance_t *inst;
11069 	scf_propertygroup_t *pg;
11070 	scf_iter_t *iter;
11071 	int ret;
11072 	int external = 0;
11073 
11074 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11075 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11076 	    (iter = scf_iter_create(g_hndl)) == NULL)
11077 		scfdie();
11078 
11079 	if (scf_iter_service_instances(iter, svc) != 0)
11080 		scfdie();
11081 
11082 	for (r = scf_iter_next_instance(iter, inst);
11083 	    r == 1;
11084 	    r = scf_iter_next_instance(iter, inst)) {
11085 
11086 		ret = lscf_instance_delete(inst, force);
11087 		if (ret == DELETE_FAILURE) {
11088 			scf_iter_destroy(iter);
11089 			scf_pg_destroy(pg);
11090 			scf_instance_destroy(inst);
11091 			return (DELETE_FAILURE);
11092 		}
11093 
11094 		/*
11095 		 * Record the fact that there is some external dependencies
11096 		 * at the instance level.
11097 		 */
11098 		if (ret == DELETE_SUCCESS_EXTDEPS)
11099 			external |= 1;
11100 	}
11101 
11102 	if (r != 0)
11103 		scfdie();
11104 
11105 	/* Delete dependency property groups in dependent services. */
11106 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
11107 		(void) delete_dependents(pg);
11108 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11109 		scfdie();
11110 
11111 	scf_iter_destroy(iter);
11112 	scf_pg_destroy(pg);
11113 	scf_instance_destroy(inst);
11114 
11115 	/*
11116 	 * If the service has some external dependencies then we don't
11117 	 * want to remove them in case the service is re-imported.
11118 	 */
11119 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11120 	    (iter = scf_iter_create(g_hndl)) == NULL)
11121 		scfdie();
11122 
11123 	if (scf_iter_service_pgs(iter, svc) < 0)
11124 		scfdie();
11125 
11126 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
11127 		if (pg_is_external_dependency(pg)) {
11128 			external |= 2;
11129 			continue;
11130 		}
11131 
11132 		if (scf_pg_delete(pg) != 0) {
11133 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11134 				scfdie();
11135 			else {
11136 				semerr(emsg_permission_denied);
11137 
11138 				(void) scf_iter_destroy(iter);
11139 				(void) scf_pg_destroy(pg);
11140 				return (DELETE_FAILURE);
11141 			}
11142 		}
11143 	}
11144 
11145 	if (r == -1)
11146 		scfdie();
11147 
11148 	(void) scf_iter_destroy(iter);
11149 	(void) scf_pg_destroy(pg);
11150 
11151 	if (external != 0)
11152 		return (DELETE_SUCCESS_EXTDEPS);
11153 
11154 	if (scf_service_delete(svc) == 0)
11155 		return (DELETE_SUCCESS_NOEXTDEPS);
11156 
11157 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11158 		scfdie();
11159 
11160 	semerr(emsg_permission_denied);
11161 	return (DELETE_FAILURE);
11162 }
11163 
11164 static int
11165 delete_callback(void *data, scf_walkinfo_t *wip)
11166 {
11167 	int force = (int)data;
11168 
11169 	if (wip->inst != NULL)
11170 		(void) lscf_instance_delete(wip->inst, force);
11171 	else
11172 		(void) lscf_service_delete(wip->svc, force);
11173 
11174 	return (0);
11175 }
11176 
11177 void
11178 lscf_delete(const char *fmri, int force)
11179 {
11180 	scf_service_t *svc;
11181 	scf_instance_t *inst;
11182 	int ret;
11183 
11184 	lscf_prep_hndl();
11185 
11186 	if (cur_snap != NULL) {
11187 		if (!snaplevel_is_instance(cur_level)) {
11188 			char *buf;
11189 
11190 			buf = safe_malloc(max_scf_name_len + 1);
11191 			if (scf_instance_get_name(cur_inst, buf,
11192 			    max_scf_name_len + 1) >= 0) {
11193 				if (strcmp(buf, fmri) == 0) {
11194 					semerr(emsg_cant_modify_snapshots);
11195 					free(buf);
11196 					return;
11197 				}
11198 			} else if (scf_error() != SCF_ERROR_DELETED) {
11199 				scfdie();
11200 			}
11201 			free(buf);
11202 		}
11203 	} else if (cur_inst != NULL) {
11204 		/* EMPTY */;
11205 	} else if (cur_svc != NULL) {
11206 		inst = scf_instance_create(g_hndl);
11207 		if (inst == NULL)
11208 			scfdie();
11209 
11210 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
11211 		    SCF_SUCCESS) {
11212 			(void) lscf_instance_delete(inst, force);
11213 			scf_instance_destroy(inst);
11214 			return;
11215 		}
11216 
11217 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11218 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11219 			scfdie();
11220 
11221 		scf_instance_destroy(inst);
11222 	} else {
11223 		assert(cur_scope != NULL);
11224 
11225 		svc = scf_service_create(g_hndl);
11226 		if (svc == NULL)
11227 			scfdie();
11228 
11229 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
11230 		    SCF_SUCCESS) {
11231 			(void) lscf_service_delete(svc, force);
11232 			scf_service_destroy(svc);
11233 			return;
11234 		}
11235 
11236 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11237 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11238 			scfdie();
11239 
11240 		scf_service_destroy(svc);
11241 	}
11242 
11243 	/*
11244 	 * Match FMRI to entity.
11245 	 */
11246 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11247 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
11248 		semerr(gettext("Failed to walk instances: %s\n"),
11249 		    scf_strerror(ret));
11250 	}
11251 }
11252 
11253 
11254 
11255 /*
11256  * :properties commands.  These all end with "pg" or "prop" and generally
11257  * operate on the currently selected entity.
11258  */
11259 
11260 /*
11261  * Property listing.  List the property groups, properties, their types and
11262  * their values for the currently selected entity.
11263  */
11264 static void
11265 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
11266 {
11267 	char *buf;
11268 	uint32_t flags;
11269 
11270 	buf = safe_malloc(max_scf_pg_type_len + 1);
11271 
11272 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
11273 		scfdie();
11274 
11275 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
11276 		scfdie();
11277 
11278 	safe_printf("%-*s  %s", namewidth, name, buf);
11279 
11280 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
11281 		safe_printf("\tNONPERSISTENT");
11282 
11283 	safe_printf("\n");
11284 
11285 	free(buf);
11286 }
11287 
11288 static boolean_t
11289 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
11290 {
11291 	if (scf_property_get_value(prop, val) == 0) {
11292 		return (B_FALSE);
11293 	} else {
11294 		switch (scf_error()) {
11295 		case SCF_ERROR_NOT_FOUND:
11296 			return (B_FALSE);
11297 		case SCF_ERROR_PERMISSION_DENIED:
11298 		case SCF_ERROR_CONSTRAINT_VIOLATED:
11299 			return (B_TRUE);
11300 		default:
11301 			scfdie();
11302 			/*NOTREACHED*/
11303 		}
11304 	}
11305 }
11306 
11307 static void
11308 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
11309 {
11310 	scf_iter_t *iter;
11311 	scf_value_t *val;
11312 	const char *type;
11313 	int multiple_strings = 0;
11314 	int ret;
11315 
11316 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11317 	    (val = scf_value_create(g_hndl)) == NULL)
11318 		scfdie();
11319 
11320 	type = prop_to_typestr(prop);
11321 	assert(type != NULL);
11322 
11323 	safe_printf("%-*s  %-7s ", len, name, type);
11324 
11325 	if (prop_has_multiple_values(prop, val) &&
11326 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
11327 	    scf_value_type(val) == SCF_TYPE_USTRING))
11328 		multiple_strings = 1;
11329 
11330 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11331 		scfdie();
11332 
11333 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11334 		char *buf;
11335 		ssize_t vlen, szret;
11336 
11337 		vlen = scf_value_get_as_string(val, NULL, 0);
11338 		if (vlen < 0)
11339 			scfdie();
11340 
11341 		buf = safe_malloc(vlen + 1);
11342 
11343 		szret = scf_value_get_as_string(val, buf, vlen + 1);
11344 		if (szret < 0)
11345 			scfdie();
11346 		assert(szret <= vlen);
11347 
11348 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11349 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
11350 			safe_printf(" \"");
11351 			(void) quote_and_print(buf, stdout, 0);
11352 			(void) putchar('"');
11353 			if (ferror(stdout)) {
11354 				(void) putchar('\n');
11355 				uu_die(gettext("Error writing to stdout.\n"));
11356 			}
11357 		} else {
11358 			safe_printf(" %s", buf);
11359 		}
11360 
11361 		free(buf);
11362 	}
11363 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11364 		scfdie();
11365 
11366 	if (putchar('\n') != '\n')
11367 		uu_die(gettext("Could not output newline"));
11368 }
11369 
11370 /*
11371  * Outputs template property group info for the describe subcommand.
11372  * If 'templates' == 2, verbose output is printed in the format expected
11373  * for describe -v, which includes all templates fields.  If pg is
11374  * not NULL, we're describing the template data, not an existing property
11375  * group, and formatting should be appropriate for describe -t.
11376  */
11377 static void
11378 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
11379 {
11380 	char *buf;
11381 	uint8_t required;
11382 	scf_property_t *stability_prop;
11383 	scf_value_t *stability_val;
11384 
11385 	if (templates == 0)
11386 		return;
11387 
11388 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
11389 	    (stability_val = scf_value_create(g_hndl)) == NULL)
11390 		scfdie();
11391 
11392 	if (templates == 2 && pg != NULL) {
11393 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
11394 		    stability_prop) == 0) {
11395 			if (prop_check_type(stability_prop,
11396 			    SCF_TYPE_ASTRING) == 0 &&
11397 			    prop_get_val(stability_prop, stability_val) == 0) {
11398 				char *stability;
11399 
11400 				stability = safe_malloc(max_scf_value_len + 1);
11401 
11402 				if (scf_value_get_astring(stability_val,
11403 				    stability, max_scf_value_len + 1) == -1 &&
11404 				    scf_error() != SCF_ERROR_NOT_FOUND)
11405 					scfdie();
11406 
11407 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11408 				    gettext("stability"), stability);
11409 
11410 				free(stability);
11411 			}
11412 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
11413 			scfdie();
11414 	}
11415 
11416 	scf_property_destroy(stability_prop);
11417 	scf_value_destroy(stability_val);
11418 
11419 	if (pgt == NULL)
11420 		return;
11421 
11422 	if (pg == NULL || templates == 2) {
11423 		/* print type info only if scf_tmpl_pg_name succeeds */
11424 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
11425 			if (pg != NULL)
11426 				safe_printf("%s", TMPL_INDENT);
11427 			safe_printf("%s: ", gettext("name"));
11428 			safe_printf("%s\n", buf);
11429 			free(buf);
11430 		}
11431 
11432 		/* print type info only if scf_tmpl_pg_type succeeds */
11433 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
11434 			if (pg != NULL)
11435 				safe_printf("%s", TMPL_INDENT);
11436 			safe_printf("%s: ", gettext("type"));
11437 			safe_printf("%s\n", buf);
11438 			free(buf);
11439 		}
11440 	}
11441 
11442 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
11443 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11444 		    required ? "true" : "false");
11445 
11446 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
11447 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
11448 		    buf);
11449 		free(buf);
11450 	}
11451 
11452 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
11453 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11454 		    buf);
11455 		free(buf);
11456 	}
11457 
11458 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
11459 		if (templates == 2)
11460 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11461 			    gettext("description"), buf);
11462 		else
11463 			safe_printf("%s%s\n", TMPL_INDENT, buf);
11464 		free(buf);
11465 	}
11466 
11467 }
11468 
11469 /*
11470  * With as_value set to true, indent as appropriate for the value level.
11471  * If false, indent to appropriate level for inclusion in constraint
11472  * or choice printout.
11473  */
11474 static void
11475 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
11476     int as_value)
11477 {
11478 	char *buf;
11479 
11480 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
11481 		if (as_value == 0)
11482 			safe_printf("%s", TMPL_CHOICE_INDENT);
11483 		else
11484 			safe_printf("%s", TMPL_INDENT);
11485 		safe_printf("%s: %s\n", gettext("value common name"), buf);
11486 		free(buf);
11487 	}
11488 
11489 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
11490 		if (as_value == 0)
11491 			safe_printf("%s", TMPL_CHOICE_INDENT);
11492 		else
11493 			safe_printf("%s", TMPL_INDENT);
11494 		safe_printf("%s: %s\n", gettext("value description"), buf);
11495 		free(buf);
11496 	}
11497 }
11498 
11499 static void
11500 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
11501 {
11502 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
11503 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11504 	safe_printf("%s\n", val_buf);
11505 
11506 	print_template_value_details(prt, val_buf, 1);
11507 }
11508 
11509 static void
11510 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
11511 {
11512 	int i, printed = 0;
11513 	scf_values_t values;
11514 	scf_count_ranges_t c_ranges;
11515 	scf_int_ranges_t i_ranges;
11516 
11517 	printed = 0;
11518 	i = 0;
11519 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
11520 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11521 		    gettext("value constraints"));
11522 		printed++;
11523 		for (i = 0; i < values.value_count; ++i) {
11524 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11525 			    gettext("value name"), values.values_as_strings[i]);
11526 			if (verbose == 1)
11527 				print_template_value_details(prt,
11528 				    values.values_as_strings[i], 0);
11529 		}
11530 
11531 		scf_values_destroy(&values);
11532 	}
11533 
11534 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
11535 		if (printed++ == 0)
11536 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11537 			    gettext("value constraints"));
11538 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11539 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11540 			    gettext("range"), c_ranges.scr_min[i],
11541 			    c_ranges.scr_max[i]);
11542 		}
11543 		scf_count_ranges_destroy(&c_ranges);
11544 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11545 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
11546 		if (printed++ == 0)
11547 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11548 			    gettext("value constraints"));
11549 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11550 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11551 			    gettext("range"), i_ranges.sir_min[i],
11552 			    i_ranges.sir_max[i]);
11553 		}
11554 		scf_int_ranges_destroy(&i_ranges);
11555 	}
11556 }
11557 
11558 static void
11559 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
11560 {
11561 	int i = 0, printed = 0;
11562 	scf_values_t values;
11563 	scf_count_ranges_t c_ranges;
11564 	scf_int_ranges_t i_ranges;
11565 
11566 	printed = 0;
11567 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
11568 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11569 		    gettext("value constraints"));
11570 		printed++;
11571 		for (i = 0; i < values.value_count; i++) {
11572 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11573 			    gettext("value name"), values.values_as_strings[i]);
11574 			if (verbose == 1)
11575 				print_template_value_details(prt,
11576 				    values.values_as_strings[i], 0);
11577 		}
11578 
11579 		scf_values_destroy(&values);
11580 	}
11581 
11582 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
11583 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11584 			if (printed++ == 0)
11585 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11586 				    gettext("value choices"));
11587 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11588 			    gettext("range"), c_ranges.scr_min[i],
11589 			    c_ranges.scr_max[i]);
11590 		}
11591 		scf_count_ranges_destroy(&c_ranges);
11592 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11593 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
11594 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11595 			if (printed++ == 0)
11596 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11597 				    gettext("value choices"));
11598 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11599 			    gettext("range"), i_ranges.sir_min[i],
11600 			    i_ranges.sir_max[i]);
11601 		}
11602 		scf_int_ranges_destroy(&i_ranges);
11603 	}
11604 }
11605 
11606 static void
11607 list_values_by_template(scf_prop_tmpl_t *prt)
11608 {
11609 	print_template_constraints(prt, 1);
11610 	print_template_choices(prt, 1);
11611 }
11612 
11613 static void
11614 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
11615 {
11616 	char *val_buf;
11617 	scf_iter_t *iter;
11618 	scf_value_t *val;
11619 	int ret;
11620 
11621 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11622 	    (val = scf_value_create(g_hndl)) == NULL)
11623 		scfdie();
11624 
11625 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11626 		scfdie();
11627 
11628 	val_buf = safe_malloc(max_scf_value_len + 1);
11629 
11630 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11631 		if (scf_value_get_as_string(val, val_buf,
11632 		    max_scf_value_len + 1) < 0)
11633 			scfdie();
11634 
11635 		print_template_value(prt, val_buf);
11636 	}
11637 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11638 		scfdie();
11639 	free(val_buf);
11640 
11641 	print_template_constraints(prt, 0);
11642 	print_template_choices(prt, 0);
11643 
11644 }
11645 
11646 /*
11647  * Outputs property info for the describe subcommand
11648  * Verbose output if templates == 2, -v option of svccfg describe
11649  * Displays template data if prop is not NULL, -t option of svccfg describe
11650  */
11651 static void
11652 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
11653 {
11654 	char *buf;
11655 	uint8_t u_buf;
11656 	int i;
11657 	uint64_t min, max;
11658 	scf_values_t values;
11659 
11660 	if (prt == NULL || templates == 0)
11661 		return;
11662 
11663 	if (prop == NULL) {
11664 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
11665 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
11666 			safe_printf("%s\n", buf);
11667 			free(buf);
11668 		} else
11669 			safe_printf("(%s)\n", gettext("any"));
11670 	}
11671 
11672 	if (prop == NULL || templates == 2) {
11673 		if (prop != NULL)
11674 			safe_printf("%s", TMPL_INDENT);
11675 		else
11676 			safe_printf("%s", TMPL_VALUE_INDENT);
11677 		safe_printf("%s: ", gettext("type"));
11678 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
11679 			safe_printf("%s\n", buf);
11680 			free(buf);
11681 		} else
11682 			safe_printf("(%s)\n", gettext("any"));
11683 	}
11684 
11685 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
11686 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11687 		    u_buf ? "true" : "false");
11688 
11689 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
11690 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11691 		    buf);
11692 		free(buf);
11693 	}
11694 
11695 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
11696 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
11697 		    buf);
11698 		free(buf);
11699 	}
11700 
11701 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
11702 		safe_printf("%s%s\n", TMPL_INDENT, buf);
11703 		free(buf);
11704 	}
11705 
11706 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
11707 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
11708 		    scf_tmpl_visibility_to_string(u_buf));
11709 
11710 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
11711 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11712 		    gettext("minimum number of values"), min);
11713 		if (max == ULLONG_MAX) {
11714 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11715 			    gettext("maximum number of values"),
11716 			    gettext("unlimited"));
11717 		} else {
11718 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11719 			    gettext("maximum number of values"), max);
11720 		}
11721 	}
11722 
11723 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
11724 		for (i = 0; i < values.value_count; i++) {
11725 			if (i == 0) {
11726 				safe_printf("%s%s:", TMPL_INDENT,
11727 				    gettext("internal separators"));
11728 			}
11729 			safe_printf(" \"%s\"", values.values_as_strings[i]);
11730 		}
11731 		safe_printf("\n");
11732 	}
11733 
11734 	if (templates != 2)
11735 		return;
11736 
11737 	if (prop != NULL)
11738 		list_values_tmpl(prt, prop);
11739 	else
11740 		list_values_by_template(prt);
11741 }
11742 
11743 static char *
11744 read_astring(scf_propertygroup_t *pg, const char *prop_name)
11745 {
11746 	char *rv;
11747 
11748 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
11749 	if (rv == NULL) {
11750 		switch (scf_error()) {
11751 		case SCF_ERROR_NOT_FOUND:
11752 			break;
11753 		default:
11754 			scfdie();
11755 		}
11756 	}
11757 	return (rv);
11758 }
11759 
11760 static void
11761 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
11762 {
11763 	size_t doc_len;
11764 	size_t man_len;
11765 	char *pg_name;
11766 	char *text = NULL;
11767 	int rv;
11768 
11769 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
11770 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
11771 	pg_name = safe_malloc(max_scf_name_len + 1);
11772 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
11773 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
11774 			scfdie();
11775 		}
11776 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
11777 			/* Display doc_link and and uri */
11778 			safe_printf("%s%s:\n", TMPL_INDENT,
11779 			    gettext("doc_link"));
11780 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
11781 			if (text != NULL) {
11782 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11783 				    TMPL_INDENT, gettext("name"), text);
11784 				uu_free(text);
11785 			}
11786 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
11787 			if (text != NULL) {
11788 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
11789 				    gettext("uri"), text);
11790 				uu_free(text);
11791 			}
11792 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
11793 		    man_len) == 0) {
11794 			/* Display manpage title, section and path */
11795 			safe_printf("%s%s:\n", TMPL_INDENT,
11796 			    gettext("manpage"));
11797 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
11798 			if (text != NULL) {
11799 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11800 				    TMPL_INDENT, gettext("title"), text);
11801 				uu_free(text);
11802 			}
11803 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
11804 			if (text != NULL) {
11805 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11806 				    TMPL_INDENT, gettext("section"), text);
11807 				uu_free(text);
11808 			}
11809 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
11810 			if (text != NULL) {
11811 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11812 				    TMPL_INDENT, gettext("manpath"), text);
11813 				uu_free(text);
11814 			}
11815 		}
11816 	}
11817 	if (rv == -1)
11818 		scfdie();
11819 
11820 done:
11821 	free(pg_name);
11822 }
11823 
11824 static void
11825 list_entity_tmpl(int templates)
11826 {
11827 	char *common_name = NULL;
11828 	char *description = NULL;
11829 	char *locale = NULL;
11830 	scf_iter_t *iter;
11831 	scf_propertygroup_t *pg;
11832 	scf_property_t *prop;
11833 	int r;
11834 	scf_value_t *val;
11835 
11836 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11837 	    (prop = scf_property_create(g_hndl)) == NULL ||
11838 	    (val = scf_value_create(g_hndl)) == NULL ||
11839 	    (iter = scf_iter_create(g_hndl)) == NULL)
11840 		scfdie();
11841 
11842 	locale = setlocale(LC_MESSAGES, NULL);
11843 
11844 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
11845 		common_name = safe_malloc(max_scf_value_len + 1);
11846 
11847 		/* Try both the current locale and the "C" locale. */
11848 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
11849 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
11850 		    scf_pg_get_property(pg, "C", prop) == 0)) {
11851 			if (prop_get_val(prop, val) == 0 &&
11852 			    scf_value_get_ustring(val, common_name,
11853 			    max_scf_value_len + 1) != -1) {
11854 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11855 				    gettext("common name"), common_name);
11856 			}
11857 		}
11858 	}
11859 
11860 	/*
11861 	 * Do description, manpages, and doc links if templates == 2.
11862 	 */
11863 	if (templates == 2) {
11864 		/* Get the description. */
11865 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
11866 			description = safe_malloc(max_scf_value_len + 1);
11867 
11868 			/* Try both the current locale and the "C" locale. */
11869 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
11870 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
11871 			    scf_pg_get_property(pg, "C", prop) == 0)) {
11872 				if (prop_get_val(prop, val) == 0 &&
11873 				    scf_value_get_ustring(val, description,
11874 				    max_scf_value_len + 1) != -1) {
11875 					safe_printf("%s%s: %s\n", TMPL_INDENT,
11876 					    gettext("description"),
11877 					    description);
11878 				}
11879 			}
11880 		}
11881 
11882 		/* Process doc_link & manpage elements. */
11883 		if (cur_level != NULL) {
11884 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
11885 			    SCF_GROUP_TEMPLATE);
11886 		} else if (cur_inst != NULL) {
11887 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
11888 			    SCF_GROUP_TEMPLATE);
11889 		} else {
11890 			r = scf_iter_service_pgs_typed(iter, cur_svc,
11891 			    SCF_GROUP_TEMPLATE);
11892 		}
11893 		if (r == 0) {
11894 			display_documentation(iter, pg);
11895 		}
11896 	}
11897 
11898 	free(common_name);
11899 	free(description);
11900 	scf_pg_destroy(pg);
11901 	scf_property_destroy(prop);
11902 	scf_value_destroy(val);
11903 	scf_iter_destroy(iter);
11904 }
11905 
11906 static void
11907 listtmpl(const char *pattern, int templates)
11908 {
11909 	scf_pg_tmpl_t *pgt;
11910 	scf_prop_tmpl_t *prt;
11911 	char *snapbuf = NULL;
11912 	char *fmribuf;
11913 	char *pg_name = NULL, *prop_name = NULL;
11914 	ssize_t prop_name_size;
11915 	char *qual_prop_name;
11916 	char *search_name;
11917 	int listed = 0;
11918 
11919 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
11920 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
11921 		scfdie();
11922 
11923 	fmribuf = safe_malloc(max_scf_name_len + 1);
11924 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
11925 
11926 	if (cur_snap != NULL) {
11927 		snapbuf = safe_malloc(max_scf_name_len + 1);
11928 		if (scf_snapshot_get_name(cur_snap, snapbuf,
11929 		    max_scf_name_len + 1) < 0)
11930 			scfdie();
11931 	}
11932 
11933 	if (cur_inst != NULL) {
11934 		if (scf_instance_to_fmri(cur_inst, fmribuf,
11935 		    max_scf_name_len + 1) < 0)
11936 			scfdie();
11937 	} else if (cur_svc != NULL) {
11938 		if (scf_service_to_fmri(cur_svc, fmribuf,
11939 		    max_scf_name_len + 1) < 0)
11940 			scfdie();
11941 	} else
11942 		abort();
11943 
11944 	/* If pattern is specified, we want to list only those items. */
11945 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
11946 		listed = 0;
11947 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
11948 		    fnmatch(pattern, pg_name, 0) == 0)) {
11949 			list_pg_tmpl(pgt, NULL, templates);
11950 			listed++;
11951 		}
11952 
11953 		scf_tmpl_prop_reset(prt);
11954 
11955 		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
11956 			search_name = NULL;
11957 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
11958 			if ((prop_name_size > 0) && (pg_name != NULL)) {
11959 				if (snprintf(qual_prop_name,
11960 				    max_scf_name_len + 1, "%s/%s",
11961 				    pg_name, prop_name) >=
11962 				    max_scf_name_len + 1) {
11963 					prop_name_size = -1;
11964 				} else {
11965 					search_name = qual_prop_name;
11966 				}
11967 			}
11968 			if (listed > 0 || pattern == NULL ||
11969 			    (prop_name_size > 0 &&
11970 			    fnmatch(pattern, search_name,
11971 			    FNM_PATHNAME) == 0))
11972 				list_prop_tmpl(prt, NULL, templates);
11973 			if (prop_name != NULL) {
11974 				free(prop_name);
11975 				prop_name = NULL;
11976 			}
11977 		}
11978 		if (pg_name != NULL) {
11979 			free(pg_name);
11980 			pg_name = NULL;
11981 		}
11982 	}
11983 
11984 	scf_tmpl_prop_destroy(prt);
11985 	scf_tmpl_pg_destroy(pgt);
11986 	free(snapbuf);
11987 	free(fmribuf);
11988 	free(qual_prop_name);
11989 }
11990 
11991 static void
11992 listprop(const char *pattern, int only_pgs, int templates)
11993 {
11994 	scf_propertygroup_t *pg;
11995 	scf_property_t *prop;
11996 	scf_iter_t *iter, *piter;
11997 	char *pgnbuf, *prnbuf, *ppnbuf;
11998 	scf_pg_tmpl_t *pgt, *pgtp;
11999 	scf_prop_tmpl_t *prt;
12000 
12001 	void **objects;
12002 	char **names;
12003 	void **tmpls;
12004 	int allocd, i;
12005 
12006 	int ret;
12007 	ssize_t pgnlen, prnlen, szret;
12008 	size_t max_len = 0;
12009 
12010 	if (cur_svc == NULL && cur_inst == NULL) {
12011 		semerr(emsg_entity_not_selected);
12012 		return;
12013 	}
12014 
12015 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12016 	    (prop = scf_property_create(g_hndl)) == NULL ||
12017 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12018 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12019 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12020 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
12021 		scfdie();
12022 
12023 	prnbuf = safe_malloc(max_scf_name_len + 1);
12024 
12025 	if (cur_level != NULL)
12026 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
12027 	else if (cur_inst != NULL)
12028 		ret = scf_iter_instance_pgs(iter, cur_inst);
12029 	else
12030 		ret = scf_iter_service_pgs(iter, cur_svc);
12031 	if (ret != 0) {
12032 		return;
12033 	}
12034 
12035 	/*
12036 	 * We want to only list items which match pattern, and we want the
12037 	 * second column to line up, so during the first pass we'll save
12038 	 * matching items, their names, and their templates in objects,
12039 	 * names, and tmpls, computing the maximum name length as we go,
12040 	 * and then we'll print them out.
12041 	 *
12042 	 * Note: We always keep an extra slot available so the array can be
12043 	 * NULL-terminated.
12044 	 */
12045 	i = 0;
12046 	allocd = 1;
12047 	objects = safe_malloc(sizeof (*objects));
12048 	names = safe_malloc(sizeof (*names));
12049 	tmpls = safe_malloc(sizeof (*tmpls));
12050 
12051 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12052 		int new_pg = 0;
12053 		int print_props = 0;
12054 		pgtp = NULL;
12055 
12056 		pgnlen = scf_pg_get_name(pg, NULL, 0);
12057 		if (pgnlen < 0)
12058 			scfdie();
12059 
12060 		pgnbuf = safe_malloc(pgnlen + 1);
12061 
12062 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
12063 		if (szret < 0)
12064 			scfdie();
12065 		assert(szret <= pgnlen);
12066 
12067 		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
12068 			if (scf_error() != SCF_ERROR_NOT_FOUND)
12069 				scfdie();
12070 			pgtp = NULL;
12071 		} else {
12072 			pgtp = pgt;
12073 		}
12074 
12075 		if (pattern == NULL ||
12076 		    fnmatch(pattern, pgnbuf, 0) == 0) {
12077 			if (i+1 >= allocd) {
12078 				allocd *= 2;
12079 				objects = realloc(objects,
12080 				    sizeof (*objects) * allocd);
12081 				names =
12082 				    realloc(names, sizeof (*names) * allocd);
12083 				tmpls = realloc(tmpls,
12084 				    sizeof (*tmpls) * allocd);
12085 				if (objects == NULL || names == NULL ||
12086 				    tmpls == NULL)
12087 					uu_die(gettext("Out of memory"));
12088 			}
12089 			objects[i] = pg;
12090 			names[i] = pgnbuf;
12091 
12092 			if (pgtp == NULL)
12093 				tmpls[i] = NULL;
12094 			else
12095 				tmpls[i] = pgt;
12096 
12097 			++i;
12098 
12099 			if (pgnlen > max_len)
12100 				max_len = pgnlen;
12101 
12102 			new_pg = 1;
12103 			print_props = 1;
12104 		}
12105 
12106 		if (only_pgs) {
12107 			if (new_pg) {
12108 				pg = scf_pg_create(g_hndl);
12109 				if (pg == NULL)
12110 					scfdie();
12111 				pgt = scf_tmpl_pg_create(g_hndl);
12112 				if (pgt == NULL)
12113 					scfdie();
12114 			} else
12115 				free(pgnbuf);
12116 
12117 			continue;
12118 		}
12119 
12120 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12121 			scfdie();
12122 
12123 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
12124 			prnlen = scf_property_get_name(prop, prnbuf,
12125 			    max_scf_name_len + 1);
12126 			if (prnlen < 0)
12127 				scfdie();
12128 
12129 			/* Will prepend the property group name and a slash. */
12130 			prnlen += pgnlen + 1;
12131 
12132 			ppnbuf = safe_malloc(prnlen + 1);
12133 
12134 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
12135 			    prnbuf) < 0)
12136 				uu_die("snprintf");
12137 
12138 			if (pattern == NULL || print_props == 1 ||
12139 			    fnmatch(pattern, ppnbuf, 0) == 0) {
12140 				if (i+1 >= allocd) {
12141 					allocd *= 2;
12142 					objects = realloc(objects,
12143 					    sizeof (*objects) * allocd);
12144 					names = realloc(names,
12145 					    sizeof (*names) * allocd);
12146 					tmpls = realloc(tmpls,
12147 					    sizeof (*tmpls) * allocd);
12148 					if (objects == NULL || names == NULL ||
12149 					    tmpls == NULL)
12150 						uu_die(gettext(
12151 						    "Out of memory"));
12152 				}
12153 
12154 				objects[i] = prop;
12155 				names[i] = ppnbuf;
12156 
12157 				if (pgtp != NULL) {
12158 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
12159 					    prt, NULL) < 0) {
12160 						if (scf_error() !=
12161 						    SCF_ERROR_NOT_FOUND)
12162 							scfdie();
12163 						tmpls[i] = NULL;
12164 					} else {
12165 						tmpls[i] = prt;
12166 					}
12167 				} else {
12168 					tmpls[i] = NULL;
12169 				}
12170 
12171 				++i;
12172 
12173 				if (prnlen > max_len)
12174 					max_len = prnlen;
12175 
12176 				prop = scf_property_create(g_hndl);
12177 				prt = scf_tmpl_prop_create(g_hndl);
12178 			} else {
12179 				free(ppnbuf);
12180 			}
12181 		}
12182 
12183 		if (new_pg) {
12184 			pg = scf_pg_create(g_hndl);
12185 			if (pg == NULL)
12186 				scfdie();
12187 			pgt = scf_tmpl_pg_create(g_hndl);
12188 			if (pgt == NULL)
12189 				scfdie();
12190 		} else
12191 			free(pgnbuf);
12192 	}
12193 	if (ret != 0)
12194 		scfdie();
12195 
12196 	objects[i] = NULL;
12197 
12198 	scf_pg_destroy(pg);
12199 	scf_tmpl_pg_destroy(pgt);
12200 	scf_property_destroy(prop);
12201 	scf_tmpl_prop_destroy(prt);
12202 
12203 	for (i = 0; objects[i] != NULL; ++i) {
12204 		if (strchr(names[i], '/') == NULL) {
12205 			/* property group */
12206 			pg = (scf_propertygroup_t *)objects[i];
12207 			pgt = (scf_pg_tmpl_t *)tmpls[i];
12208 			list_pg_info(pg, names[i], max_len);
12209 			list_pg_tmpl(pgt, pg, templates);
12210 			free(names[i]);
12211 			scf_pg_destroy(pg);
12212 			if (pgt != NULL)
12213 				scf_tmpl_pg_destroy(pgt);
12214 		} else {
12215 			/* property */
12216 			prop = (scf_property_t *)objects[i];
12217 			prt = (scf_prop_tmpl_t *)tmpls[i];
12218 			list_prop_info(prop, names[i], max_len);
12219 			list_prop_tmpl(prt, prop, templates);
12220 			free(names[i]);
12221 			scf_property_destroy(prop);
12222 			if (prt != NULL)
12223 				scf_tmpl_prop_destroy(prt);
12224 		}
12225 	}
12226 
12227 	free(names);
12228 	free(objects);
12229 	free(tmpls);
12230 }
12231 
12232 void
12233 lscf_listpg(const char *pattern)
12234 {
12235 	lscf_prep_hndl();
12236 
12237 	listprop(pattern, 1, 0);
12238 }
12239 
12240 /*
12241  * Property group and property creation, setting, and deletion.  setprop (and
12242  * its alias, addprop) can either create a property group of a given type, or
12243  * it can create or set a property to a given type and list of values.
12244  */
12245 void
12246 lscf_addpg(const char *name, const char *type, const char *flags)
12247 {
12248 	scf_propertygroup_t *pg;
12249 	int ret;
12250 	uint32_t flgs = 0;
12251 	const char *cp;
12252 
12253 
12254 	lscf_prep_hndl();
12255 
12256 	if (cur_snap != NULL) {
12257 		semerr(emsg_cant_modify_snapshots);
12258 		return;
12259 	}
12260 
12261 	if (cur_inst == NULL && cur_svc == NULL) {
12262 		semerr(emsg_entity_not_selected);
12263 		return;
12264 	}
12265 
12266 	if (flags != NULL) {
12267 		for (cp = flags; *cp != '\0'; ++cp) {
12268 			switch (*cp) {
12269 			case 'P':
12270 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
12271 				break;
12272 
12273 			case 'p':
12274 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
12275 				break;
12276 
12277 			default:
12278 				semerr(gettext("Invalid property group flag "
12279 				    "%c."), *cp);
12280 				return;
12281 			}
12282 		}
12283 	}
12284 
12285 	pg = scf_pg_create(g_hndl);
12286 	if (pg == NULL)
12287 		scfdie();
12288 
12289 	if (cur_inst != NULL)
12290 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
12291 	else
12292 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
12293 
12294 	if (ret != SCF_SUCCESS) {
12295 		switch (scf_error()) {
12296 		case SCF_ERROR_INVALID_ARGUMENT:
12297 			semerr(gettext("Name, type, or flags are invalid.\n"));
12298 			break;
12299 
12300 		case SCF_ERROR_EXISTS:
12301 			semerr(gettext("Property group already exists.\n"));
12302 			break;
12303 
12304 		case SCF_ERROR_PERMISSION_DENIED:
12305 			semerr(emsg_permission_denied);
12306 			break;
12307 
12308 		case SCF_ERROR_BACKEND_ACCESS:
12309 			semerr(gettext("Backend refused access.\n"));
12310 			break;
12311 
12312 		default:
12313 			scfdie();
12314 		}
12315 	}
12316 
12317 	scf_pg_destroy(pg);
12318 
12319 	private_refresh();
12320 }
12321 
12322 void
12323 lscf_delpg(char *name)
12324 {
12325 	lscf_prep_hndl();
12326 
12327 	if (cur_snap != NULL) {
12328 		semerr(emsg_cant_modify_snapshots);
12329 		return;
12330 	}
12331 
12332 	if (cur_inst == NULL && cur_svc == NULL) {
12333 		semerr(emsg_entity_not_selected);
12334 		return;
12335 	}
12336 
12337 	if (strchr(name, '/') != NULL) {
12338 		semerr(emsg_invalid_pg_name, name);
12339 		return;
12340 	}
12341 
12342 	lscf_delprop(name);
12343 }
12344 
12345 /*
12346  * scf_delhash() is used to remove the property group related to the
12347  * hash entry for a specific manifest in the repository. pgname will be
12348  * constructed from the location of the manifest file. If deathrow isn't 0,
12349  * manifest file doesn't need to exist (manifest string will be used as
12350  * an absolute path).
12351  */
12352 void
12353 lscf_delhash(char *manifest, int deathrow)
12354 {
12355 	char *pgname;
12356 
12357 	if (cur_snap != NULL ||
12358 	    cur_inst != NULL || cur_svc != NULL) {
12359 		warn(gettext("error, an entity is selected\n"));
12360 		return;
12361 	}
12362 
12363 	/* select smf/manifest */
12364 	lscf_select("smf/manifest");
12365 	/*
12366 	 * Translate the manifest file name to property name. In the deathrow
12367 	 * case, the manifest file does not need to exist.
12368 	 */
12369 	pgname = mhash_filename_to_propname(manifest,
12370 	    deathrow ? B_TRUE : B_FALSE);
12371 	if (pgname == NULL) {
12372 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
12373 		return;
12374 	}
12375 	/* delete the hash property name */
12376 	lscf_delpg(pgname);
12377 }
12378 
12379 void
12380 lscf_listprop(const char *pattern)
12381 {
12382 	lscf_prep_hndl();
12383 
12384 	listprop(pattern, 0, 0);
12385 }
12386 
12387 int
12388 lscf_setprop(const char *pgname, const char *type, const char *value,
12389     const uu_list_t *values)
12390 {
12391 	scf_type_t ty, current_ty;
12392 	scf_service_t *svc;
12393 	scf_propertygroup_t *pg, *parent_pg;
12394 	scf_property_t *prop, *parent_prop;
12395 	scf_pg_tmpl_t *pgt;
12396 	scf_prop_tmpl_t *prt;
12397 	int ret, result = 0;
12398 	scf_transaction_t *tx;
12399 	scf_transaction_entry_t *e;
12400 	scf_value_t *v;
12401 	uu_list_walk_t *walk;
12402 	string_list_t *sp;
12403 	char *propname;
12404 	int req_quotes = 0;
12405 
12406 	lscf_prep_hndl();
12407 
12408 	if ((e = scf_entry_create(g_hndl)) == NULL ||
12409 	    (svc = scf_service_create(g_hndl)) == NULL ||
12410 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
12411 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12412 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
12413 	    (prop = scf_property_create(g_hndl)) == NULL ||
12414 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12415 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12416 	    (tx = scf_transaction_create(g_hndl)) == NULL)
12417 		scfdie();
12418 
12419 	if (cur_snap != NULL) {
12420 		semerr(emsg_cant_modify_snapshots);
12421 		goto fail;
12422 	}
12423 
12424 	if (cur_inst == NULL && cur_svc == NULL) {
12425 		semerr(emsg_entity_not_selected);
12426 		goto fail;
12427 	}
12428 
12429 	propname = strchr(pgname, '/');
12430 	if (propname == NULL) {
12431 		semerr(gettext("Property names must contain a `/'.\n"));
12432 		goto fail;
12433 	}
12434 
12435 	*propname = '\0';
12436 	++propname;
12437 
12438 	if (type != NULL) {
12439 		ty = string_to_type(type);
12440 		if (ty == SCF_TYPE_INVALID) {
12441 			semerr(gettext("Unknown type \"%s\".\n"), type);
12442 			goto fail;
12443 		}
12444 	}
12445 
12446 	if (cur_inst != NULL)
12447 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12448 	else
12449 		ret = scf_service_get_pg(cur_svc, pgname, pg);
12450 	if (ret != SCF_SUCCESS) {
12451 		switch (scf_error()) {
12452 		case SCF_ERROR_NOT_FOUND:
12453 			semerr(emsg_no_such_pg, pgname);
12454 			goto fail;
12455 
12456 		case SCF_ERROR_INVALID_ARGUMENT:
12457 			semerr(emsg_invalid_pg_name, pgname);
12458 			goto fail;
12459 
12460 		default:
12461 			scfdie();
12462 			break;
12463 		}
12464 	}
12465 
12466 	do {
12467 		if (scf_pg_update(pg) == -1)
12468 			scfdie();
12469 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12470 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12471 				scfdie();
12472 
12473 			semerr(emsg_permission_denied);
12474 			goto fail;
12475 		}
12476 
12477 		ret = scf_pg_get_property(pg, propname, prop);
12478 		if (ret == SCF_SUCCESS) {
12479 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
12480 				scfdie();
12481 
12482 			if (type == NULL)
12483 				ty = current_ty;
12484 			if (scf_transaction_property_change_type(tx, e,
12485 			    propname, ty) == -1)
12486 				scfdie();
12487 
12488 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12489 			/* Infer the type, if possible. */
12490 			if (type == NULL) {
12491 				/*
12492 				 * First check if we're an instance and the
12493 				 * property is set on the service.
12494 				 */
12495 				if (cur_inst != NULL &&
12496 				    scf_instance_get_parent(cur_inst,
12497 				    svc) == 0 &&
12498 				    scf_service_get_pg(cur_svc, pgname,
12499 				    parent_pg) == 0 &&
12500 				    scf_pg_get_property(parent_pg, propname,
12501 				    parent_prop) == 0 &&
12502 				    scf_property_type(parent_prop,
12503 				    &current_ty) == 0) {
12504 					ty = current_ty;
12505 
12506 				/* Then check for a type set in a template. */
12507 				} else if (scf_tmpl_get_by_pg(pg, pgt,
12508 				    NULL) == 0 &&
12509 				    scf_tmpl_get_by_prop(pgt, propname, prt,
12510 				    NULL) == 0 &&
12511 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
12512 					ty = current_ty;
12513 
12514 				/* If type can't be inferred, fail. */
12515 				} else {
12516 					semerr(gettext("Type required for new "
12517 					    "properties.\n"));
12518 					goto fail;
12519 				}
12520 			}
12521 			if (scf_transaction_property_new(tx, e, propname,
12522 			    ty) == -1)
12523 				scfdie();
12524 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12525 			semerr(emsg_invalid_prop_name, propname);
12526 			goto fail;
12527 		} else {
12528 			scfdie();
12529 		}
12530 
12531 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
12532 			req_quotes = 1;
12533 
12534 		if (value != NULL) {
12535 			v = string_to_value(value, ty, 0);
12536 
12537 			if (v == NULL)
12538 				goto fail;
12539 
12540 			ret = scf_entry_add_value(e, v);
12541 			assert(ret == SCF_SUCCESS);
12542 		} else {
12543 			assert(values != NULL);
12544 
12545 			walk = uu_list_walk_start((uu_list_t *)values,
12546 			    UU_DEFAULT);
12547 			if (walk == NULL)
12548 				uu_die(gettext("Could not walk list"));
12549 
12550 			for (sp = uu_list_walk_next(walk); sp != NULL;
12551 			    sp = uu_list_walk_next(walk)) {
12552 				v = string_to_value(sp->str, ty, req_quotes);
12553 
12554 				if (v == NULL) {
12555 					scf_entry_destroy_children(e);
12556 					goto fail;
12557 				}
12558 
12559 				ret = scf_entry_add_value(e, v);
12560 				assert(ret == SCF_SUCCESS);
12561 			}
12562 			uu_list_walk_end(walk);
12563 		}
12564 		result = scf_transaction_commit(tx);
12565 
12566 		scf_transaction_reset(tx);
12567 		scf_entry_destroy_children(e);
12568 	} while (result == 0);
12569 
12570 	if (result < 0) {
12571 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12572 			scfdie();
12573 
12574 		semerr(emsg_permission_denied);
12575 		goto fail;
12576 	}
12577 
12578 	ret = 0;
12579 
12580 	private_refresh();
12581 
12582 	goto cleanup;
12583 
12584 fail:
12585 	ret = -1;
12586 
12587 cleanup:
12588 	scf_transaction_destroy(tx);
12589 	scf_entry_destroy(e);
12590 	scf_service_destroy(svc);
12591 	scf_pg_destroy(parent_pg);
12592 	scf_pg_destroy(pg);
12593 	scf_property_destroy(parent_prop);
12594 	scf_property_destroy(prop);
12595 	scf_tmpl_pg_destroy(pgt);
12596 	scf_tmpl_prop_destroy(prt);
12597 
12598 	return (ret);
12599 }
12600 
12601 void
12602 lscf_delprop(char *pgn)
12603 {
12604 	char *slash, *pn;
12605 	scf_propertygroup_t *pg;
12606 	scf_transaction_t *tx;
12607 	scf_transaction_entry_t *e;
12608 	int ret;
12609 
12610 
12611 	lscf_prep_hndl();
12612 
12613 	if (cur_snap != NULL) {
12614 		semerr(emsg_cant_modify_snapshots);
12615 		return;
12616 	}
12617 
12618 	if (cur_inst == NULL && cur_svc == NULL) {
12619 		semerr(emsg_entity_not_selected);
12620 		return;
12621 	}
12622 
12623 	pg = scf_pg_create(g_hndl);
12624 	if (pg == NULL)
12625 		scfdie();
12626 
12627 	slash = strchr(pgn, '/');
12628 	if (slash == NULL) {
12629 		pn = NULL;
12630 	} else {
12631 		*slash = '\0';
12632 		pn = slash + 1;
12633 	}
12634 
12635 	if (cur_inst != NULL)
12636 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
12637 	else
12638 		ret = scf_service_get_pg(cur_svc, pgn, pg);
12639 	if (ret != SCF_SUCCESS) {
12640 		switch (scf_error()) {
12641 		case SCF_ERROR_NOT_FOUND:
12642 			semerr(emsg_no_such_pg, pgn);
12643 			break;
12644 
12645 		case SCF_ERROR_INVALID_ARGUMENT:
12646 			semerr(emsg_invalid_pg_name, pgn);
12647 			break;
12648 
12649 		default:
12650 			scfdie();
12651 		}
12652 
12653 		scf_pg_destroy(pg);
12654 
12655 		return;
12656 	}
12657 
12658 	if (pn == NULL) {
12659 		/* Try to delete the property group. */
12660 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
12661 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12662 				scfdie();
12663 
12664 			semerr(emsg_permission_denied);
12665 		} else {
12666 			private_refresh();
12667 		}
12668 
12669 		scf_pg_destroy(pg);
12670 		return;
12671 	}
12672 
12673 	e = scf_entry_create(g_hndl);
12674 	tx = scf_transaction_create(g_hndl);
12675 
12676 	do {
12677 		if (scf_pg_update(pg) == -1)
12678 			scfdie();
12679 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12680 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12681 				scfdie();
12682 
12683 			semerr(emsg_permission_denied);
12684 			break;
12685 		}
12686 
12687 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
12688 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
12689 				semerr(gettext("No such property %s/%s.\n"),
12690 				    pgn, pn);
12691 				break;
12692 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12693 				semerr(emsg_invalid_prop_name, pn);
12694 				break;
12695 			} else {
12696 				scfdie();
12697 			}
12698 		}
12699 
12700 		ret = scf_transaction_commit(tx);
12701 
12702 		if (ret == 0)
12703 			scf_transaction_reset(tx);
12704 	} while (ret == 0);
12705 
12706 	if (ret < 0) {
12707 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12708 			scfdie();
12709 
12710 		semerr(emsg_permission_denied);
12711 	} else {
12712 		private_refresh();
12713 	}
12714 
12715 	scf_transaction_destroy(tx);
12716 	scf_entry_destroy(e);
12717 	scf_pg_destroy(pg);
12718 }
12719 
12720 /*
12721  * Property editing.
12722  */
12723 
12724 static int
12725 write_edit_script(FILE *strm)
12726 {
12727 	char *fmribuf;
12728 	ssize_t fmrilen;
12729 
12730 	scf_propertygroup_t *pg;
12731 	scf_property_t *prop;
12732 	scf_value_t *val;
12733 	scf_type_t ty;
12734 	int ret, result = 0;
12735 	scf_iter_t *iter, *piter, *viter;
12736 	char *buf, *tybuf, *pname;
12737 	const char *emsg_write_error;
12738 
12739 
12740 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
12741 
12742 
12743 	/* select fmri */
12744 	if (cur_inst != NULL) {
12745 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
12746 		if (fmrilen < 0)
12747 			scfdie();
12748 		fmribuf = safe_malloc(fmrilen + 1);
12749 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
12750 			scfdie();
12751 	} else {
12752 		assert(cur_svc != NULL);
12753 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
12754 		if (fmrilen < 0)
12755 			scfdie();
12756 		fmribuf = safe_malloc(fmrilen + 1);
12757 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
12758 			scfdie();
12759 	}
12760 
12761 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
12762 		warn(emsg_write_error, strerror(errno));
12763 		free(fmribuf);
12764 		return (-1);
12765 	}
12766 
12767 	free(fmribuf);
12768 
12769 
12770 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12771 	    (prop = scf_property_create(g_hndl)) == NULL ||
12772 	    (val = scf_value_create(g_hndl)) == NULL ||
12773 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12774 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12775 	    (viter = scf_iter_create(g_hndl)) == NULL)
12776 		scfdie();
12777 
12778 	buf = safe_malloc(max_scf_name_len + 1);
12779 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
12780 	pname = safe_malloc(max_scf_name_len + 1);
12781 
12782 	if (cur_inst != NULL)
12783 		ret = scf_iter_instance_pgs(iter, cur_inst);
12784 	else
12785 		ret = scf_iter_service_pgs(iter, cur_svc);
12786 	if (ret != SCF_SUCCESS)
12787 		scfdie();
12788 
12789 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12790 		int ret2;
12791 
12792 		/*
12793 		 * # delprop pg
12794 		 * # addpg pg type
12795 		 */
12796 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
12797 			scfdie();
12798 
12799 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
12800 			scfdie();
12801 
12802 		if (fprintf(strm, "# Property group \"%s\"\n"
12803 		    "# delprop %s\n"
12804 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
12805 			warn(emsg_write_error, strerror(errno));
12806 			result = -1;
12807 			goto out;
12808 		}
12809 
12810 		/* # setprop pg/prop = (values) */
12811 
12812 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12813 			scfdie();
12814 
12815 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
12816 			int first = 1;
12817 			int ret3;
12818 			int multiple;
12819 			int is_str;
12820 			scf_type_t bty;
12821 
12822 			if (scf_property_get_name(prop, pname,
12823 			    max_scf_name_len + 1) < 0)
12824 				scfdie();
12825 
12826 			if (scf_property_type(prop, &ty) != 0)
12827 				scfdie();
12828 
12829 			multiple = prop_has_multiple_values(prop, val);
12830 
12831 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
12832 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
12833 			    < 0) {
12834 				warn(emsg_write_error, strerror(errno));
12835 				result = -1;
12836 				goto out;
12837 			}
12838 
12839 			(void) scf_type_base_type(ty, &bty);
12840 			is_str = (bty == SCF_TYPE_ASTRING);
12841 
12842 			if (scf_iter_property_values(viter, prop) !=
12843 			    SCF_SUCCESS)
12844 				scfdie();
12845 
12846 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
12847 				char *buf;
12848 				ssize_t buflen;
12849 
12850 				buflen = scf_value_get_as_string(val, NULL, 0);
12851 				if (buflen < 0)
12852 					scfdie();
12853 
12854 				buf = safe_malloc(buflen + 1);
12855 
12856 				if (scf_value_get_as_string(val, buf,
12857 				    buflen + 1) < 0)
12858 					scfdie();
12859 
12860 				if (first)
12861 					first = 0;
12862 				else {
12863 					if (putc(' ', strm) != ' ') {
12864 						warn(emsg_write_error,
12865 						    strerror(errno));
12866 						result = -1;
12867 						goto out;
12868 					}
12869 				}
12870 
12871 				if ((is_str && multiple) ||
12872 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
12873 					(void) putc('"', strm);
12874 					(void) quote_and_print(buf, strm, 1);
12875 					(void) putc('"', strm);
12876 
12877 					if (ferror(strm)) {
12878 						warn(emsg_write_error,
12879 						    strerror(errno));
12880 						result = -1;
12881 						goto out;
12882 					}
12883 				} else {
12884 					if (fprintf(strm, "%s", buf) < 0) {
12885 						warn(emsg_write_error,
12886 						    strerror(errno));
12887 						result = -1;
12888 						goto out;
12889 					}
12890 				}
12891 
12892 				free(buf);
12893 			}
12894 			if (ret3 < 0 &&
12895 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
12896 				scfdie();
12897 
12898 			/* Write closing paren if mult-value property */
12899 			if ((multiple && putc(')', strm) == EOF) ||
12900 
12901 			    /* Write final newline */
12902 			    fputc('\n', strm) == EOF) {
12903 				warn(emsg_write_error, strerror(errno));
12904 				result = -1;
12905 				goto out;
12906 			}
12907 		}
12908 		if (ret2 < 0)
12909 			scfdie();
12910 
12911 		if (fputc('\n', strm) == EOF) {
12912 			warn(emsg_write_error, strerror(errno));
12913 			result = -1;
12914 			goto out;
12915 		}
12916 	}
12917 	if (ret < 0)
12918 		scfdie();
12919 
12920 out:
12921 	free(pname);
12922 	free(tybuf);
12923 	free(buf);
12924 	scf_iter_destroy(viter);
12925 	scf_iter_destroy(piter);
12926 	scf_iter_destroy(iter);
12927 	scf_value_destroy(val);
12928 	scf_property_destroy(prop);
12929 	scf_pg_destroy(pg);
12930 
12931 	if (result == 0) {
12932 		if (fflush(strm) != 0) {
12933 			warn(emsg_write_error, strerror(errno));
12934 			return (-1);
12935 		}
12936 	}
12937 
12938 	return (result);
12939 }
12940 
12941 int
12942 lscf_editprop()
12943 {
12944 	char *buf, *editor;
12945 	size_t bufsz;
12946 	int tmpfd;
12947 	char tempname[] = TEMP_FILE_PATTERN;
12948 
12949 	lscf_prep_hndl();
12950 
12951 	if (cur_snap != NULL) {
12952 		semerr(emsg_cant_modify_snapshots);
12953 		return (-1);
12954 	}
12955 
12956 	if (cur_svc == NULL && cur_inst == NULL) {
12957 		semerr(emsg_entity_not_selected);
12958 		return (-1);
12959 	}
12960 
12961 	tmpfd = mkstemp(tempname);
12962 	if (tmpfd == -1) {
12963 		semerr(gettext("Could not create temporary file.\n"));
12964 		return (-1);
12965 	}
12966 
12967 	(void) strcpy(tempfilename, tempname);
12968 
12969 	tempfile = fdopen(tmpfd, "r+");
12970 	if (tempfile == NULL) {
12971 		warn(gettext("Could not create temporary file.\n"));
12972 		if (close(tmpfd) == -1)
12973 			warn(gettext("Could not close temporary file: %s.\n"),
12974 			    strerror(errno));
12975 
12976 		remove_tempfile();
12977 
12978 		return (-1);
12979 	}
12980 
12981 	if (write_edit_script(tempfile) == -1) {
12982 		remove_tempfile();
12983 		return (-1);
12984 	}
12985 
12986 	editor = getenv("EDITOR");
12987 	if (editor == NULL)
12988 		editor = "vi";
12989 
12990 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
12991 	buf = safe_malloc(bufsz);
12992 
12993 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
12994 		uu_die(gettext("Error creating editor command"));
12995 
12996 	if (system(buf) == -1) {
12997 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
12998 		    strerror(errno));
12999 		free(buf);
13000 		remove_tempfile();
13001 		return (-1);
13002 	}
13003 
13004 	free(buf);
13005 
13006 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
13007 
13008 	remove_tempfile();
13009 
13010 	return (0);
13011 }
13012 
13013 static void
13014 add_string(uu_list_t *strlist, const char *str)
13015 {
13016 	string_list_t *elem;
13017 	elem = safe_malloc(sizeof (*elem));
13018 	uu_list_node_init(elem, &elem->node, string_pool);
13019 	elem->str = safe_strdup(str);
13020 	if (uu_list_append(strlist, elem) != 0)
13021 		uu_die(gettext("libuutil error: %s\n"),
13022 		    uu_strerror(uu_error()));
13023 }
13024 
13025 /*
13026  * Get all property values that don't match the given glob pattern,
13027  * if a pattern is specified.
13028  */
13029 static void
13030 get_prop_values(scf_property_t *prop, uu_list_t *values,
13031     const char *pattern)
13032 {
13033 	scf_iter_t *iter;
13034 	scf_value_t *val;
13035 	int ret;
13036 
13037 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13038 	    (val = scf_value_create(g_hndl)) == NULL)
13039 		scfdie();
13040 
13041 	if (scf_iter_property_values(iter, prop) != 0)
13042 		scfdie();
13043 
13044 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13045 		char *buf;
13046 		ssize_t vlen, szret;
13047 
13048 		vlen = scf_value_get_as_string(val, NULL, 0);
13049 		if (vlen < 0)
13050 			scfdie();
13051 
13052 		buf = safe_malloc(vlen + 1);
13053 
13054 		szret = scf_value_get_as_string(val, buf, vlen + 1);
13055 		if (szret < 0)
13056 			scfdie();
13057 		assert(szret <= vlen);
13058 
13059 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
13060 			add_string(values, buf);
13061 
13062 		free(buf);
13063 	}
13064 
13065 	if (ret == -1)
13066 		scfdie();
13067 
13068 	scf_value_destroy(val);
13069 	scf_iter_destroy(iter);
13070 }
13071 
13072 static int
13073 lscf_setpropvalue(const char *pgname, const char *type,
13074     const char *arg, int isadd, int isnotfoundok)
13075 {
13076 	scf_type_t ty;
13077 	scf_propertygroup_t *pg;
13078 	scf_property_t *prop;
13079 	int ret, result = 0;
13080 	scf_transaction_t *tx;
13081 	scf_transaction_entry_t *e;
13082 	scf_value_t *v;
13083 	string_list_t *sp;
13084 	char *propname;
13085 	uu_list_t *values;
13086 	uu_list_walk_t *walk;
13087 	void *cookie = NULL;
13088 	char *pattern = NULL;
13089 
13090 	lscf_prep_hndl();
13091 
13092 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
13093 		uu_die(gettext("Could not create property list: %s\n"),
13094 		    uu_strerror(uu_error()));
13095 
13096 	if (!isadd)
13097 		pattern = safe_strdup(arg);
13098 
13099 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13100 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13101 	    (prop = scf_property_create(g_hndl)) == NULL ||
13102 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13103 		scfdie();
13104 
13105 	if (cur_snap != NULL) {
13106 		semerr(emsg_cant_modify_snapshots);
13107 		goto fail;
13108 	}
13109 
13110 	if (cur_inst == NULL && cur_svc == NULL) {
13111 		semerr(emsg_entity_not_selected);
13112 		goto fail;
13113 	}
13114 
13115 	propname = strchr(pgname, '/');
13116 	if (propname == NULL) {
13117 		semerr(gettext("Property names must contain a `/'.\n"));
13118 		goto fail;
13119 	}
13120 
13121 	*propname = '\0';
13122 	++propname;
13123 
13124 	if (type != NULL) {
13125 		ty = string_to_type(type);
13126 		if (ty == SCF_TYPE_INVALID) {
13127 			semerr(gettext("Unknown type \"%s\".\n"), type);
13128 			goto fail;
13129 		}
13130 	}
13131 
13132 	if (cur_inst != NULL)
13133 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13134 	else
13135 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13136 	if (ret != 0) {
13137 		switch (scf_error()) {
13138 		case SCF_ERROR_NOT_FOUND:
13139 			if (isnotfoundok) {
13140 				result = 0;
13141 			} else {
13142 				semerr(emsg_no_such_pg, pgname);
13143 				result = -1;
13144 			}
13145 			goto out;
13146 
13147 		case SCF_ERROR_INVALID_ARGUMENT:
13148 			semerr(emsg_invalid_pg_name, pgname);
13149 			goto fail;
13150 
13151 		default:
13152 			scfdie();
13153 		}
13154 	}
13155 
13156 	do {
13157 		if (scf_pg_update(pg) == -1)
13158 			scfdie();
13159 		if (scf_transaction_start(tx, pg) != 0) {
13160 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13161 				scfdie();
13162 
13163 			semerr(emsg_permission_denied);
13164 			goto fail;
13165 		}
13166 
13167 		ret = scf_pg_get_property(pg, propname, prop);
13168 		if (ret == 0) {
13169 			scf_type_t ptype;
13170 			char *pat = pattern;
13171 
13172 			if (scf_property_type(prop, &ptype) != 0)
13173 				scfdie();
13174 
13175 			if (isadd) {
13176 				if (type != NULL && ptype != ty) {
13177 					semerr(gettext("Property \"%s\" is not "
13178 					    "of type \"%s\".\n"), propname,
13179 					    type);
13180 					goto fail;
13181 				}
13182 
13183 				pat = NULL;
13184 			} else {
13185 				size_t len = strlen(pat);
13186 				if (len > 0 && pat[len - 1] == '\"')
13187 					pat[len - 1] = '\0';
13188 				if (len > 0 && pat[0] == '\"')
13189 					pat++;
13190 			}
13191 
13192 			ty = ptype;
13193 
13194 			get_prop_values(prop, values, pat);
13195 
13196 			if (isadd)
13197 				add_string(values, arg);
13198 
13199 			if (scf_transaction_property_change(tx, e,
13200 			    propname, ty) == -1)
13201 				scfdie();
13202 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13203 			if (isadd) {
13204 				if (type == NULL) {
13205 					semerr(gettext("Type required "
13206 					    "for new properties.\n"));
13207 					goto fail;
13208 				}
13209 
13210 				add_string(values, arg);
13211 
13212 				if (scf_transaction_property_new(tx, e,
13213 				    propname, ty) == -1)
13214 					scfdie();
13215 			} else if (isnotfoundok) {
13216 				result = 0;
13217 				goto out;
13218 			} else {
13219 				semerr(gettext("No such property %s/%s.\n"),
13220 				    pgname, propname);
13221 				result = -1;
13222 				goto out;
13223 			}
13224 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13225 			semerr(emsg_invalid_prop_name, propname);
13226 			goto fail;
13227 		} else {
13228 			scfdie();
13229 		}
13230 
13231 		walk = uu_list_walk_start(values, UU_DEFAULT);
13232 		if (walk == NULL)
13233 			uu_die(gettext("Could not walk property list.\n"));
13234 
13235 		for (sp = uu_list_walk_next(walk); sp != NULL;
13236 		    sp = uu_list_walk_next(walk)) {
13237 			v = string_to_value(sp->str, ty, 0);
13238 
13239 			if (v == NULL) {
13240 				scf_entry_destroy_children(e);
13241 				goto fail;
13242 			}
13243 			ret = scf_entry_add_value(e, v);
13244 			assert(ret == 0);
13245 		}
13246 		uu_list_walk_end(walk);
13247 
13248 		result = scf_transaction_commit(tx);
13249 
13250 		scf_transaction_reset(tx);
13251 		scf_entry_destroy_children(e);
13252 	} while (result == 0);
13253 
13254 	if (result < 0) {
13255 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13256 			scfdie();
13257 
13258 		semerr(emsg_permission_denied);
13259 		goto fail;
13260 	}
13261 
13262 	result = 0;
13263 
13264 	private_refresh();
13265 
13266 out:
13267 	scf_transaction_destroy(tx);
13268 	scf_entry_destroy(e);
13269 	scf_pg_destroy(pg);
13270 	scf_property_destroy(prop);
13271 	free(pattern);
13272 
13273 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
13274 		free(sp->str);
13275 		free(sp);
13276 	}
13277 
13278 	uu_list_destroy(values);
13279 
13280 	return (result);
13281 
13282 fail:
13283 	result = -1;
13284 	goto out;
13285 }
13286 
13287 int
13288 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
13289 {
13290 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
13291 }
13292 
13293 int
13294 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
13295 {
13296 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
13297 }
13298 
13299 /*
13300  * Look for a standard start method, first in the instance (if any),
13301  * then the service.
13302  */
13303 static const char *
13304 start_method_name(int *in_instance)
13305 {
13306 	scf_propertygroup_t *pg;
13307 	char **p;
13308 	int ret;
13309 	scf_instance_t *inst = cur_inst;
13310 
13311 	if ((pg = scf_pg_create(g_hndl)) == NULL)
13312 		scfdie();
13313 
13314 again:
13315 	for (p = start_method_names; *p != NULL; p++) {
13316 		if (inst != NULL)
13317 			ret = scf_instance_get_pg(inst, *p, pg);
13318 		else
13319 			ret = scf_service_get_pg(cur_svc, *p, pg);
13320 
13321 		if (ret == 0) {
13322 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
13323 			char *buf = safe_malloc(bufsz);
13324 
13325 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
13326 				free(buf);
13327 				continue;
13328 			}
13329 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
13330 				free(buf);
13331 				continue;
13332 			}
13333 
13334 			free(buf);
13335 			*in_instance = (inst != NULL);
13336 			scf_pg_destroy(pg);
13337 			return (*p);
13338 		}
13339 
13340 		if (scf_error() == SCF_ERROR_NOT_FOUND)
13341 			continue;
13342 
13343 		scfdie();
13344 	}
13345 
13346 	if (inst != NULL) {
13347 		inst = NULL;
13348 		goto again;
13349 	}
13350 
13351 	scf_pg_destroy(pg);
13352 	return (NULL);
13353 }
13354 
13355 static int
13356 addpg(const char *name, const char *type)
13357 {
13358 	scf_propertygroup_t *pg;
13359 	int ret;
13360 
13361 	pg = scf_pg_create(g_hndl);
13362 	if (pg == NULL)
13363 		scfdie();
13364 
13365 	if (cur_inst != NULL)
13366 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
13367 	else
13368 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
13369 
13370 	if (ret != 0) {
13371 		switch (scf_error()) {
13372 		case SCF_ERROR_EXISTS:
13373 			ret = 0;
13374 			break;
13375 
13376 		case SCF_ERROR_PERMISSION_DENIED:
13377 			semerr(emsg_permission_denied);
13378 			break;
13379 
13380 		default:
13381 			scfdie();
13382 		}
13383 	}
13384 
13385 	scf_pg_destroy(pg);
13386 	return (ret);
13387 }
13388 
13389 int
13390 lscf_setenv(uu_list_t *args, int isunset)
13391 {
13392 	int ret = 0;
13393 	size_t i;
13394 	int argc;
13395 	char **argv = NULL;
13396 	string_list_t *slp;
13397 	char *pattern;
13398 	char *prop;
13399 	int do_service = 0;
13400 	int do_instance = 0;
13401 	const char *method = NULL;
13402 	const char *name = NULL;
13403 	const char *value = NULL;
13404 	scf_instance_t *saved_cur_inst = cur_inst;
13405 
13406 	lscf_prep_hndl();
13407 
13408 	argc = uu_list_numnodes(args);
13409 	if (argc < 1)
13410 		goto usage;
13411 
13412 	argv = calloc(argc + 1, sizeof (char *));
13413 	if (argv == NULL)
13414 		uu_die(gettext("Out of memory.\n"));
13415 
13416 	for (slp = uu_list_first(args), i = 0;
13417 	    slp != NULL;
13418 	    slp = uu_list_next(args, slp), ++i)
13419 		argv[i] = slp->str;
13420 
13421 	argv[i] = NULL;
13422 
13423 	opterr = 0;
13424 	optind = 0;
13425 	for (;;) {
13426 		ret = getopt(argc, argv, "sim:");
13427 		if (ret == -1)
13428 			break;
13429 
13430 		switch (ret) {
13431 		case 's':
13432 			do_service = 1;
13433 			cur_inst = NULL;
13434 			break;
13435 
13436 		case 'i':
13437 			do_instance = 1;
13438 			break;
13439 
13440 		case 'm':
13441 			method = optarg;
13442 			break;
13443 
13444 		case '?':
13445 			goto usage;
13446 
13447 		default:
13448 			bad_error("getopt", ret);
13449 		}
13450 	}
13451 
13452 	argc -= optind;
13453 	if ((do_service && do_instance) ||
13454 	    (isunset && argc != 1) ||
13455 	    (!isunset && argc != 2))
13456 		goto usage;
13457 
13458 	name = argv[optind];
13459 	if (!isunset)
13460 		value = argv[optind + 1];
13461 
13462 	if (cur_snap != NULL) {
13463 		semerr(emsg_cant_modify_snapshots);
13464 		ret = -1;
13465 		goto out;
13466 	}
13467 
13468 	if (cur_inst == NULL && cur_svc == NULL) {
13469 		semerr(emsg_entity_not_selected);
13470 		ret = -1;
13471 		goto out;
13472 	}
13473 
13474 	if (do_instance && cur_inst == NULL) {
13475 		semerr(gettext("No instance is selected.\n"));
13476 		ret = -1;
13477 		goto out;
13478 	}
13479 
13480 	if (do_service && cur_svc == NULL) {
13481 		semerr(gettext("No service is selected.\n"));
13482 		ret = -1;
13483 		goto out;
13484 	}
13485 
13486 	if (method == NULL) {
13487 		if (do_instance || do_service) {
13488 			method = "method_context";
13489 			if (!isunset) {
13490 				ret = addpg("method_context",
13491 				    SCF_GROUP_FRAMEWORK);
13492 				if (ret != 0)
13493 					goto out;
13494 			}
13495 		} else {
13496 			int in_instance;
13497 			method = start_method_name(&in_instance);
13498 			if (method == NULL) {
13499 				semerr(gettext(
13500 				    "Couldn't find start method; please "
13501 				    "specify a method with '-m'.\n"));
13502 				ret = -1;
13503 				goto out;
13504 			}
13505 			if (!in_instance)
13506 				cur_inst = NULL;
13507 		}
13508 	} else {
13509 		scf_propertygroup_t *pg;
13510 		size_t bufsz;
13511 		char *buf;
13512 		int ret;
13513 
13514 		if ((pg = scf_pg_create(g_hndl)) == NULL)
13515 			scfdie();
13516 
13517 		if (cur_inst != NULL)
13518 			ret = scf_instance_get_pg(cur_inst, method, pg);
13519 		else
13520 			ret = scf_service_get_pg(cur_svc, method, pg);
13521 
13522 		if (ret != 0) {
13523 			scf_pg_destroy(pg);
13524 			switch (scf_error()) {
13525 			case SCF_ERROR_NOT_FOUND:
13526 				semerr(gettext("Couldn't find the method "
13527 				    "\"%s\".\n"), method);
13528 				goto out;
13529 
13530 			case SCF_ERROR_INVALID_ARGUMENT:
13531 				semerr(gettext("Invalid method name \"%s\".\n"),
13532 				    method);
13533 				goto out;
13534 
13535 			default:
13536 				scfdie();
13537 			}
13538 		}
13539 
13540 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
13541 		buf = safe_malloc(bufsz);
13542 
13543 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
13544 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
13545 			semerr(gettext("Property group \"%s\" is not of type "
13546 			    "\"method\".\n"), method);
13547 			ret = -1;
13548 			free(buf);
13549 			scf_pg_destroy(pg);
13550 			goto out;
13551 		}
13552 
13553 		free(buf);
13554 		scf_pg_destroy(pg);
13555 	}
13556 
13557 	prop = uu_msprintf("%s/environment", method);
13558 	pattern = uu_msprintf("%s=*", name);
13559 
13560 	if (prop == NULL || pattern == NULL)
13561 		uu_die(gettext("Out of memory.\n"));
13562 
13563 	ret = lscf_delpropvalue(prop, pattern, !isunset);
13564 
13565 	if (ret == 0 && !isunset) {
13566 		uu_free(pattern);
13567 		uu_free(prop);
13568 		prop = uu_msprintf("%s/environment", method);
13569 		pattern = uu_msprintf("%s=%s", name, value);
13570 		if (prop == NULL || pattern == NULL)
13571 			uu_die(gettext("Out of memory.\n"));
13572 		ret = lscf_addpropvalue(prop, "astring:", pattern);
13573 	}
13574 	uu_free(pattern);
13575 	uu_free(prop);
13576 
13577 out:
13578 	cur_inst = saved_cur_inst;
13579 
13580 	free(argv);
13581 	return (ret);
13582 usage:
13583 	ret = -2;
13584 	goto out;
13585 }
13586 
13587 /*
13588  * Snapshot commands
13589  */
13590 
13591 void
13592 lscf_listsnap()
13593 {
13594 	scf_snapshot_t *snap;
13595 	scf_iter_t *iter;
13596 	char *nb;
13597 	int r;
13598 
13599 	lscf_prep_hndl();
13600 
13601 	if (cur_inst == NULL) {
13602 		semerr(gettext("Instance not selected.\n"));
13603 		return;
13604 	}
13605 
13606 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13607 	    (iter = scf_iter_create(g_hndl)) == NULL)
13608 		scfdie();
13609 
13610 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
13611 		scfdie();
13612 
13613 	nb = safe_malloc(max_scf_name_len + 1);
13614 
13615 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
13616 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
13617 			scfdie();
13618 
13619 		(void) puts(nb);
13620 	}
13621 	if (r < 0)
13622 		scfdie();
13623 
13624 	free(nb);
13625 	scf_iter_destroy(iter);
13626 	scf_snapshot_destroy(snap);
13627 }
13628 
13629 void
13630 lscf_selectsnap(const char *name)
13631 {
13632 	scf_snapshot_t *snap;
13633 	scf_snaplevel_t *level;
13634 
13635 	lscf_prep_hndl();
13636 
13637 	if (cur_inst == NULL) {
13638 		semerr(gettext("Instance not selected.\n"));
13639 		return;
13640 	}
13641 
13642 	if (cur_snap != NULL) {
13643 		if (name != NULL) {
13644 			char *cur_snap_name;
13645 			boolean_t nochange;
13646 
13647 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
13648 
13649 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
13650 			    max_scf_name_len + 1) < 0)
13651 				scfdie();
13652 
13653 			nochange = strcmp(name, cur_snap_name) == 0;
13654 
13655 			free(cur_snap_name);
13656 
13657 			if (nochange)
13658 				return;
13659 		}
13660 
13661 		unselect_cursnap();
13662 	}
13663 
13664 	if (name == NULL)
13665 		return;
13666 
13667 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13668 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
13669 		scfdie();
13670 
13671 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
13672 	    SCF_SUCCESS) {
13673 		switch (scf_error()) {
13674 		case SCF_ERROR_INVALID_ARGUMENT:
13675 			semerr(gettext("Invalid name \"%s\".\n"), name);
13676 			break;
13677 
13678 		case SCF_ERROR_NOT_FOUND:
13679 			semerr(gettext("No such snapshot \"%s\".\n"), name);
13680 			break;
13681 
13682 		default:
13683 			scfdie();
13684 		}
13685 
13686 		scf_snaplevel_destroy(level);
13687 		scf_snapshot_destroy(snap);
13688 		return;
13689 	}
13690 
13691 	/* Load the snaplevels into our list. */
13692 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
13693 	if (cur_levels == NULL)
13694 		uu_die(gettext("Could not create list: %s\n"),
13695 		    uu_strerror(uu_error()));
13696 
13697 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13698 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13699 			scfdie();
13700 
13701 		semerr(gettext("Snapshot has no snaplevels.\n"));
13702 
13703 		scf_snaplevel_destroy(level);
13704 		scf_snapshot_destroy(snap);
13705 		return;
13706 	}
13707 
13708 	cur_snap = snap;
13709 
13710 	for (;;) {
13711 		cur_elt = safe_malloc(sizeof (*cur_elt));
13712 		uu_list_node_init(cur_elt, &cur_elt->list_node,
13713 		    snaplevel_pool);
13714 		cur_elt->sl = level;
13715 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
13716 			uu_die(gettext("libuutil error: %s\n"),
13717 			    uu_strerror(uu_error()));
13718 
13719 		level = scf_snaplevel_create(g_hndl);
13720 		if (level == NULL)
13721 			scfdie();
13722 
13723 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
13724 		    level) != SCF_SUCCESS) {
13725 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13726 				scfdie();
13727 
13728 			scf_snaplevel_destroy(level);
13729 			break;
13730 		}
13731 	}
13732 
13733 	cur_elt = uu_list_last(cur_levels);
13734 	cur_level = cur_elt->sl;
13735 }
13736 
13737 /*
13738  * Copies the properties & values in src to dst.  Assumes src won't change.
13739  * Returns -1 if permission is denied, -2 if another transaction interrupts,
13740  * and 0 on success.
13741  *
13742  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
13743  * property, if it is copied and has type boolean.  (See comment in
13744  * lscf_revert()).
13745  */
13746 static int
13747 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
13748     uint8_t enabled)
13749 {
13750 	scf_transaction_t *tx;
13751 	scf_iter_t *iter, *viter;
13752 	scf_property_t *prop;
13753 	scf_value_t *v;
13754 	char *nbuf;
13755 	int r;
13756 
13757 	tx = scf_transaction_create(g_hndl);
13758 	if (tx == NULL)
13759 		scfdie();
13760 
13761 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
13762 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13763 			scfdie();
13764 
13765 		scf_transaction_destroy(tx);
13766 
13767 		return (-1);
13768 	}
13769 
13770 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13771 	    (prop = scf_property_create(g_hndl)) == NULL ||
13772 	    (viter = scf_iter_create(g_hndl)) == NULL)
13773 		scfdie();
13774 
13775 	nbuf = safe_malloc(max_scf_name_len + 1);
13776 
13777 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
13778 		scfdie();
13779 
13780 	for (;;) {
13781 		scf_transaction_entry_t *e;
13782 		scf_type_t ty;
13783 
13784 		r = scf_iter_next_property(iter, prop);
13785 		if (r == -1)
13786 			scfdie();
13787 		if (r == 0)
13788 			break;
13789 
13790 		e = scf_entry_create(g_hndl);
13791 		if (e == NULL)
13792 			scfdie();
13793 
13794 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
13795 			scfdie();
13796 
13797 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
13798 			scfdie();
13799 
13800 		if (scf_transaction_property_new(tx, e, nbuf,
13801 		    ty) != SCF_SUCCESS)
13802 			scfdie();
13803 
13804 		if ((enabled == 0 || enabled == 1) &&
13805 		    strcmp(nbuf, scf_property_enabled) == 0 &&
13806 		    ty == SCF_TYPE_BOOLEAN) {
13807 			v = scf_value_create(g_hndl);
13808 			if (v == NULL)
13809 				scfdie();
13810 
13811 			scf_value_set_boolean(v, enabled);
13812 
13813 			if (scf_entry_add_value(e, v) != 0)
13814 				scfdie();
13815 		} else {
13816 			if (scf_iter_property_values(viter, prop) != 0)
13817 				scfdie();
13818 
13819 			for (;;) {
13820 				v = scf_value_create(g_hndl);
13821 				if (v == NULL)
13822 					scfdie();
13823 
13824 				r = scf_iter_next_value(viter, v);
13825 				if (r == -1)
13826 					scfdie();
13827 				if (r == 0) {
13828 					scf_value_destroy(v);
13829 					break;
13830 				}
13831 
13832 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
13833 					scfdie();
13834 			}
13835 		}
13836 	}
13837 
13838 	free(nbuf);
13839 	scf_iter_destroy(viter);
13840 	scf_property_destroy(prop);
13841 	scf_iter_destroy(iter);
13842 
13843 	r = scf_transaction_commit(tx);
13844 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13845 		scfdie();
13846 
13847 	scf_transaction_destroy_children(tx);
13848 	scf_transaction_destroy(tx);
13849 
13850 	switch (r) {
13851 	case 1:		return (0);
13852 	case 0:		return (-2);
13853 	case -1:	return (-1);
13854 
13855 	default:
13856 		abort();
13857 	}
13858 
13859 	/* NOTREACHED */
13860 }
13861 
13862 void
13863 lscf_revert(const char *snapname)
13864 {
13865 	scf_snapshot_t *snap, *prev;
13866 	scf_snaplevel_t *level, *nlevel;
13867 	scf_iter_t *iter;
13868 	scf_propertygroup_t *pg, *npg;
13869 	scf_property_t *prop;
13870 	scf_value_t *val;
13871 	char *nbuf, *tbuf;
13872 	uint8_t enabled;
13873 
13874 	lscf_prep_hndl();
13875 
13876 	if (cur_inst == NULL) {
13877 		semerr(gettext("Instance not selected.\n"));
13878 		return;
13879 	}
13880 
13881 	if (snapname != NULL) {
13882 		snap = scf_snapshot_create(g_hndl);
13883 		if (snap == NULL)
13884 			scfdie();
13885 
13886 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
13887 		    SCF_SUCCESS) {
13888 			switch (scf_error()) {
13889 			case SCF_ERROR_INVALID_ARGUMENT:
13890 				semerr(gettext("Invalid snapshot name "
13891 				    "\"%s\".\n"), snapname);
13892 				break;
13893 
13894 			case SCF_ERROR_NOT_FOUND:
13895 				semerr(gettext("No such snapshot.\n"));
13896 				break;
13897 
13898 			default:
13899 				scfdie();
13900 			}
13901 
13902 			scf_snapshot_destroy(snap);
13903 			return;
13904 		}
13905 	} else {
13906 		if (cur_snap != NULL) {
13907 			snap = cur_snap;
13908 		} else {
13909 			semerr(gettext("No snapshot selected.\n"));
13910 			return;
13911 		}
13912 	}
13913 
13914 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
13915 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
13916 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13917 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13918 	    (npg = scf_pg_create(g_hndl)) == NULL ||
13919 	    (prop = scf_property_create(g_hndl)) == NULL ||
13920 	    (val = scf_value_create(g_hndl)) == NULL)
13921 		scfdie();
13922 
13923 	nbuf = safe_malloc(max_scf_name_len + 1);
13924 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
13925 
13926 	/* Take the "previous" snapshot before we blow away the properties. */
13927 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
13928 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
13929 			scfdie();
13930 	} else {
13931 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13932 			scfdie();
13933 
13934 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
13935 			scfdie();
13936 	}
13937 
13938 	/* Save general/enabled, since we're probably going to replace it. */
13939 	enabled = 2;
13940 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
13941 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
13942 	    scf_property_get_value(prop, val) == 0)
13943 		(void) scf_value_get_boolean(val, &enabled);
13944 
13945 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13946 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13947 			scfdie();
13948 
13949 		goto out;
13950 	}
13951 
13952 	for (;;) {
13953 		boolean_t isinst;
13954 		uint32_t flags;
13955 		int r;
13956 
13957 		/* Clear the properties from the corresponding entity. */
13958 		isinst = snaplevel_is_instance(level);
13959 
13960 		if (!isinst)
13961 			r = scf_iter_service_pgs(iter, cur_svc);
13962 		else
13963 			r = scf_iter_instance_pgs(iter, cur_inst);
13964 		if (r != SCF_SUCCESS)
13965 			scfdie();
13966 
13967 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13968 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13969 				scfdie();
13970 
13971 			/* Skip nonpersistent pgs. */
13972 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
13973 				continue;
13974 
13975 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
13976 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13977 					scfdie();
13978 
13979 				semerr(emsg_permission_denied);
13980 				goto out;
13981 			}
13982 		}
13983 		if (r == -1)
13984 			scfdie();
13985 
13986 		/* Copy the properties to the corresponding entity. */
13987 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
13988 			scfdie();
13989 
13990 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13991 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
13992 				scfdie();
13993 
13994 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
13995 			    0)
13996 				scfdie();
13997 
13998 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13999 				scfdie();
14000 
14001 			if (!isinst)
14002 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
14003 				    flags, npg);
14004 			else
14005 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
14006 				    flags, npg);
14007 			if (r != SCF_SUCCESS) {
14008 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14009 					scfdie();
14010 
14011 				semerr(emsg_permission_denied);
14012 				goto out;
14013 			}
14014 
14015 			if ((enabled == 0 || enabled == 1) &&
14016 			    strcmp(nbuf, scf_pg_general) == 0)
14017 				r = pg_copy(pg, npg, enabled);
14018 			else
14019 				r = pg_copy(pg, npg, 2);
14020 
14021 			switch (r) {
14022 			case 0:
14023 				break;
14024 
14025 			case -1:
14026 				semerr(emsg_permission_denied);
14027 				goto out;
14028 
14029 			case -2:
14030 				semerr(gettext(
14031 				    "Interrupted by another change.\n"));
14032 				goto out;
14033 
14034 			default:
14035 				abort();
14036 			}
14037 		}
14038 		if (r == -1)
14039 			scfdie();
14040 
14041 		/* Get next level. */
14042 		nlevel = scf_snaplevel_create(g_hndl);
14043 		if (nlevel == NULL)
14044 			scfdie();
14045 
14046 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
14047 		    SCF_SUCCESS) {
14048 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14049 				scfdie();
14050 
14051 			scf_snaplevel_destroy(nlevel);
14052 			break;
14053 		}
14054 
14055 		scf_snaplevel_destroy(level);
14056 		level = nlevel;
14057 	}
14058 
14059 	if (snapname == NULL) {
14060 		lscf_selectsnap(NULL);
14061 		snap = NULL;		/* cur_snap has been destroyed */
14062 	}
14063 
14064 out:
14065 	free(tbuf);
14066 	free(nbuf);
14067 	scf_value_destroy(val);
14068 	scf_property_destroy(prop);
14069 	scf_pg_destroy(npg);
14070 	scf_pg_destroy(pg);
14071 	scf_iter_destroy(iter);
14072 	scf_snaplevel_destroy(level);
14073 	scf_snapshot_destroy(prev);
14074 	if (snap != cur_snap)
14075 		scf_snapshot_destroy(snap);
14076 }
14077 
14078 void
14079 lscf_refresh(void)
14080 {
14081 	ssize_t fmrilen;
14082 	size_t bufsz;
14083 	char *fmribuf;
14084 	int r;
14085 
14086 	lscf_prep_hndl();
14087 
14088 	if (cur_inst == NULL) {
14089 		semerr(gettext("Instance not selected.\n"));
14090 		return;
14091 	}
14092 
14093 	bufsz = max_scf_fmri_len + 1;
14094 	fmribuf = safe_malloc(bufsz);
14095 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
14096 	if (fmrilen < 0) {
14097 		free(fmribuf);
14098 		if (scf_error() != SCF_ERROR_DELETED)
14099 			scfdie();
14100 		scf_instance_destroy(cur_inst);
14101 		cur_inst = NULL;
14102 		warn(emsg_deleted);
14103 		return;
14104 	}
14105 	assert(fmrilen < bufsz);
14106 
14107 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
14108 	switch (r) {
14109 	case 0:
14110 		break;
14111 
14112 	case ECONNABORTED:
14113 		warn(gettext("Could not refresh %s "
14114 		    "(repository connection broken).\n"), fmribuf);
14115 		break;
14116 
14117 	case ECANCELED:
14118 		warn(emsg_deleted);
14119 		break;
14120 
14121 	case EPERM:
14122 		warn(gettext("Could not refresh %s "
14123 		    "(permission denied).\n"), fmribuf);
14124 		break;
14125 
14126 	case ENOSPC:
14127 		warn(gettext("Could not refresh %s "
14128 		    "(repository server out of resources).\n"),
14129 		    fmribuf);
14130 		break;
14131 
14132 	case EACCES:
14133 	default:
14134 		bad_error("refresh_entity", scf_error());
14135 	}
14136 
14137 	free(fmribuf);
14138 }
14139 
14140 /*
14141  * describe [-v] [-t] [pg/prop]
14142  */
14143 int
14144 lscf_describe(uu_list_t *args, int hasargs)
14145 {
14146 	int ret = 0;
14147 	size_t i;
14148 	int argc;
14149 	char **argv = NULL;
14150 	string_list_t *slp;
14151 	int do_verbose = 0;
14152 	int do_templates = 0;
14153 	char *pattern = NULL;
14154 
14155 	lscf_prep_hndl();
14156 
14157 	if (hasargs != 0)  {
14158 		argc = uu_list_numnodes(args);
14159 		if (argc < 1)
14160 			goto usage;
14161 
14162 		argv = calloc(argc + 1, sizeof (char *));
14163 		if (argv == NULL)
14164 			uu_die(gettext("Out of memory.\n"));
14165 
14166 		for (slp = uu_list_first(args), i = 0;
14167 		    slp != NULL;
14168 		    slp = uu_list_next(args, slp), ++i)
14169 			argv[i] = slp->str;
14170 
14171 		argv[i] = NULL;
14172 
14173 		/*
14174 		 * We start optind = 0 because our list of arguments
14175 		 * starts at argv[0]
14176 		 */
14177 		optind = 0;
14178 		opterr = 0;
14179 		for (;;) {
14180 			ret = getopt(argc, argv, "vt");
14181 			if (ret == -1)
14182 				break;
14183 
14184 			switch (ret) {
14185 			case 'v':
14186 				do_verbose = 1;
14187 				break;
14188 
14189 			case 't':
14190 				do_templates = 1;
14191 				break;
14192 
14193 			case '?':
14194 				goto usage;
14195 
14196 			default:
14197 				bad_error("getopt", ret);
14198 			}
14199 		}
14200 
14201 		pattern = argv[optind];
14202 	}
14203 
14204 	if (cur_inst == NULL && cur_svc == NULL) {
14205 		semerr(emsg_entity_not_selected);
14206 		ret = -1;
14207 		goto out;
14208 	}
14209 
14210 	/*
14211 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
14212 	 * output if their last parameter is set to 2.  Less information is
14213 	 * produced if the parameter is set to 1.
14214 	 */
14215 	if (pattern == NULL) {
14216 		if (do_verbose == 1)
14217 			list_entity_tmpl(2);
14218 		else
14219 			list_entity_tmpl(1);
14220 	}
14221 
14222 	if (do_templates == 0) {
14223 		if (do_verbose == 1)
14224 			listprop(pattern, 0, 2);
14225 		else
14226 			listprop(pattern, 0, 1);
14227 	} else {
14228 		if (do_verbose == 1)
14229 			listtmpl(pattern, 2);
14230 		else
14231 			listtmpl(pattern, 1);
14232 	}
14233 
14234 	ret = 0;
14235 out:
14236 	if (argv != NULL)
14237 		free(argv);
14238 	return (ret);
14239 usage:
14240 	ret = -2;
14241 	goto out;
14242 }
14243 
14244 #ifndef NATIVE_BUILD
14245 /* ARGSUSED */
14246 CPL_MATCH_FN(complete_select)
14247 {
14248 	const char *arg0, *arg1, *arg1end;
14249 	int word_start, err = 0, r;
14250 	size_t len;
14251 	char *buf;
14252 
14253 	lscf_prep_hndl();
14254 
14255 	arg0 = line + strspn(line, " \t");
14256 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
14257 
14258 	arg1 = arg0 + sizeof ("select") - 1;
14259 	arg1 += strspn(arg1, " \t");
14260 	word_start = arg1 - line;
14261 
14262 	arg1end = arg1 + strcspn(arg1, " \t");
14263 	if (arg1end < line + word_end)
14264 		return (0);
14265 
14266 	len = line + word_end - arg1;
14267 
14268 	buf = safe_malloc(max_scf_name_len + 1);
14269 
14270 	if (cur_snap != NULL) {
14271 		return (0);
14272 	} else if (cur_inst != NULL) {
14273 		return (0);
14274 	} else if (cur_svc != NULL) {
14275 		scf_instance_t *inst;
14276 		scf_iter_t *iter;
14277 
14278 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
14279 		    (iter = scf_iter_create(g_hndl)) == NULL)
14280 			scfdie();
14281 
14282 		if (scf_iter_service_instances(iter, cur_svc) != 0)
14283 			scfdie();
14284 
14285 		for (;;) {
14286 			r = scf_iter_next_instance(iter, inst);
14287 			if (r == 0)
14288 				break;
14289 			if (r != 1)
14290 				scfdie();
14291 
14292 			if (scf_instance_get_name(inst, buf,
14293 			    max_scf_name_len + 1) < 0)
14294 				scfdie();
14295 
14296 			if (strncmp(buf, arg1, len) == 0) {
14297 				err = cpl_add_completion(cpl, line, word_start,
14298 				    word_end, buf + len, "", " ");
14299 				if (err != 0)
14300 					break;
14301 			}
14302 		}
14303 
14304 		scf_iter_destroy(iter);
14305 		scf_instance_destroy(inst);
14306 
14307 		return (err);
14308 	} else {
14309 		scf_service_t *svc;
14310 		scf_iter_t *iter;
14311 
14312 		assert(cur_scope != NULL);
14313 
14314 		if ((svc = scf_service_create(g_hndl)) == NULL ||
14315 		    (iter = scf_iter_create(g_hndl)) == NULL)
14316 			scfdie();
14317 
14318 		if (scf_iter_scope_services(iter, cur_scope) != 0)
14319 			scfdie();
14320 
14321 		for (;;) {
14322 			r = scf_iter_next_service(iter, svc);
14323 			if (r == 0)
14324 				break;
14325 			if (r != 1)
14326 				scfdie();
14327 
14328 			if (scf_service_get_name(svc, buf,
14329 			    max_scf_name_len + 1) < 0)
14330 				scfdie();
14331 
14332 			if (strncmp(buf, arg1, len) == 0) {
14333 				err = cpl_add_completion(cpl, line, word_start,
14334 				    word_end, buf + len, "", " ");
14335 				if (err != 0)
14336 					break;
14337 			}
14338 		}
14339 
14340 		scf_iter_destroy(iter);
14341 		scf_service_destroy(svc);
14342 
14343 		return (err);
14344 	}
14345 }
14346 
14347 /* ARGSUSED */
14348 CPL_MATCH_FN(complete_command)
14349 {
14350 	uint32_t scope = 0;
14351 
14352 	if (cur_snap != NULL)
14353 		scope = CS_SNAP;
14354 	else if (cur_inst != NULL)
14355 		scope = CS_INST;
14356 	else if (cur_svc != NULL)
14357 		scope = CS_SVC;
14358 	else
14359 		scope = CS_SCOPE;
14360 
14361 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
14362 }
14363 #endif	/* NATIVE_BUILD */
14364