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