svccfg_libscf.c revision 11996:91b62f7b8186
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 2010 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#include <poll.h>
49
50#include <libxml/tree.h>
51
52#include <sys/param.h>
53
54#include <sys/stat.h>
55#include <sys/mman.h>
56
57#include "svccfg.h"
58#include "manifest_hash.h"
59#include "manifest_find.h"
60
61/* The colon namespaces in each entity (each followed by a newline). */
62#define	COLON_NAMESPACES	":properties\n"
63
64#define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
65
66/* These are characters which the lexer requires to be in double-quotes. */
67#define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
68
69#define	HASH_SIZE		16
70#define	HASH_PG_TYPE		"framework"
71#define	HASH_PG_FLAGS		0
72#define	HASH_PROP		"md5sum"
73
74/*
75 * Indentation used in the output of the describe subcommand.
76 */
77#define	TMPL_VALUE_INDENT	"  "
78#define	TMPL_INDENT		"    "
79#define	TMPL_INDENT_2X		"        "
80#define	TMPL_CHOICE_INDENT	"      "
81
82/*
83 * Directory locations for manifests
84 */
85#define	VARSVC_DIR		"/var/svc/manifest"
86#define	LIBSVC_DIR		"/lib/svc/manifest"
87#define	VARSVC_PR		"var_svc_manifest"
88#define	LIBSVC_PR		"lib_svc_manifest"
89#define	MFSTFILEPR		"manifestfile"
90
91#define	SUPPORTPROP		"support"
92
93#define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
94
95#define	MFSTFILE_MAX		16
96
97/*
98 * These are the classes of elements which may appear as children of service
99 * or instance elements in XML manifests.
100 */
101struct entity_elts {
102	xmlNodePtr	create_default_instance;
103	xmlNodePtr	single_instance;
104	xmlNodePtr	restarter;
105	xmlNodePtr	dependencies;
106	xmlNodePtr	dependents;
107	xmlNodePtr	method_context;
108	xmlNodePtr	exec_methods;
109	xmlNodePtr	property_groups;
110	xmlNodePtr	instances;
111	xmlNodePtr	stability;
112	xmlNodePtr	template;
113};
114
115/*
116 * Likewise for property_group elements.
117 */
118struct pg_elts {
119	xmlNodePtr	stability;
120	xmlNodePtr	propvals;
121	xmlNodePtr	properties;
122};
123
124/*
125 * Likewise for template elements.
126 */
127struct template_elts {
128	xmlNodePtr	common_name;
129	xmlNodePtr	description;
130	xmlNodePtr	documentation;
131};
132
133/*
134 * This structure is for snaplevel lists.  They are convenient because libscf
135 * only allows traversing snaplevels in one direction.
136 */
137struct snaplevel {
138	uu_list_node_t	list_node;
139	scf_snaplevel_t	*sl;
140};
141
142/*
143 * This is used for communication between lscf_service_export and
144 * export_callback.
145 */
146struct export_args {
147	const char	*filename;
148	int 		flags;
149};
150
151/*
152 * The service_manifest structure is used by the upgrade process
153 * to create a list of service to manifest linkages from the manifests
154 * in a set of given directories.
155 */
156typedef struct service_manifest {
157	const char 	*servicename;
158	uu_list_t	*mfstlist;
159	size_t	mfstlist_sz;
160
161	uu_avl_node_t	svcmfst_node;
162} service_manifest_t;
163
164/*
165 * Structure to track the manifest file property group
166 * and the manifest file associated with that property
167 * group.  Also, a flag to keep the access once it has
168 * been checked.
169 */
170struct mpg_mfile {
171	char	*mpg;
172	char	*mfile;
173	int	access;
174};
175
176const char * const scf_pg_general = SCF_PG_GENERAL;
177const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
178const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
179const char * const scf_property_external = "external";
180
181const char * const snap_initial = "initial";
182const char * const snap_lastimport = "last-import";
183const char * const snap_previous = "previous";
184const char * const snap_running = "running";
185
186scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
187
188ssize_t max_scf_fmri_len;
189ssize_t max_scf_name_len;
190ssize_t max_scf_pg_type_len;
191ssize_t max_scf_value_len;
192static size_t max_scf_len;
193
194static scf_scope_t *cur_scope;
195static scf_service_t *cur_svc = NULL;
196static scf_instance_t *cur_inst = NULL;
197static scf_snapshot_t *cur_snap = NULL;
198static scf_snaplevel_t *cur_level = NULL;
199
200static uu_list_pool_t *snaplevel_pool;
201/* cur_levels is the snaplevels of cur_snap, from least specific to most. */
202static uu_list_t *cur_levels;
203static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
204
205static FILE *tempfile = NULL;
206static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
207
208static const char *emsg_entity_not_selected;
209static const char *emsg_permission_denied;
210static const char *emsg_create_xml;
211static const char *emsg_cant_modify_snapshots;
212static const char *emsg_read_only;
213static const char *emsg_deleted;
214static const char *emsg_invalid_pg_name;
215static const char *emsg_invalid_prop_name;
216static const char *emsg_no_such_pg;
217static const char *emsg_fmri_invalid_pg_name;
218static const char *emsg_fmri_invalid_pg_name_type;
219static const char *emsg_pg_added;
220static const char *emsg_pg_changed;
221static const char *emsg_pg_deleted;
222static const char *emsg_pg_mod_perm;
223static const char *emsg_pg_add_perm;
224static const char *emsg_pg_del_perm;
225static const char *emsg_snap_perm;
226static const char *emsg_dpt_dangling;
227static const char *emsg_dpt_no_dep;
228
229static int li_only = 0;
230static int no_refresh = 0;
231
232/* import globals, to minimize allocations */
233static scf_scope_t *imp_scope = NULL;
234static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
235static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
236static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
237static scf_snapshot_t *imp_rsnap = NULL;
238static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
239static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
240static scf_property_t *imp_prop = NULL;
241static scf_iter_t *imp_iter = NULL;
242static scf_iter_t *imp_rpg_iter = NULL;
243static scf_iter_t *imp_up_iter = NULL;
244static scf_transaction_t *imp_tx = NULL;	/* always reset this */
245static char *imp_str = NULL;
246static size_t imp_str_sz;
247static char *imp_tsname = NULL;
248static char *imp_fe1 = NULL;		/* for fmri_equal() */
249static char *imp_fe2 = NULL;
250static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
251
252/* upgrade_dependents() globals */
253static scf_instance_t *ud_inst = NULL;
254static scf_snaplevel_t *ud_snpl = NULL;
255static scf_propertygroup_t *ud_pg = NULL;
256static scf_propertygroup_t *ud_cur_depts_pg = NULL;
257static scf_propertygroup_t *ud_run_dpts_pg = NULL;
258static int ud_run_dpts_pg_set = 0;
259static scf_property_t *ud_prop = NULL;
260static scf_property_t *ud_dpt_prop = NULL;
261static scf_value_t *ud_val = NULL;
262static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
263static scf_transaction_t *ud_tx = NULL;
264static char *ud_ctarg = NULL;
265static char *ud_oldtarg = NULL;
266static char *ud_name = NULL;
267
268/* export globals */
269static scf_instance_t *exp_inst;
270static scf_propertygroup_t *exp_pg;
271static scf_property_t *exp_prop;
272static scf_value_t *exp_val;
273static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
274static char *exp_str;
275static size_t exp_str_sz;
276
277/* cleanup globals */
278static uu_avl_pool_t *service_manifest_pool = NULL;
279static uu_avl_t *service_manifest_tree = NULL;
280
281static void scfdie_lineno(int lineno) __NORETURN;
282
283static char *start_method_names[] = {
284	"start",
285	"inetd_start",
286	NULL
287};
288
289static void
290safe_printf(const char *fmt, ...)
291{
292	va_list va;
293
294	va_start(va, fmt);
295	if (vprintf(fmt, va) < 0)
296		uu_die(gettext("Error writing to stdout"));
297	va_end(va);
298}
299
300/*
301 * For unexpected libscf errors.
302 */
303#ifdef NDEBUG
304
305static void scfdie(void) __NORETURN;
306
307static void
308scfdie(void)
309{
310	scf_error_t err = scf_error();
311
312	if (err == SCF_ERROR_CONNECTION_BROKEN)
313		uu_die(gettext("Repository connection broken.  Exiting.\n"));
314
315	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
316	    scf_strerror(err));
317}
318
319#else
320
321#define	scfdie()	scfdie_lineno(__LINE__)
322
323static void
324scfdie_lineno(int lineno)
325{
326	scf_error_t err = scf_error();
327
328	if (err == SCF_ERROR_CONNECTION_BROKEN)
329		uu_die(gettext("Repository connection broken.  Exiting.\n"));
330
331	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
332	    ": %s.\n"), lineno, scf_strerror(err));
333}
334
335#endif
336
337static void
338scfwarn(void)
339{
340	warn(gettext("Unexpected libscf error: %s.\n"),
341	    scf_strerror(scf_error()));
342}
343
344/*
345 * Clear a field of a structure.
346 */
347static int
348clear_int(void *a, void *b)
349{
350	/* LINTED */
351	*(int *)((char *)a + (size_t)b) = 0;
352
353	return (UU_WALK_NEXT);
354}
355
356static int
357scferror2errno(scf_error_t err)
358{
359	switch (err) {
360	case SCF_ERROR_BACKEND_ACCESS:
361		return (EACCES);
362
363	case SCF_ERROR_BACKEND_READONLY:
364		return (EROFS);
365
366	case SCF_ERROR_CONNECTION_BROKEN:
367		return (ECONNABORTED);
368
369	case SCF_ERROR_CONSTRAINT_VIOLATED:
370	case SCF_ERROR_INVALID_ARGUMENT:
371		return (EINVAL);
372
373	case SCF_ERROR_DELETED:
374		return (ECANCELED);
375
376	case SCF_ERROR_EXISTS:
377		return (EEXIST);
378
379	case SCF_ERROR_NO_MEMORY:
380		return (ENOMEM);
381
382	case SCF_ERROR_NO_RESOURCES:
383		return (ENOSPC);
384
385	case SCF_ERROR_NOT_FOUND:
386		return (ENOENT);
387
388	case SCF_ERROR_PERMISSION_DENIED:
389		return (EPERM);
390
391	default:
392#ifndef NDEBUG
393		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
394		    __FILE__, __LINE__, err);
395#else
396		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
397#endif
398		abort();
399		/* NOTREACHED */
400	}
401}
402
403static int
404entity_get_pg(void *ent, int issvc, const char *name,
405    scf_propertygroup_t *pg)
406{
407	if (issvc)
408		return (scf_service_get_pg(ent, name, pg));
409	else
410		return (scf_instance_get_pg(ent, name, pg));
411}
412
413static void
414entity_destroy(void *ent, int issvc)
415{
416	if (issvc)
417		scf_service_destroy(ent);
418	else
419		scf_instance_destroy(ent);
420}
421
422static int
423get_pg(const char *pg_name, scf_propertygroup_t *pg)
424{
425	int ret;
426
427	if (cur_level != NULL)
428		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
429	else if (cur_inst != NULL)
430		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
431	else
432		ret = scf_service_get_pg(cur_svc, pg_name, pg);
433
434	return (ret);
435}
436
437/*
438 * Find a snaplevel in a snapshot.  If get_svc is true, find the service
439 * snaplevel.  Otherwise find the instance snaplevel.
440 *
441 * Returns
442 *   0 - success
443 *   ECONNABORTED - repository connection broken
444 *   ECANCELED - instance containing snap was deleted
445 *   ENOENT - snap has no snaplevels
446 *	    - requested snaplevel not found
447 */
448static int
449get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
450{
451	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
452		switch (scf_error()) {
453		case SCF_ERROR_CONNECTION_BROKEN:
454		case SCF_ERROR_DELETED:
455		case SCF_ERROR_NOT_FOUND:
456			return (scferror2errno(scf_error()));
457
458		case SCF_ERROR_HANDLE_MISMATCH:
459		case SCF_ERROR_NOT_BOUND:
460		case SCF_ERROR_NOT_SET:
461		default:
462			bad_error("scf_snapshot_get_base_snaplevel",
463			    scf_error());
464		}
465	}
466
467	for (;;) {
468		ssize_t ssz;
469
470		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
471		if (ssz >= 0) {
472			if (!get_svc)
473				return (0);
474		} else {
475			switch (scf_error()) {
476			case SCF_ERROR_CONSTRAINT_VIOLATED:
477				if (get_svc)
478					return (0);
479				break;
480
481			case SCF_ERROR_DELETED:
482			case SCF_ERROR_CONNECTION_BROKEN:
483				return (scferror2errno(scf_error()));
484
485			case SCF_ERROR_NOT_SET:
486			case SCF_ERROR_NOT_BOUND:
487			default:
488				bad_error("scf_snaplevel_get_instance_name",
489				    scf_error());
490			}
491		}
492
493		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
494			switch (scf_error()) {
495			case SCF_ERROR_NOT_FOUND:
496			case SCF_ERROR_CONNECTION_BROKEN:
497			case SCF_ERROR_DELETED:
498				return (scferror2errno(scf_error()));
499
500			case SCF_ERROR_HANDLE_MISMATCH:
501			case SCF_ERROR_NOT_BOUND:
502			case SCF_ERROR_NOT_SET:
503			case SCF_ERROR_INVALID_ARGUMENT:
504			default:
505				bad_error("scf_snaplevel_get_next_snaplevel",
506				    scf_error());
507			}
508		}
509	}
510}
511
512/*
513 * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
514 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
515 * the property group named name in it.  If it doesn't have a running
516 * snapshot, set pg to the instance's current property group named name.
517 *
518 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
519 * its instances.  If one has a running snapshot with a service snaplevel, set
520 * pg to the property group named name in it.  If no such snaplevel could be
521 * found, set pg to the service's current property group named name.
522 *
523 * iter, inst, snap, and snpl are required scratch objects.
524 *
525 * Returns
526 *   0 - success
527 *   ECONNABORTED - repository connection broken
528 *   ECANCELED - ent was deleted
529 *   ENOENT - no such property group
530 *   EINVAL - name is an invalid property group name
531 *   EBADF - found running snapshot is missing a snaplevel
532 */
533static int
534entity_get_running_pg(void *ent, int issvc, const char *name,
535    scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
536    scf_snapshot_t *snap, scf_snaplevel_t *snpl)
537{
538	int r;
539
540	if (issvc) {
541		/* Search for an instance with a running snapshot. */
542		if (scf_iter_service_instances(iter, ent) != 0) {
543			switch (scf_error()) {
544			case SCF_ERROR_DELETED:
545			case SCF_ERROR_CONNECTION_BROKEN:
546				return (scferror2errno(scf_error()));
547
548			case SCF_ERROR_NOT_SET:
549			case SCF_ERROR_NOT_BOUND:
550			case SCF_ERROR_HANDLE_MISMATCH:
551			default:
552				bad_error("scf_iter_service_instances",
553				    scf_error());
554			}
555		}
556
557		for (;;) {
558			r = scf_iter_next_instance(iter, inst);
559			if (r == 0) {
560				if (scf_service_get_pg(ent, name, pg) == 0)
561					return (0);
562
563				switch (scf_error()) {
564				case SCF_ERROR_DELETED:
565				case SCF_ERROR_NOT_FOUND:
566				case SCF_ERROR_INVALID_ARGUMENT:
567				case SCF_ERROR_CONNECTION_BROKEN:
568					return (scferror2errno(scf_error()));
569
570				case SCF_ERROR_NOT_BOUND:
571				case SCF_ERROR_HANDLE_MISMATCH:
572				case SCF_ERROR_NOT_SET:
573				default:
574					bad_error("scf_service_get_pg",
575					    scf_error());
576				}
577			}
578			if (r != 1) {
579				switch (scf_error()) {
580				case SCF_ERROR_DELETED:
581				case SCF_ERROR_CONNECTION_BROKEN:
582					return (scferror2errno(scf_error()));
583
584				case SCF_ERROR_INVALID_ARGUMENT:
585				case SCF_ERROR_NOT_SET:
586				case SCF_ERROR_NOT_BOUND:
587				case SCF_ERROR_HANDLE_MISMATCH:
588				default:
589					bad_error("scf_iter_next_instance",
590					    scf_error());
591				}
592			}
593
594			if (scf_instance_get_snapshot(inst, snap_running,
595			    snap) == 0)
596				break;
597
598			switch (scf_error()) {
599			case SCF_ERROR_NOT_FOUND:
600			case SCF_ERROR_DELETED:
601				continue;
602
603			case SCF_ERROR_CONNECTION_BROKEN:
604				return (ECONNABORTED);
605
606			case SCF_ERROR_HANDLE_MISMATCH:
607			case SCF_ERROR_INVALID_ARGUMENT:
608			case SCF_ERROR_NOT_SET:
609			case SCF_ERROR_NOT_BOUND:
610			default:
611				bad_error("scf_instance_get_snapshot",
612				    scf_error());
613			}
614		}
615	} else {
616		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
617			switch (scf_error()) {
618			case SCF_ERROR_NOT_FOUND:
619				break;
620
621			case SCF_ERROR_DELETED:
622			case SCF_ERROR_CONNECTION_BROKEN:
623				return (scferror2errno(scf_error()));
624
625			case SCF_ERROR_NOT_BOUND:
626			case SCF_ERROR_HANDLE_MISMATCH:
627			case SCF_ERROR_INVALID_ARGUMENT:
628			case SCF_ERROR_NOT_SET:
629			default:
630				bad_error("scf_instance_get_snapshot",
631				    scf_error());
632			}
633
634			if (scf_instance_get_pg(ent, name, pg) == 0)
635				return (0);
636
637			switch (scf_error()) {
638			case SCF_ERROR_DELETED:
639			case SCF_ERROR_NOT_FOUND:
640			case SCF_ERROR_INVALID_ARGUMENT:
641			case SCF_ERROR_CONNECTION_BROKEN:
642				return (scferror2errno(scf_error()));
643
644			case SCF_ERROR_NOT_BOUND:
645			case SCF_ERROR_HANDLE_MISMATCH:
646			case SCF_ERROR_NOT_SET:
647			default:
648				bad_error("scf_instance_get_pg", scf_error());
649			}
650		}
651	}
652
653	r = get_snaplevel(snap, issvc, snpl);
654	switch (r) {
655	case 0:
656		break;
657
658	case ECONNABORTED:
659	case ECANCELED:
660		return (r);
661
662	case ENOENT:
663		return (EBADF);
664
665	default:
666		bad_error("get_snaplevel", r);
667	}
668
669	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
670		return (0);
671
672	switch (scf_error()) {
673	case SCF_ERROR_DELETED:
674	case SCF_ERROR_INVALID_ARGUMENT:
675	case SCF_ERROR_CONNECTION_BROKEN:
676	case SCF_ERROR_NOT_FOUND:
677		return (scferror2errno(scf_error()));
678
679	case SCF_ERROR_NOT_BOUND:
680	case SCF_ERROR_HANDLE_MISMATCH:
681	case SCF_ERROR_NOT_SET:
682	default:
683		bad_error("scf_snaplevel_get_pg", scf_error());
684		/* NOTREACHED */
685	}
686}
687
688/*
689 * To be registered with atexit().
690 */
691static void
692remove_tempfile(void)
693{
694	int ret;
695
696	if (tempfile != NULL) {
697		if (fclose(tempfile) == EOF)
698			(void) warn(gettext("Could not close temporary file"));
699		tempfile = NULL;
700	}
701
702	if (tempfilename[0] != '\0') {
703		do {
704			ret = remove(tempfilename);
705		} while (ret == -1 && errno == EINTR);
706		if (ret == -1)
707			warn(gettext("Could not remove temporary file"));
708		tempfilename[0] = '\0';
709	}
710}
711
712/*
713 * Launch private svc.configd(1M) for manipulating alternate repositories.
714 */
715static void
716start_private_repository(engine_state_t *est)
717{
718	int fd, stat;
719	struct door_info info;
720	pid_t pid;
721
722	/*
723	 * 1.  Create a temporary file for the door.
724	 */
725	if (est->sc_repo_doorname != NULL)
726		free((void *)est->sc_repo_doorname);
727
728	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
729	if (est->sc_repo_doorname == NULL)
730		uu_die(gettext("Could not acquire temporary filename"));
731
732	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
733	if (fd < 0)
734		uu_die(gettext("Could not create temporary file for "
735		    "repository server"));
736
737	(void) close(fd);
738
739	/*
740	 * 2.  Launch a configd with that door, using the specified
741	 * repository.
742	 */
743	if ((est->sc_repo_pid = fork()) == 0) {
744		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
745		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
746		    NULL);
747		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
748	} else if (est->sc_repo_pid == -1)
749		uu_die(gettext("Attempt to fork failed"));
750
751	do {
752		pid = waitpid(est->sc_repo_pid, &stat, 0);
753	} while (pid == -1 && errno == EINTR);
754
755	if (pid == -1)
756		uu_die(gettext("Could not waitpid() for repository server"));
757
758	if (!WIFEXITED(stat)) {
759		uu_die(gettext("Repository server failed (status %d).\n"),
760		    stat);
761	} else if (WEXITSTATUS(stat) != 0) {
762		uu_die(gettext("Repository server failed (exit %d).\n"),
763		    WEXITSTATUS(stat));
764	}
765
766	/*
767	 * See if it was successful by checking if the door is a door.
768	 */
769
770	fd = open(est->sc_repo_doorname, O_RDWR);
771	if (fd < 0)
772		uu_die(gettext("Could not open door \"%s\""),
773		    est->sc_repo_doorname);
774
775	if (door_info(fd, &info) < 0)
776		uu_die(gettext("Unexpected door_info() error"));
777
778	if (close(fd) == -1)
779		warn(gettext("Could not close repository door"),
780		    strerror(errno));
781
782	est->sc_repo_pid = info.di_target;
783}
784
785void
786lscf_cleanup(void)
787{
788	/*
789	 * In the case where we've launched a private svc.configd(1M)
790	 * instance, we must terminate our child and remove the temporary
791	 * rendezvous point.
792	 */
793	if (est->sc_repo_pid > 0) {
794		(void) kill(est->sc_repo_pid, SIGTERM);
795		(void) waitpid(est->sc_repo_pid, NULL, 0);
796		(void) unlink(est->sc_repo_doorname);
797
798		est->sc_repo_pid = 0;
799	}
800}
801
802void
803unselect_cursnap(void)
804{
805	void *cookie;
806
807	cur_level = NULL;
808
809	cookie = NULL;
810	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
811		scf_snaplevel_destroy(cur_elt->sl);
812		free(cur_elt);
813	}
814
815	scf_snapshot_destroy(cur_snap);
816	cur_snap = NULL;
817}
818
819void
820lscf_prep_hndl(void)
821{
822	if (g_hndl != NULL)
823		return;
824
825	g_hndl = scf_handle_create(SCF_VERSION);
826	if (g_hndl == NULL)
827		scfdie();
828
829	if (est->sc_repo_filename != NULL)
830		start_private_repository(est);
831
832	if (est->sc_repo_doorname != NULL) {
833		scf_value_t *repo_value;
834		int ret;
835
836		repo_value = scf_value_create(g_hndl);
837		if (repo_value == NULL)
838			scfdie();
839
840		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
841		assert(ret == SCF_SUCCESS);
842
843		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
844		    SCF_SUCCESS)
845			scfdie();
846
847		scf_value_destroy(repo_value);
848	}
849
850	if (scf_handle_bind(g_hndl) != 0)
851		uu_die(gettext("Could not connect to repository server: %s.\n"),
852		    scf_strerror(scf_error()));
853
854	cur_scope = scf_scope_create(g_hndl);
855	if (cur_scope == NULL)
856		scfdie();
857
858	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
859		scfdie();
860}
861
862static void
863repository_teardown(void)
864{
865	if (g_hndl != NULL) {
866		if (cur_snap != NULL)
867			unselect_cursnap();
868		scf_instance_destroy(cur_inst);
869		scf_service_destroy(cur_svc);
870		scf_scope_destroy(cur_scope);
871		scf_handle_destroy(g_hndl);
872		cur_inst = NULL;
873		cur_svc = NULL;
874		cur_scope = NULL;
875		g_hndl = NULL;
876		lscf_cleanup();
877	}
878}
879
880void
881lscf_set_repository(const char *repfile, int force)
882{
883	repository_teardown();
884
885	if (est->sc_repo_filename != NULL) {
886		free((void *)est->sc_repo_filename);
887		est->sc_repo_filename = NULL;
888	}
889
890	if ((force == 0) && (access(repfile, R_OK) != 0)) {
891		/*
892		 * Repository file does not exist
893		 * or has no read permission.
894		 */
895		warn(gettext("Cannot access \"%s\": %s\n"),
896		    repfile, strerror(errno));
897	} else {
898		est->sc_repo_filename = safe_strdup(repfile);
899	}
900
901	lscf_prep_hndl();
902}
903
904void
905lscf_init()
906{
907	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
908	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
909	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
910	    0 ||
911	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
912		scfdie();
913
914	max_scf_len = max_scf_fmri_len;
915	if (max_scf_name_len > max_scf_len)
916		max_scf_len = max_scf_name_len;
917	if (max_scf_pg_type_len > max_scf_len)
918		max_scf_len = max_scf_pg_type_len;
919	if (max_scf_value_len > max_scf_len)
920		max_scf_len = max_scf_value_len;
921
922	if (atexit(remove_tempfile) != 0)
923		uu_die(gettext("Could not register atexit() function"));
924
925	emsg_entity_not_selected = gettext("An entity is not selected.\n");
926	emsg_permission_denied = gettext("Permission denied.\n");
927	emsg_create_xml = gettext("Could not create XML node.\n");
928	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
929	emsg_read_only = gettext("Backend read-only.\n");
930	emsg_deleted = gettext("Current selection has been deleted.\n");
931	emsg_invalid_pg_name =
932	    gettext("Invalid property group name \"%s\".\n");
933	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
934	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
935	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
936	    "with invalid name \"%s\".\n");
937	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
938	    "group with invalid name \"%s\" or type \"%s\".\n");
939	emsg_pg_added = gettext("%s changed unexpectedly "
940	    "(property group \"%s\" added).\n");
941	emsg_pg_changed = gettext("%s changed unexpectedly "
942	    "(property group \"%s\" changed).\n");
943	emsg_pg_deleted = gettext("%s changed unexpectedly "
944	    "(property group \"%s\" or an ancestor was deleted).\n");
945	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
946	    "in %s (permission denied).\n");
947	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
948	    "in %s (permission denied).\n");
949	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
950	    "in %s (permission denied).\n");
951	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
952	    "(permission denied).\n");
953	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
954	    "new dependent \"%s\" because it already exists).  Warning: The "
955	    "current dependent's target (%s) does not exist.\n");
956	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
957	    "dependent \"%s\" because it already exists).  Warning: The "
958	    "current dependent's target (%s) does not have a dependency named "
959	    "\"%s\" as expected.\n");
960
961	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
962	    offsetof(string_list_t, node), NULL, 0);
963	snaplevel_pool = uu_list_pool_create("snaplevels",
964	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
965	    NULL, 0);
966}
967
968
969static const char *
970prop_to_typestr(const scf_property_t *prop)
971{
972	scf_type_t ty;
973
974	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
975		scfdie();
976
977	return (scf_type_to_string(ty));
978}
979
980static scf_type_t
981string_to_type(const char *type)
982{
983	size_t len = strlen(type);
984	char *buf;
985
986	if (len == 0 || type[len - 1] != ':')
987		return (SCF_TYPE_INVALID);
988
989	buf = (char *)alloca(len + 1);
990	(void) strlcpy(buf, type, len + 1);
991	buf[len - 1] = 0;
992
993	return (scf_string_to_type(buf));
994}
995
996static scf_value_t *
997string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
998{
999	scf_value_t *v;
1000	char *dup, *nstr;
1001	size_t len;
1002
1003	v = scf_value_create(g_hndl);
1004	if (v == NULL)
1005		scfdie();
1006
1007	len = strlen(str);
1008	if (require_quotes &&
1009	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1010		semerr(gettext("Multiple string values or string values "
1011		    "with spaces must be quoted with '\"'.\n"));
1012		scf_value_destroy(v);
1013		return (NULL);
1014	}
1015
1016	nstr = dup = safe_strdup(str);
1017	if (dup[0] == '\"') {
1018		/*
1019		 * Strip out the first and the last quote.
1020		 */
1021		dup[len - 1] = '\0';
1022		nstr = dup + 1;
1023	}
1024
1025	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1026		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1027		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1028		    scf_type_to_string(ty), nstr);
1029		scf_value_destroy(v);
1030		v = NULL;
1031	}
1032	free(dup);
1033	return (v);
1034}
1035
1036/*
1037 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1038 * Optionally append a comment prefix ('#') to newlines ('\n').
1039 */
1040static int
1041quote_and_print(const char *str, FILE *strm, int commentnl)
1042{
1043	const char *cp;
1044
1045	for (cp = str; *cp != '\0'; ++cp) {
1046		if (*cp == '"' || *cp == '\\')
1047			(void) putc('\\', strm);
1048
1049		(void) putc(*cp, strm);
1050
1051		if (commentnl && *cp == '\n') {
1052			(void) putc('#', strm);
1053		}
1054	}
1055
1056	return (ferror(strm));
1057}
1058
1059/*
1060 * These wrappers around lowlevel functions provide consistent error checking
1061 * and warnings.
1062 */
1063static int
1064pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1065{
1066	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1067		return (0);
1068
1069	if (scf_error() != SCF_ERROR_NOT_FOUND)
1070		scfdie();
1071
1072	if (g_verbose) {
1073		ssize_t len;
1074		char *fmri;
1075
1076		len = scf_pg_to_fmri(pg, NULL, 0);
1077		if (len < 0)
1078			scfdie();
1079
1080		fmri = safe_malloc(len + 1);
1081
1082		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1083			scfdie();
1084
1085		warn(gettext("Expected property %s of property group %s is "
1086		    "missing.\n"), propname, fmri);
1087
1088		free(fmri);
1089	}
1090
1091	return (-1);
1092}
1093
1094static int
1095prop_check_type(scf_property_t *prop, scf_type_t ty)
1096{
1097	scf_type_t pty;
1098
1099	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1100		scfdie();
1101
1102	if (ty == pty)
1103		return (0);
1104
1105	if (g_verbose) {
1106		ssize_t len;
1107		char *fmri;
1108		const char *tystr;
1109
1110		len = scf_property_to_fmri(prop, NULL, 0);
1111		if (len < 0)
1112			scfdie();
1113
1114		fmri = safe_malloc(len + 1);
1115
1116		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1117			scfdie();
1118
1119		tystr = scf_type_to_string(ty);
1120		if (tystr == NULL)
1121			tystr = "?";
1122
1123		warn(gettext("Property %s is not of expected type %s.\n"),
1124		    fmri, tystr);
1125
1126		free(fmri);
1127	}
1128
1129	return (-1);
1130}
1131
1132static int
1133prop_get_val(scf_property_t *prop, scf_value_t *val)
1134{
1135	scf_error_t err;
1136
1137	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1138		return (0);
1139
1140	err = scf_error();
1141
1142	if (err != SCF_ERROR_NOT_FOUND &&
1143	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1144	    err != SCF_ERROR_PERMISSION_DENIED)
1145		scfdie();
1146
1147	if (g_verbose) {
1148		ssize_t len;
1149		char *fmri, *emsg;
1150
1151		len = scf_property_to_fmri(prop, NULL, 0);
1152		if (len < 0)
1153			scfdie();
1154
1155		fmri = safe_malloc(len + 1);
1156
1157		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1158			scfdie();
1159
1160		if (err == SCF_ERROR_NOT_FOUND)
1161			emsg = gettext("Property %s has no values; expected "
1162			    "one.\n");
1163		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1164			emsg = gettext("Property %s has multiple values; "
1165			    "expected one.\n");
1166		else
1167			emsg = gettext("No permission to read property %s.\n");
1168
1169		warn(emsg, fmri);
1170
1171		free(fmri);
1172	}
1173
1174	return (-1);
1175}
1176
1177
1178static boolean_t
1179snaplevel_is_instance(const scf_snaplevel_t *level)
1180{
1181	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1182		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1183			scfdie();
1184		return (0);
1185	} else {
1186		return (1);
1187	}
1188}
1189
1190/*
1191 * Decode FMRI into a service or instance, and put the result in *ep.  If
1192 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1193 * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1194 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1195 * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1196 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1197 * whether *ep is a service.
1198 */
1199static scf_error_t
1200fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1201{
1202	char *fmri_copy;
1203	const char *sstr, *istr, *pgstr;
1204	scf_service_t *svc;
1205	scf_instance_t *inst;
1206
1207	fmri_copy = strdup(fmri);
1208	if (fmri_copy == NULL)
1209		return (SCF_ERROR_NO_MEMORY);
1210
1211	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1212	    SCF_SUCCESS) {
1213		free(fmri_copy);
1214		return (SCF_ERROR_INVALID_ARGUMENT);
1215	}
1216
1217	free(fmri_copy);
1218
1219	if (sstr == NULL || pgstr != NULL)
1220		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1221
1222	if (istr == NULL) {
1223		svc = scf_service_create(h);
1224		if (svc == NULL)
1225			return (SCF_ERROR_NO_MEMORY);
1226
1227		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1228		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1229			if (scf_error() != SCF_ERROR_NOT_FOUND)
1230				scfdie();
1231
1232			return (SCF_ERROR_NOT_FOUND);
1233		}
1234
1235		*ep = svc;
1236		*isservice = 1;
1237	} else {
1238		inst = scf_instance_create(h);
1239		if (inst == NULL)
1240			return (SCF_ERROR_NO_MEMORY);
1241
1242		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1243		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1244			if (scf_error() != SCF_ERROR_NOT_FOUND)
1245				scfdie();
1246
1247			return (SCF_ERROR_NOT_FOUND);
1248		}
1249
1250		*ep = inst;
1251		*isservice = 0;
1252	}
1253
1254	return (SCF_ERROR_NONE);
1255}
1256
1257/*
1258 * Create the entity named by fmri.  Place a pointer to its libscf handle in
1259 * *ep, and set or clear *isservicep if it is a service or an instance.
1260 * Returns
1261 *   SCF_ERROR_NONE - success
1262 *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1263 *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1264 *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1265 *   SCF_ERROR_NOT_FOUND - no such scope
1266 *   SCF_ERROR_PERMISSION_DENIED
1267 *   SCF_ERROR_BACKEND_READONLY
1268 *   SCF_ERROR_BACKEND_ACCESS
1269 */
1270static scf_error_t
1271create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1272{
1273	char *fmri_copy;
1274	const char *scstr, *sstr, *istr, *pgstr;
1275	scf_scope_t *scope = NULL;
1276	scf_service_t *svc = NULL;
1277	scf_instance_t *inst = NULL;
1278	scf_error_t scfe;
1279
1280	fmri_copy = safe_strdup(fmri);
1281
1282	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1283	    0) {
1284		free(fmri_copy);
1285		return (SCF_ERROR_INVALID_ARGUMENT);
1286	}
1287
1288	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1289		free(fmri_copy);
1290		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1291	}
1292
1293	*ep = NULL;
1294
1295	if ((scope = scf_scope_create(h)) == NULL ||
1296	    (svc = scf_service_create(h)) == NULL ||
1297	    (inst = scf_instance_create(h)) == NULL) {
1298		scfe = SCF_ERROR_NO_MEMORY;
1299		goto out;
1300	}
1301
1302get_scope:
1303	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1304		switch (scf_error()) {
1305		case SCF_ERROR_CONNECTION_BROKEN:
1306			scfdie();
1307			/* NOTREACHED */
1308
1309		case SCF_ERROR_NOT_FOUND:
1310			scfe = SCF_ERROR_NOT_FOUND;
1311			goto out;
1312
1313		case SCF_ERROR_HANDLE_MISMATCH:
1314		case SCF_ERROR_NOT_BOUND:
1315		case SCF_ERROR_INVALID_ARGUMENT:
1316		default:
1317			bad_error("scf_handle_get_scope", scf_error());
1318		}
1319	}
1320
1321get_svc:
1322	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1323		switch (scf_error()) {
1324		case SCF_ERROR_CONNECTION_BROKEN:
1325			scfdie();
1326			/* NOTREACHED */
1327
1328		case SCF_ERROR_DELETED:
1329			goto get_scope;
1330
1331		case SCF_ERROR_NOT_FOUND:
1332			break;
1333
1334		case SCF_ERROR_HANDLE_MISMATCH:
1335		case SCF_ERROR_INVALID_ARGUMENT:
1336		case SCF_ERROR_NOT_BOUND:
1337		case SCF_ERROR_NOT_SET:
1338		default:
1339			bad_error("scf_scope_get_service", scf_error());
1340		}
1341
1342		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1343			switch (scf_error()) {
1344			case SCF_ERROR_CONNECTION_BROKEN:
1345				scfdie();
1346				/* NOTREACHED */
1347
1348			case SCF_ERROR_DELETED:
1349				goto get_scope;
1350
1351			case SCF_ERROR_PERMISSION_DENIED:
1352			case SCF_ERROR_BACKEND_READONLY:
1353			case SCF_ERROR_BACKEND_ACCESS:
1354				scfe = scf_error();
1355				goto out;
1356
1357			case SCF_ERROR_HANDLE_MISMATCH:
1358			case SCF_ERROR_INVALID_ARGUMENT:
1359			case SCF_ERROR_NOT_BOUND:
1360			case SCF_ERROR_NOT_SET:
1361			default:
1362				bad_error("scf_scope_get_service", scf_error());
1363			}
1364		}
1365	}
1366
1367	if (istr == NULL) {
1368		scfe = SCF_ERROR_NONE;
1369		*ep = svc;
1370		*isservicep = 1;
1371		goto out;
1372	}
1373
1374get_inst:
1375	if (scf_service_get_instance(svc, istr, inst) != 0) {
1376		switch (scf_error()) {
1377		case SCF_ERROR_CONNECTION_BROKEN:
1378			scfdie();
1379			/* NOTREACHED */
1380
1381		case SCF_ERROR_DELETED:
1382			goto get_svc;
1383
1384		case SCF_ERROR_NOT_FOUND:
1385			break;
1386
1387		case SCF_ERROR_HANDLE_MISMATCH:
1388		case SCF_ERROR_INVALID_ARGUMENT:
1389		case SCF_ERROR_NOT_BOUND:
1390		case SCF_ERROR_NOT_SET:
1391		default:
1392			bad_error("scf_service_get_instance", scf_error());
1393		}
1394
1395		if (scf_service_add_instance(svc, istr, inst) != 0) {
1396			switch (scf_error()) {
1397			case SCF_ERROR_CONNECTION_BROKEN:
1398				scfdie();
1399				/* NOTREACHED */
1400
1401			case SCF_ERROR_DELETED:
1402				goto get_svc;
1403
1404			case SCF_ERROR_PERMISSION_DENIED:
1405			case SCF_ERROR_BACKEND_READONLY:
1406			case SCF_ERROR_BACKEND_ACCESS:
1407				scfe = scf_error();
1408				goto out;
1409
1410			case SCF_ERROR_HANDLE_MISMATCH:
1411			case SCF_ERROR_INVALID_ARGUMENT:
1412			case SCF_ERROR_NOT_BOUND:
1413			case SCF_ERROR_NOT_SET:
1414			default:
1415				bad_error("scf_service_add_instance",
1416				    scf_error());
1417			}
1418		}
1419	}
1420
1421	scfe = SCF_ERROR_NONE;
1422	*ep = inst;
1423	*isservicep = 0;
1424
1425out:
1426	if (*ep != inst)
1427		scf_instance_destroy(inst);
1428	if (*ep != svc)
1429		scf_service_destroy(svc);
1430	scf_scope_destroy(scope);
1431	free(fmri_copy);
1432	return (scfe);
1433}
1434
1435/*
1436 * Create or update a snapshot of inst.  snap is a required scratch object.
1437 *
1438 * Returns
1439 *   0 - success
1440 *   ECONNABORTED - repository connection broken
1441 *   EPERM - permission denied
1442 *   ENOSPC - configd is out of resources
1443 *   ECANCELED - inst was deleted
1444 *   -1 - unknown libscf error (message printed)
1445 */
1446static int
1447take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1448{
1449again:
1450	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1451		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1452			switch (scf_error()) {
1453			case SCF_ERROR_CONNECTION_BROKEN:
1454			case SCF_ERROR_PERMISSION_DENIED:
1455			case SCF_ERROR_NO_RESOURCES:
1456				return (scferror2errno(scf_error()));
1457
1458			case SCF_ERROR_NOT_SET:
1459			case SCF_ERROR_INVALID_ARGUMENT:
1460			default:
1461				bad_error("_scf_snapshot_take_attach",
1462				    scf_error());
1463			}
1464		}
1465	} else {
1466		switch (scf_error()) {
1467		case SCF_ERROR_NOT_FOUND:
1468			break;
1469
1470		case SCF_ERROR_DELETED:
1471		case SCF_ERROR_CONNECTION_BROKEN:
1472			return (scferror2errno(scf_error()));
1473
1474		case SCF_ERROR_HANDLE_MISMATCH:
1475		case SCF_ERROR_NOT_BOUND:
1476		case SCF_ERROR_INVALID_ARGUMENT:
1477		case SCF_ERROR_NOT_SET:
1478		default:
1479			bad_error("scf_instance_get_snapshot", scf_error());
1480		}
1481
1482		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1483			switch (scf_error()) {
1484			case SCF_ERROR_EXISTS:
1485				goto again;
1486
1487			case SCF_ERROR_CONNECTION_BROKEN:
1488			case SCF_ERROR_NO_RESOURCES:
1489			case SCF_ERROR_PERMISSION_DENIED:
1490				return (scferror2errno(scf_error()));
1491
1492			default:
1493				scfwarn();
1494				return (-1);
1495
1496			case SCF_ERROR_NOT_SET:
1497			case SCF_ERROR_INTERNAL:
1498			case SCF_ERROR_INVALID_ARGUMENT:
1499			case SCF_ERROR_HANDLE_MISMATCH:
1500				bad_error("_scf_snapshot_take_new",
1501				    scf_error());
1502			}
1503		}
1504	}
1505
1506	return (0);
1507}
1508
1509static int
1510refresh_running_snapshot(void *entity)
1511{
1512	scf_snapshot_t *snap;
1513	int r;
1514
1515	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1516		scfdie();
1517	r = take_snap(entity, snap_running, snap);
1518	scf_snapshot_destroy(snap);
1519
1520	return (r);
1521}
1522
1523/*
1524 * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1525 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1526 * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1527 * for scratch space.  Returns
1528 *   0 - success
1529 *   ECONNABORTED - repository connection broken
1530 *   ECANCELED - entity was deleted
1531 *   EACCES - backend denied access
1532 *   EPERM - permission denied
1533 *   ENOSPC - repository server out of resources
1534 *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1535 */
1536static int
1537refresh_entity(int isservice, void *entity, const char *fmri,
1538    scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1539{
1540	scf_error_t scfe;
1541	int r;
1542
1543	if (!isservice) {
1544		/*
1545		 * Let restarter handles refreshing and making new running
1546		 * snapshot only if operating on a live repository and not
1547		 * running in early import.
1548		 */
1549		if (est->sc_repo_filename == NULL &&
1550		    est->sc_repo_doorname == NULL &&
1551		    est->sc_in_emi == 0) {
1552			if (_smf_refresh_instance_i(entity) == 0) {
1553				if (g_verbose)
1554					warn(gettext("Refreshed %s.\n"), fmri);
1555				return (0);
1556			}
1557
1558			switch (scf_error()) {
1559			case SCF_ERROR_BACKEND_ACCESS:
1560				return (EACCES);
1561
1562			case SCF_ERROR_PERMISSION_DENIED:
1563				return (EPERM);
1564
1565			default:
1566				return (-1);
1567			}
1568		} else {
1569			r = refresh_running_snapshot(entity);
1570			switch (r) {
1571			case 0:
1572				break;
1573
1574			case ECONNABORTED:
1575			case ECANCELED:
1576			case EPERM:
1577			case ENOSPC:
1578				break;
1579
1580			default:
1581				bad_error("refresh_running_snapshot",
1582				    scf_error());
1583			}
1584
1585			return (r);
1586		}
1587	}
1588
1589	if (scf_iter_service_instances(iter, entity) != 0) {
1590		switch (scf_error()) {
1591		case SCF_ERROR_CONNECTION_BROKEN:
1592			return (ECONNABORTED);
1593
1594		case SCF_ERROR_DELETED:
1595			return (ECANCELED);
1596
1597		case SCF_ERROR_HANDLE_MISMATCH:
1598		case SCF_ERROR_NOT_BOUND:
1599		case SCF_ERROR_NOT_SET:
1600		default:
1601			bad_error("scf_iter_service_instances", scf_error());
1602		}
1603	}
1604
1605	for (;;) {
1606		r = scf_iter_next_instance(iter, inst);
1607		if (r == 0)
1608			break;
1609		if (r != 1) {
1610			switch (scf_error()) {
1611			case SCF_ERROR_CONNECTION_BROKEN:
1612				return (ECONNABORTED);
1613
1614			case SCF_ERROR_DELETED:
1615				return (ECANCELED);
1616
1617			case SCF_ERROR_HANDLE_MISMATCH:
1618			case SCF_ERROR_NOT_BOUND:
1619			case SCF_ERROR_NOT_SET:
1620			case SCF_ERROR_INVALID_ARGUMENT:
1621			default:
1622				bad_error("scf_iter_next_instance",
1623				    scf_error());
1624			}
1625		}
1626
1627		/*
1628		 * Similarly, just take a new running snapshot if operating on
1629		 * a non-live repository or running during early import.
1630		 */
1631		if (est->sc_repo_filename != NULL ||
1632		    est->sc_repo_doorname != NULL ||
1633		    est->sc_in_emi == 1) {
1634			r = refresh_running_snapshot(inst);
1635			switch (r) {
1636			case 0:
1637				continue;
1638
1639			case ECONNABORTED:
1640			case ECANCELED:
1641			case EPERM:
1642			case ENOSPC:
1643				break;
1644			default:
1645				bad_error("refresh_running_snapshot",
1646				    scf_error());
1647			}
1648
1649			return (r);
1650
1651		}
1652
1653		if (_smf_refresh_instance_i(inst) == 0) {
1654			if (g_verbose) {
1655				if (scf_instance_get_name(inst, name_buf,
1656				    max_scf_name_len + 1) < 0)
1657					(void) strcpy(name_buf, "?");
1658
1659				warn(gettext("Refreshed %s:%s.\n"),
1660				    fmri, name_buf);
1661			}
1662		} else {
1663			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1664			    g_verbose) {
1665				scfe = scf_error();
1666
1667				if (scf_instance_to_fmri(inst, name_buf,
1668				    max_scf_name_len + 1) < 0)
1669					(void) strcpy(name_buf, "?");
1670
1671				warn(gettext(
1672				    "Refresh of %s:%s failed: %s.\n"), fmri,
1673				    name_buf, scf_strerror(scfe));
1674			}
1675		}
1676	}
1677
1678	return (0);
1679}
1680
1681static void
1682private_refresh(void)
1683{
1684	scf_instance_t *pinst = NULL;
1685	scf_iter_t *piter = NULL;
1686	ssize_t fmrilen;
1687	size_t bufsz;
1688	char *fmribuf;
1689	void *ent;
1690	int issvc;
1691	int r;
1692
1693	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1694		return;
1695
1696	assert(cur_svc != NULL);
1697
1698	bufsz = max_scf_fmri_len + 1;
1699	fmribuf = safe_malloc(bufsz);
1700	if (cur_inst) {
1701		issvc = 0;
1702		ent = cur_inst;
1703		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1704	} else {
1705		issvc = 1;
1706		ent = cur_svc;
1707		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1708		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1709			scfdie();
1710
1711		if ((piter = scf_iter_create(g_hndl)) == NULL)
1712			scfdie();
1713	}
1714	if (fmrilen < 0) {
1715		free(fmribuf);
1716		if (scf_error() != SCF_ERROR_DELETED)
1717			scfdie();
1718
1719		warn(emsg_deleted);
1720		return;
1721	}
1722	assert(fmrilen < bufsz);
1723
1724	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1725	switch (r) {
1726	case 0:
1727		break;
1728
1729	case ECONNABORTED:
1730		warn(gettext("Could not refresh %s "
1731		    "(repository connection broken).\n"), fmribuf);
1732		break;
1733
1734	case ECANCELED:
1735		warn(emsg_deleted);
1736		break;
1737
1738	case EPERM:
1739		warn(gettext("Could not refresh %s "
1740		    "(permission denied).\n"), fmribuf);
1741		break;
1742
1743	case ENOSPC:
1744		warn(gettext("Could not refresh %s "
1745		    "(repository server out of resources).\n"),
1746		    fmribuf);
1747		break;
1748
1749	case EACCES:
1750	default:
1751		bad_error("refresh_entity", scf_error());
1752	}
1753
1754	if (issvc) {
1755		scf_instance_destroy(pinst);
1756		scf_iter_destroy(piter);
1757	}
1758
1759	free(fmribuf);
1760}
1761
1762
1763static int
1764stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1765{
1766	cbp->sc_err = scferror2errno(err);
1767	return (UU_WALK_ERROR);
1768}
1769
1770static int
1771stash_scferror(scf_callback_t *cbp)
1772{
1773	return (stash_scferror_err(cbp, scf_error()));
1774}
1775
1776/*
1777 * Import.  These functions import a bundle into the repository.
1778 */
1779
1780/*
1781 * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
1782 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
1783 * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1784 * lcbdata->sc_err to
1785 *   ENOMEM - out of memory
1786 *   ECONNABORTED - repository connection broken
1787 *   ECANCELED - sc_trans's property group was deleted
1788 *   EINVAL - p's name is invalid (error printed)
1789 *	    - p has an invalid value (error printed)
1790 */
1791static int
1792lscf_property_import(void *v, void *pvt)
1793{
1794	property_t *p = v;
1795	scf_callback_t *lcbdata = pvt;
1796	value_t *vp;
1797	scf_transaction_t *trans = lcbdata->sc_trans;
1798	scf_transaction_entry_t *entr;
1799	scf_value_t *val;
1800	scf_type_t tp;
1801
1802	if ((lcbdata->sc_flags & SCI_NOENABLED ||
1803	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
1804	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
1805		lcbdata->sc_enable = p;
1806		return (UU_WALK_NEXT);
1807	}
1808
1809	entr = scf_entry_create(lcbdata->sc_handle);
1810	if (entr == NULL) {
1811		switch (scf_error()) {
1812		case SCF_ERROR_NO_MEMORY:
1813			return (stash_scferror(lcbdata));
1814
1815		case SCF_ERROR_INVALID_ARGUMENT:
1816		default:
1817			bad_error("scf_entry_create", scf_error());
1818		}
1819	}
1820
1821	tp = p->sc_value_type;
1822
1823	if (scf_transaction_property_new(trans, entr,
1824	    p->sc_property_name, tp) != 0) {
1825		switch (scf_error()) {
1826		case SCF_ERROR_INVALID_ARGUMENT:
1827			semerr(emsg_invalid_prop_name, p->sc_property_name);
1828			scf_entry_destroy(entr);
1829			return (stash_scferror(lcbdata));
1830
1831		case SCF_ERROR_EXISTS:
1832			break;
1833
1834		case SCF_ERROR_DELETED:
1835		case SCF_ERROR_CONNECTION_BROKEN:
1836			scf_entry_destroy(entr);
1837			return (stash_scferror(lcbdata));
1838
1839		case SCF_ERROR_NOT_BOUND:
1840		case SCF_ERROR_HANDLE_MISMATCH:
1841		case SCF_ERROR_NOT_SET:
1842		default:
1843			bad_error("scf_transaction_property_new", scf_error());
1844		}
1845
1846		if (scf_transaction_property_change_type(trans, entr,
1847		    p->sc_property_name, tp) != 0) {
1848			switch (scf_error()) {
1849			case SCF_ERROR_DELETED:
1850			case SCF_ERROR_CONNECTION_BROKEN:
1851				scf_entry_destroy(entr);
1852				return (stash_scferror(lcbdata));
1853
1854			case SCF_ERROR_INVALID_ARGUMENT:
1855				semerr(emsg_invalid_prop_name,
1856				    p->sc_property_name);
1857				scf_entry_destroy(entr);
1858				return (stash_scferror(lcbdata));
1859
1860			case SCF_ERROR_NOT_FOUND:
1861			case SCF_ERROR_NOT_SET:
1862			case SCF_ERROR_HANDLE_MISMATCH:
1863			case SCF_ERROR_NOT_BOUND:
1864			default:
1865				bad_error(
1866				    "scf_transaction_property_change_type",
1867				    scf_error());
1868			}
1869		}
1870	}
1871
1872	for (vp = uu_list_first(p->sc_property_values);
1873	    vp != NULL;
1874	    vp = uu_list_next(p->sc_property_values, vp)) {
1875		val = scf_value_create(g_hndl);
1876		if (val == NULL) {
1877			switch (scf_error()) {
1878			case SCF_ERROR_NO_MEMORY:
1879				return (stash_scferror(lcbdata));
1880
1881			case SCF_ERROR_INVALID_ARGUMENT:
1882			default:
1883				bad_error("scf_value_create", scf_error());
1884			}
1885		}
1886
1887		switch (tp) {
1888		case SCF_TYPE_BOOLEAN:
1889			scf_value_set_boolean(val, vp->sc_u.sc_count);
1890			break;
1891		case SCF_TYPE_COUNT:
1892			scf_value_set_count(val, vp->sc_u.sc_count);
1893			break;
1894		case SCF_TYPE_INTEGER:
1895			scf_value_set_integer(val, vp->sc_u.sc_integer);
1896			break;
1897		default:
1898			assert(vp->sc_u.sc_string != NULL);
1899			if (scf_value_set_from_string(val, tp,
1900			    vp->sc_u.sc_string) != 0) {
1901				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
1902					bad_error("scf_value_set_from_string",
1903					    scf_error());
1904
1905				warn(gettext("Value \"%s\" is not a valid "
1906				    "%s.\n"), vp->sc_u.sc_string,
1907				    scf_type_to_string(tp));
1908				scf_value_destroy(val);
1909				return (stash_scferror(lcbdata));
1910			}
1911			break;
1912		}
1913
1914		if (scf_entry_add_value(entr, val) != 0)
1915			bad_error("scf_entry_add_value", scf_error());
1916	}
1917
1918	return (UU_WALK_NEXT);
1919}
1920
1921/*
1922 * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
1923 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
1924 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
1925 * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1926 * lcbdata->sc_err to
1927 *   ECONNABORTED - repository connection broken
1928 *   ENOMEM - out of memory
1929 *   ENOSPC - svc.configd is out of resources
1930 *   ECANCELED - sc_parent was deleted
1931 *   EPERM - could not create property group (permission denied) (error printed)
1932 *	   - could not modify property group (permission denied) (error printed)
1933 *	   - could not delete property group (permission denied) (error	printed)
1934 *   EROFS - could not create property group (repository is read-only)
1935 *	   - could not delete property group (repository is read-only)
1936 *   EACCES - could not create property group (backend access denied)
1937 *	    - could not delete property group (backend access denied)
1938 *   EEXIST - could not create property group (already exists)
1939 *   EINVAL - invalid property group name (error printed)
1940 *	    - invalid property name (error printed)
1941 *	    - invalid value (error printed)
1942 *   EBUSY - new property group deleted (error printed)
1943 *	   - new property group changed (error printed)
1944 *	   - property group added (error printed)
1945 *	   - property group deleted (error printed)
1946 */
1947static int
1948entity_pgroup_import(void *v, void *pvt)
1949{
1950	pgroup_t *p = v;
1951	scf_callback_t cbdata;
1952	scf_callback_t *lcbdata = pvt;
1953	void *ent = lcbdata->sc_parent;
1954	int issvc = lcbdata->sc_service;
1955	int r;
1956
1957	const char * const pg_changed = gettext("%s changed unexpectedly "
1958	    "(new property group \"%s\" changed).\n");
1959
1960	/* Never import deleted property groups. */
1961	if (p->sc_pgroup_delete)
1962		return (UU_WALK_NEXT);
1963
1964	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
1965	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
1966		lcbdata->sc_general = p;
1967		return (UU_WALK_NEXT);
1968	}
1969
1970add_pg:
1971	if (issvc)
1972		r = scf_service_add_pg(ent, p->sc_pgroup_name,
1973		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1974	else
1975		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
1976		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1977	if (r != 0) {
1978		switch (scf_error()) {
1979		case SCF_ERROR_DELETED:
1980		case SCF_ERROR_CONNECTION_BROKEN:
1981		case SCF_ERROR_BACKEND_READONLY:
1982		case SCF_ERROR_BACKEND_ACCESS:
1983		case SCF_ERROR_NO_RESOURCES:
1984			return (stash_scferror(lcbdata));
1985
1986		case SCF_ERROR_EXISTS:
1987			if (lcbdata->sc_flags & SCI_FORCE)
1988				break;
1989			return (stash_scferror(lcbdata));
1990
1991		case SCF_ERROR_INVALID_ARGUMENT:
1992			warn(emsg_fmri_invalid_pg_name_type,
1993			    lcbdata->sc_source_fmri,
1994			    p->sc_pgroup_name, p->sc_pgroup_type);
1995			return (stash_scferror(lcbdata));
1996
1997		case SCF_ERROR_PERMISSION_DENIED:
1998			warn(emsg_pg_add_perm, p->sc_pgroup_name,
1999			    lcbdata->sc_target_fmri);
2000			return (stash_scferror(lcbdata));
2001
2002		case SCF_ERROR_NOT_BOUND:
2003		case SCF_ERROR_HANDLE_MISMATCH:
2004		case SCF_ERROR_NOT_SET:
2005		default:
2006			bad_error("scf_service_add_pg", scf_error());
2007		}
2008
2009		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2010			switch (scf_error()) {
2011			case SCF_ERROR_CONNECTION_BROKEN:
2012			case SCF_ERROR_DELETED:
2013				return (stash_scferror(lcbdata));
2014
2015			case SCF_ERROR_INVALID_ARGUMENT:
2016				warn(emsg_fmri_invalid_pg_name,
2017				    lcbdata->sc_source_fmri,
2018				    p->sc_pgroup_name);
2019				return (stash_scferror(lcbdata));
2020
2021			case SCF_ERROR_NOT_FOUND:
2022				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2023				    p->sc_pgroup_name);
2024				lcbdata->sc_err = EBUSY;
2025				return (UU_WALK_ERROR);
2026
2027			case SCF_ERROR_NOT_BOUND:
2028			case SCF_ERROR_HANDLE_MISMATCH:
2029			case SCF_ERROR_NOT_SET:
2030			default:
2031				bad_error("entity_get_pg", scf_error());
2032			}
2033		}
2034
2035		if (lcbdata->sc_flags & SCI_KEEP)
2036			goto props;
2037
2038		if (scf_pg_delete(imp_pg) != 0) {
2039			switch (scf_error()) {
2040			case SCF_ERROR_DELETED:
2041				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2042				    p->sc_pgroup_name);
2043				lcbdata->sc_err = EBUSY;
2044				return (UU_WALK_ERROR);
2045
2046			case SCF_ERROR_PERMISSION_DENIED:
2047				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2048				    lcbdata->sc_target_fmri);
2049				return (stash_scferror(lcbdata));
2050
2051			case SCF_ERROR_BACKEND_READONLY:
2052			case SCF_ERROR_BACKEND_ACCESS:
2053			case SCF_ERROR_CONNECTION_BROKEN:
2054				return (stash_scferror(lcbdata));
2055
2056			case SCF_ERROR_NOT_SET:
2057			default:
2058				bad_error("scf_pg_delete", scf_error());
2059			}
2060		}
2061
2062		goto add_pg;
2063	}
2064
2065props:
2066
2067	/*
2068	 * Add properties to property group, if any.
2069	 */
2070	cbdata.sc_handle = lcbdata->sc_handle;
2071	cbdata.sc_parent = imp_pg;
2072	cbdata.sc_flags = lcbdata->sc_flags;
2073	cbdata.sc_trans = imp_tx;
2074	cbdata.sc_enable = NULL;
2075
2076	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2077		switch (scf_error()) {
2078		case SCF_ERROR_BACKEND_ACCESS:
2079		case SCF_ERROR_BACKEND_READONLY:
2080		case SCF_ERROR_CONNECTION_BROKEN:
2081			return (stash_scferror(lcbdata));
2082
2083		case SCF_ERROR_DELETED:
2084			warn(pg_changed, lcbdata->sc_target_fmri,
2085			    p->sc_pgroup_name);
2086			lcbdata->sc_err = EBUSY;
2087			return (UU_WALK_ERROR);
2088
2089		case SCF_ERROR_PERMISSION_DENIED:
2090			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2091			    lcbdata->sc_target_fmri);
2092			return (stash_scferror(lcbdata));
2093
2094		case SCF_ERROR_NOT_BOUND:
2095		case SCF_ERROR_NOT_SET:
2096		case SCF_ERROR_IN_USE:
2097		case SCF_ERROR_HANDLE_MISMATCH:
2098		default:
2099			bad_error("scf_transaction_start", scf_error());
2100		}
2101	}
2102
2103	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2104	    UU_DEFAULT) != 0) {
2105		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2106			bad_error("uu_list_walk", uu_error());
2107		scf_transaction_reset(imp_tx);
2108
2109		lcbdata->sc_err = cbdata.sc_err;
2110		if (cbdata.sc_err == ECANCELED) {
2111			warn(pg_changed, lcbdata->sc_target_fmri,
2112			    p->sc_pgroup_name);
2113			lcbdata->sc_err = EBUSY;
2114		}
2115		return (UU_WALK_ERROR);
2116	}
2117
2118	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2119		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2120
2121		/*
2122		 * take the snapshot running snapshot then
2123		 * import the stored general/enable property
2124		 */
2125		r = take_snap(ent, snap_running, imp_rsnap);
2126		switch (r) {
2127		case 0:
2128			break;
2129
2130		case ECONNABORTED:
2131			warn(gettext("Could not take %s snapshot on import "
2132			    "(repository connection broken).\n"),
2133			    snap_running);
2134			lcbdata->sc_err = r;
2135			return (UU_WALK_ERROR);
2136		case ECANCELED:
2137			warn(emsg_deleted);
2138			lcbdata->sc_err = r;
2139			return (UU_WALK_ERROR);
2140
2141		case EPERM:
2142			warn(gettext("Could not take %s snapshot "
2143			    "(permission denied).\n"), snap_running);
2144			lcbdata->sc_err = r;
2145			return (UU_WALK_ERROR);
2146
2147		case ENOSPC:
2148			warn(gettext("Could not take %s snapshot"
2149			    "(repository server out of resources).\n"),
2150			    snap_running);
2151			lcbdata->sc_err = r;
2152			return (UU_WALK_ERROR);
2153
2154		default:
2155			bad_error("take_snap", r);
2156		}
2157
2158		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2159		if (r != UU_WALK_NEXT) {
2160			if (r != UU_WALK_ERROR)
2161				bad_error("lscf_property_import", r);
2162			return (EINVAL);
2163		}
2164	}
2165
2166	r = scf_transaction_commit(imp_tx);
2167	switch (r) {
2168	case 1:
2169		r = UU_WALK_NEXT;
2170		break;
2171
2172	case 0:
2173		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2174		lcbdata->sc_err = EBUSY;
2175		r = UU_WALK_ERROR;
2176		break;
2177
2178	case -1:
2179		switch (scf_error()) {
2180		case SCF_ERROR_BACKEND_READONLY:
2181		case SCF_ERROR_BACKEND_ACCESS:
2182		case SCF_ERROR_CONNECTION_BROKEN:
2183		case SCF_ERROR_NO_RESOURCES:
2184			r = stash_scferror(lcbdata);
2185			break;
2186
2187		case SCF_ERROR_DELETED:
2188			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2189			    p->sc_pgroup_name);
2190			lcbdata->sc_err = EBUSY;
2191			r = UU_WALK_ERROR;
2192			break;
2193
2194		case SCF_ERROR_PERMISSION_DENIED:
2195			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2196			    lcbdata->sc_target_fmri);
2197			r = stash_scferror(lcbdata);
2198			break;
2199
2200		case SCF_ERROR_NOT_SET:
2201		case SCF_ERROR_INVALID_ARGUMENT:
2202		case SCF_ERROR_NOT_BOUND:
2203		default:
2204			bad_error("scf_transaction_commit", scf_error());
2205		}
2206		break;
2207
2208	default:
2209		bad_error("scf_transaction_commit", r);
2210	}
2211
2212	scf_transaction_destroy_children(imp_tx);
2213
2214	return (r);
2215}
2216
2217/*
2218 * Returns
2219 *   0 - success
2220 *   ECONNABORTED - repository connection broken
2221 *   ENOMEM - out of memory
2222 *   ENOSPC - svc.configd is out of resources
2223 *   ECANCELED - inst was deleted
2224 *   EPERM - could not create property group (permission denied) (error printed)
2225 *	   - could not modify property group (permission denied) (error printed)
2226 *   EROFS - could not create property group (repository is read-only)
2227 *   EACCES - could not create property group (backend access denied)
2228 *   EEXIST - could not create property group (already exists)
2229 *   EINVAL - invalid property group name (error printed)
2230 *	    - invalid property name (error printed)
2231 *	    - invalid value (error printed)
2232 *   EBUSY - new property group changed (error printed)
2233 */
2234static int
2235lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2236    const entity_t *isvc, int flags)
2237{
2238	scf_callback_t cbdata;
2239
2240	cbdata.sc_handle = scf_service_handle(svc);
2241	cbdata.sc_parent = svc;
2242	cbdata.sc_service = 1;
2243	cbdata.sc_general = 0;
2244	cbdata.sc_enable = 0;
2245	cbdata.sc_flags = flags;
2246	cbdata.sc_source_fmri = isvc->sc_fmri;
2247	cbdata.sc_target_fmri = target_fmri;
2248
2249	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2250	    UU_DEFAULT) != 0) {
2251		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2252			bad_error("uu_list_walk", uu_error());
2253
2254		return (cbdata.sc_err);
2255	}
2256
2257	return (0);
2258}
2259
2260/*
2261 * Returns
2262 *   0 - success
2263 *   ECONNABORTED - repository connection broken
2264 *   ENOMEM - out of memory
2265 *   ENOSPC - svc.configd is out of resources
2266 *   ECANCELED - inst was deleted
2267 *   EPERM - could not create property group (permission denied) (error printed)
2268 *	   - could not modify property group (permission denied) (error printed)
2269 *   EROFS - could not create property group (repository is read-only)
2270 *   EACCES - could not create property group (backend access denied)
2271 *   EEXIST - could not create property group (already exists)
2272 *   EINVAL - invalid property group name (error printed)
2273 *	    - invalid property name (error printed)
2274 *	    - invalid value (error printed)
2275 *   EBUSY - new property group changed (error printed)
2276 */
2277static int
2278lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2279    const entity_t *iinst, int flags)
2280{
2281	scf_callback_t cbdata;
2282
2283	cbdata.sc_handle = scf_instance_handle(inst);
2284	cbdata.sc_parent = inst;
2285	cbdata.sc_service = 0;
2286	cbdata.sc_general = NULL;
2287	cbdata.sc_enable = NULL;
2288	cbdata.sc_flags = flags;
2289	cbdata.sc_source_fmri = iinst->sc_fmri;
2290	cbdata.sc_target_fmri = target_fmri;
2291
2292	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2293	    UU_DEFAULT) != 0) {
2294		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2295			bad_error("uu_list_walk", uu_error());
2296
2297		return (cbdata.sc_err);
2298	}
2299
2300	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2301		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2302		/*
2303		 * If importing with the SCI_NOENABLED flag then
2304		 * skip the delay, but if not then add the delay
2305		 * of the enable property.
2306		 */
2307		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2308			cbdata.sc_flags |= SCI_DELAYENABLE;
2309		}
2310
2311		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2312		    != UU_WALK_NEXT)
2313			return (cbdata.sc_err);
2314	}
2315
2316	return (0);
2317}
2318
2319/*
2320 * Report the reasons why we can't upgrade pg2 to pg1.
2321 */
2322static void
2323report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2324    int new)
2325{
2326	property_t *p1, *p2;
2327
2328	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2329
2330	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2331		return;
2332
2333	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2334	    p1 != NULL;
2335	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2336		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2337		if (p2 != NULL) {
2338			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2339			    new);
2340			continue;
2341		}
2342
2343		if (new)
2344			warn(gettext("Conflict upgrading %s (new property "
2345			    "group \"%s\" is missing property \"%s\").\n"),
2346			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2347		else
2348			warn(gettext("Conflict upgrading %s (property "
2349			    "\"%s/%s\" is missing).\n"), fmri,
2350			    pg1->sc_pgroup_name, p1->sc_property_name);
2351	}
2352
2353	/*
2354	 * Since pg1 should be from the manifest, any properties in pg2 which
2355	 * aren't in pg1 shouldn't be reported as conflicts.
2356	 */
2357}
2358
2359/*
2360 * Add transaction entries to tx which will upgrade cur's pg according to old
2361 * & new.
2362 *
2363 * Returns
2364 *   0 - success
2365 *   EINVAL - new has a property with an invalid name or value (message emitted)
2366 *   ENOMEM - out of memory
2367 */
2368static int
2369add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2370    pgroup_t *cur, int speak, const char *fmri)
2371{
2372	property_t *p, *new_p, *cur_p;
2373	scf_transaction_entry_t *e;
2374	int r;
2375	int is_general;
2376	int is_protected;
2377
2378	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2379	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2380		bad_error("uu_list_walk", uu_error());
2381
2382	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2383
2384	for (p = uu_list_first(old->sc_pgroup_props);
2385	    p != NULL;
2386	    p = uu_list_next(old->sc_pgroup_props, p)) {
2387		/* p is a property in the old property group. */
2388
2389		/* Protect live properties. */
2390		is_protected = 0;
2391		if (is_general) {
2392			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2393			    0 ||
2394			    strcmp(p->sc_property_name,
2395			    SCF_PROPERTY_RESTARTER) == 0)
2396				is_protected = 1;
2397		}
2398
2399		/* Look for the same property in the new properties. */
2400		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2401		if (new_p != NULL) {
2402			new_p->sc_seen = 1;
2403
2404			/*
2405			 * If the new property is the same as the old, don't do
2406			 * anything (leave any user customizations).
2407			 */
2408			if (prop_equal(p, new_p, NULL, NULL, 0))
2409				continue;
2410
2411			if (new_p->sc_property_override)
2412				goto upgrade;
2413		}
2414
2415		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2416		if (cur_p == NULL) {
2417			/*
2418			 * p has been deleted from the repository.  If we were
2419			 * going to delete it anyway, do nothing.  Otherwise
2420			 * report a conflict.
2421			 */
2422			if (new_p == NULL)
2423				continue;
2424
2425			if (is_protected)
2426				continue;
2427
2428			warn(gettext("Conflict upgrading %s "
2429			    "(property \"%s/%s\" is missing).\n"), fmri,
2430			    old->sc_pgroup_name, p->sc_property_name);
2431			continue;
2432		}
2433
2434		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2435			/*
2436			 * Conflict.  Don't warn if the property is already the
2437			 * way we want it, though.
2438			 */
2439			if (is_protected)
2440				continue;
2441
2442			if (new_p == NULL)
2443				(void) prop_equal(p, cur_p, fmri,
2444				    old->sc_pgroup_name, 0);
2445			else
2446				(void) prop_equal(cur_p, new_p, fmri,
2447				    old->sc_pgroup_name, 0);
2448			continue;
2449		}
2450
2451		if (is_protected) {
2452			if (speak)
2453				warn(gettext("%s: Refusing to upgrade "
2454				    "\"%s/%s\" (live property).\n"), fmri,
2455				    old->sc_pgroup_name, p->sc_property_name);
2456			continue;
2457		}
2458
2459upgrade:
2460		/* p hasn't been customized in the repository.  Upgrade it. */
2461		if (new_p == NULL) {
2462			/* p was deleted.  Delete from cur if unchanged. */
2463			if (speak)
2464				warn(gettext(
2465				    "%s: Deleting property \"%s/%s\".\n"),
2466				    fmri, old->sc_pgroup_name,
2467				    p->sc_property_name);
2468
2469			e = scf_entry_create(g_hndl);
2470			if (e == NULL)
2471				return (ENOMEM);
2472
2473			if (scf_transaction_property_delete(tx, e,
2474			    p->sc_property_name) != 0) {
2475				switch (scf_error()) {
2476				case SCF_ERROR_DELETED:
2477					scf_entry_destroy(e);
2478					return (ECANCELED);
2479
2480				case SCF_ERROR_CONNECTION_BROKEN:
2481					scf_entry_destroy(e);
2482					return (ECONNABORTED);
2483
2484				case SCF_ERROR_NOT_FOUND:
2485					/*
2486					 * This can happen if cur is from the
2487					 * running snapshot (and it differs
2488					 * from the live properties).
2489					 */
2490					scf_entry_destroy(e);
2491					break;
2492
2493				case SCF_ERROR_HANDLE_MISMATCH:
2494				case SCF_ERROR_NOT_BOUND:
2495				case SCF_ERROR_NOT_SET:
2496				case SCF_ERROR_INVALID_ARGUMENT:
2497				default:
2498					bad_error(
2499					    "scf_transaction_property_delete",
2500					    scf_error());
2501				}
2502			}
2503		} else {
2504			scf_callback_t ctx;
2505
2506			if (speak)
2507				warn(gettext(
2508				    "%s: Upgrading property \"%s/%s\".\n"),
2509				    fmri, old->sc_pgroup_name,
2510				    p->sc_property_name);
2511
2512			ctx.sc_handle = g_hndl;
2513			ctx.sc_trans = tx;
2514			ctx.sc_flags = 0;
2515
2516			r = lscf_property_import(new_p, &ctx);
2517			if (r != UU_WALK_NEXT) {
2518				if (r != UU_WALK_ERROR)
2519					bad_error("lscf_property_import", r);
2520				return (EINVAL);
2521			}
2522		}
2523	}
2524
2525	/* Go over the properties which were added. */
2526	for (new_p = uu_list_first(new->sc_pgroup_props);
2527	    new_p != NULL;
2528	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
2529		if (new_p->sc_seen)
2530			continue;
2531
2532		/* This is a new property. */
2533		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
2534		if (cur_p == NULL) {
2535			scf_callback_t ctx;
2536
2537			ctx.sc_handle = g_hndl;
2538			ctx.sc_trans = tx;
2539			ctx.sc_flags = 0;
2540
2541			r = lscf_property_import(new_p, &ctx);
2542			if (r != UU_WALK_NEXT) {
2543				if (r != UU_WALK_ERROR)
2544					bad_error("lscf_property_import", r);
2545				return (EINVAL);
2546			}
2547			continue;
2548		}
2549
2550		/*
2551		 * Report a conflict if the new property differs from the
2552		 * current one.  Unless it's general/enabled, since that's
2553		 * never in the last-import snapshot.
2554		 */
2555		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2556		    0 &&
2557		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
2558			continue;
2559
2560		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
2561	}
2562
2563	return (0);
2564}
2565
2566/*
2567 * Upgrade pg according to old & new.
2568 *
2569 * Returns
2570 *   0 - success
2571 *   ECONNABORTED - repository connection broken
2572 *   ENOMEM - out of memory
2573 *   ENOSPC - svc.configd is out of resources
2574 *   ECANCELED - pg was deleted
2575 *   EPERM - couldn't modify pg (permission denied)
2576 *   EROFS - couldn't modify pg (backend read-only)
2577 *   EACCES - couldn't modify pg (backend access denied)
2578 *   EINVAL - new has a property with invalid name or value (error printed)
2579 *   EBUSY - pg changed unexpectedly
2580 */
2581static int
2582upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
2583    pgroup_t *new, int speak, const char *fmri)
2584{
2585	int r;
2586
2587	if (scf_transaction_start(imp_tx, pg) != 0) {
2588		switch (scf_error()) {
2589		case SCF_ERROR_CONNECTION_BROKEN:
2590		case SCF_ERROR_DELETED:
2591		case SCF_ERROR_PERMISSION_DENIED:
2592		case SCF_ERROR_BACKEND_READONLY:
2593		case SCF_ERROR_BACKEND_ACCESS:
2594			return (scferror2errno(scf_error()));
2595
2596		case SCF_ERROR_HANDLE_MISMATCH:
2597		case SCF_ERROR_IN_USE:
2598		case SCF_ERROR_NOT_BOUND:
2599		case SCF_ERROR_NOT_SET:
2600		default:
2601			bad_error("scf_transaction_start", scf_error());
2602		}
2603	}
2604
2605	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
2606	switch (r) {
2607	case 0:
2608		break;
2609
2610	case EINVAL:
2611	case ENOMEM:
2612		scf_transaction_destroy_children(imp_tx);
2613		return (r);
2614
2615	default:
2616		bad_error("add_upgrade_entries", r);
2617	}
2618
2619	r = scf_transaction_commit(imp_tx);
2620
2621	scf_transaction_destroy_children(imp_tx);
2622
2623	switch (r) {
2624	case 1:
2625		break;
2626
2627	case 0:
2628		return (EBUSY);
2629
2630	case -1:
2631		switch (scf_error()) {
2632		case SCF_ERROR_CONNECTION_BROKEN:
2633		case SCF_ERROR_NO_RESOURCES:
2634		case SCF_ERROR_PERMISSION_DENIED:
2635		case SCF_ERROR_BACKEND_READONLY:
2636		case SCF_ERROR_BACKEND_ACCESS:
2637		case SCF_ERROR_DELETED:
2638			return (scferror2errno(scf_error()));
2639
2640		case SCF_ERROR_NOT_BOUND:
2641		case SCF_ERROR_INVALID_ARGUMENT:
2642		case SCF_ERROR_NOT_SET:
2643		default:
2644			bad_error("scf_transaction_commit", scf_error());
2645		}
2646
2647	default:
2648		bad_error("scf_transaction_commit", r);
2649	}
2650
2651	return (0);
2652}
2653
2654/*
2655 * Compares two entity FMRIs.  Returns
2656 *
2657 *   1 - equal
2658 *   0 - not equal
2659 *   -1 - f1 is invalid or not an entity
2660 *   -2 - f2 is invalid or not an entity
2661 */
2662static int
2663fmri_equal(const char *f1, const char *f2)
2664{
2665	int r;
2666	const char *s1, *i1, *pg1;
2667	const char *s2, *i2, *pg2;
2668
2669	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2670		return (-1);
2671	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
2672		return (-1);
2673
2674	if (s1 == NULL || pg1 != NULL)
2675		return (-1);
2676
2677	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2678		return (-2);
2679	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
2680		return (-2);
2681
2682	if (s2 == NULL || pg2 != NULL)
2683		return (-2);
2684
2685	r = strcmp(s1, s2);
2686	if (r != 0)
2687		return (0);
2688
2689	if (i1 == NULL && i2 == NULL)
2690		return (1);
2691
2692	if (i1 == NULL || i2 == NULL)
2693		return (0);
2694
2695	return (strcmp(i1, i2) == 0);
2696}
2697
2698/*
2699 * Import a dependent by creating a dependency property group in the dependent
2700 * entity.  If lcbdata->sc_trans is set, assume it's been started on the
2701 * dependents pg, and add an entry to create a new property for this
2702 * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
2703 *
2704 * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
2705 * lcbdata->sc_err to
2706 *   ECONNABORTED - repository connection broken
2707 *   ENOMEM - out of memory
2708 *   ENOSPC - configd is out of resources
2709 *   EINVAL - target is invalid (error printed)
2710 *	    - target is not an entity (error printed)
2711 *	    - dependent has invalid name (error printed)
2712 *	    - invalid property name (error printed)
2713 *	    - invalid value (error printed)
2714 *	    - scope of target does not exist (error printed)
2715 *   EPERM - couldn't create target (permission denied) (error printed)
2716 *	   - couldn't create dependency pg (permission denied) (error printed)
2717 *	   - couldn't modify dependency pg (permission denied) (error printed)
2718 *   EROFS - couldn't create target (repository read-only)
2719 *	   - couldn't create dependency pg (repository read-only)
2720 *   EACCES - couldn't create target (backend access denied)
2721 *	    - couldn't create dependency pg (backend access denied)
2722 *   ECANCELED - sc_trans's pg was deleted
2723 *   EALREADY - property for dependent already exists in sc_trans's pg
2724 *   EEXIST - dependency pg already exists in target (error printed)
2725 *   EBUSY - target deleted (error printed)
2726 *         - property group changed during import (error printed)
2727 */
2728static int
2729lscf_dependent_import(void *a1, void *pvt)
2730{
2731	pgroup_t *pgrp = a1;
2732	scf_callback_t *lcbdata = pvt;
2733
2734	int isservice;
2735	int ret;
2736	scf_transaction_entry_t *e;
2737	scf_value_t *val;
2738	scf_callback_t dependent_cbdata;
2739	scf_error_t scfe;
2740
2741	/*
2742	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
2743	 * it's invalid, we fail before modifying the repository.
2744	 */
2745	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2746	    &dependent_cbdata.sc_parent, &isservice);
2747	switch (scfe) {
2748	case SCF_ERROR_NONE:
2749		break;
2750
2751	case SCF_ERROR_NO_MEMORY:
2752		return (stash_scferror_err(lcbdata, scfe));
2753
2754	case SCF_ERROR_INVALID_ARGUMENT:
2755		semerr(gettext("The FMRI for the \"%s\" dependent is "
2756		    "invalid.\n"), pgrp->sc_pgroup_name);
2757		return (stash_scferror_err(lcbdata, scfe));
2758
2759	case SCF_ERROR_CONSTRAINT_VIOLATED:
2760		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
2761		    "specifies neither a service nor an instance.\n"),
2762		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2763		return (stash_scferror_err(lcbdata, scfe));
2764
2765	case SCF_ERROR_NOT_FOUND:
2766		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2767		    &dependent_cbdata.sc_parent, &isservice);
2768		switch (scfe) {
2769		case SCF_ERROR_NONE:
2770			break;
2771
2772		case SCF_ERROR_NO_MEMORY:
2773		case SCF_ERROR_BACKEND_READONLY:
2774		case SCF_ERROR_BACKEND_ACCESS:
2775			return (stash_scferror_err(lcbdata, scfe));
2776
2777		case SCF_ERROR_NOT_FOUND:
2778			semerr(gettext("The scope in FMRI \"%s\" for the "
2779			    "\"%s\" dependent does not exist.\n"),
2780			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2781			lcbdata->sc_err = EINVAL;
2782			return (UU_WALK_ERROR);
2783
2784		case SCF_ERROR_PERMISSION_DENIED:
2785			warn(gettext(
2786			    "Could not create %s (permission denied).\n"),
2787			    pgrp->sc_pgroup_fmri);
2788			return (stash_scferror_err(lcbdata, scfe));
2789
2790		case SCF_ERROR_INVALID_ARGUMENT:
2791		case SCF_ERROR_CONSTRAINT_VIOLATED:
2792		default:
2793			bad_error("create_entity", scfe);
2794		}
2795		break;
2796
2797	default:
2798		bad_error("fmri_to_entity", scfe);
2799	}
2800
2801	if (lcbdata->sc_trans != NULL) {
2802		e = scf_entry_create(lcbdata->sc_handle);
2803		if (e == NULL) {
2804			if (scf_error() != SCF_ERROR_NO_MEMORY)
2805				bad_error("scf_entry_create", scf_error());
2806
2807			entity_destroy(dependent_cbdata.sc_parent, isservice);
2808			return (stash_scferror(lcbdata));
2809		}
2810
2811		if (scf_transaction_property_new(lcbdata->sc_trans, e,
2812		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
2813			switch (scf_error()) {
2814			case SCF_ERROR_INVALID_ARGUMENT:
2815				warn(gettext("Dependent of %s has invalid name "
2816				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
2817				    pgrp->sc_pgroup_name);
2818				/* FALLTHROUGH */
2819
2820			case SCF_ERROR_DELETED:
2821			case SCF_ERROR_CONNECTION_BROKEN:
2822				scf_entry_destroy(e);
2823				entity_destroy(dependent_cbdata.sc_parent,
2824				    isservice);
2825				return (stash_scferror(lcbdata));
2826
2827			case SCF_ERROR_EXISTS:
2828				scf_entry_destroy(e);
2829				entity_destroy(dependent_cbdata.sc_parent,
2830				    isservice);
2831				lcbdata->sc_err = EALREADY;
2832				return (UU_WALK_ERROR);
2833
2834			case SCF_ERROR_NOT_BOUND:
2835			case SCF_ERROR_HANDLE_MISMATCH:
2836			case SCF_ERROR_NOT_SET:
2837			default:
2838				bad_error("scf_transaction_property_new",
2839				    scf_error());
2840			}
2841		}
2842
2843		val = scf_value_create(lcbdata->sc_handle);
2844		if (val == NULL) {
2845			if (scf_error() != SCF_ERROR_NO_MEMORY)
2846				bad_error("scf_value_create", scf_error());
2847
2848			entity_destroy(dependent_cbdata.sc_parent, isservice);
2849			return (stash_scferror(lcbdata));
2850		}
2851
2852		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
2853		    pgrp->sc_pgroup_fmri) != 0)
2854			/* invalid should have been caught above */
2855			bad_error("scf_value_set_from_string", scf_error());
2856
2857		if (scf_entry_add_value(e, val) != 0)
2858			bad_error("scf_entry_add_value", scf_error());
2859	}
2860
2861	/* Add the property group to the target entity. */
2862
2863	dependent_cbdata.sc_handle = lcbdata->sc_handle;
2864	dependent_cbdata.sc_flags = 0;
2865	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
2866	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
2867
2868	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
2869
2870	entity_destroy(dependent_cbdata.sc_parent, isservice);
2871
2872	if (ret == UU_WALK_NEXT)
2873		return (ret);
2874
2875	if (ret != UU_WALK_ERROR)
2876		bad_error("entity_pgroup_import", ret);
2877
2878	switch (dependent_cbdata.sc_err) {
2879	case ECANCELED:
2880		warn(gettext("%s deleted unexpectedly.\n"),
2881		    pgrp->sc_pgroup_fmri);
2882		lcbdata->sc_err = EBUSY;
2883		break;
2884
2885	case EEXIST:
2886		warn(gettext("Could not create \"%s\" dependency in %s "
2887		    "(already exists).\n"), pgrp->sc_pgroup_name,
2888		    pgrp->sc_pgroup_fmri);
2889		/* FALLTHROUGH */
2890
2891	default:
2892		lcbdata->sc_err = dependent_cbdata.sc_err;
2893	}
2894
2895	return (UU_WALK_ERROR);
2896}
2897
2898static int upgrade_dependent(const scf_property_t *, const entity_t *,
2899    const scf_snaplevel_t *, scf_transaction_t *);
2900static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
2901    const pgroup_t *);
2902
2903/*
2904 * Upgrade uncustomized dependents of ent to those specified in ient.  Read
2905 * the current dependent targets from running (the snaplevel of a running
2906 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
2907 * scf_instance_t * according to ient, otherwise).  Draw the ancestral
2908 * dependent targets and dependency properties from li_dpts_pg (the
2909 * "dependents" property group in snpl) and snpl (the snaplevel which
2910 * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
2911 * snpl doesn't have a "dependents" property group, and any dependents in ient
2912 * are new.
2913 *
2914 * Returns
2915 *   0 - success
2916 *   ECONNABORTED - repository connection broken
2917 *   ENOMEM - out of memory
2918 *   ENOSPC - configd is out of resources
2919 *   ECANCELED - ent was deleted
2920 *   ENODEV - the entity containing li_dpts_pg was deleted
2921 *   EPERM - could not modify dependents pg (permission denied) (error printed)
2922 *	   - couldn't upgrade dependent (permission denied) (error printed)
2923 *	   - couldn't create dependent (permission denied) (error printed)
2924 *   EROFS - could not modify dependents pg (repository read-only)
2925 *	   - couldn't upgrade dependent (repository read-only)
2926 *	   - couldn't create dependent (repository read-only)
2927 *   EACCES - could not modify dependents pg (backend access denied)
2928 *	    - could not upgrade dependent (backend access denied)
2929 *	    - could not create dependent (backend access denied)
2930 *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
2931 *	   - dependent target deleted (error printed)
2932 *	   - dependent pg changed (error printed)
2933 *   EINVAL - new dependent is invalid (error printed)
2934 *   EBADF - snpl is corrupt (error printed)
2935 *	   - snpl has corrupt pg (error printed)
2936 *	   - dependency pg in target is corrupt (error printed)
2937 *	   - target has corrupt snapshot (error printed)
2938 *   EEXIST - dependency pg already existed in target service (error printed)
2939 */
2940static int
2941upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
2942    const scf_snaplevel_t *snpl, const entity_t *ient,
2943    const scf_snaplevel_t *running, void *ent)
2944{
2945	pgroup_t *new_dpt_pgroup;
2946	scf_callback_t cbdata;
2947	int r, unseen, tx_started = 0;
2948	int have_cur_depts;
2949
2950	const char * const dependents = "dependents";
2951
2952	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
2953
2954	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
2955		/* Nothing to do. */
2956		return (0);
2957
2958	/* Fetch the current version of the "dependents" property group. */
2959	have_cur_depts = 1;
2960	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
2961		switch (scf_error()) {
2962		case SCF_ERROR_NOT_FOUND:
2963			break;
2964
2965		case SCF_ERROR_DELETED:
2966		case SCF_ERROR_CONNECTION_BROKEN:
2967			return (scferror2errno(scf_error()));
2968
2969		case SCF_ERROR_NOT_SET:
2970		case SCF_ERROR_INVALID_ARGUMENT:
2971		case SCF_ERROR_HANDLE_MISMATCH:
2972		case SCF_ERROR_NOT_BOUND:
2973		default:
2974			bad_error("entity_get_pg", scf_error());
2975		}
2976
2977		have_cur_depts = 0;
2978	}
2979
2980	/* Fetch the running version of the "dependents" property group. */
2981	ud_run_dpts_pg_set = 0;
2982	if (running != NULL)
2983		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
2984	else
2985		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
2986	if (r == 0) {
2987		ud_run_dpts_pg_set = 1;
2988	} else {
2989		switch (scf_error()) {
2990		case SCF_ERROR_NOT_FOUND:
2991			break;
2992
2993		case SCF_ERROR_DELETED:
2994		case SCF_ERROR_CONNECTION_BROKEN:
2995			return (scferror2errno(scf_error()));
2996
2997		case SCF_ERROR_NOT_SET:
2998		case SCF_ERROR_INVALID_ARGUMENT:
2999		case SCF_ERROR_HANDLE_MISMATCH:
3000		case SCF_ERROR_NOT_BOUND:
3001		default:
3002			bad_error(running ? "scf_snaplevel_get_pg" :
3003			    "entity_get_pg", scf_error());
3004		}
3005	}
3006
3007	/*
3008	 * Clear the seen fields of the dependents, so we can tell which ones
3009	 * are new.
3010	 */
3011	if (uu_list_walk(ient->sc_dependents, clear_int,
3012	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3013		bad_error("uu_list_walk", uu_error());
3014
3015	if (li_dpts_pg != NULL) {
3016		/*
3017		 * Each property in li_dpts_pg represents a dependent tag in
3018		 * the old manifest.  For each, call upgrade_dependent(),
3019		 * which will change ud_cur_depts_pg or dependencies in other
3020		 * services as appropriate.  Note (a) that changes to
3021		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3022		 * made en masse, and (b) it's ok if the entity doesn't have
3023		 * a current version of the "dependents" property group,
3024		 * because we'll just consider all dependents as customized
3025		 * (by being deleted).
3026		 */
3027
3028		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3029			switch (scf_error()) {
3030			case SCF_ERROR_DELETED:
3031				return (ENODEV);
3032
3033			case SCF_ERROR_CONNECTION_BROKEN:
3034				return (ECONNABORTED);
3035
3036			case SCF_ERROR_HANDLE_MISMATCH:
3037			case SCF_ERROR_NOT_BOUND:
3038			case SCF_ERROR_NOT_SET:
3039			default:
3040				bad_error("scf_iter_pg_properties",
3041				    scf_error());
3042			}
3043		}
3044
3045		if (have_cur_depts &&
3046		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3047			switch (scf_error()) {
3048			case SCF_ERROR_BACKEND_ACCESS:
3049			case SCF_ERROR_BACKEND_READONLY:
3050			case SCF_ERROR_CONNECTION_BROKEN:
3051				return (scferror2errno(scf_error()));
3052
3053			case SCF_ERROR_DELETED:
3054				warn(emsg_pg_deleted, ient->sc_fmri,
3055				    dependents);
3056				return (EBUSY);
3057
3058			case SCF_ERROR_PERMISSION_DENIED:
3059				warn(emsg_pg_mod_perm, dependents,
3060				    ient->sc_fmri);
3061				return (scferror2errno(scf_error()));
3062
3063			case SCF_ERROR_HANDLE_MISMATCH:
3064			case SCF_ERROR_IN_USE:
3065			case SCF_ERROR_NOT_BOUND:
3066			case SCF_ERROR_NOT_SET:
3067			default:
3068				bad_error("scf_transaction_start", scf_error());
3069			}
3070		}
3071		tx_started = have_cur_depts;
3072
3073		for (;;) {
3074			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3075			if (r == 0)
3076				break;
3077			if (r == 1) {
3078				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3079				    tx_started ? ud_tx : NULL);
3080				switch (r) {
3081				case 0:
3082					continue;
3083
3084				case ECONNABORTED:
3085				case ENOMEM:
3086				case ENOSPC:
3087				case EBADF:
3088				case EBUSY:
3089				case EINVAL:
3090				case EPERM:
3091				case EROFS:
3092				case EACCES:
3093				case EEXIST:
3094					break;
3095
3096				case ECANCELED:
3097					r = ENODEV;
3098					break;
3099
3100				default:
3101					bad_error("upgrade_dependent", r);
3102				}
3103
3104				if (tx_started)
3105					scf_transaction_destroy_children(ud_tx);
3106				return (r);
3107			}
3108			if (r != -1)
3109				bad_error("scf_iter_next_property", r);
3110
3111			switch (scf_error()) {
3112			case SCF_ERROR_DELETED:
3113				r = ENODEV;
3114				break;
3115
3116			case SCF_ERROR_CONNECTION_BROKEN:
3117				r = ECONNABORTED;
3118				break;
3119
3120			case SCF_ERROR_NOT_SET:
3121			case SCF_ERROR_INVALID_ARGUMENT:
3122			case SCF_ERROR_NOT_BOUND:
3123			case SCF_ERROR_HANDLE_MISMATCH:
3124			default:
3125				bad_error("scf_iter_next_property",
3126				    scf_error());
3127			}
3128
3129			if (tx_started)
3130				scf_transaction_destroy_children(ud_tx);
3131			return (r);
3132		}
3133	}
3134
3135	/* import unseen dependents */
3136	unseen = 0;
3137	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3138	    new_dpt_pgroup != NULL;
3139	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3140	    new_dpt_pgroup)) {
3141		if (!new_dpt_pgroup->sc_pgroup_seen) {
3142			unseen = 1;
3143			break;
3144		}
3145	}
3146
3147	/* If there are none, exit early. */
3148	if (unseen == 0)
3149		goto commit;
3150
3151	/* Set up for lscf_dependent_import() */
3152	cbdata.sc_handle = g_hndl;
3153	cbdata.sc_parent = ent;
3154	cbdata.sc_service = issvc;
3155	cbdata.sc_flags = 0;
3156
3157	if (!have_cur_depts) {
3158		/*
3159		 * We have new dependents to import, so we need a "dependents"
3160		 * property group.
3161		 */
3162		if (issvc)
3163			r = scf_service_add_pg(ent, dependents,
3164			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3165		else
3166			r = scf_instance_add_pg(ent, dependents,
3167			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3168		if (r != 0) {
3169			switch (scf_error()) {
3170			case SCF_ERROR_DELETED:
3171			case SCF_ERROR_CONNECTION_BROKEN:
3172			case SCF_ERROR_BACKEND_READONLY:
3173			case SCF_ERROR_BACKEND_ACCESS:
3174			case SCF_ERROR_NO_RESOURCES:
3175				return (scferror2errno(scf_error()));
3176
3177			case SCF_ERROR_EXISTS:
3178				warn(emsg_pg_added, ient->sc_fmri, dependents);
3179				return (EBUSY);
3180
3181			case SCF_ERROR_PERMISSION_DENIED:
3182				warn(emsg_pg_add_perm, dependents,
3183				    ient->sc_fmri);
3184				return (scferror2errno(scf_error()));
3185
3186			case SCF_ERROR_NOT_BOUND:
3187			case SCF_ERROR_HANDLE_MISMATCH:
3188			case SCF_ERROR_INVALID_ARGUMENT:
3189			case SCF_ERROR_NOT_SET:
3190			default:
3191				bad_error("scf_service_add_pg", scf_error());
3192			}
3193		}
3194	}
3195
3196	cbdata.sc_trans = ud_tx;
3197
3198	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3199		switch (scf_error()) {
3200		case SCF_ERROR_CONNECTION_BROKEN:
3201		case SCF_ERROR_BACKEND_ACCESS:
3202		case SCF_ERROR_BACKEND_READONLY:
3203			return (scferror2errno(scf_error()));
3204
3205		case SCF_ERROR_DELETED:
3206			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3207			return (EBUSY);
3208
3209		case SCF_ERROR_PERMISSION_DENIED:
3210			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3211			return (scferror2errno(scf_error()));
3212
3213		case SCF_ERROR_HANDLE_MISMATCH:
3214		case SCF_ERROR_IN_USE:
3215		case SCF_ERROR_NOT_BOUND:
3216		case SCF_ERROR_NOT_SET:
3217		default:
3218			bad_error("scf_transaction_start", scf_error());
3219		}
3220	}
3221	tx_started = 1;
3222
3223	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3224	    new_dpt_pgroup != NULL;
3225	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3226	    new_dpt_pgroup)) {
3227		if (new_dpt_pgroup->sc_pgroup_seen)
3228			continue;
3229
3230		if (ud_run_dpts_pg_set) {
3231			/*
3232			 * If the dependent is already there, then we have
3233			 * a conflict.
3234			 */
3235			if (scf_pg_get_property(ud_run_dpts_pg,
3236			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3237				r = handle_dependent_conflict(ient, ud_prop,
3238				    new_dpt_pgroup);
3239				switch (r) {
3240				case 0:
3241					continue;
3242
3243				case ECONNABORTED:
3244				case ENOMEM:
3245				case EBUSY:
3246				case EBADF:
3247				case EINVAL:
3248					scf_transaction_destroy_children(ud_tx);
3249					return (r);
3250
3251				default:
3252					bad_error("handle_dependent_conflict",
3253					    r);
3254				}
3255			} else {
3256				switch (scf_error()) {
3257				case SCF_ERROR_NOT_FOUND:
3258					break;
3259
3260				case SCF_ERROR_INVALID_ARGUMENT:
3261					warn(emsg_fmri_invalid_pg_name,
3262					    ient->sc_fmri,
3263					    new_dpt_pgroup->sc_pgroup_name);
3264					scf_transaction_destroy_children(ud_tx);
3265					return (EINVAL);
3266
3267				case SCF_ERROR_DELETED:
3268					warn(emsg_pg_deleted, ient->sc_fmri,
3269					    new_dpt_pgroup->sc_pgroup_name);
3270					scf_transaction_destroy_children(ud_tx);
3271					return (EBUSY);
3272
3273				case SCF_ERROR_CONNECTION_BROKEN:
3274					scf_transaction_destroy_children(ud_tx);
3275					return (ECONNABORTED);
3276
3277				case SCF_ERROR_NOT_BOUND:
3278				case SCF_ERROR_HANDLE_MISMATCH:
3279				case SCF_ERROR_NOT_SET:
3280				default:
3281					bad_error("scf_pg_get_property",
3282					    scf_error());
3283				}
3284			}
3285		}
3286
3287		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3288		if (r != UU_WALK_NEXT) {
3289			if (r != UU_WALK_ERROR)
3290				bad_error("lscf_dependent_import", r);
3291
3292			if (cbdata.sc_err == EALREADY) {
3293				/* Collisions were handled preemptively. */
3294				bad_error("lscf_dependent_import",
3295				    cbdata.sc_err);
3296			}
3297
3298			scf_transaction_destroy_children(ud_tx);
3299			return (cbdata.sc_err);
3300		}
3301	}
3302
3303commit:
3304	if (!tx_started)
3305		return (0);
3306
3307	r = scf_transaction_commit(ud_tx);
3308
3309	scf_transaction_destroy_children(ud_tx);
3310
3311	switch (r) {
3312	case 1:
3313		return (0);
3314
3315	case 0:
3316		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3317		return (EBUSY);
3318
3319	case -1:
3320		break;
3321
3322	default:
3323		bad_error("scf_transaction_commit", r);
3324	}
3325
3326	switch (scf_error()) {
3327	case SCF_ERROR_CONNECTION_BROKEN:
3328	case SCF_ERROR_BACKEND_READONLY:
3329	case SCF_ERROR_BACKEND_ACCESS:
3330	case SCF_ERROR_NO_RESOURCES:
3331		return (scferror2errno(scf_error()));
3332
3333	case SCF_ERROR_DELETED:
3334		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3335		return (EBUSY);
3336
3337	case SCF_ERROR_PERMISSION_DENIED:
3338		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3339		return (scferror2errno(scf_error()));
3340
3341	case SCF_ERROR_NOT_BOUND:
3342	case SCF_ERROR_INVALID_ARGUMENT:
3343	case SCF_ERROR_NOT_SET:
3344	default:
3345		bad_error("scf_transaction_destroy", scf_error());
3346		/* NOTREACHED */
3347	}
3348}
3349
3350/*
3351 * Used to add the manifests to the list of currently supported manifests.
3352 * We can modify the existing manifest list removing entries if the files
3353 * don't exist.
3354 *
3355 * Get the old list and the new file name
3356 * If the new file name is in the list return
3357 * If not then add the file to the list.
3358 * As we process the list check to see if the files in the old list exist
3359 * 	if not then remove the file from the list.
3360 * Commit the list of manifest file names.
3361 *
3362 */
3363static int
3364upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3365    const scf_snaplevel_t *running, void *ent)
3366{
3367	scf_propertygroup_t *ud_mfsts_pg = NULL;
3368	scf_property_t *ud_prop = NULL;
3369	scf_iter_t *ud_prop_iter;
3370	scf_value_t *fname_value;
3371	scf_callback_t cbdata;
3372	pgroup_t *mfst_pgroup;
3373	property_t *mfst_prop;
3374	property_t *old_prop;
3375	char *pname = malloc(MAXPATHLEN);
3376	char *fval = NULL;
3377	char *old_pname;
3378	char *old_fval;
3379	int no_upgrade_pg;
3380	int mfst_seen;
3381	int r;
3382
3383	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3384
3385	/*
3386	 * This should always be the service base on the code
3387	 * path, and the fact that the manifests pg is a service
3388	 * level property group only.
3389	 */
3390	ud_mfsts_pg = scf_pg_create(g_hndl);
3391	ud_prop = scf_property_create(g_hndl);
3392	ud_prop_iter = scf_iter_create(g_hndl);
3393	fname_value = scf_value_create(g_hndl);
3394
3395	/* Fetch the "manifests" property group */
3396	no_upgrade_pg = 0;
3397	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3398	    ud_mfsts_pg);
3399	if (r != 0) {
3400		switch (scf_error()) {
3401		case SCF_ERROR_NOT_FOUND:
3402			no_upgrade_pg = 1;
3403			break;
3404
3405		case SCF_ERROR_DELETED:
3406		case SCF_ERROR_CONNECTION_BROKEN:
3407			return (scferror2errno(scf_error()));
3408
3409		case SCF_ERROR_NOT_SET:
3410		case SCF_ERROR_INVALID_ARGUMENT:
3411		case SCF_ERROR_HANDLE_MISMATCH:
3412		case SCF_ERROR_NOT_BOUND:
3413		default:
3414			bad_error(running ? "scf_snaplevel_get_pg" :
3415			    "entity_get_pg", scf_error());
3416		}
3417	}
3418
3419	if (no_upgrade_pg) {
3420		cbdata.sc_handle = g_hndl;
3421		cbdata.sc_parent = ent;
3422		cbdata.sc_service = issvc;
3423		cbdata.sc_flags = SCI_FORCE;
3424		cbdata.sc_source_fmri = ient->sc_fmri;
3425		cbdata.sc_target_fmri = ient->sc_fmri;
3426
3427		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3428			return (cbdata.sc_err);
3429
3430		return (0);
3431	}
3432
3433	/* Fetch the new manifests property group */
3434	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3435	    mfst_pgroup != NULL;
3436	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3437		if (strcmp(mfst_pgroup->sc_pgroup_name,
3438		    SCF_PG_MANIFESTFILES) == 0)
3439			break;
3440	}
3441
3442	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3443	    SCF_SUCCESS)
3444		return (-1);
3445
3446	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3447		mfst_seen = 0;
3448		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3449			continue;
3450
3451		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3452		    mfst_prop != NULL;
3453		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3454		    mfst_prop)) {
3455			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3456				mfst_seen = 1;
3457			}
3458		}
3459
3460		/*
3461		 * If the manifest is not seen then add it to the new mfst
3462		 * property list to get proccessed into the repo.
3463		 */
3464		if (mfst_seen == 0) {
3465			if (fval == NULL)
3466				fval = malloc(MAXPATHLEN);
3467
3468			/*
3469			 * If we cannot get the value then there is no
3470			 * reason to attempt to attach the value to
3471			 * the property group
3472			 */
3473			if (fval != NULL &&
3474			    prop_get_val(ud_prop, fname_value) == 0 &&
3475			    scf_value_get_astring(fname_value, fval,
3476			    MAXPATHLEN) != -1)  {
3477				/*
3478				 * If the filesystem/minimal service is
3479				 * online check to see if the manifest is
3480				 * there.  If not then there is no need to
3481				 * add it.
3482				 *
3483				 * If filesystem/minimal service is not
3484				 * online, we go ahead and record the
3485				 * manifest file name.  We don't check for
3486				 * its existence because it may be on a
3487				 * file system that is not yet mounted.
3488				 */
3489				if ((est->sc_fs_minimal) &&
3490				    (access(fval, F_OK) == -1)) {
3491					continue;
3492				}
3493
3494				old_pname = safe_strdup(pname);
3495				old_fval = safe_strdup(fval);
3496				old_prop = internal_property_create(old_pname,
3497				    SCF_TYPE_ASTRING, 1, old_fval);
3498
3499				/*
3500				 * Already checked to see if the property exists
3501				 * in the group, and it does not.
3502				 */
3503				(void) internal_attach_property(mfst_pgroup,
3504				    old_prop);
3505			}
3506		}
3507	}
3508	free(fval);
3509
3510	cbdata.sc_handle = g_hndl;
3511	cbdata.sc_parent = ent;
3512	cbdata.sc_service = issvc;
3513	cbdata.sc_flags = SCI_FORCE;
3514	cbdata.sc_source_fmri = ient->sc_fmri;
3515	cbdata.sc_target_fmri = ient->sc_fmri;
3516
3517	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
3518		return (cbdata.sc_err);
3519
3520	return (r);
3521}
3522
3523/*
3524 * prop is taken to be a property in the "dependents" property group of snpl,
3525 * which is taken to be the snaplevel of a last-import snapshot corresponding
3526 * to ient.  If prop is a valid dependents property, upgrade the dependent it
3527 * represents according to the repository & ient.  If ud_run_dpts_pg_set is
3528 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
3529 * of the entity ient represents (possibly in the running snapshot).  If it
3530 * needs to be changed, an entry will be added to tx, if not NULL.
3531 *
3532 * Returns
3533 *   0 - success
3534 *   ECONNABORTED - repository connection broken
3535 *   ENOMEM - out of memory
3536 *   ENOSPC - configd was out of resources
3537 *   ECANCELED - snpl's entity was deleted
3538 *   EINVAL - dependent target is invalid (error printed)
3539 *	    - dependent is invalid (error printed)
3540 *   EBADF - snpl is corrupt (error printed)
3541 *	   - snpl has corrupt pg (error printed)
3542 *	   - dependency pg in target is corrupt (error printed)
3543 *	   - running snapshot in dependent is missing snaplevel (error printed)
3544 *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
3545 *	   - couldn't create dependent (permission denied) (error printed)
3546 *	   - couldn't modify dependent pg (permission denied) (error printed)
3547 *   EROFS - couldn't delete dependency pg (repository read-only)
3548 *	   - couldn't create dependent (repository read-only)
3549 *   EACCES - couldn't delete dependency pg (backend access denied)
3550 *	    - couldn't create dependent (backend access denied)
3551 *   EBUSY - ud_run_dpts_pg was deleted (error printed)
3552 *	   - tx's pg was deleted (error printed)
3553 *	   - dependent pg was changed or deleted (error printed)
3554 *   EEXIST - dependency pg already exists in new target (error printed)
3555 */
3556static int
3557upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
3558    const scf_snaplevel_t *snpl, scf_transaction_t *tx)
3559{
3560	pgroup_t pgrp;
3561	scf_type_t ty;
3562	pgroup_t *new_dpt_pgroup;
3563	pgroup_t *old_dpt_pgroup = NULL;
3564	pgroup_t *current_pg;
3565	scf_callback_t cbdata;
3566	int tissvc;
3567	void *target_ent;
3568	scf_error_t serr;
3569	int r;
3570	scf_transaction_entry_t *ent;
3571
3572	const char * const cf_inval = gettext("Conflict upgrading %s "
3573	    "(dependent \"%s\" has invalid dependents property).\n");
3574	const char * const cf_missing = gettext("Conflict upgrading %s "
3575	    "(dependent \"%s\" is missing).\n");
3576	const char * const cf_newdpg = gettext("Conflict upgrading %s "
3577	    "(dependent \"%s\" has new dependency property group).\n");
3578	const char * const cf_newtarg = gettext("Conflict upgrading %s "
3579	    "(dependent \"%s\" has new target).\n");
3580	const char * const li_corrupt =
3581	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
3582	const char * const upgrading =
3583	    gettext("%s: Upgrading dependent \"%s\".\n");
3584	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
3585	    "corrupt (missing snaplevel).\n");
3586
3587	if (scf_property_type(prop, &ty) != 0) {
3588		switch (scf_error()) {
3589		case SCF_ERROR_DELETED:
3590		case SCF_ERROR_CONNECTION_BROKEN:
3591			return (scferror2errno(scf_error()));
3592
3593		case SCF_ERROR_NOT_BOUND:
3594		case SCF_ERROR_NOT_SET:
3595		default:
3596			bad_error("scf_property_type", scf_error());
3597		}
3598	}
3599
3600	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3601		warn(li_corrupt, ient->sc_fmri);
3602		return (EBADF);
3603	}
3604
3605	/*
3606	 * prop represents a dependent in the old manifest.  It is named after
3607	 * the dependent.
3608	 */
3609	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
3610		switch (scf_error()) {
3611		case SCF_ERROR_DELETED:
3612		case SCF_ERROR_CONNECTION_BROKEN:
3613			return (scferror2errno(scf_error()));
3614
3615		case SCF_ERROR_NOT_BOUND:
3616		case SCF_ERROR_NOT_SET:
3617		default:
3618			bad_error("scf_property_get_name", scf_error());
3619		}
3620	}
3621
3622	/* See if it's in the new manifest. */
3623	pgrp.sc_pgroup_name = ud_name;
3624	new_dpt_pgroup =
3625	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
3626
3627	/* If it's not, delete it... if it hasn't been customized. */
3628	if (new_dpt_pgroup == NULL) {
3629		pgroup_t *dpt;
3630
3631		if (!ud_run_dpts_pg_set)
3632			return (0);
3633
3634		if (scf_property_get_value(prop, ud_val) != 0) {
3635			switch (scf_error()) {
3636			case SCF_ERROR_NOT_FOUND:
3637			case SCF_ERROR_CONSTRAINT_VIOLATED:
3638				warn(li_corrupt, ient->sc_fmri);
3639				return (EBADF);
3640
3641			case SCF_ERROR_DELETED:
3642			case SCF_ERROR_CONNECTION_BROKEN:
3643				return (scferror2errno(scf_error()));
3644
3645			case SCF_ERROR_HANDLE_MISMATCH:
3646			case SCF_ERROR_NOT_BOUND:
3647			case SCF_ERROR_NOT_SET:
3648			case SCF_ERROR_PERMISSION_DENIED:
3649			default:
3650				bad_error("scf_property_get_value",
3651				    scf_error());
3652			}
3653		}
3654
3655		if (scf_value_get_as_string(ud_val, ud_oldtarg,
3656		    max_scf_value_len + 1) < 0)
3657			bad_error("scf_value_get_as_string", scf_error());
3658
3659		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
3660		    0) {
3661			switch (scf_error()) {
3662			case SCF_ERROR_NOT_FOUND:
3663				return (0);
3664
3665			case SCF_ERROR_CONNECTION_BROKEN:
3666				return (scferror2errno(scf_error()));
3667
3668			case SCF_ERROR_DELETED:
3669				warn(emsg_pg_deleted, ient->sc_fmri,
3670				    "dependents");
3671				return (EBUSY);
3672
3673			case SCF_ERROR_INVALID_ARGUMENT:
3674			case SCF_ERROR_NOT_BOUND:
3675			case SCF_ERROR_HANDLE_MISMATCH:
3676			case SCF_ERROR_NOT_SET:
3677			default:
3678				bad_error("scf_pg_get_property", scf_error());
3679			}
3680		}
3681		if (scf_property_get_value(ud_prop, ud_val) != 0) {
3682			switch (scf_error()) {
3683			case SCF_ERROR_NOT_FOUND:
3684			case SCF_ERROR_CONSTRAINT_VIOLATED:
3685				warn(cf_inval, ient->sc_fmri, ud_name);
3686				return (0);
3687
3688			case SCF_ERROR_DELETED:
3689			case SCF_ERROR_CONNECTION_BROKEN:
3690				return (scferror2errno(scf_error()));
3691
3692			case SCF_ERROR_HANDLE_MISMATCH:
3693			case SCF_ERROR_NOT_BOUND:
3694			case SCF_ERROR_NOT_SET:
3695			case SCF_ERROR_PERMISSION_DENIED:
3696			default:
3697				bad_error("scf_property_get_value",
3698				    scf_error());
3699			}
3700		}
3701
3702		ty = scf_value_type(ud_val);
3703		assert(ty != SCF_TYPE_INVALID);
3704		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3705			warn(cf_inval, ient->sc_fmri, ud_name);
3706			return (0);
3707		}
3708
3709		if (scf_value_get_as_string(ud_val, ud_ctarg,
3710		    max_scf_value_len + 1) < 0)
3711			bad_error("scf_value_get_as_string", scf_error());
3712
3713		r = fmri_equal(ud_ctarg, ud_oldtarg);
3714		switch (r) {
3715		case 1:
3716			break;
3717
3718		case 0:
3719		case -1:	/* warn? */
3720			warn(cf_newtarg, ient->sc_fmri, ud_name);
3721			return (0);
3722
3723		case -2:
3724			warn(li_corrupt, ient->sc_fmri);
3725			return (EBADF);
3726
3727		default:
3728			bad_error("fmri_equal", r);
3729		}
3730
3731		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3732			switch (scf_error()) {
3733			case SCF_ERROR_NOT_FOUND:
3734				warn(li_corrupt, ient->sc_fmri);
3735				return (EBADF);
3736
3737			case SCF_ERROR_DELETED:
3738			case SCF_ERROR_CONNECTION_BROKEN:
3739				return (scferror2errno(scf_error()));
3740
3741			case SCF_ERROR_NOT_BOUND:
3742			case SCF_ERROR_HANDLE_MISMATCH:
3743			case SCF_ERROR_INVALID_ARGUMENT:
3744			case SCF_ERROR_NOT_SET:
3745			default:
3746				bad_error("scf_snaplevel_get_pg", scf_error());
3747			}
3748		}
3749
3750		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3751		    snap_lastimport);
3752		switch (r) {
3753		case 0:
3754			break;
3755
3756		case ECANCELED:
3757		case ECONNABORTED:
3758		case ENOMEM:
3759		case EBADF:
3760			return (r);
3761
3762		case EACCES:
3763		default:
3764			bad_error("load_pg", r);
3765		}
3766
3767		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3768		switch (serr) {
3769		case SCF_ERROR_NONE:
3770			break;
3771
3772		case SCF_ERROR_NO_MEMORY:
3773			internal_pgroup_free(old_dpt_pgroup);
3774			return (ENOMEM);
3775
3776		case SCF_ERROR_NOT_FOUND:
3777			internal_pgroup_free(old_dpt_pgroup);
3778			goto delprop;
3779
3780		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
3781		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
3782		default:
3783			bad_error("fmri_to_entity", serr);
3784		}
3785
3786		r = entity_get_running_pg(target_ent, tissvc, ud_name,
3787		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
3788		switch (r) {
3789		case 0:
3790			break;
3791
3792		case ECONNABORTED:
3793			internal_pgroup_free(old_dpt_pgroup);
3794			return (r);
3795
3796		case ECANCELED:
3797		case ENOENT:
3798			internal_pgroup_free(old_dpt_pgroup);
3799			goto delprop;
3800
3801		case EBADF:
3802			warn(r_no_lvl, ud_ctarg);
3803			internal_pgroup_free(old_dpt_pgroup);
3804			return (r);
3805
3806		case EINVAL:
3807		default:
3808			bad_error("entity_get_running_pg", r);
3809		}
3810
3811		/* load it */
3812		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
3813		switch (r) {
3814		case 0:
3815			break;
3816
3817		case ECANCELED:
3818			internal_pgroup_free(old_dpt_pgroup);
3819			goto delprop;
3820
3821		case ECONNABORTED:
3822		case ENOMEM:
3823		case EBADF:
3824			internal_pgroup_free(old_dpt_pgroup);
3825			return (r);
3826
3827		case EACCES:
3828		default:
3829			bad_error("load_pg", r);
3830		}
3831
3832		/* compare property groups */
3833		if (!pg_equal(old_dpt_pgroup, current_pg)) {
3834			warn(cf_newdpg, ient->sc_fmri, ud_name);
3835			internal_pgroup_free(old_dpt_pgroup);
3836			internal_pgroup_free(current_pg);
3837			return (0);
3838		}
3839
3840		internal_pgroup_free(old_dpt_pgroup);
3841		internal_pgroup_free(current_pg);
3842
3843		if (g_verbose)
3844			warn(gettext("%s: Deleting dependent \"%s\".\n"),
3845			    ient->sc_fmri, ud_name);
3846
3847		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
3848			switch (scf_error()) {
3849			case SCF_ERROR_NOT_FOUND:
3850			case SCF_ERROR_DELETED:
3851				internal_pgroup_free(old_dpt_pgroup);
3852				goto delprop;
3853
3854			case SCF_ERROR_CONNECTION_BROKEN:
3855				internal_pgroup_free(old_dpt_pgroup);
3856				return (ECONNABORTED);
3857
3858			case SCF_ERROR_NOT_SET:
3859			case SCF_ERROR_INVALID_ARGUMENT:
3860			case SCF_ERROR_HANDLE_MISMATCH:
3861			case SCF_ERROR_NOT_BOUND:
3862			default:
3863				bad_error("entity_get_pg", scf_error());
3864			}
3865		}
3866
3867		if (scf_pg_delete(ud_pg) != 0) {
3868			switch (scf_error()) {
3869			case SCF_ERROR_DELETED:
3870				break;
3871
3872			case SCF_ERROR_CONNECTION_BROKEN:
3873			case SCF_ERROR_BACKEND_READONLY:
3874			case SCF_ERROR_BACKEND_ACCESS:
3875				return (scferror2errno(scf_error()));
3876
3877			case SCF_ERROR_PERMISSION_DENIED:
3878				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
3879				return (scferror2errno(scf_error()));
3880
3881			case SCF_ERROR_NOT_SET:
3882			default:
3883				bad_error("scf_pg_delete", scf_error());
3884			}
3885		}
3886
3887		/*
3888		 * This service was changed, so it must be refreshed.  But
3889		 * since it's not mentioned in the new manifest, we have to
3890		 * record its FMRI here for use later.  We record the name
3891		 * & the entity (via sc_parent) in case we need to print error
3892		 * messages during the refresh.
3893		 */
3894		dpt = internal_pgroup_new();
3895		if (dpt == NULL)
3896			return (ENOMEM);
3897		dpt->sc_pgroup_name = strdup(ud_name);
3898		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
3899		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
3900			return (ENOMEM);
3901		dpt->sc_parent = (entity_t *)ient;
3902		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
3903			uu_die(gettext("libuutil error: %s\n"),
3904			    uu_strerror(uu_error()));
3905
3906delprop:
3907		if (tx == NULL)
3908			return (0);
3909
3910		ent = scf_entry_create(g_hndl);
3911		if (ent == NULL)
3912			return (ENOMEM);
3913
3914		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
3915			scf_entry_destroy(ent);
3916			switch (scf_error()) {
3917			case SCF_ERROR_DELETED:
3918				warn(emsg_pg_deleted, ient->sc_fmri,
3919				    "dependents");
3920				return (EBUSY);
3921
3922			case SCF_ERROR_CONNECTION_BROKEN:
3923				return (scferror2errno(scf_error()));
3924
3925			case SCF_ERROR_NOT_FOUND:
3926				break;
3927
3928			case SCF_ERROR_HANDLE_MISMATCH:
3929			case SCF_ERROR_NOT_BOUND:
3930			case SCF_ERROR_INVALID_ARGUMENT:
3931			case SCF_ERROR_NOT_SET:
3932			default:
3933				bad_error("scf_transaction_property_delete",
3934				    scf_error());
3935			}
3936		}
3937
3938		return (0);
3939	}
3940
3941	new_dpt_pgroup->sc_pgroup_seen = 1;
3942
3943	/*
3944	 * Decide whether the dependent has changed in the manifest.
3945	 */
3946	/* Compare the target. */
3947	if (scf_property_get_value(prop, ud_val) != 0) {
3948		switch (scf_error()) {
3949		case SCF_ERROR_NOT_FOUND:
3950		case SCF_ERROR_CONSTRAINT_VIOLATED:
3951			warn(li_corrupt, ient->sc_fmri);
3952			return (EBADF);
3953
3954		case SCF_ERROR_DELETED:
3955		case SCF_ERROR_CONNECTION_BROKEN:
3956			return (scferror2errno(scf_error()));
3957
3958		case SCF_ERROR_HANDLE_MISMATCH:
3959		case SCF_ERROR_NOT_BOUND:
3960		case SCF_ERROR_NOT_SET:
3961		case SCF_ERROR_PERMISSION_DENIED:
3962		default:
3963			bad_error("scf_property_get_value", scf_error());
3964		}
3965	}
3966
3967	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
3968	    0)
3969		bad_error("scf_value_get_as_string", scf_error());
3970
3971	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
3972	switch (r) {
3973	case 0:
3974		break;
3975
3976	case 1:
3977		/* Compare the dependency pgs. */
3978		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3979			switch (scf_error()) {
3980			case SCF_ERROR_NOT_FOUND:
3981				warn(li_corrupt, ient->sc_fmri);
3982				return (EBADF);
3983
3984			case SCF_ERROR_DELETED:
3985			case SCF_ERROR_CONNECTION_BROKEN:
3986				return (scferror2errno(scf_error()));
3987
3988			case SCF_ERROR_NOT_BOUND:
3989			case SCF_ERROR_HANDLE_MISMATCH:
3990			case SCF_ERROR_INVALID_ARGUMENT:
3991			case SCF_ERROR_NOT_SET:
3992			default:
3993				bad_error("scf_snaplevel_get_pg", scf_error());
3994			}
3995		}
3996
3997		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3998		    snap_lastimport);
3999		switch (r) {
4000		case 0:
4001			break;
4002
4003		case ECANCELED:
4004		case ECONNABORTED:
4005		case ENOMEM:
4006		case EBADF:
4007			return (r);
4008
4009		case EACCES:
4010		default:
4011			bad_error("load_pg", r);
4012		}
4013
4014		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4015			/* no change, leave customizations */
4016			internal_pgroup_free(old_dpt_pgroup);
4017			return (0);
4018		}
4019		break;
4020
4021	case -1:
4022		warn(li_corrupt, ient->sc_fmri);
4023		return (EBADF);
4024
4025	case -2:
4026		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4027		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4028		return (EINVAL);
4029
4030	default:
4031		bad_error("fmri_equal", r);
4032	}
4033
4034	/*
4035	 * The dependent has changed in the manifest.  Upgrade the current
4036	 * properties if they haven't been customized.
4037	 */
4038
4039	/*
4040	 * If new_dpt_pgroup->sc_override, then act as though the property
4041	 * group hasn't been customized.
4042	 */
4043	if (new_dpt_pgroup->sc_pgroup_override)
4044		goto nocust;
4045
4046	if (!ud_run_dpts_pg_set) {
4047		warn(cf_missing, ient->sc_fmri, ud_name);
4048		r = 0;
4049		goto out;
4050	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4051		switch (scf_error()) {
4052		case SCF_ERROR_NOT_FOUND:
4053			warn(cf_missing, ient->sc_fmri, ud_name);
4054			r = 0;
4055			goto out;
4056
4057		case SCF_ERROR_CONNECTION_BROKEN:
4058			r = scferror2errno(scf_error());
4059			goto out;
4060
4061		case SCF_ERROR_DELETED:
4062			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4063			r = EBUSY;
4064			goto out;
4065
4066		case SCF_ERROR_INVALID_ARGUMENT:
4067		case SCF_ERROR_NOT_BOUND:
4068		case SCF_ERROR_HANDLE_MISMATCH:
4069		case SCF_ERROR_NOT_SET:
4070		default:
4071			bad_error("scf_pg_get_property", scf_error());
4072		}
4073	}
4074
4075	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4076		switch (scf_error()) {
4077		case SCF_ERROR_NOT_FOUND:
4078		case SCF_ERROR_CONSTRAINT_VIOLATED:
4079			warn(cf_inval, ient->sc_fmri, ud_name);
4080			r = 0;
4081			goto out;
4082
4083		case SCF_ERROR_DELETED:
4084		case SCF_ERROR_CONNECTION_BROKEN:
4085			r = scferror2errno(scf_error());
4086			goto out;
4087
4088		case SCF_ERROR_HANDLE_MISMATCH:
4089		case SCF_ERROR_NOT_BOUND:
4090		case SCF_ERROR_NOT_SET:
4091		case SCF_ERROR_PERMISSION_DENIED:
4092		default:
4093			bad_error("scf_property_get_value", scf_error());
4094		}
4095	}
4096
4097	ty = scf_value_type(ud_val);
4098	assert(ty != SCF_TYPE_INVALID);
4099	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4100		warn(cf_inval, ient->sc_fmri, ud_name);
4101		r = 0;
4102		goto out;
4103	}
4104	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4105	    0)
4106		bad_error("scf_value_get_as_string", scf_error());
4107
4108	r = fmri_equal(ud_ctarg, ud_oldtarg);
4109	if (r == -1) {
4110		warn(cf_inval, ient->sc_fmri, ud_name);
4111		r = 0;
4112		goto out;
4113	} else if (r == -2) {
4114		warn(li_corrupt, ient->sc_fmri);
4115		r = EBADF;
4116		goto out;
4117	} else if (r == 0) {
4118		/*
4119		 * Target has been changed.  Only abort now if it's been
4120		 * changed to something other than what's in the manifest.
4121		 */
4122		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4123		if (r == -1) {
4124			warn(cf_inval, ient->sc_fmri, ud_name);
4125			r = 0;
4126			goto out;
4127		} else if (r == 0) {
4128			warn(cf_newtarg, ient->sc_fmri, ud_name);
4129			r = 0;
4130			goto out;
4131		} else if (r != 1) {
4132			/* invalid sc_pgroup_fmri caught above */
4133			bad_error("fmri_equal", r);
4134		}
4135
4136		/*
4137		 * Fetch the current dependency pg.  If it's what the manifest
4138		 * says, then no problem.
4139		 */
4140		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4141		switch (serr) {
4142		case SCF_ERROR_NONE:
4143			break;
4144
4145		case SCF_ERROR_NOT_FOUND:
4146			warn(cf_missing, ient->sc_fmri, ud_name);
4147			r = 0;
4148			goto out;
4149
4150		case SCF_ERROR_NO_MEMORY:
4151			r = ENOMEM;
4152			goto out;
4153
4154		case SCF_ERROR_CONSTRAINT_VIOLATED:
4155		case SCF_ERROR_INVALID_ARGUMENT:
4156		default:
4157			bad_error("fmri_to_entity", serr);
4158		}
4159
4160		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4161		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4162		switch (r) {
4163		case 0:
4164			break;
4165
4166		case ECONNABORTED:
4167			goto out;
4168
4169		case ECANCELED:
4170		case ENOENT:
4171			warn(cf_missing, ient->sc_fmri, ud_name);
4172			r = 0;
4173			goto out;
4174
4175		case EBADF:
4176			warn(r_no_lvl, ud_ctarg);
4177			goto out;
4178
4179		case EINVAL:
4180		default:
4181			bad_error("entity_get_running_pg", r);
4182		}
4183
4184		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4185		switch (r) {
4186		case 0:
4187			break;
4188
4189		case ECANCELED:
4190			warn(cf_missing, ient->sc_fmri, ud_name);
4191			r = 0;
4192			goto out;
4193
4194		case ECONNABORTED:
4195		case ENOMEM:
4196		case EBADF:
4197			goto out;
4198
4199		case EACCES:
4200		default:
4201			bad_error("load_pg", r);
4202		}
4203
4204		if (!pg_equal(current_pg, new_dpt_pgroup))
4205			warn(cf_newdpg, ient->sc_fmri, ud_name);
4206		internal_pgroup_free(current_pg);
4207		r = 0;
4208		goto out;
4209	} else if (r != 1) {
4210		bad_error("fmri_equal", r);
4211	}
4212
4213nocust:
4214	/*
4215	 * Target has not been customized.  Check the dependency property
4216	 * group.
4217	 */
4218
4219	if (old_dpt_pgroup == NULL) {
4220		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4221		    ud_pg) != 0) {
4222			switch (scf_error()) {
4223			case SCF_ERROR_NOT_FOUND:
4224				warn(li_corrupt, ient->sc_fmri);
4225				return (EBADF);
4226
4227			case SCF_ERROR_DELETED:
4228			case SCF_ERROR_CONNECTION_BROKEN:
4229				return (scferror2errno(scf_error()));
4230
4231			case SCF_ERROR_NOT_BOUND:
4232			case SCF_ERROR_HANDLE_MISMATCH:
4233			case SCF_ERROR_INVALID_ARGUMENT:
4234			case SCF_ERROR_NOT_SET:
4235			default:
4236				bad_error("scf_snaplevel_get_pg", scf_error());
4237			}
4238		}
4239
4240		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4241		    snap_lastimport);
4242		switch (r) {
4243		case 0:
4244			break;
4245
4246		case ECANCELED:
4247		case ECONNABORTED:
4248		case ENOMEM:
4249		case EBADF:
4250			return (r);
4251
4252		case EACCES:
4253		default:
4254			bad_error("load_pg", r);
4255		}
4256	}
4257
4258	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4259	switch (serr) {
4260	case SCF_ERROR_NONE:
4261		break;
4262
4263	case SCF_ERROR_NOT_FOUND:
4264		warn(cf_missing, ient->sc_fmri, ud_name);
4265		r = 0;
4266		goto out;
4267
4268	case SCF_ERROR_NO_MEMORY:
4269		r = ENOMEM;
4270		goto out;
4271
4272	case SCF_ERROR_CONSTRAINT_VIOLATED:
4273	case SCF_ERROR_INVALID_ARGUMENT:
4274	default:
4275		bad_error("fmri_to_entity", serr);
4276	}
4277
4278	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4279	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4280	switch (r) {
4281	case 0:
4282		break;
4283
4284	case ECONNABORTED:
4285		goto out;
4286
4287	case ECANCELED:
4288	case ENOENT:
4289		warn(cf_missing, ient->sc_fmri, ud_name);
4290		r = 0;
4291		goto out;
4292
4293	case EBADF:
4294		warn(r_no_lvl, ud_ctarg);
4295		goto out;
4296
4297	case EINVAL:
4298	default:
4299		bad_error("entity_get_running_pg", r);
4300	}
4301
4302	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4303	switch (r) {
4304	case 0:
4305		break;
4306
4307	case ECANCELED:
4308		warn(cf_missing, ient->sc_fmri, ud_name);
4309		goto out;
4310
4311	case ECONNABORTED:
4312	case ENOMEM:
4313	case EBADF:
4314		goto out;
4315
4316	case EACCES:
4317	default:
4318		bad_error("load_pg", r);
4319	}
4320
4321	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4322		if (!pg_equal(current_pg, new_dpt_pgroup))
4323			warn(cf_newdpg, ient->sc_fmri, ud_name);
4324		internal_pgroup_free(current_pg);
4325		r = 0;
4326		goto out;
4327	}
4328
4329	/* Uncustomized.  Upgrade. */
4330
4331	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4332	switch (r) {
4333	case 1:
4334		if (pg_equal(current_pg, new_dpt_pgroup)) {
4335			/* Already upgraded. */
4336			internal_pgroup_free(current_pg);
4337			r = 0;
4338			goto out;
4339		}
4340
4341		internal_pgroup_free(current_pg);
4342
4343		/* upgrade current_pg */
4344		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4345			switch (scf_error()) {
4346			case SCF_ERROR_CONNECTION_BROKEN:
4347				r = scferror2errno(scf_error());
4348				goto out;
4349
4350			case SCF_ERROR_DELETED:
4351				warn(cf_missing, ient->sc_fmri, ud_name);
4352				r = 0;
4353				goto out;
4354
4355			case SCF_ERROR_NOT_FOUND:
4356				break;
4357
4358			case SCF_ERROR_INVALID_ARGUMENT:
4359			case SCF_ERROR_NOT_BOUND:
4360			case SCF_ERROR_NOT_SET:
4361			case SCF_ERROR_HANDLE_MISMATCH:
4362			default:
4363				bad_error("entity_get_pg", scf_error());
4364			}
4365
4366			if (tissvc)
4367				r = scf_service_add_pg(target_ent, ud_name,
4368				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4369			else
4370				r = scf_instance_add_pg(target_ent, ud_name,
4371				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4372			if (r != 0) {
4373				switch (scf_error()) {
4374				case SCF_ERROR_CONNECTION_BROKEN:
4375				case SCF_ERROR_NO_RESOURCES:
4376				case SCF_ERROR_BACKEND_READONLY:
4377				case SCF_ERROR_BACKEND_ACCESS:
4378					r = scferror2errno(scf_error());
4379					goto out;
4380
4381				case SCF_ERROR_DELETED:
4382					warn(cf_missing, ient->sc_fmri,
4383					    ud_name);
4384					r = 0;
4385					goto out;
4386
4387				case SCF_ERROR_PERMISSION_DENIED:
4388					warn(emsg_pg_deleted, ud_ctarg,
4389					    ud_name);
4390					r = EPERM;
4391					goto out;
4392
4393				case SCF_ERROR_EXISTS:
4394					warn(emsg_pg_added, ud_ctarg, ud_name);
4395					r = EBUSY;
4396					goto out;
4397
4398				case SCF_ERROR_NOT_BOUND:
4399				case SCF_ERROR_HANDLE_MISMATCH:
4400				case SCF_ERROR_INVALID_ARGUMENT:
4401				case SCF_ERROR_NOT_SET:
4402				default:
4403					bad_error("entity_add_pg", scf_error());
4404				}
4405			}
4406		}
4407
4408		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4409		switch (r) {
4410		case 0:
4411			break;
4412
4413		case ECANCELED:
4414			warn(cf_missing, ient->sc_fmri, ud_name);
4415			goto out;
4416
4417		case ECONNABORTED:
4418		case ENOMEM:
4419		case EBADF:
4420			goto out;
4421
4422		case EACCES:
4423		default:
4424			bad_error("load_pg", r);
4425		}
4426
4427		if (g_verbose)
4428			warn(upgrading, ient->sc_fmri, ud_name);
4429
4430		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4431		    new_dpt_pgroup, 0, ient->sc_fmri);
4432		switch (r) {
4433		case 0:
4434			break;
4435
4436		case ECANCELED:
4437			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4438			r = EBUSY;
4439			goto out;
4440
4441		case EPERM:
4442			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4443			goto out;
4444
4445		case EBUSY:
4446			warn(emsg_pg_changed, ud_ctarg, ud_name);
4447			goto out;
4448
4449		case ECONNABORTED:
4450		case ENOMEM:
4451		case ENOSPC:
4452		case EROFS:
4453		case EACCES:
4454		case EINVAL:
4455			goto out;
4456
4457		default:
4458			bad_error("upgrade_pg", r);
4459		}
4460		break;
4461
4462	case 0: {
4463		scf_transaction_entry_t *ent;
4464		scf_value_t *val;
4465
4466		internal_pgroup_free(current_pg);
4467
4468		/* delete old pg */
4469		if (g_verbose)
4470			warn(upgrading, ient->sc_fmri, ud_name);
4471
4472		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 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(cf_missing, ient->sc_fmri, ud_name);
4480				r = 0;
4481				goto out;
4482
4483			case SCF_ERROR_NOT_FOUND:
4484				break;
4485
4486			case SCF_ERROR_INVALID_ARGUMENT:
4487			case SCF_ERROR_NOT_BOUND:
4488			case SCF_ERROR_NOT_SET:
4489			case SCF_ERROR_HANDLE_MISMATCH:
4490			default:
4491				bad_error("entity_get_pg", scf_error());
4492			}
4493		} else if (scf_pg_delete(ud_pg) != 0) {
4494			switch (scf_error()) {
4495			case SCF_ERROR_DELETED:
4496				break;
4497
4498			case SCF_ERROR_CONNECTION_BROKEN:
4499			case SCF_ERROR_BACKEND_READONLY:
4500			case SCF_ERROR_BACKEND_ACCESS:
4501				r = scferror2errno(scf_error());
4502				goto out;
4503
4504			case SCF_ERROR_PERMISSION_DENIED:
4505				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4506				r = scferror2errno(scf_error());
4507				goto out;
4508
4509			case SCF_ERROR_NOT_SET:
4510			default:
4511				bad_error("scf_pg_delete", scf_error());
4512			}
4513		}
4514
4515		/* import new one */
4516		cbdata.sc_handle = g_hndl;
4517		cbdata.sc_trans = NULL;		/* handled below */
4518
4519		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
4520		if (r != UU_WALK_NEXT) {
4521			if (r != UU_WALK_ERROR)
4522				bad_error("lscf_dependent_import", r);
4523
4524			r = cbdata.sc_err;
4525			goto out;
4526		}
4527
4528		if (tx == NULL)
4529			break;
4530
4531		if ((ent = scf_entry_create(g_hndl)) == NULL ||
4532		    (val = scf_value_create(g_hndl)) == NULL) {
4533			if (scf_error() == SCF_ERROR_NO_MEMORY)
4534				return (ENOMEM);
4535
4536			bad_error("scf_entry_create", scf_error());
4537		}
4538
4539		if (scf_transaction_property_change_type(tx, ent, ud_name,
4540		    SCF_TYPE_FMRI) != 0) {
4541			switch (scf_error()) {
4542			case SCF_ERROR_CONNECTION_BROKEN:
4543				r = scferror2errno(scf_error());
4544				goto out;
4545
4546			case SCF_ERROR_DELETED:
4547				warn(emsg_pg_deleted, ient->sc_fmri,
4548				    "dependents");
4549				r = EBUSY;
4550				goto out;
4551
4552			case SCF_ERROR_NOT_FOUND:
4553				break;
4554
4555			case SCF_ERROR_NOT_BOUND:
4556			case SCF_ERROR_HANDLE_MISMATCH:
4557			case SCF_ERROR_INVALID_ARGUMENT:
4558			case SCF_ERROR_NOT_SET:
4559			default:
4560				bad_error("scf_transaction_property_"
4561				    "change_type", scf_error());
4562			}
4563
4564			if (scf_transaction_property_new(tx, ent, ud_name,
4565			    SCF_TYPE_FMRI) != 0) {
4566				switch (scf_error()) {
4567				case SCF_ERROR_CONNECTION_BROKEN:
4568					r = scferror2errno(scf_error());
4569					goto out;
4570
4571				case SCF_ERROR_DELETED:
4572					warn(emsg_pg_deleted, ient->sc_fmri,
4573					    "dependents");
4574					r = EBUSY;
4575					goto out;
4576
4577				case SCF_ERROR_EXISTS:
4578					warn(emsg_pg_changed, ient->sc_fmri,
4579					    "dependents");
4580					r = EBUSY;
4581					goto out;
4582
4583				case SCF_ERROR_INVALID_ARGUMENT:
4584				case SCF_ERROR_HANDLE_MISMATCH:
4585				case SCF_ERROR_NOT_BOUND:
4586				case SCF_ERROR_NOT_SET:
4587				default:
4588					bad_error("scf_transaction_property_"
4589					    "new", scf_error());
4590				}
4591			}
4592		}
4593
4594		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
4595		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
4596			/* invalid sc_pgroup_fmri caught above */
4597			bad_error("scf_value_set_from_string",
4598			    scf_error());
4599
4600		if (scf_entry_add_value(ent, val) != 0)
4601			bad_error("scf_entry_add_value", scf_error());
4602		break;
4603	}
4604
4605	case -2:
4606		warn(li_corrupt, ient->sc_fmri);
4607		internal_pgroup_free(current_pg);
4608		r = EBADF;
4609		goto out;
4610
4611	case -1:
4612	default:
4613		/* invalid sc_pgroup_fmri caught above */
4614		bad_error("fmri_equal", r);
4615	}
4616
4617	r = 0;
4618
4619out:
4620	if (old_dpt_pgroup != NULL)
4621		internal_pgroup_free(old_dpt_pgroup);
4622
4623	return (r);
4624}
4625
4626/*
4627 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
4628 * would import it, except it seems to exist in the service anyway.  Compare
4629 * the existent dependent with the one we would import, and report any
4630 * differences (if there are none, be silent).  prop is the property which
4631 * represents the existent dependent (in the dependents property group) in the
4632 * entity corresponding to ient.
4633 *
4634 * Returns
4635 *   0 - success (Sort of.  At least, we can continue importing.)
4636 *   ECONNABORTED - repository connection broken
4637 *   EBUSY - ancestor of prop was deleted (error printed)
4638 *   ENOMEM - out of memory
4639 *   EBADF - corrupt property group (error printed)
4640 *   EINVAL - new_dpt_pgroup has invalid target (error printed)
4641 */
4642static int
4643handle_dependent_conflict(const entity_t * const ient,
4644    const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
4645{
4646	int r;
4647	scf_type_t ty;
4648	scf_error_t scfe;
4649	void *tptr;
4650	int tissvc;
4651	pgroup_t *pgroup;
4652
4653	if (scf_property_get_value(prop, ud_val) != 0) {
4654		switch (scf_error()) {
4655		case SCF_ERROR_CONNECTION_BROKEN:
4656			return (scferror2errno(scf_error()));
4657
4658		case SCF_ERROR_DELETED:
4659			warn(emsg_pg_deleted, ient->sc_fmri,
4660			    new_dpt_pgroup->sc_pgroup_name);
4661			return (EBUSY);
4662
4663		case SCF_ERROR_CONSTRAINT_VIOLATED:
4664		case SCF_ERROR_NOT_FOUND:
4665			warn(gettext("Conflict upgrading %s (not importing "
4666			    "dependent \"%s\" because it already exists.)  "
4667			    "Warning: The \"%s/%2$s\" property has more or "
4668			    "fewer than one value)).\n"), ient->sc_fmri,
4669			    new_dpt_pgroup->sc_pgroup_name, "dependents");
4670			return (0);
4671
4672		case SCF_ERROR_HANDLE_MISMATCH:
4673		case SCF_ERROR_NOT_BOUND:
4674		case SCF_ERROR_NOT_SET:
4675		case SCF_ERROR_PERMISSION_DENIED:
4676		default:
4677			bad_error("scf_property_get_value",
4678			    scf_error());
4679		}
4680	}
4681
4682	ty = scf_value_type(ud_val);
4683	assert(ty != SCF_TYPE_INVALID);
4684	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4685		warn(gettext("Conflict upgrading %s (not importing dependent "
4686		    "\"%s\" because it already exists).  Warning: The "
4687		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
4688		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
4689		    scf_type_to_string(ty), "dependents");
4690		return (0);
4691	}
4692
4693	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4694	    0)
4695		bad_error("scf_value_get_as_string", scf_error());
4696
4697	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4698	switch (r) {
4699	case 0:
4700		warn(gettext("Conflict upgrading %s (not importing dependent "
4701		    "\"%s\" (target \"%s\") because it already exists with "
4702		    "target \"%s\").\n"), ient->sc_fmri,
4703		    new_dpt_pgroup->sc_pgroup_name,
4704		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
4705		return (0);
4706
4707	case 1:
4708		break;
4709
4710	case -1:
4711		warn(gettext("Conflict upgrading %s (not importing dependent "
4712		    "\"%s\" because it already exists).  Warning: The current "
4713		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
4714		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4715		return (0);
4716
4717	case -2:
4718		warn(gettext("Dependent \"%s\" of %s has invalid target "
4719		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
4720		    new_dpt_pgroup->sc_pgroup_fmri);
4721		return (EINVAL);
4722
4723	default:
4724		bad_error("fmri_equal", r);
4725	}
4726
4727	/* compare dependency pgs in target */
4728	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
4729	switch (scfe) {
4730	case SCF_ERROR_NONE:
4731		break;
4732
4733	case SCF_ERROR_NO_MEMORY:
4734		return (ENOMEM);
4735
4736	case SCF_ERROR_NOT_FOUND:
4737		warn(emsg_dpt_dangling, ient->sc_fmri,
4738		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4739		return (0);
4740
4741	case SCF_ERROR_CONSTRAINT_VIOLATED:
4742	case SCF_ERROR_INVALID_ARGUMENT:
4743	default:
4744		bad_error("fmri_to_entity", scfe);
4745	}
4746
4747	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
4748	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
4749	switch (r) {
4750	case 0:
4751		break;
4752
4753	case ECONNABORTED:
4754		return (r);
4755
4756	case ECANCELED:
4757		warn(emsg_dpt_dangling, ient->sc_fmri,
4758		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4759		return (0);
4760
4761	case EBADF:
4762		if (tissvc)
4763			warn(gettext("%s has an instance with a \"%s\" "
4764			    "snapshot which is missing a snaplevel.\n"),
4765			    ud_ctarg, "running");
4766		else
4767			warn(gettext("%s has a \"%s\" snapshot which is "
4768			    "missing a snaplevel.\n"), ud_ctarg, "running");
4769		/* FALLTHROUGH */
4770
4771	case ENOENT:
4772		warn(emsg_dpt_no_dep, ient->sc_fmri,
4773		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4774		    new_dpt_pgroup->sc_pgroup_name);
4775		return (0);
4776
4777	case EINVAL:
4778	default:
4779		bad_error("entity_get_running_pg", r);
4780	}
4781
4782	pgroup = internal_pgroup_new();
4783	if (pgroup == NULL)
4784		return (ENOMEM);
4785
4786	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
4787	switch (r) {
4788	case 0:
4789		break;
4790
4791	case ECONNABORTED:
4792	case EBADF:
4793	case ENOMEM:
4794		internal_pgroup_free(pgroup);
4795		return (r);
4796
4797	case ECANCELED:
4798		warn(emsg_dpt_no_dep, ient->sc_fmri,
4799		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4800		    new_dpt_pgroup->sc_pgroup_name);
4801		internal_pgroup_free(pgroup);
4802		return (0);
4803
4804	case EACCES:
4805	default:
4806		bad_error("load_pg", r);
4807	}
4808
4809	/* report differences */
4810	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
4811	internal_pgroup_free(pgroup);
4812	return (0);
4813}
4814
4815/*
4816 * lipg is a property group in the last-import snapshot of ent, which is an
4817 * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
4818 * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
4819 * in ents's property groups, compare and upgrade ent appropriately.
4820 *
4821 * Returns
4822 *   0 - success
4823 *   ECONNABORTED - repository connection broken
4824 *   ENOMEM - out of memory
4825 *   ENOSPC - configd is out of resources
4826 *   EINVAL - ient has invalid dependent (error printed)
4827 *	    - ient has invalid pgroup_t (error printed)
4828 *   ECANCELED - ent has been deleted
4829 *   ENODEV - entity containing lipg has been deleted
4830 *	    - entity containing running has been deleted
4831 *   EPERM - could not delete pg (permission denied) (error printed)
4832 *	   - couldn't upgrade dependents (permission denied) (error printed)
4833 *	   - couldn't import pg (permission denied) (error printed)
4834 *	   - couldn't upgrade pg (permission denied) (error printed)
4835 *   EROFS - could not delete pg (repository read-only)
4836 *	   - couldn't upgrade dependents (repository read-only)
4837 *	   - couldn't import pg (repository read-only)
4838 *	   - couldn't upgrade pg (repository read-only)
4839 *   EACCES - could not delete pg (backend access denied)
4840 *	    - couldn't upgrade dependents (backend access denied)
4841 *	    - couldn't import pg (backend access denied)
4842 *	    - couldn't upgrade pg (backend access denied)
4843 *	    - couldn't read property (backend access denied)
4844 *   EBUSY - property group was added (error printed)
4845 *	   - property group was deleted (error printed)
4846 *	   - property group changed (error printed)
4847 *	   - "dependents" pg was added, changed, or deleted (error printed)
4848 *	   - dependent target deleted (error printed)
4849 *	   - dependent pg changed (error printed)
4850 *   EBADF - imp_snpl is corrupt (error printed)
4851 *	   - ent has bad pg (error printed)
4852 *   EEXIST - dependent collision in target service (error printed)
4853 */
4854static int
4855process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
4856    const scf_snaplevel_t *running)
4857{
4858	int r;
4859	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
4860	scf_callback_t cbdata;
4861
4862	const char * const cf_pg_missing =
4863	    gettext("Conflict upgrading %s (property group %s is missing)\n");
4864	const char * const deleting =
4865	    gettext("%s: Deleting property group \"%s\".\n");
4866
4867	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
4868
4869	/* Skip dependent property groups. */
4870	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
4871		switch (scf_error()) {
4872		case SCF_ERROR_DELETED:
4873			return (ENODEV);
4874
4875		case SCF_ERROR_CONNECTION_BROKEN:
4876			return (ECONNABORTED);
4877
4878		case SCF_ERROR_NOT_SET:
4879		case SCF_ERROR_NOT_BOUND:
4880		default:
4881			bad_error("scf_pg_get_type", scf_error());
4882		}
4883	}
4884
4885	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
4886		if (scf_pg_get_property(lipg, "external", NULL) == 0)
4887			return (0);
4888
4889		switch (scf_error()) {
4890		case SCF_ERROR_NOT_FOUND:
4891			break;
4892
4893		case SCF_ERROR_CONNECTION_BROKEN:
4894			return (ECONNABORTED);
4895
4896		case SCF_ERROR_DELETED:
4897			return (ENODEV);
4898
4899		case SCF_ERROR_INVALID_ARGUMENT:
4900		case SCF_ERROR_NOT_BOUND:
4901		case SCF_ERROR_HANDLE_MISMATCH:
4902		case SCF_ERROR_NOT_SET:
4903		default:
4904			bad_error("scf_pg_get_property", scf_error());
4905		}
4906	}
4907
4908	/* lookup pg in new properties */
4909	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
4910		switch (scf_error()) {
4911		case SCF_ERROR_DELETED:
4912			return (ENODEV);
4913
4914		case SCF_ERROR_CONNECTION_BROKEN:
4915			return (ECONNABORTED);
4916
4917		case SCF_ERROR_NOT_SET:
4918		case SCF_ERROR_NOT_BOUND:
4919		default:
4920			bad_error("scf_pg_get_name", scf_error());
4921		}
4922	}
4923
4924	pgrp.sc_pgroup_name = imp_str;
4925	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
4926
4927	if (mpg != NULL)
4928		mpg->sc_pgroup_seen = 1;
4929
4930	/* Special handling for dependents */
4931	if (strcmp(imp_str, "dependents") == 0)
4932		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
4933
4934	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
4935		return (upgrade_manifestfiles(NULL, ient, running, ent));
4936
4937	if (mpg == NULL || mpg->sc_pgroup_delete) {
4938		/* property group was deleted from manifest */
4939		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4940			switch (scf_error()) {
4941			case SCF_ERROR_NOT_FOUND:
4942				return (0);
4943
4944			case SCF_ERROR_DELETED:
4945			case SCF_ERROR_CONNECTION_BROKEN:
4946				return (scferror2errno(scf_error()));
4947
4948			case SCF_ERROR_INVALID_ARGUMENT:
4949			case SCF_ERROR_HANDLE_MISMATCH:
4950			case SCF_ERROR_NOT_BOUND:
4951			case SCF_ERROR_NOT_SET:
4952			default:
4953				bad_error("entity_get_pg", scf_error());
4954			}
4955		}
4956
4957		if (mpg != NULL && mpg->sc_pgroup_delete) {
4958			if (g_verbose)
4959				warn(deleting, ient->sc_fmri, imp_str);
4960			if (scf_pg_delete(imp_pg2) == 0)
4961				return (0);
4962
4963			switch (scf_error()) {
4964			case SCF_ERROR_DELETED:
4965				return (0);
4966
4967			case SCF_ERROR_CONNECTION_BROKEN:
4968			case SCF_ERROR_BACKEND_READONLY:
4969			case SCF_ERROR_BACKEND_ACCESS:
4970				return (scferror2errno(scf_error()));
4971
4972			case SCF_ERROR_PERMISSION_DENIED:
4973				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
4974				return (scferror2errno(scf_error()));
4975
4976			case SCF_ERROR_NOT_SET:
4977			default:
4978				bad_error("scf_pg_delete", scf_error());
4979			}
4980		}
4981
4982		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4983		switch (r) {
4984		case 0:
4985			break;
4986
4987		case ECANCELED:
4988			return (ENODEV);
4989
4990		case ECONNABORTED:
4991		case ENOMEM:
4992		case EBADF:
4993		case EACCES:
4994			return (r);
4995
4996		default:
4997			bad_error("load_pg", r);
4998		}
4999
5000		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5001		switch (r) {
5002		case 0:
5003			break;
5004
5005		case ECANCELED:
5006		case ECONNABORTED:
5007		case ENOMEM:
5008		case EBADF:
5009		case EACCES:
5010			internal_pgroup_free(lipg_i);
5011			return (r);
5012
5013		default:
5014			bad_error("load_pg", r);
5015		}
5016
5017		if (pg_equal(lipg_i, curpg_i)) {
5018			if (g_verbose)
5019				warn(deleting, ient->sc_fmri, imp_str);
5020			if (scf_pg_delete(imp_pg2) != 0) {
5021				switch (scf_error()) {
5022				case SCF_ERROR_DELETED:
5023					break;
5024
5025				case SCF_ERROR_CONNECTION_BROKEN:
5026					internal_pgroup_free(lipg_i);
5027					internal_pgroup_free(curpg_i);
5028					return (ECONNABORTED);
5029
5030				case SCF_ERROR_NOT_SET:
5031				case SCF_ERROR_NOT_BOUND:
5032				default:
5033					bad_error("scf_pg_delete", scf_error());
5034				}
5035			}
5036		} else {
5037			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5038		}
5039
5040		internal_pgroup_free(lipg_i);
5041		internal_pgroup_free(curpg_i);
5042
5043		return (0);
5044	}
5045
5046	/*
5047	 * Only dependent pgs can have override set, and we skipped those
5048	 * above.
5049	 */
5050	assert(!mpg->sc_pgroup_override);
5051
5052	/* compare */
5053	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5054	switch (r) {
5055	case 0:
5056		break;
5057
5058	case ECANCELED:
5059		return (ENODEV);
5060
5061	case ECONNABORTED:
5062	case EBADF:
5063	case ENOMEM:
5064	case EACCES:
5065		return (r);
5066
5067	default:
5068		bad_error("load_pg", r);
5069	}
5070
5071	if (pg_equal(mpg, lipg_i)) {
5072		/* The manifest pg has not changed.  Move on. */
5073		r = 0;
5074		goto out;
5075	}
5076
5077	/* upgrade current properties according to lipg & mpg */
5078	if (running != NULL)
5079		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5080	else
5081		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5082	if (r != 0) {
5083		switch (scf_error()) {
5084		case SCF_ERROR_CONNECTION_BROKEN:
5085			r = scferror2errno(scf_error());
5086			goto out;
5087
5088		case SCF_ERROR_DELETED:
5089			if (running != NULL)
5090				r = ENODEV;
5091			else
5092				r = ECANCELED;
5093			goto out;
5094
5095		case SCF_ERROR_NOT_FOUND:
5096			break;
5097
5098		case SCF_ERROR_INVALID_ARGUMENT:
5099		case SCF_ERROR_HANDLE_MISMATCH:
5100		case SCF_ERROR_NOT_BOUND:
5101		case SCF_ERROR_NOT_SET:
5102		default:
5103			bad_error("entity_get_pg", scf_error());
5104		}
5105
5106		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5107
5108		r = 0;
5109		goto out;
5110	}
5111
5112	r = load_pg_attrs(imp_pg2, &curpg_i);
5113	switch (r) {
5114	case 0:
5115		break;
5116
5117	case ECANCELED:
5118		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5119		r = 0;
5120		goto out;
5121
5122	case ECONNABORTED:
5123	case ENOMEM:
5124		goto out;
5125
5126	default:
5127		bad_error("load_pg_attrs", r);
5128	}
5129
5130	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5131		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5132		internal_pgroup_free(curpg_i);
5133		r = 0;
5134		goto out;
5135	}
5136
5137	internal_pgroup_free(curpg_i);
5138
5139	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5140	switch (r) {
5141	case 0:
5142		break;
5143
5144	case ECANCELED:
5145		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5146		r = 0;
5147		goto out;
5148
5149	case ECONNABORTED:
5150	case EBADF:
5151	case ENOMEM:
5152	case EACCES:
5153		goto out;
5154
5155	default:
5156		bad_error("load_pg", r);
5157	}
5158
5159	if (pg_equal(lipg_i, curpg_i) &&
5160	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5161		int do_delete = 1;
5162
5163		if (g_verbose)
5164			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5165			    ient->sc_fmri, mpg->sc_pgroup_name);
5166
5167		internal_pgroup_free(curpg_i);
5168
5169		if (running != NULL &&
5170		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5171			switch (scf_error()) {
5172			case SCF_ERROR_DELETED:
5173				r = ECANCELED;
5174				goto out;
5175
5176			case SCF_ERROR_NOT_FOUND:
5177				do_delete = 0;
5178				break;
5179
5180			case SCF_ERROR_CONNECTION_BROKEN:
5181				r = scferror2errno(scf_error());
5182				goto out;
5183
5184			case SCF_ERROR_HANDLE_MISMATCH:
5185			case SCF_ERROR_INVALID_ARGUMENT:
5186			case SCF_ERROR_NOT_SET:
5187			case SCF_ERROR_NOT_BOUND:
5188			default:
5189				bad_error("entity_get_pg", scf_error());
5190			}
5191		}
5192
5193		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5194			switch (scf_error()) {
5195			case SCF_ERROR_DELETED:
5196				break;
5197
5198			case SCF_ERROR_CONNECTION_BROKEN:
5199			case SCF_ERROR_BACKEND_READONLY:
5200			case SCF_ERROR_BACKEND_ACCESS:
5201				r = scferror2errno(scf_error());
5202				goto out;
5203
5204			case SCF_ERROR_PERMISSION_DENIED:
5205				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5206				    ient->sc_fmri);
5207				r = scferror2errno(scf_error());
5208				goto out;
5209
5210			case SCF_ERROR_NOT_SET:
5211			case SCF_ERROR_NOT_BOUND:
5212			default:
5213				bad_error("scf_pg_delete", scf_error());
5214			}
5215		}
5216
5217		cbdata.sc_handle = g_hndl;
5218		cbdata.sc_parent = ent;
5219		cbdata.sc_service = issvc;
5220		cbdata.sc_flags = 0;
5221		cbdata.sc_source_fmri = ient->sc_fmri;
5222		cbdata.sc_target_fmri = ient->sc_fmri;
5223
5224		r = entity_pgroup_import(mpg, &cbdata);
5225		switch (r) {
5226		case UU_WALK_NEXT:
5227			r = 0;
5228			goto out;
5229
5230		case UU_WALK_ERROR:
5231			if (cbdata.sc_err == EEXIST) {
5232				warn(emsg_pg_added, ient->sc_fmri,
5233				    mpg->sc_pgroup_name);
5234				r = EBUSY;
5235			} else {
5236				r = cbdata.sc_err;
5237			}
5238			goto out;
5239
5240		default:
5241			bad_error("entity_pgroup_import", r);
5242		}
5243	}
5244
5245	if (running != NULL &&
5246	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5247		switch (scf_error()) {
5248		case SCF_ERROR_CONNECTION_BROKEN:
5249		case SCF_ERROR_DELETED:
5250			r = scferror2errno(scf_error());
5251			goto out;
5252
5253		case SCF_ERROR_NOT_FOUND:
5254			break;
5255
5256		case SCF_ERROR_HANDLE_MISMATCH:
5257		case SCF_ERROR_INVALID_ARGUMENT:
5258		case SCF_ERROR_NOT_SET:
5259		case SCF_ERROR_NOT_BOUND:
5260		default:
5261			bad_error("entity_get_pg", scf_error());
5262		}
5263
5264		cbdata.sc_handle = g_hndl;
5265		cbdata.sc_parent = ent;
5266		cbdata.sc_service = issvc;
5267		cbdata.sc_flags = SCI_FORCE;
5268		cbdata.sc_source_fmri = ient->sc_fmri;
5269		cbdata.sc_target_fmri = ient->sc_fmri;
5270
5271		r = entity_pgroup_import(mpg, &cbdata);
5272		switch (r) {
5273		case UU_WALK_NEXT:
5274			r = 0;
5275			goto out;
5276
5277		case UU_WALK_ERROR:
5278			if (cbdata.sc_err == EEXIST) {
5279				warn(emsg_pg_added, ient->sc_fmri,
5280				    mpg->sc_pgroup_name);
5281				r = EBUSY;
5282			} else {
5283				r = cbdata.sc_err;
5284			}
5285			goto out;
5286
5287		default:
5288			bad_error("entity_pgroup_import", r);
5289		}
5290	}
5291
5292	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5293	internal_pgroup_free(curpg_i);
5294	switch (r) {
5295	case 0:
5296		ient->sc_import_state = IMPORT_PROP_BEGUN;
5297		break;
5298
5299	case ECANCELED:
5300		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5301		r = EBUSY;
5302		break;
5303
5304	case EPERM:
5305		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5306		break;
5307
5308	case EBUSY:
5309		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5310		break;
5311
5312	case ECONNABORTED:
5313	case ENOMEM:
5314	case ENOSPC:
5315	case EROFS:
5316	case EACCES:
5317	case EINVAL:
5318		break;
5319
5320	default:
5321		bad_error("upgrade_pg", r);
5322	}
5323
5324out:
5325	internal_pgroup_free(lipg_i);
5326	return (r);
5327}
5328
5329/*
5330 * Upgrade the properties of ent according to snpl & ient.
5331 *
5332 * Returns
5333 *   0 - success
5334 *   ECONNABORTED - repository connection broken
5335 *   ENOMEM - out of memory
5336 *   ENOSPC - configd is out of resources
5337 *   ECANCELED - ent was deleted
5338 *   ENODEV - entity containing snpl was deleted
5339 *	    - entity containing running was deleted
5340 *   EBADF - imp_snpl is corrupt (error printed)
5341 *	   - ent has corrupt pg (error printed)
5342 *	   - dependent has corrupt pg (error printed)
5343 *	   - dependent target has a corrupt snapshot (error printed)
5344 *   EBUSY - pg was added, changed, or deleted (error printed)
5345 *	   - dependent target was deleted (error printed)
5346 *	   - dependent pg changed (error printed)
5347 *   EINVAL - invalid property group name (error printed)
5348 *	    - invalid property name (error printed)
5349 *	    - invalid value (error printed)
5350 *	    - ient has invalid pgroup or dependent (error printed)
5351 *   EPERM - could not create property group (permission denied) (error printed)
5352 *	   - could not modify property group (permission denied) (error printed)
5353 *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5354 *   EROFS - could not create property group (repository read-only)
5355 *	   - couldn't delete, upgrade, or import pg or dependent
5356 *   EACCES - could not create property group (backend access denied)
5357 *	    - couldn't delete, upgrade, or import pg or dependent
5358 *   EEXIST - dependent collision in target service (error printed)
5359 */
5360static int
5361upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5362    entity_t *ient)
5363{
5364	pgroup_t *pg, *rpg;
5365	int r;
5366	uu_list_t *pgs = ient->sc_pgroups;
5367
5368	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5369
5370	/* clear sc_sceen for pgs */
5371	if (uu_list_walk(pgs, clear_int,
5372	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5373		bad_error("uu_list_walk", uu_error());
5374
5375	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5376		switch (scf_error()) {
5377		case SCF_ERROR_DELETED:
5378			return (ENODEV);
5379
5380		case SCF_ERROR_CONNECTION_BROKEN:
5381			return (ECONNABORTED);
5382
5383		case SCF_ERROR_NOT_SET:
5384		case SCF_ERROR_NOT_BOUND:
5385		case SCF_ERROR_HANDLE_MISMATCH:
5386		default:
5387			bad_error("scf_iter_snaplevel_pgs", scf_error());
5388		}
5389	}
5390
5391	for (;;) {
5392		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5393		if (r == 0)
5394			break;
5395		if (r == 1) {
5396			r = process_old_pg(imp_pg, ient, ent, running);
5397			switch (r) {
5398			case 0:
5399				break;
5400
5401			case ECONNABORTED:
5402			case ENOMEM:
5403			case ENOSPC:
5404			case ECANCELED:
5405			case ENODEV:
5406			case EPERM:
5407			case EROFS:
5408			case EACCES:
5409			case EBADF:
5410			case EBUSY:
5411			case EINVAL:
5412			case EEXIST:
5413				return (r);
5414
5415			default:
5416				bad_error("process_old_pg", r);
5417			}
5418			continue;
5419		}
5420		if (r != -1)
5421			bad_error("scf_iter_next_pg", r);
5422
5423		switch (scf_error()) {
5424		case SCF_ERROR_DELETED:
5425			return (ENODEV);
5426
5427		case SCF_ERROR_CONNECTION_BROKEN:
5428			return (ECONNABORTED);
5429
5430		case SCF_ERROR_HANDLE_MISMATCH:
5431		case SCF_ERROR_NOT_BOUND:
5432		case SCF_ERROR_NOT_SET:
5433		case SCF_ERROR_INVALID_ARGUMENT:
5434		default:
5435			bad_error("scf_iter_next_pg", scf_error());
5436		}
5437	}
5438
5439	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5440		if (pg->sc_pgroup_seen)
5441			continue;
5442
5443		/* pg is new */
5444
5445		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5446			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5447			    ent);
5448			switch (r) {
5449			case 0:
5450				break;
5451
5452			case ECONNABORTED:
5453			case ENOMEM:
5454			case ENOSPC:
5455			case ECANCELED:
5456			case ENODEV:
5457			case EBADF:
5458			case EBUSY:
5459			case EINVAL:
5460			case EPERM:
5461			case EROFS:
5462			case EACCES:
5463			case EEXIST:
5464				return (r);
5465
5466			default:
5467				bad_error("upgrade_dependents", r);
5468			}
5469			continue;
5470		}
5471
5472		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
5473			r = upgrade_manifestfiles(pg, ient, running, ent);
5474			switch (r) {
5475			case 0:
5476				break;
5477
5478			case ECONNABORTED:
5479			case ENOMEM:
5480			case ENOSPC:
5481			case ECANCELED:
5482			case ENODEV:
5483			case EBADF:
5484			case EBUSY:
5485			case EINVAL:
5486			case EPERM:
5487			case EROFS:
5488			case EACCES:
5489			case EEXIST:
5490				return (r);
5491
5492			default:
5493				bad_error("upgrade_manifestfiles", r);
5494			}
5495			continue;
5496		}
5497
5498		if (running != NULL) {
5499			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
5500			    imp_pg);
5501		} else {
5502			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
5503			    imp_pg);
5504		}
5505		if (r != 0) {
5506			scf_callback_t cbdata;
5507
5508			switch (scf_error()) {
5509			case SCF_ERROR_NOT_FOUND:
5510				break;
5511
5512			case SCF_ERROR_CONNECTION_BROKEN:
5513				return (scferror2errno(scf_error()));
5514
5515			case SCF_ERROR_DELETED:
5516				if (running != NULL)
5517					return (ENODEV);
5518				else
5519					return (scferror2errno(scf_error()));
5520
5521			case SCF_ERROR_INVALID_ARGUMENT:
5522				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
5523				    pg->sc_pgroup_name);
5524				return (EINVAL);
5525
5526			case SCF_ERROR_NOT_SET:
5527			case SCF_ERROR_HANDLE_MISMATCH:
5528			case SCF_ERROR_NOT_BOUND:
5529			default:
5530				bad_error("entity_get_pg", scf_error());
5531			}
5532
5533			/* User doesn't have pg, so import it. */
5534
5535			cbdata.sc_handle = g_hndl;
5536			cbdata.sc_parent = ent;
5537			cbdata.sc_service = issvc;
5538			cbdata.sc_flags = SCI_FORCE;
5539			cbdata.sc_source_fmri = ient->sc_fmri;
5540			cbdata.sc_target_fmri = ient->sc_fmri;
5541
5542			r = entity_pgroup_import(pg, &cbdata);
5543			switch (r) {
5544			case UU_WALK_NEXT:
5545				ient->sc_import_state = IMPORT_PROP_BEGUN;
5546				continue;
5547
5548			case UU_WALK_ERROR:
5549				if (cbdata.sc_err == EEXIST) {
5550					warn(emsg_pg_added, ient->sc_fmri,
5551					    pg->sc_pgroup_name);
5552					return (EBUSY);
5553				}
5554				return (cbdata.sc_err);
5555
5556			default:
5557				bad_error("entity_pgroup_import", r);
5558			}
5559		}
5560
5561		/* report differences between pg & current */
5562		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
5563		switch (r) {
5564		case 0:
5565			break;
5566
5567		case ECANCELED:
5568			warn(emsg_pg_deleted, ient->sc_fmri,
5569			    pg->sc_pgroup_name);
5570			return (EBUSY);
5571
5572		case ECONNABORTED:
5573		case EBADF:
5574		case ENOMEM:
5575		case EACCES:
5576			return (r);
5577
5578		default:
5579			bad_error("load_pg", r);
5580		}
5581		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
5582		internal_pgroup_free(rpg);
5583		rpg = NULL;
5584	}
5585
5586	return (0);
5587}
5588
5589/*
5590 * Import an instance.  If it doesn't exist, create it.  If it has
5591 * a last-import snapshot, upgrade its properties.  Finish by updating its
5592 * last-import snapshot.  If it doesn't have a last-import snapshot then it
5593 * could have been created for a dependent tag in another manifest.  Import the
5594 * new properties.  If there's a conflict, don't override, like now?
5595 *
5596 * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
5597 * lcbdata->sc_err to
5598 *   ECONNABORTED - repository connection broken
5599 *   ENOMEM - out of memory
5600 *   ENOSPC - svc.configd is out of resources
5601 *   EEXIST - dependency collision in dependent service (error printed)
5602 *   EPERM - couldn't create temporary instance (permission denied)
5603 *	   - couldn't import into temporary instance (permission denied)
5604 *	   - couldn't take snapshot (permission denied)
5605 *	   - couldn't upgrade properties (permission denied)
5606 *	   - couldn't import properties (permission denied)
5607 *	   - couldn't import dependents (permission denied)
5608 *   EROFS - couldn't create temporary instance (repository read-only)
5609 *	   - couldn't import into temporary instance (repository read-only)
5610 *	   - couldn't upgrade properties (repository read-only)
5611 *	   - couldn't import properties (repository read-only)
5612 *	   - couldn't import dependents (repository read-only)
5613 *   EACCES - couldn't create temporary instance (backend access denied)
5614 *	    - couldn't import into temporary instance (backend access denied)
5615 *	    - couldn't upgrade properties (backend access denied)
5616 *	    - couldn't import properties (backend access denied)
5617 *	    - couldn't import dependents (backend access denied)
5618 *   EINVAL - invalid instance name (error printed)
5619 *	    - invalid pgroup_t's (error printed)
5620 *	    - invalid dependents (error printed)
5621 *   EBUSY - temporary service deleted (error printed)
5622 *	   - temporary instance deleted (error printed)
5623 *	   - temporary instance changed (error printed)
5624 *	   - temporary instance already exists (error printed)
5625 *	   - instance deleted (error printed)
5626 *   EBADF - instance has corrupt last-import snapshot (error printed)
5627 *	   - instance is corrupt (error printed)
5628 *	   - dependent has corrupt pg (error printed)
5629 *	   - dependent target has a corrupt snapshot (error printed)
5630 *   -1 - unknown libscf error (error printed)
5631 */
5632static int
5633lscf_instance_import(void *v, void *pvt)
5634{
5635	entity_t *inst = v;
5636	scf_callback_t ctx;
5637	scf_callback_t *lcbdata = pvt;
5638	scf_service_t *rsvc = lcbdata->sc_parent;
5639	int r;
5640	scf_snaplevel_t *running;
5641	int flags = lcbdata->sc_flags;
5642
5643	const char * const emsg_tdel =
5644	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
5645	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
5646	    "changed unexpectedly.\n");
5647	const char * const emsg_del = gettext("%s changed unexpectedly "
5648	    "(instance \"%s\" was deleted.)\n");
5649	const char * const emsg_badsnap = gettext(
5650	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
5651
5652	/*
5653	 * prepare last-import snapshot:
5654	 * create temporary instance (service was precreated)
5655	 * populate with properties from bundle
5656	 * take snapshot
5657	 */
5658	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
5659		switch (scf_error()) {
5660		case SCF_ERROR_CONNECTION_BROKEN:
5661		case SCF_ERROR_NO_RESOURCES:
5662		case SCF_ERROR_BACKEND_READONLY:
5663		case SCF_ERROR_BACKEND_ACCESS:
5664			return (stash_scferror(lcbdata));
5665
5666		case SCF_ERROR_EXISTS:
5667			warn(gettext("Temporary service svc:/%s "
5668			    "changed unexpectedly (instance \"%s\" added).\n"),
5669			    imp_tsname, inst->sc_name);
5670			lcbdata->sc_err = EBUSY;
5671			return (UU_WALK_ERROR);
5672
5673		case SCF_ERROR_DELETED:
5674			warn(gettext("Temporary service svc:/%s "
5675			    "was deleted unexpectedly.\n"), imp_tsname);
5676			lcbdata->sc_err = EBUSY;
5677			return (UU_WALK_ERROR);
5678
5679		case SCF_ERROR_INVALID_ARGUMENT:
5680			warn(gettext("Invalid instance name \"%s\".\n"),
5681			    inst->sc_name);
5682			return (stash_scferror(lcbdata));
5683
5684		case SCF_ERROR_PERMISSION_DENIED:
5685			warn(gettext("Could not create temporary instance "
5686			    "\"%s\" in svc:/%s (permission denied).\n"),
5687			    inst->sc_name, imp_tsname);
5688			return (stash_scferror(lcbdata));
5689
5690		case SCF_ERROR_HANDLE_MISMATCH:
5691		case SCF_ERROR_NOT_BOUND:
5692		case SCF_ERROR_NOT_SET:
5693		default:
5694			bad_error("scf_service_add_instance", scf_error());
5695		}
5696	}
5697
5698	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5699	    inst->sc_name);
5700	if (r < 0)
5701		bad_error("snprintf", errno);
5702
5703	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
5704	    lcbdata->sc_flags | SCI_NOENABLED);
5705	switch (r) {
5706	case 0:
5707		break;
5708
5709	case ECANCELED:
5710		warn(emsg_tdel, imp_tsname, inst->sc_name);
5711		lcbdata->sc_err = EBUSY;
5712		r = UU_WALK_ERROR;
5713		goto deltemp;
5714
5715	case EEXIST:
5716		warn(emsg_tchg, imp_tsname, inst->sc_name);
5717		lcbdata->sc_err = EBUSY;
5718		r = UU_WALK_ERROR;
5719		goto deltemp;
5720
5721	case ECONNABORTED:
5722		goto connaborted;
5723
5724	case ENOMEM:
5725	case ENOSPC:
5726	case EPERM:
5727	case EROFS:
5728	case EACCES:
5729	case EINVAL:
5730	case EBUSY:
5731		lcbdata->sc_err = r;
5732		r = UU_WALK_ERROR;
5733		goto deltemp;
5734
5735	default:
5736		bad_error("lscf_import_instance_pgs", r);
5737	}
5738
5739	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5740	    inst->sc_name);
5741	if (r < 0)
5742		bad_error("snprintf", errno);
5743
5744	ctx.sc_handle = lcbdata->sc_handle;
5745	ctx.sc_parent = imp_tinst;
5746	ctx.sc_service = 0;
5747	ctx.sc_source_fmri = inst->sc_fmri;
5748	ctx.sc_target_fmri = imp_str;
5749	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
5750	    UU_DEFAULT) != 0) {
5751		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5752			bad_error("uu_list_walk", uu_error());
5753
5754		switch (ctx.sc_err) {
5755		case ECONNABORTED:
5756			goto connaborted;
5757
5758		case ECANCELED:
5759			warn(emsg_tdel, imp_tsname, inst->sc_name);
5760			lcbdata->sc_err = EBUSY;
5761			break;
5762
5763		case EEXIST:
5764			warn(emsg_tchg, imp_tsname, inst->sc_name);
5765			lcbdata->sc_err = EBUSY;
5766			break;
5767
5768		default:
5769			lcbdata->sc_err = ctx.sc_err;
5770		}
5771		r = UU_WALK_ERROR;
5772		goto deltemp;
5773	}
5774
5775	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
5776	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
5777		switch (scf_error()) {
5778		case SCF_ERROR_CONNECTION_BROKEN:
5779			goto connaborted;
5780
5781		case SCF_ERROR_NO_RESOURCES:
5782			r = stash_scferror(lcbdata);
5783			goto deltemp;
5784
5785		case SCF_ERROR_EXISTS:
5786			warn(emsg_tchg, imp_tsname, inst->sc_name);
5787			lcbdata->sc_err = EBUSY;
5788			r = UU_WALK_ERROR;
5789			goto deltemp;
5790
5791		case SCF_ERROR_PERMISSION_DENIED:
5792			warn(gettext("Could not take \"%s\" snapshot of %s "
5793			    "(permission denied).\n"), snap_lastimport,
5794			    imp_str);
5795			r = stash_scferror(lcbdata);
5796			goto deltemp;
5797
5798		default:
5799			scfwarn();
5800			lcbdata->sc_err = -1;
5801			r = UU_WALK_ERROR;
5802			goto deltemp;
5803
5804		case SCF_ERROR_HANDLE_MISMATCH:
5805		case SCF_ERROR_INVALID_ARGUMENT:
5806		case SCF_ERROR_NOT_SET:
5807			bad_error("_scf_snapshot_take_new_named", scf_error());
5808		}
5809	}
5810
5811	if (lcbdata->sc_flags & SCI_FRESH)
5812		goto fresh;
5813
5814	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
5815		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
5816		    imp_lisnap) != 0) {
5817			switch (scf_error()) {
5818			case SCF_ERROR_DELETED:
5819				warn(emsg_del, inst->sc_parent->sc_fmri,
5820				    inst->sc_name);
5821				lcbdata->sc_err = EBUSY;
5822				r = UU_WALK_ERROR;
5823				goto deltemp;
5824
5825			case SCF_ERROR_NOT_FOUND:
5826				flags |= SCI_FORCE;
5827				goto nosnap;
5828
5829			case SCF_ERROR_CONNECTION_BROKEN:
5830				goto connaborted;
5831
5832			case SCF_ERROR_INVALID_ARGUMENT:
5833			case SCF_ERROR_HANDLE_MISMATCH:
5834			case SCF_ERROR_NOT_BOUND:
5835			case SCF_ERROR_NOT_SET:
5836			default:
5837				bad_error("scf_instance_get_snapshot",
5838				    scf_error());
5839			}
5840		}
5841
5842		/* upgrade */
5843
5844		/*
5845		 * compare new properties with last-import properties
5846		 * upgrade current properties
5847		 */
5848		/* clear sc_sceen for pgs */
5849		if (uu_list_walk(inst->sc_pgroups, clear_int,
5850		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
5851		    0)
5852			bad_error("uu_list_walk", uu_error());
5853
5854		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
5855		switch (r) {
5856		case 0:
5857			break;
5858
5859		case ECONNABORTED:
5860			goto connaborted;
5861
5862		case ECANCELED:
5863			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5864			lcbdata->sc_err = EBUSY;
5865			r = UU_WALK_ERROR;
5866			goto deltemp;
5867
5868		case ENOENT:
5869			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
5870			lcbdata->sc_err = EBADF;
5871			r = UU_WALK_ERROR;
5872			goto deltemp;
5873
5874		default:
5875			bad_error("get_snaplevel", r);
5876		}
5877
5878		if (scf_instance_get_snapshot(imp_inst, snap_running,
5879		    imp_rsnap) != 0) {
5880			switch (scf_error()) {
5881			case SCF_ERROR_DELETED:
5882				warn(emsg_del, inst->sc_parent->sc_fmri,
5883				    inst->sc_name);
5884				lcbdata->sc_err = EBUSY;
5885				r = UU_WALK_ERROR;
5886				goto deltemp;
5887
5888			case SCF_ERROR_NOT_FOUND:
5889				break;
5890
5891			case SCF_ERROR_CONNECTION_BROKEN:
5892				goto connaborted;
5893
5894			case SCF_ERROR_INVALID_ARGUMENT:
5895			case SCF_ERROR_HANDLE_MISMATCH:
5896			case SCF_ERROR_NOT_BOUND:
5897			case SCF_ERROR_NOT_SET:
5898			default:
5899				bad_error("scf_instance_get_snapshot",
5900				    scf_error());
5901			}
5902
5903			running = NULL;
5904		} else {
5905			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
5906			switch (r) {
5907			case 0:
5908				running = imp_rsnpl;
5909				break;
5910
5911			case ECONNABORTED:
5912				goto connaborted;
5913
5914			case ECANCELED:
5915				warn(emsg_del, inst->sc_parent->sc_fmri,
5916				    inst->sc_name);
5917				lcbdata->sc_err = EBUSY;
5918				r = UU_WALK_ERROR;
5919				goto deltemp;
5920
5921			case ENOENT:
5922				warn(emsg_badsnap, snap_running, inst->sc_fmri);
5923				lcbdata->sc_err = EBADF;
5924				r = UU_WALK_ERROR;
5925				goto deltemp;
5926
5927			default:
5928				bad_error("get_snaplevel", r);
5929			}
5930		}
5931
5932		r = upgrade_props(imp_inst, running, imp_snpl, inst);
5933		switch (r) {
5934		case 0:
5935			break;
5936
5937		case ECANCELED:
5938		case ENODEV:
5939			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5940			lcbdata->sc_err = EBUSY;
5941			r = UU_WALK_ERROR;
5942			goto deltemp;
5943
5944		case ECONNABORTED:
5945			goto connaborted;
5946
5947		case ENOMEM:
5948		case ENOSPC:
5949		case EBADF:
5950		case EBUSY:
5951		case EINVAL:
5952		case EPERM:
5953		case EROFS:
5954		case EACCES:
5955		case EEXIST:
5956			lcbdata->sc_err = r;
5957			r = UU_WALK_ERROR;
5958			goto deltemp;
5959
5960		default:
5961			bad_error("upgrade_props", r);
5962		}
5963
5964		inst->sc_import_state = IMPORT_PROP_DONE;
5965	} else {
5966		switch (scf_error()) {
5967		case SCF_ERROR_CONNECTION_BROKEN:
5968			goto connaborted;
5969
5970		case SCF_ERROR_NOT_FOUND:
5971			break;
5972
5973		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
5974		case SCF_ERROR_HANDLE_MISMATCH:
5975		case SCF_ERROR_NOT_BOUND:
5976		case SCF_ERROR_NOT_SET:
5977		default:
5978			bad_error("scf_service_get_instance", scf_error());
5979		}
5980
5981fresh:
5982		/* create instance */
5983		if (scf_service_add_instance(rsvc, inst->sc_name,
5984		    imp_inst) != 0) {
5985			switch (scf_error()) {
5986			case SCF_ERROR_CONNECTION_BROKEN:
5987				goto connaborted;
5988
5989			case SCF_ERROR_NO_RESOURCES:
5990			case SCF_ERROR_BACKEND_READONLY:
5991			case SCF_ERROR_BACKEND_ACCESS:
5992				r = stash_scferror(lcbdata);
5993				goto deltemp;
5994
5995			case SCF_ERROR_EXISTS:
5996				warn(gettext("%s changed unexpectedly "
5997				    "(instance \"%s\" added).\n"),
5998				    inst->sc_parent->sc_fmri, inst->sc_name);
5999				lcbdata->sc_err = EBUSY;
6000				r = UU_WALK_ERROR;
6001				goto deltemp;
6002
6003			case SCF_ERROR_PERMISSION_DENIED:
6004				warn(gettext("Could not create \"%s\" instance "
6005				    "in %s (permission denied).\n"),
6006				    inst->sc_name, inst->sc_parent->sc_fmri);
6007				r = stash_scferror(lcbdata);
6008				goto deltemp;
6009
6010			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6011			case SCF_ERROR_HANDLE_MISMATCH:
6012			case SCF_ERROR_NOT_BOUND:
6013			case SCF_ERROR_NOT_SET:
6014			default:
6015				bad_error("scf_service_add_instance",
6016				    scf_error());
6017			}
6018		}
6019
6020nosnap:
6021		/*
6022		 * Create a last-import snapshot to serve as an attachment
6023		 * point for the real one from the temporary instance.  Since
6024		 * the contents is irrelevant, take it now, while the instance
6025		 * is empty, to minimize svc.configd's work.
6026		 */
6027		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6028		    imp_lisnap) != 0) {
6029			switch (scf_error()) {
6030			case SCF_ERROR_CONNECTION_BROKEN:
6031				goto connaborted;
6032
6033			case SCF_ERROR_NO_RESOURCES:
6034				r = stash_scferror(lcbdata);
6035				goto deltemp;
6036
6037			case SCF_ERROR_EXISTS:
6038				warn(gettext("%s changed unexpectedly "
6039				    "(snapshot \"%s\" added).\n"),
6040				    inst->sc_fmri, snap_lastimport);
6041				lcbdata->sc_err = EBUSY;
6042				r = UU_WALK_ERROR;
6043				goto deltemp;
6044
6045			case SCF_ERROR_PERMISSION_DENIED:
6046				warn(gettext("Could not take \"%s\" snapshot "
6047				    "of %s (permission denied).\n"),
6048				    snap_lastimport, inst->sc_fmri);
6049				r = stash_scferror(lcbdata);
6050				goto deltemp;
6051
6052			default:
6053				scfwarn();
6054				lcbdata->sc_err = -1;
6055				r = UU_WALK_ERROR;
6056				goto deltemp;
6057
6058			case SCF_ERROR_NOT_SET:
6059			case SCF_ERROR_INTERNAL:
6060			case SCF_ERROR_INVALID_ARGUMENT:
6061			case SCF_ERROR_HANDLE_MISMATCH:
6062				bad_error("_scf_snapshot_take_new",
6063				    scf_error());
6064			}
6065		}
6066
6067		if (li_only)
6068			goto lionly;
6069
6070		inst->sc_import_state = IMPORT_PROP_BEGUN;
6071
6072		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6073		    flags);
6074		switch (r) {
6075		case 0:
6076			break;
6077
6078		case ECONNABORTED:
6079			goto connaborted;
6080
6081		case ECANCELED:
6082			warn(gettext("%s changed unexpectedly "
6083			    "(instance \"%s\" deleted).\n"),
6084			    inst->sc_parent->sc_fmri, inst->sc_name);
6085			lcbdata->sc_err = EBUSY;
6086			r = UU_WALK_ERROR;
6087			goto deltemp;
6088
6089		case EEXIST:
6090			warn(gettext("%s changed unexpectedly "
6091			    "(property group added).\n"), inst->sc_fmri);
6092			lcbdata->sc_err = EBUSY;
6093			r = UU_WALK_ERROR;
6094			goto deltemp;
6095
6096		default:
6097			lcbdata->sc_err = r;
6098			r = UU_WALK_ERROR;
6099			goto deltemp;
6100
6101		case EINVAL:	/* caught above */
6102			bad_error("lscf_import_instance_pgs", r);
6103		}
6104
6105		ctx.sc_parent = imp_inst;
6106		ctx.sc_service = 0;
6107		ctx.sc_trans = NULL;
6108		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6109		    &ctx, UU_DEFAULT) != 0) {
6110			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6111				bad_error("uu_list_walk", uu_error());
6112
6113			if (ctx.sc_err == ECONNABORTED)
6114				goto connaborted;
6115			lcbdata->sc_err = ctx.sc_err;
6116			r = UU_WALK_ERROR;
6117			goto deltemp;
6118		}
6119
6120		inst->sc_import_state = IMPORT_PROP_DONE;
6121
6122		if (g_verbose)
6123			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6124			    snap_initial, inst->sc_fmri);
6125		r = take_snap(imp_inst, snap_initial, imp_snap);
6126		switch (r) {
6127		case 0:
6128			break;
6129
6130		case ECONNABORTED:
6131			goto connaborted;
6132
6133		case ENOSPC:
6134		case -1:
6135			lcbdata->sc_err = r;
6136			r = UU_WALK_ERROR;
6137			goto deltemp;
6138
6139		case ECANCELED:
6140			warn(gettext("%s changed unexpectedly "
6141			    "(instance %s deleted).\n"),
6142			    inst->sc_parent->sc_fmri, inst->sc_name);
6143			lcbdata->sc_err = r;
6144			r = UU_WALK_ERROR;
6145			goto deltemp;
6146
6147		case EPERM:
6148			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6149			lcbdata->sc_err = r;
6150			r = UU_WALK_ERROR;
6151			goto deltemp;
6152
6153		default:
6154			bad_error("take_snap", r);
6155		}
6156	}
6157
6158lionly:
6159	if (lcbdata->sc_flags & SCI_NOSNAP)
6160		goto deltemp;
6161
6162	/* transfer snapshot from temporary instance */
6163	if (g_verbose)
6164		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6165		    snap_lastimport, inst->sc_fmri);
6166	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6167		switch (scf_error()) {
6168		case SCF_ERROR_CONNECTION_BROKEN:
6169			goto connaborted;
6170
6171		case SCF_ERROR_NO_RESOURCES:
6172			r = stash_scferror(lcbdata);
6173			goto deltemp;
6174
6175		case SCF_ERROR_PERMISSION_DENIED:
6176			warn(gettext("Could not take \"%s\" snapshot for %s "
6177			    "(permission denied).\n"), snap_lastimport,
6178			    inst->sc_fmri);
6179			r = stash_scferror(lcbdata);
6180			goto deltemp;
6181
6182		case SCF_ERROR_NOT_SET:
6183		case SCF_ERROR_HANDLE_MISMATCH:
6184		default:
6185			bad_error("_scf_snapshot_attach", scf_error());
6186		}
6187	}
6188
6189	inst->sc_import_state = IMPORT_COMPLETE;
6190
6191	r = UU_WALK_NEXT;
6192
6193deltemp:
6194	/* delete temporary instance */
6195	if (scf_instance_delete(imp_tinst) != 0) {
6196		switch (scf_error()) {
6197		case SCF_ERROR_DELETED:
6198			break;
6199
6200		case SCF_ERROR_CONNECTION_BROKEN:
6201			goto connaborted;
6202
6203		case SCF_ERROR_NOT_SET:
6204		case SCF_ERROR_NOT_BOUND:
6205		default:
6206			bad_error("scf_instance_delete", scf_error());
6207		}
6208	}
6209
6210	return (r);
6211
6212connaborted:
6213	warn(gettext("Could not delete svc:/%s:%s "
6214	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6215	lcbdata->sc_err = ECONNABORTED;
6216	return (UU_WALK_ERROR);
6217}
6218
6219/*
6220 * If the service is missing, create it, import its properties, and import the
6221 * instances.  Since the service is brand new, it should be empty, and if we
6222 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6223 *
6224 * If the service exists, we want to upgrade its properties and import the
6225 * instances.  Upgrade requires a last-import snapshot, though, which are
6226 * children of instances, so first we'll have to go through the instances
6227 * looking for a last-import snapshot.  If we don't find one then we'll just
6228 * override-import the service properties (but don't delete existing
6229 * properties: another service might have declared us as a dependent).  Before
6230 * we change anything, though, we want to take the previous snapshots.  We
6231 * also give lscf_instance_import() a leg up on taking last-import snapshots
6232 * by importing the manifest's service properties into a temporary service.
6233 *
6234 * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6235 * sets lcbdata->sc_err to
6236 *   ECONNABORTED - repository connection broken
6237 *   ENOMEM - out of memory
6238 *   ENOSPC - svc.configd is out of resources
6239 *   EPERM - couldn't create temporary service (error printed)
6240 *	   - couldn't import into temp service (error printed)
6241 *	   - couldn't create service (error printed)
6242 *	   - couldn't import dependent (error printed)
6243 *	   - couldn't take snapshot (error printed)
6244 *	   - couldn't create instance (error printed)
6245 *	   - couldn't create, modify, or delete pg (error printed)
6246 *	   - couldn't create, modify, or delete dependent (error printed)
6247 *	   - couldn't import instance (error printed)
6248 *   EROFS - couldn't create temporary service (repository read-only)
6249 *	   - couldn't import into temporary service (repository read-only)
6250 *	   - couldn't create service (repository read-only)
6251 *	   - couldn't import dependent (repository read-only)
6252 *	   - couldn't create instance (repository read-only)
6253 *	   - couldn't create, modify, or delete pg or dependent
6254 *	   - couldn't import instance (repository read-only)
6255 *   EACCES - couldn't create temporary service (backend access denied)
6256 *	    - couldn't import into temporary service (backend access denied)
6257 *	    - couldn't create service (backend access denied)
6258 *	    - couldn't import dependent (backend access denied)
6259 *	    - couldn't create instance (backend access denied)
6260 *	    - couldn't create, modify, or delete pg or dependent
6261 *	    - couldn't import instance (backend access denied)
6262 *   EINVAL - service name is invalid (error printed)
6263 *	    - service name is too long (error printed)
6264 *	    - s has invalid pgroup (error printed)
6265 *	    - s has invalid dependent (error printed)
6266 *	    - instance name is invalid (error printed)
6267 *	    - instance entity_t is invalid (error printed)
6268 *   EEXIST - couldn't create temporary service (already exists) (error printed)
6269 *	    - couldn't import dependent (dependency pg already exists) (printed)
6270 *	    - dependency collision in dependent service (error printed)
6271 *   EBUSY - temporary service deleted (error printed)
6272 *	   - property group added to temporary service (error printed)
6273 *	   - new property group changed or was deleted (error printed)
6274 *	   - service was added unexpectedly (error printed)
6275 *	   - service was deleted unexpectedly (error printed)
6276 *	   - property group added to new service (error printed)
6277 *	   - instance added unexpectedly (error printed)
6278 *	   - instance deleted unexpectedly (error printed)
6279 *	   - dependent service deleted unexpectedly (error printed)
6280 *	   - pg was added, changed, or deleted (error printed)
6281 *	   - dependent pg changed (error printed)
6282 *	   - temporary instance added, changed, or deleted (error printed)
6283 *   EBADF - a last-import snapshot is corrupt (error printed)
6284 *	   - the service is corrupt (error printed)
6285 *	   - a dependent is corrupt (error printed)
6286 *	   - an instance is corrupt (error printed)
6287 *	   - an instance has a corrupt last-import snapshot (error printed)
6288 *	   - dependent target has a corrupt snapshot (error printed)
6289 *   -1 - unknown libscf error (error printed)
6290 */
6291static int
6292lscf_service_import(void *v, void *pvt)
6293{
6294	entity_t *s = v;
6295	scf_callback_t cbdata;
6296	scf_callback_t *lcbdata = pvt;
6297	scf_scope_t *scope = lcbdata->sc_parent;
6298	entity_t *inst, linst;
6299	int r;
6300	int fresh = 0;
6301	scf_snaplevel_t *running;
6302	int have_ge = 0;
6303
6304	const char * const ts_deleted = gettext("Temporary service svc:/%s "
6305	    "was deleted unexpectedly.\n");
6306	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6307	    "changed unexpectedly (property group added).\n");
6308	const char * const s_deleted =
6309	    gettext("%s was deleted unexpectedly.\n");
6310	const char * const i_deleted =
6311	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6312	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6313	    "is corrupt (missing service snaplevel).\n");
6314
6315	li_only = 0;
6316	/* Validate the service name */
6317	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6318		switch (scf_error()) {
6319		case SCF_ERROR_CONNECTION_BROKEN:
6320			return (stash_scferror(lcbdata));
6321
6322		case SCF_ERROR_INVALID_ARGUMENT:
6323			warn(gettext("\"%s\" is an invalid service name.  "
6324			    "Cannot import.\n"), s->sc_name);
6325			return (stash_scferror(lcbdata));
6326
6327		case SCF_ERROR_NOT_FOUND:
6328			break;
6329
6330		case SCF_ERROR_HANDLE_MISMATCH:
6331		case SCF_ERROR_NOT_BOUND:
6332		case SCF_ERROR_NOT_SET:
6333		default:
6334			bad_error("scf_scope_get_service", scf_error());
6335		}
6336	}
6337
6338	/* create temporary service */
6339	/*
6340	 * the size of the buffer was reduced to max_scf_name_len to prevent
6341	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6342	 * should be restored to its original value (max_scf_name_len +1)
6343	 */
6344	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6345	if (r < 0)
6346		bad_error("snprintf", errno);
6347	if (r > max_scf_name_len) {
6348		warn(gettext(
6349		    "Service name \"%s\" is too long.  Cannot import.\n"),
6350		    s->sc_name);
6351		lcbdata->sc_err = EINVAL;
6352		return (UU_WALK_ERROR);
6353	}
6354
6355	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6356		switch (scf_error()) {
6357		case SCF_ERROR_CONNECTION_BROKEN:
6358		case SCF_ERROR_NO_RESOURCES:
6359		case SCF_ERROR_BACKEND_READONLY:
6360		case SCF_ERROR_BACKEND_ACCESS:
6361			return (stash_scferror(lcbdata));
6362
6363		case SCF_ERROR_EXISTS:
6364			warn(gettext(
6365			    "Temporary service \"%s\" must be deleted before "
6366			    "this manifest can be imported.\n"), imp_tsname);
6367			return (stash_scferror(lcbdata));
6368
6369		case SCF_ERROR_PERMISSION_DENIED:
6370			warn(gettext("Could not create temporary service "
6371			    "\"%s\" (permission denied).\n"), imp_tsname);
6372			return (stash_scferror(lcbdata));
6373
6374		case SCF_ERROR_INVALID_ARGUMENT:
6375		case SCF_ERROR_HANDLE_MISMATCH:
6376		case SCF_ERROR_NOT_BOUND:
6377		case SCF_ERROR_NOT_SET:
6378		default:
6379			bad_error("scf_scope_add_service", scf_error());
6380		}
6381	}
6382
6383	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6384	if (r < 0)
6385		bad_error("snprintf", errno);
6386
6387	cbdata.sc_handle = lcbdata->sc_handle;
6388	cbdata.sc_parent = imp_tsvc;
6389	cbdata.sc_service = 1;
6390	cbdata.sc_source_fmri = s->sc_fmri;
6391	cbdata.sc_target_fmri = imp_str;
6392	cbdata.sc_flags = 0;
6393
6394	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6395	    UU_DEFAULT) != 0) {
6396		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6397			bad_error("uu_list_walk", uu_error());
6398
6399		lcbdata->sc_err = cbdata.sc_err;
6400		switch (cbdata.sc_err) {
6401		case ECONNABORTED:
6402			goto connaborted;
6403
6404		case ECANCELED:
6405			warn(ts_deleted, imp_tsname);
6406			lcbdata->sc_err = EBUSY;
6407			return (UU_WALK_ERROR);
6408
6409		case EEXIST:
6410			warn(ts_pg_added, imp_tsname);
6411			lcbdata->sc_err = EBUSY;
6412			return (UU_WALK_ERROR);
6413		}
6414
6415		r = UU_WALK_ERROR;
6416		goto deltemp;
6417	}
6418
6419	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6420	    UU_DEFAULT) != 0) {
6421		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6422			bad_error("uu_list_walk", uu_error());
6423
6424		lcbdata->sc_err = cbdata.sc_err;
6425		switch (cbdata.sc_err) {
6426		case ECONNABORTED:
6427			goto connaborted;
6428
6429		case ECANCELED:
6430			warn(ts_deleted, imp_tsname);
6431			lcbdata->sc_err = EBUSY;
6432			return (UU_WALK_ERROR);
6433
6434		case EEXIST:
6435			warn(ts_pg_added, imp_tsname);
6436			lcbdata->sc_err = EBUSY;
6437			return (UU_WALK_ERROR);
6438		}
6439
6440		r = UU_WALK_ERROR;
6441		goto deltemp;
6442	}
6443
6444	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6445		switch (scf_error()) {
6446		case SCF_ERROR_NOT_FOUND:
6447			break;
6448
6449		case SCF_ERROR_CONNECTION_BROKEN:
6450			goto connaborted;
6451
6452		case SCF_ERROR_INVALID_ARGUMENT:
6453		case SCF_ERROR_HANDLE_MISMATCH:
6454		case SCF_ERROR_NOT_BOUND:
6455		case SCF_ERROR_NOT_SET:
6456		default:
6457			bad_error("scf_scope_get_service", scf_error());
6458		}
6459
6460		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6461			switch (scf_error()) {
6462			case SCF_ERROR_CONNECTION_BROKEN:
6463				goto connaborted;
6464
6465			case SCF_ERROR_NO_RESOURCES:
6466			case SCF_ERROR_BACKEND_READONLY:
6467			case SCF_ERROR_BACKEND_ACCESS:
6468				r = stash_scferror(lcbdata);
6469				goto deltemp;
6470
6471			case SCF_ERROR_EXISTS:
6472				warn(gettext("Scope \"%s\" changed unexpectedly"
6473				    " (service \"%s\" added).\n"),
6474				    SCF_SCOPE_LOCAL, s->sc_name);
6475				lcbdata->sc_err = EBUSY;
6476				goto deltemp;
6477
6478			case SCF_ERROR_PERMISSION_DENIED:
6479				warn(gettext("Could not create service \"%s\" "
6480				    "(permission denied).\n"), s->sc_name);
6481				goto deltemp;
6482
6483			case SCF_ERROR_INVALID_ARGUMENT:
6484			case SCF_ERROR_HANDLE_MISMATCH:
6485			case SCF_ERROR_NOT_BOUND:
6486			case SCF_ERROR_NOT_SET:
6487			default:
6488				bad_error("scf_scope_add_service", scf_error());
6489			}
6490		}
6491
6492		s->sc_import_state = IMPORT_PROP_BEGUN;
6493
6494		/* import service properties */
6495		cbdata.sc_handle = lcbdata->sc_handle;
6496		cbdata.sc_parent = imp_svc;
6497		cbdata.sc_service = 1;
6498		cbdata.sc_flags = lcbdata->sc_flags;
6499		cbdata.sc_source_fmri = s->sc_fmri;
6500		cbdata.sc_target_fmri = s->sc_fmri;
6501
6502		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6503		    &cbdata, UU_DEFAULT) != 0) {
6504			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6505				bad_error("uu_list_walk", uu_error());
6506
6507			lcbdata->sc_err = cbdata.sc_err;
6508			switch (cbdata.sc_err) {
6509			case ECONNABORTED:
6510				goto connaborted;
6511
6512			case ECANCELED:
6513				warn(s_deleted, s->sc_fmri);
6514				lcbdata->sc_err = EBUSY;
6515				return (UU_WALK_ERROR);
6516
6517			case EEXIST:
6518				warn(gettext("%s changed unexpectedly "
6519				    "(property group added).\n"), s->sc_fmri);
6520				lcbdata->sc_err = EBUSY;
6521				return (UU_WALK_ERROR);
6522
6523			case EINVAL:
6524				/* caught above */
6525				bad_error("entity_pgroup_import",
6526				    cbdata.sc_err);
6527			}
6528
6529			r = UU_WALK_ERROR;
6530			goto deltemp;
6531		}
6532
6533		cbdata.sc_trans = NULL;
6534		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
6535		    &cbdata, UU_DEFAULT) != 0) {
6536			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6537				bad_error("uu_list_walk", uu_error());
6538
6539			lcbdata->sc_err = cbdata.sc_err;
6540			if (cbdata.sc_err == ECONNABORTED)
6541				goto connaborted;
6542			r = UU_WALK_ERROR;
6543			goto deltemp;
6544		}
6545
6546		s->sc_import_state = IMPORT_PROP_DONE;
6547
6548		/*
6549		 * This is a new service, so we can't take previous snapshots
6550		 * or upgrade service properties.
6551		 */
6552		fresh = 1;
6553		goto instances;
6554	}
6555
6556	/* Clear sc_seen for the instances. */
6557	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
6558	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
6559		bad_error("uu_list_walk", uu_error());
6560
6561	/*
6562	 * Take previous snapshots for all instances.  Even for ones not
6563	 * mentioned in the bundle, since we might change their service
6564	 * properties.
6565	 */
6566	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6567		switch (scf_error()) {
6568		case SCF_ERROR_CONNECTION_BROKEN:
6569			goto connaborted;
6570
6571		case SCF_ERROR_DELETED:
6572			warn(s_deleted, s->sc_fmri);
6573			lcbdata->sc_err = EBUSY;
6574			r = UU_WALK_ERROR;
6575			goto deltemp;
6576
6577		case SCF_ERROR_HANDLE_MISMATCH:
6578		case SCF_ERROR_NOT_BOUND:
6579		case SCF_ERROR_NOT_SET:
6580		default:
6581			bad_error("scf_iter_service_instances", scf_error());
6582		}
6583	}
6584
6585	for (;;) {
6586		r = scf_iter_next_instance(imp_iter, imp_inst);
6587		if (r == 0)
6588			break;
6589		if (r != 1) {
6590			switch (scf_error()) {
6591			case SCF_ERROR_DELETED:
6592				warn(s_deleted, s->sc_fmri);
6593				lcbdata->sc_err = EBUSY;
6594				r = UU_WALK_ERROR;
6595				goto deltemp;
6596
6597			case SCF_ERROR_CONNECTION_BROKEN:
6598				goto connaborted;
6599
6600			case SCF_ERROR_NOT_BOUND:
6601			case SCF_ERROR_HANDLE_MISMATCH:
6602			case SCF_ERROR_INVALID_ARGUMENT:
6603			case SCF_ERROR_NOT_SET:
6604			default:
6605				bad_error("scf_iter_next_instance",
6606				    scf_error());
6607			}
6608		}
6609
6610		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
6611			switch (scf_error()) {
6612			case SCF_ERROR_DELETED:
6613				continue;
6614
6615			case SCF_ERROR_CONNECTION_BROKEN:
6616				goto connaborted;
6617
6618			case SCF_ERROR_NOT_SET:
6619			case SCF_ERROR_NOT_BOUND:
6620			default:
6621				bad_error("scf_instance_get_name", scf_error());
6622			}
6623		}
6624
6625		if (g_verbose)
6626			warn(gettext(
6627			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
6628			    snap_previous, s->sc_name, imp_str);
6629
6630		r = take_snap(imp_inst, snap_previous, imp_snap);
6631		switch (r) {
6632		case 0:
6633			break;
6634
6635		case ECANCELED:
6636			continue;
6637
6638		case ECONNABORTED:
6639			goto connaborted;
6640
6641		case EPERM:
6642			warn(gettext("Could not take \"%s\" snapshot of "
6643			    "svc:/%s:%s (permission denied).\n"),
6644			    snap_previous, s->sc_name, imp_str);
6645			lcbdata->sc_err = r;
6646			return (UU_WALK_ERROR);
6647
6648		case ENOSPC:
6649		case -1:
6650			lcbdata->sc_err = r;
6651			r = UU_WALK_ERROR;
6652			goto deltemp;
6653
6654		default:
6655			bad_error("take_snap", r);
6656		}
6657
6658		linst.sc_name = imp_str;
6659		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
6660		    &linst, NULL, NULL);
6661		if (inst != NULL) {
6662			inst->sc_import_state = IMPORT_PREVIOUS;
6663			inst->sc_seen = 1;
6664		}
6665	}
6666
6667	/*
6668	 * Create the new instances and take previous snapshots of
6669	 * them.  This is not necessary, but it maximizes data preservation.
6670	 */
6671	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
6672	    inst != NULL;
6673	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
6674	    inst)) {
6675		if (inst->sc_seen)
6676			continue;
6677
6678		if (scf_service_add_instance(imp_svc, inst->sc_name,
6679		    imp_inst) != 0) {
6680			switch (scf_error()) {
6681			case SCF_ERROR_CONNECTION_BROKEN:
6682				goto connaborted;
6683
6684			case SCF_ERROR_BACKEND_READONLY:
6685			case SCF_ERROR_BACKEND_ACCESS:
6686			case SCF_ERROR_NO_RESOURCES:
6687				r = stash_scferror(lcbdata);
6688				goto deltemp;
6689
6690			case SCF_ERROR_EXISTS:
6691				warn(gettext("%s changed unexpectedly "
6692				    "(instance \"%s\" added).\n"), s->sc_fmri,
6693				    inst->sc_name);
6694				lcbdata->sc_err = EBUSY;
6695				r = UU_WALK_ERROR;
6696				goto deltemp;
6697
6698			case SCF_ERROR_INVALID_ARGUMENT:
6699				warn(gettext("Service \"%s\" has instance with "
6700				    "invalid name \"%s\".\n"), s->sc_name,
6701				    inst->sc_name);
6702				r = stash_scferror(lcbdata);
6703				goto deltemp;
6704
6705			case SCF_ERROR_PERMISSION_DENIED:
6706				warn(gettext("Could not create instance \"%s\" "
6707				    "in %s (permission denied).\n"),
6708				    inst->sc_name, s->sc_fmri);
6709				r = stash_scferror(lcbdata);
6710				goto deltemp;
6711
6712			case SCF_ERROR_HANDLE_MISMATCH:
6713			case SCF_ERROR_NOT_BOUND:
6714			case SCF_ERROR_NOT_SET:
6715			default:
6716				bad_error("scf_service_add_instance",
6717				    scf_error());
6718			}
6719		}
6720
6721		if (g_verbose)
6722			warn(gettext("Taking \"%s\" snapshot for "
6723			    "new service %s.\n"), snap_previous, inst->sc_fmri);
6724		r = take_snap(imp_inst, snap_previous, imp_snap);
6725		switch (r) {
6726		case 0:
6727			break;
6728
6729		case ECANCELED:
6730			warn(i_deleted, s->sc_fmri, inst->sc_name);
6731			lcbdata->sc_err = EBUSY;
6732			r = UU_WALK_ERROR;
6733			goto deltemp;
6734
6735		case ECONNABORTED:
6736			goto connaborted;
6737
6738		case EPERM:
6739			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
6740			lcbdata->sc_err = r;
6741			r = UU_WALK_ERROR;
6742			goto deltemp;
6743
6744		case ENOSPC:
6745		case -1:
6746			r = UU_WALK_ERROR;
6747			goto deltemp;
6748
6749		default:
6750			bad_error("take_snap", r);
6751		}
6752	}
6753
6754	s->sc_import_state = IMPORT_PREVIOUS;
6755
6756	/*
6757	 * Upgrade service properties, if we can find a last-import snapshot.
6758	 * Any will do because we don't support different service properties
6759	 * in different manifests, so all snaplevels of the service in all of
6760	 * the last-import snapshots of the instances should be the same.
6761	 */
6762	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6763		switch (scf_error()) {
6764		case SCF_ERROR_CONNECTION_BROKEN:
6765			goto connaborted;
6766
6767		case SCF_ERROR_DELETED:
6768			warn(s_deleted, s->sc_fmri);
6769			lcbdata->sc_err = EBUSY;
6770			r = UU_WALK_ERROR;
6771			goto deltemp;
6772
6773		case SCF_ERROR_HANDLE_MISMATCH:
6774		case SCF_ERROR_NOT_BOUND:
6775		case SCF_ERROR_NOT_SET:
6776		default:
6777			bad_error("scf_iter_service_instances", scf_error());
6778		}
6779	}
6780
6781	for (;;) {
6782		r = scf_iter_next_instance(imp_iter, imp_inst);
6783		if (r == -1) {
6784			switch (scf_error()) {
6785			case SCF_ERROR_DELETED:
6786				warn(s_deleted, s->sc_fmri);
6787				lcbdata->sc_err = EBUSY;
6788				r = UU_WALK_ERROR;
6789				goto deltemp;
6790
6791			case SCF_ERROR_CONNECTION_BROKEN:
6792				goto connaborted;
6793
6794			case SCF_ERROR_NOT_BOUND:
6795			case SCF_ERROR_HANDLE_MISMATCH:
6796			case SCF_ERROR_INVALID_ARGUMENT:
6797			case SCF_ERROR_NOT_SET:
6798			default:
6799				bad_error("scf_iter_next_instance",
6800				    scf_error());
6801			}
6802		}
6803
6804		if (r == 0) {
6805			/*
6806			 * Didn't find any last-import snapshots.  Override-
6807			 * import the properties.  Unless one of the instances
6808			 * has a general/enabled property, in which case we're
6809			 * probably running a last-import-capable svccfg for
6810			 * the first time, and we should only take the
6811			 * last-import snapshot.
6812			 */
6813			if (have_ge) {
6814				li_only = 1;
6815				no_refresh = 1;
6816				break;
6817			}
6818
6819			s->sc_import_state = IMPORT_PROP_BEGUN;
6820
6821			cbdata.sc_handle = g_hndl;
6822			cbdata.sc_parent = imp_svc;
6823			cbdata.sc_service = 1;
6824			cbdata.sc_flags = SCI_FORCE;
6825			cbdata.sc_source_fmri = s->sc_fmri;
6826			cbdata.sc_target_fmri = s->sc_fmri;
6827			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6828			    &cbdata, UU_DEFAULT) != 0) {
6829				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6830					bad_error("uu_list_walk", uu_error());
6831				lcbdata->sc_err = cbdata.sc_err;
6832				switch (cbdata.sc_err) {
6833				case ECONNABORTED:
6834					goto connaborted;
6835
6836				case ECANCELED:
6837					warn(s_deleted, s->sc_fmri);
6838					lcbdata->sc_err = EBUSY;
6839					break;
6840
6841				case EINVAL:	/* caught above */
6842				case EEXIST:
6843					bad_error("entity_pgroup_import",
6844					    cbdata.sc_err);
6845				}
6846
6847				r = UU_WALK_ERROR;
6848				goto deltemp;
6849			}
6850
6851			cbdata.sc_trans = NULL;
6852			if (uu_list_walk(s->sc_dependents,
6853			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
6854				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6855					bad_error("uu_list_walk", uu_error());
6856				lcbdata->sc_err = cbdata.sc_err;
6857				if (cbdata.sc_err == ECONNABORTED)
6858					goto connaborted;
6859				r = UU_WALK_ERROR;
6860				goto deltemp;
6861			}
6862			break;
6863		}
6864
6865		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6866		    imp_snap) != 0) {
6867			switch (scf_error()) {
6868			case SCF_ERROR_DELETED:
6869				continue;
6870
6871			case SCF_ERROR_NOT_FOUND:
6872				break;
6873
6874			case SCF_ERROR_CONNECTION_BROKEN:
6875				goto connaborted;
6876
6877			case SCF_ERROR_HANDLE_MISMATCH:
6878			case SCF_ERROR_NOT_BOUND:
6879			case SCF_ERROR_INVALID_ARGUMENT:
6880			case SCF_ERROR_NOT_SET:
6881			default:
6882				bad_error("scf_instance_get_snapshot",
6883				    scf_error());
6884			}
6885
6886			if (have_ge)
6887				continue;
6888
6889			/*
6890			 * Check for a general/enabled property.  This is how
6891			 * we tell whether to import if there turn out to be
6892			 * no last-import snapshots.
6893			 */
6894			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
6895			    imp_pg) == 0) {
6896				if (scf_pg_get_property(imp_pg,
6897				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
6898					have_ge = 1;
6899				} else {
6900					switch (scf_error()) {
6901					case SCF_ERROR_DELETED:
6902					case SCF_ERROR_NOT_FOUND:
6903						continue;
6904
6905					case SCF_ERROR_INVALID_ARGUMENT:
6906					case SCF_ERROR_HANDLE_MISMATCH:
6907					case SCF_ERROR_CONNECTION_BROKEN:
6908					case SCF_ERROR_NOT_BOUND:
6909					case SCF_ERROR_NOT_SET:
6910					default:
6911						bad_error("scf_pg_get_property",
6912						    scf_error());
6913					}
6914				}
6915			} else {
6916				switch (scf_error()) {
6917				case SCF_ERROR_DELETED:
6918				case SCF_ERROR_NOT_FOUND:
6919					continue;
6920
6921				case SCF_ERROR_CONNECTION_BROKEN:
6922					goto connaborted;
6923
6924				case SCF_ERROR_NOT_BOUND:
6925				case SCF_ERROR_NOT_SET:
6926				case SCF_ERROR_INVALID_ARGUMENT:
6927				case SCF_ERROR_HANDLE_MISMATCH:
6928				default:
6929					bad_error("scf_instance_get_pg",
6930					    scf_error());
6931				}
6932			}
6933			continue;
6934		}
6935
6936		/* find service snaplevel */
6937		r = get_snaplevel(imp_snap, 1, imp_snpl);
6938		switch (r) {
6939		case 0:
6940			break;
6941
6942		case ECONNABORTED:
6943			goto connaborted;
6944
6945		case ECANCELED:
6946			continue;
6947
6948		case ENOENT:
6949			if (scf_instance_get_name(imp_inst, imp_str,
6950			    imp_str_sz) < 0)
6951				(void) strcpy(imp_str, "?");
6952			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
6953			lcbdata->sc_err = EBADF;
6954			r = UU_WALK_ERROR;
6955			goto deltemp;
6956
6957		default:
6958			bad_error("get_snaplevel", r);
6959		}
6960
6961		if (scf_instance_get_snapshot(imp_inst, snap_running,
6962		    imp_rsnap) != 0) {
6963			switch (scf_error()) {
6964			case SCF_ERROR_DELETED:
6965				continue;
6966
6967			case SCF_ERROR_NOT_FOUND:
6968				break;
6969
6970			case SCF_ERROR_CONNECTION_BROKEN:
6971				goto connaborted;
6972
6973			case SCF_ERROR_INVALID_ARGUMENT:
6974			case SCF_ERROR_HANDLE_MISMATCH:
6975			case SCF_ERROR_NOT_BOUND:
6976			case SCF_ERROR_NOT_SET:
6977			default:
6978				bad_error("scf_instance_get_snapshot",
6979				    scf_error());
6980			}
6981			running = NULL;
6982		} else {
6983			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
6984			switch (r) {
6985			case 0:
6986				running = imp_rsnpl;
6987				break;
6988
6989			case ECONNABORTED:
6990				goto connaborted;
6991
6992			case ECANCELED:
6993				continue;
6994
6995			case ENOENT:
6996				if (scf_instance_get_name(imp_inst, imp_str,
6997				    imp_str_sz) < 0)
6998					(void) strcpy(imp_str, "?");
6999				warn(badsnap, snap_running, s->sc_name,
7000				    imp_str);
7001				lcbdata->sc_err = EBADF;
7002				r = UU_WALK_ERROR;
7003				goto deltemp;
7004
7005			default:
7006				bad_error("get_snaplevel", r);
7007			}
7008		}
7009
7010		if (g_verbose) {
7011			if (scf_instance_get_name(imp_inst, imp_str,
7012			    imp_str_sz) < 0)
7013				(void) strcpy(imp_str, "?");
7014			warn(gettext("Upgrading properties of %s according to "
7015			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7016		}
7017
7018		/* upgrade service properties */
7019		r = upgrade_props(imp_svc, running, imp_snpl, s);
7020		if (r == 0)
7021			break;
7022
7023		switch (r) {
7024		case ECONNABORTED:
7025			goto connaborted;
7026
7027		case ECANCELED:
7028			warn(s_deleted, s->sc_fmri);
7029			lcbdata->sc_err = EBUSY;
7030			break;
7031
7032		case ENODEV:
7033			if (scf_instance_get_name(imp_inst, imp_str,
7034			    imp_str_sz) < 0)
7035				(void) strcpy(imp_str, "?");
7036			warn(i_deleted, s->sc_fmri, imp_str);
7037			lcbdata->sc_err = EBUSY;
7038			break;
7039
7040		default:
7041			lcbdata->sc_err = r;
7042		}
7043
7044		r = UU_WALK_ERROR;
7045		goto deltemp;
7046	}
7047
7048	s->sc_import_state = IMPORT_PROP_DONE;
7049
7050instances:
7051	/* import instances */
7052	cbdata.sc_handle = lcbdata->sc_handle;
7053	cbdata.sc_parent = imp_svc;
7054	cbdata.sc_service = 1;
7055	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7056	cbdata.sc_general = NULL;
7057
7058	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7059	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7060		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7061			bad_error("uu_list_walk", uu_error());
7062
7063		lcbdata->sc_err = cbdata.sc_err;
7064		if (cbdata.sc_err == ECONNABORTED)
7065			goto connaborted;
7066		r = UU_WALK_ERROR;
7067		goto deltemp;
7068	}
7069
7070	s->sc_import_state = IMPORT_COMPLETE;
7071	r = UU_WALK_NEXT;
7072
7073deltemp:
7074	/* delete temporary service */
7075	if (scf_service_delete(imp_tsvc) != 0) {
7076		switch (scf_error()) {
7077		case SCF_ERROR_DELETED:
7078			break;
7079
7080		case SCF_ERROR_CONNECTION_BROKEN:
7081			goto connaborted;
7082
7083		case SCF_ERROR_EXISTS:
7084			warn(gettext(
7085			    "Could not delete svc:/%s (instances exist).\n"),
7086			    imp_tsname);
7087			break;
7088
7089		case SCF_ERROR_NOT_SET:
7090		case SCF_ERROR_NOT_BOUND:
7091		default:
7092			bad_error("scf_service_delete", scf_error());
7093		}
7094	}
7095
7096	return (r);
7097
7098connaborted:
7099	warn(gettext("Could not delete svc:/%s "
7100	    "(repository connection broken).\n"), imp_tsname);
7101	lcbdata->sc_err = ECONNABORTED;
7102	return (UU_WALK_ERROR);
7103}
7104
7105static const char *
7106import_progress(int st)
7107{
7108	switch (st) {
7109	case 0:
7110		return (gettext("not reached."));
7111
7112	case IMPORT_PREVIOUS:
7113		return (gettext("previous snapshot taken."));
7114
7115	case IMPORT_PROP_BEGUN:
7116		return (gettext("some properties imported."));
7117
7118	case IMPORT_PROP_DONE:
7119		return (gettext("properties imported."));
7120
7121	case IMPORT_COMPLETE:
7122		return (gettext("imported."));
7123
7124	case IMPORT_REFRESHED:
7125		return (gettext("refresh requested."));
7126
7127	default:
7128#ifndef NDEBUG
7129		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7130		    __FILE__, __LINE__, st);
7131#endif
7132		abort();
7133		/* NOTREACHED */
7134	}
7135}
7136
7137/*
7138 * Returns
7139 *   0 - success
7140 *     - fmri wasn't found (error printed)
7141 *     - entity was deleted (error printed)
7142 *     - backend denied access (error printed)
7143 *   ENOMEM - out of memory (error printed)
7144 *   ECONNABORTED - repository connection broken (error printed)
7145 *   EPERM - permission denied (error printed)
7146 *   -1 - unknown libscf error (error printed)
7147 */
7148static int
7149imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7150{
7151	scf_error_t serr;
7152	void *ent;
7153	int issvc;
7154	int r;
7155
7156	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7157	const char *dpt_deleted = gettext("Could not refresh %s "
7158	    "(dependent \"%s\" of %s) (deleted).\n");
7159
7160	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7161	switch (serr) {
7162	case SCF_ERROR_NONE:
7163		break;
7164
7165	case SCF_ERROR_NO_MEMORY:
7166		if (name == NULL)
7167			warn(gettext("Could not refresh %s (out of memory).\n"),
7168			    fmri);
7169		else
7170			warn(gettext("Could not refresh %s "
7171			    "(dependent \"%s\" of %s) (out of memory).\n"),
7172			    fmri, name, d_fmri);
7173		return (ENOMEM);
7174
7175	case SCF_ERROR_NOT_FOUND:
7176		if (name == NULL)
7177			warn(deleted, fmri);
7178		else
7179			warn(dpt_deleted, fmri, name, d_fmri);
7180		return (0);
7181
7182	case SCF_ERROR_INVALID_ARGUMENT:
7183	case SCF_ERROR_CONSTRAINT_VIOLATED:
7184	default:
7185		bad_error("fmri_to_entity", serr);
7186	}
7187
7188	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7189	switch (r) {
7190	case 0:
7191		break;
7192
7193	case ECONNABORTED:
7194		if (name != NULL)
7195			warn(gettext("Could not refresh %s "
7196			    "(dependent \"%s\" of %s) "
7197			    "(repository connection broken).\n"), fmri, name,
7198			    d_fmri);
7199		return (r);
7200
7201	case ECANCELED:
7202		if (name == NULL)
7203			warn(deleted, fmri);
7204		else
7205			warn(dpt_deleted, fmri, name, d_fmri);
7206		return (0);
7207
7208	case EACCES:
7209		if (!g_verbose)
7210			return (0);
7211		if (name == NULL)
7212			warn(gettext("Could not refresh %s "
7213			    "(backend access denied).\n"), fmri);
7214		else
7215			warn(gettext("Could not refresh %s "
7216			    "(dependent \"%s\" of %s) "
7217			    "(backend access denied).\n"), fmri, name, d_fmri);
7218		return (0);
7219
7220	case EPERM:
7221		if (name == NULL)
7222			warn(gettext("Could not refresh %s "
7223			    "(permission denied).\n"), fmri);
7224		else
7225			warn(gettext("Could not refresh %s "
7226			    "(dependent \"%s\" of %s) "
7227			    "(permission denied).\n"), fmri, name, d_fmri);
7228		return (r);
7229
7230	case ENOSPC:
7231		if (name == NULL)
7232			warn(gettext("Could not refresh %s "
7233			    "(repository server out of resources).\n"),
7234			    fmri);
7235		else
7236			warn(gettext("Could not refresh %s "
7237			    "(dependent \"%s\" of %s) "
7238			    "(repository server out of resources).\n"),
7239			    fmri, name, d_fmri);
7240		return (r);
7241
7242	case -1:
7243		scfwarn();
7244		return (r);
7245
7246	default:
7247		bad_error("refresh_entity", r);
7248	}
7249
7250	if (issvc)
7251		scf_service_destroy(ent);
7252	else
7253		scf_instance_destroy(ent);
7254
7255	return (0);
7256}
7257
7258int
7259lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7260{
7261	scf_callback_t cbdata;
7262	int result = 0;
7263	entity_t *svc, *inst;
7264	uu_list_t *insts;
7265	int r;
7266	pgroup_t *old_dpt;
7267	void *cookie;
7268	int annotation_set = 0;
7269
7270	const char * const emsg_nomem = gettext("Out of memory.\n");
7271	const char * const emsg_nores =
7272	    gettext("svc.configd is out of resources.\n");
7273
7274	lscf_prep_hndl();
7275
7276	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7277	    max_scf_name_len : max_scf_fmri_len) + 1;
7278
7279	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7280	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
7281	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7282	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7283	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7284	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7285	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7286	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7287	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7288	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7289	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7290	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7291	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7292	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7293	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7294	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7295	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7296	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7297	    (imp_str = malloc(imp_str_sz)) == NULL ||
7298	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7299	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7300	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7301	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7302	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7303	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7304	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7305	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7306	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7307	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7308	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7309	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7310	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7311	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7312	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7313	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7314	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7315	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7316		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7317			warn(emsg_nores);
7318		else
7319			warn(emsg_nomem);
7320		result = -1;
7321		goto out;
7322	}
7323
7324	r = load_init();
7325	switch (r) {
7326	case 0:
7327		break;
7328
7329	case ENOMEM:
7330		warn(emsg_nomem);
7331		result = -1;
7332		goto out;
7333
7334	default:
7335		bad_error("load_init", r);
7336	}
7337
7338	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7339		switch (scf_error()) {
7340		case SCF_ERROR_CONNECTION_BROKEN:
7341			warn(gettext("Repository connection broken.\n"));
7342			repository_teardown();
7343			result = -1;
7344			goto out;
7345
7346		case SCF_ERROR_NOT_FOUND:
7347		case SCF_ERROR_INVALID_ARGUMENT:
7348		case SCF_ERROR_NOT_BOUND:
7349		case SCF_ERROR_HANDLE_MISMATCH:
7350		default:
7351			bad_error("scf_handle_get_scope", scf_error());
7352		}
7353	}
7354
7355	/* Set up the auditing annotation. */
7356	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7357		annotation_set = 1;
7358	} else {
7359		switch (scf_error()) {
7360		case SCF_ERROR_CONNECTION_BROKEN:
7361			warn(gettext("Repository connection broken.\n"));
7362			repository_teardown();
7363			result = -1;
7364			goto out;
7365
7366		case SCF_ERROR_INVALID_ARGUMENT:
7367		case SCF_ERROR_NOT_BOUND:
7368		case SCF_ERROR_NO_RESOURCES:
7369		case SCF_ERROR_INTERNAL:
7370			bad_error("_scf_set_annotation", scf_error());
7371			/* NOTREACHED */
7372
7373		default:
7374			/*
7375			 * Do not terminate import because of inability to
7376			 * generate annotation audit event.
7377			 */
7378			warn(gettext("_scf_set_annotation() unexpectedly "
7379			    "failed with return code of %d\n"), scf_error());
7380			break;
7381		}
7382	}
7383
7384	/*
7385	 * Clear the sc_import_state's of all services & instances so we can
7386	 * report how far we got if we fail.
7387	 */
7388	for (svc = uu_list_first(bndl->sc_bundle_services);
7389	    svc != NULL;
7390	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7391		svc->sc_import_state = 0;
7392
7393		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
7394		    clear_int, (void *)offsetof(entity_t, sc_import_state),
7395		    UU_DEFAULT) != 0)
7396			bad_error("uu_list_walk", uu_error());
7397	}
7398
7399	cbdata.sc_handle = g_hndl;
7400	cbdata.sc_parent = imp_scope;
7401	cbdata.sc_flags = flags;
7402	cbdata.sc_general = NULL;
7403
7404	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
7405	    &cbdata, UU_DEFAULT) == 0) {
7406		/* Success.  Refresh everything. */
7407
7408		if (flags & SCI_NOREFRESH || no_refresh) {
7409			no_refresh = 0;
7410			result = 0;
7411			goto out;
7412		}
7413
7414		for (svc = uu_list_first(bndl->sc_bundle_services);
7415		    svc != NULL;
7416		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7417			pgroup_t *dpt;
7418
7419			insts = svc->sc_u.sc_service.sc_service_instances;
7420
7421			for (inst = uu_list_first(insts);
7422			    inst != NULL;
7423			    inst = uu_list_next(insts, inst)) {
7424				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
7425				switch (r) {
7426				case 0:
7427					break;
7428
7429				case ENOMEM:
7430				case ECONNABORTED:
7431				case EPERM:
7432				case -1:
7433					goto progress;
7434
7435				default:
7436					bad_error("imp_refresh_fmri", r);
7437				}
7438
7439				inst->sc_import_state = IMPORT_REFRESHED;
7440
7441				for (dpt = uu_list_first(inst->sc_dependents);
7442				    dpt != NULL;
7443				    dpt = uu_list_next(inst->sc_dependents,
7444				    dpt))
7445					if (imp_refresh_fmri(
7446					    dpt->sc_pgroup_fmri,
7447					    dpt->sc_pgroup_name,
7448					    inst->sc_fmri) != 0)
7449						goto progress;
7450			}
7451
7452			for (dpt = uu_list_first(svc->sc_dependents);
7453			    dpt != NULL;
7454			    dpt = uu_list_next(svc->sc_dependents, dpt))
7455				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
7456				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
7457					goto progress;
7458		}
7459
7460		for (old_dpt = uu_list_first(imp_deleted_dpts);
7461		    old_dpt != NULL;
7462		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
7463			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
7464			    old_dpt->sc_pgroup_name,
7465			    old_dpt->sc_parent->sc_fmri) != 0)
7466				goto progress;
7467
7468		result = 0;
7469		goto out;
7470	}
7471
7472	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7473		bad_error("uu_list_walk", uu_error());
7474
7475printerr:
7476	/* If the error hasn't been printed yet, do so here. */
7477	switch (cbdata.sc_err) {
7478	case ECONNABORTED:
7479		warn(gettext("Repository connection broken.\n"));
7480		break;
7481
7482	case ENOMEM:
7483		warn(emsg_nomem);
7484		break;
7485
7486	case ENOSPC:
7487		warn(emsg_nores);
7488		break;
7489
7490	case EROFS:
7491		warn(gettext("Repository is read-only.\n"));
7492		break;
7493
7494	case EACCES:
7495		warn(gettext("Repository backend denied access.\n"));
7496		break;
7497
7498	case EPERM:
7499	case EINVAL:
7500	case EEXIST:
7501	case EBUSY:
7502	case EBADF:
7503	case -1:
7504		break;
7505
7506	default:
7507		bad_error("lscf_service_import", cbdata.sc_err);
7508	}
7509
7510progress:
7511	warn(gettext("Import of %s failed.  Progress:\n"), filename);
7512
7513	for (svc = uu_list_first(bndl->sc_bundle_services);
7514	    svc != NULL;
7515	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7516		insts = svc->sc_u.sc_service.sc_service_instances;
7517
7518		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
7519		    import_progress(svc->sc_import_state));
7520
7521		for (inst = uu_list_first(insts);
7522		    inst != NULL;
7523		    inst = uu_list_next(insts, inst))
7524			warn(gettext("    Instance \"%s\": %s\n"),
7525			    inst->sc_name,
7526			    import_progress(inst->sc_import_state));
7527	}
7528
7529	if (cbdata.sc_err == ECONNABORTED)
7530		repository_teardown();
7531
7532
7533	result = -1;
7534
7535out:
7536	if (annotation_set != 0) {
7537		/* Turn off annotation.  It is no longer needed. */
7538		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7539	}
7540	load_fini();
7541
7542	free(ud_ctarg);
7543	free(ud_oldtarg);
7544	free(ud_name);
7545	ud_ctarg = ud_oldtarg = ud_name = NULL;
7546
7547	scf_transaction_destroy(ud_tx);
7548	ud_tx = NULL;
7549	scf_iter_destroy(ud_iter);
7550	scf_iter_destroy(ud_iter2);
7551	ud_iter = ud_iter2 = NULL;
7552	scf_value_destroy(ud_val);
7553	ud_val = NULL;
7554	scf_property_destroy(ud_prop);
7555	scf_property_destroy(ud_dpt_prop);
7556	ud_prop = ud_dpt_prop = NULL;
7557	scf_pg_destroy(ud_pg);
7558	scf_pg_destroy(ud_cur_depts_pg);
7559	scf_pg_destroy(ud_run_dpts_pg);
7560	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7561	scf_snaplevel_destroy(ud_snpl);
7562	ud_snpl = NULL;
7563	scf_instance_destroy(ud_inst);
7564	ud_inst = NULL;
7565
7566	free(imp_str);
7567	free(imp_tsname);
7568	free(imp_fe1);
7569	free(imp_fe2);
7570	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7571
7572	cookie = NULL;
7573	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7574	    NULL) {
7575		free((char *)old_dpt->sc_pgroup_name);
7576		free((char *)old_dpt->sc_pgroup_fmri);
7577		internal_pgroup_free(old_dpt);
7578	}
7579	uu_list_destroy(imp_deleted_dpts);
7580
7581	scf_transaction_destroy(imp_tx);
7582	imp_tx = NULL;
7583	scf_iter_destroy(imp_iter);
7584	scf_iter_destroy(imp_rpg_iter);
7585	scf_iter_destroy(imp_up_iter);
7586	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7587	scf_property_destroy(imp_prop);
7588	imp_prop = NULL;
7589	scf_pg_destroy(imp_pg);
7590	scf_pg_destroy(imp_pg2);
7591	imp_pg = imp_pg2 = NULL;
7592	scf_snaplevel_destroy(imp_snpl);
7593	scf_snaplevel_destroy(imp_rsnpl);
7594	imp_snpl = imp_rsnpl = NULL;
7595	scf_snapshot_destroy(imp_snap);
7596	scf_snapshot_destroy(imp_lisnap);
7597	scf_snapshot_destroy(imp_tlisnap);
7598	scf_snapshot_destroy(imp_rsnap);
7599	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7600	scf_instance_destroy(imp_inst);
7601	scf_instance_destroy(imp_tinst);
7602	imp_inst = imp_tinst = NULL;
7603	scf_service_destroy(imp_svc);
7604	scf_service_destroy(imp_tsvc);
7605	imp_svc = imp_tsvc = NULL;
7606	scf_scope_destroy(imp_scope);
7607	imp_scope = NULL;
7608
7609	return (result);
7610}
7611
7612/*
7613 * _lscf_import_err() summarize the error handling returned by
7614 * lscf_import_{instance | service}_pgs
7615 * Return values are:
7616 * IMPORT_NEXT
7617 * IMPORT_OUT
7618 * IMPORT_BAD
7619 */
7620
7621#define	IMPORT_BAD	-1
7622#define	IMPORT_NEXT	0
7623#define	IMPORT_OUT	1
7624
7625static int
7626_lscf_import_err(int err, const char *fmri)
7627{
7628	switch (err) {
7629	case 0:
7630		if (g_verbose)
7631			warn(gettext("%s updated.\n"), fmri);
7632		return (IMPORT_NEXT);
7633
7634	case ECONNABORTED:
7635		warn(gettext("Could not update %s "
7636		    "(repository connection broken).\n"), fmri);
7637		return (IMPORT_OUT);
7638
7639	case ENOMEM:
7640		warn(gettext("Could not update %s (out of memory).\n"), fmri);
7641		return (IMPORT_OUT);
7642
7643	case ENOSPC:
7644		warn(gettext("Could not update %s "
7645		    "(repository server out of resources).\n"), fmri);
7646		return (IMPORT_OUT);
7647
7648	case ECANCELED:
7649		warn(gettext(
7650		    "Could not update %s (deleted).\n"), fmri);
7651		return (IMPORT_NEXT);
7652
7653	case EPERM:
7654	case EINVAL:
7655	case EBUSY:
7656		return (IMPORT_NEXT);
7657
7658	case EROFS:
7659		warn(gettext("Could not update %s (repository read-only).\n"),
7660		    fmri);
7661		return (IMPORT_OUT);
7662
7663	case EACCES:
7664		warn(gettext("Could not update %s "
7665		    "(backend access denied).\n"), fmri);
7666		return (IMPORT_NEXT);
7667
7668	case EEXIST:
7669	default:
7670		return (IMPORT_BAD);
7671	}
7672
7673	/*NOTREACHED*/
7674}
7675
7676/*
7677 * Returns
7678 *   0 - success
7679 *   -1 - lscf_import_instance_pgs() failed.
7680 */
7681int
7682lscf_bundle_apply(bundle_t *bndl, const char *file)
7683{
7684	entity_t *svc, *inst;
7685	scf_scope_t *rscope;
7686	scf_service_t *rsvc;
7687	scf_instance_t *rinst;
7688	scf_snapshot_t *rsnap;
7689	scf_iter_t *iter;
7690	int annotation_set = 0;
7691	int r;
7692
7693	lscf_prep_hndl();
7694
7695	if ((rscope = scf_scope_create(g_hndl)) == NULL ||
7696	    (rsvc = scf_service_create(g_hndl)) == NULL ||
7697	    (rinst = scf_instance_create(g_hndl)) == NULL ||
7698	    (rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7699	    (iter = scf_iter_create(g_hndl)) == NULL ||
7700	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7701	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7702	    (imp_tx = scf_transaction_create(g_hndl)) == NULL)
7703		scfdie();
7704
7705	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0)
7706		scfdie();
7707
7708	/*
7709	 * Set the strings to be used for the security audit annotation
7710	 * event.
7711	 */
7712	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
7713		annotation_set = 1;
7714	} else {
7715		switch (scf_error()) {
7716		case SCF_ERROR_CONNECTION_BROKEN:
7717			warn(gettext("Repository connection broken.\n"));
7718			goto out;
7719
7720		case SCF_ERROR_INVALID_ARGUMENT:
7721		case SCF_ERROR_NOT_BOUND:
7722		case SCF_ERROR_NO_RESOURCES:
7723		case SCF_ERROR_INTERNAL:
7724			bad_error("_scf_set_annotation", scf_error());
7725			/* NOTREACHED */
7726
7727		default:
7728			/*
7729			 * Do not abort apply operation because of
7730			 * inability to create annotation audit event.
7731			 */
7732			warn(gettext("_scf_set_annotation() unexpectedly "
7733			    "failed with return code of %d\n"), scf_error());
7734			break;
7735		}
7736	}
7737
7738	for (svc = uu_list_first(bndl->sc_bundle_services);
7739	    svc != NULL;
7740	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7741		int refresh = 0;
7742
7743		if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) {
7744			switch (scf_error()) {
7745			case SCF_ERROR_NOT_FOUND:
7746				if (g_verbose)
7747					warn(gettext("Ignoring nonexistent "
7748					    "service %s.\n"), svc->sc_name);
7749				continue;
7750
7751			default:
7752				scfdie();
7753			}
7754		}
7755
7756		/*
7757		 * if we have pgs in the profile, we need to refresh ALL
7758		 * instances of the service
7759		 */
7760		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
7761			refresh = 1;
7762			r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc,
7763			    SCI_FORCE | SCI_KEEP);
7764			switch (_lscf_import_err(r, svc->sc_fmri)) {
7765			case IMPORT_NEXT:
7766				break;
7767
7768			case IMPORT_OUT:
7769				goto out;
7770
7771			case IMPORT_BAD:
7772			default:
7773				bad_error("lscf_import_service_pgs", r);
7774			}
7775		}
7776
7777		for (inst = uu_list_first(
7778		    svc->sc_u.sc_service.sc_service_instances);
7779		    inst != NULL;
7780		    inst = uu_list_next(
7781		    svc->sc_u.sc_service.sc_service_instances, inst)) {
7782			if (scf_service_get_instance(rsvc, inst->sc_name,
7783			    rinst) != 0) {
7784				switch (scf_error()) {
7785				case SCF_ERROR_NOT_FOUND:
7786					if (g_verbose)
7787						warn(gettext("Ignoring "
7788						    "nonexistant instance "
7789						    "%s:%s.\n"),
7790						    inst->sc_parent->sc_name,
7791						    inst->sc_name);
7792					continue;
7793
7794				default:
7795					scfdie();
7796				}
7797			}
7798
7799			/*
7800			 * If the instance does not have a general/enabled
7801			 * property and no last-import snapshot then the
7802			 * instance is not a fully installed instance and
7803			 * should not have a profile applied to it.
7804			 *
7805			 * This could happen if a service/instance declares
7806			 * a dependent on behalf of another service/instance.
7807			 */
7808			if (scf_instance_get_snapshot(rinst, snap_lastimport,
7809			    rsnap) != 0) {
7810				if (scf_instance_get_pg(rinst, SCF_PG_GENERAL,
7811				    imp_pg) != 0 || scf_pg_get_property(imp_pg,
7812				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
7813					if (g_verbose)
7814						warn(gettext("Ignoreing "
7815						    "partial instance "
7816						    "%s:%s.\n"),
7817						    inst->sc_parent->sc_name,
7818						    inst->sc_name);
7819					continue;
7820				}
7821			}
7822
7823			r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst,
7824			    SCI_FORCE | SCI_KEEP);
7825			switch (_lscf_import_err(r, inst->sc_fmri)) {
7826			case IMPORT_NEXT:
7827				break;
7828
7829			case IMPORT_OUT:
7830				goto out;
7831
7832			case IMPORT_BAD:
7833			default:
7834				bad_error("lscf_import_instance_pgs", r);
7835			}
7836
7837			/* refresh only if there is no pgs in the service */
7838			if (refresh == 0)
7839				(void) refresh_entity(0, rinst, inst->sc_fmri,
7840				    NULL, NULL, NULL);
7841		}
7842
7843		if (refresh == 1) {
7844			char *name_buf = safe_malloc(max_scf_name_len + 1);
7845
7846			(void) refresh_entity(1, rsvc, svc->sc_name, rinst,
7847			    iter, name_buf);
7848			free(name_buf);
7849		}
7850	}
7851
7852out:
7853	if (annotation_set) {
7854		/* Remove security audit annotation strings. */
7855		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7856	}
7857
7858	scf_transaction_destroy(imp_tx);
7859	imp_tx = NULL;
7860	scf_pg_destroy(imp_pg);
7861	imp_pg = NULL;
7862	scf_property_destroy(imp_prop);
7863	imp_prop = NULL;
7864
7865	scf_snapshot_destroy(rsnap);
7866	scf_iter_destroy(iter);
7867	scf_instance_destroy(rinst);
7868	scf_service_destroy(rsvc);
7869	scf_scope_destroy(rscope);
7870	return (0);
7871}
7872
7873
7874/*
7875 * Export.  These functions create and output an XML tree of a service
7876 * description from the repository.  This is largely the inverse of
7877 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
7878 *
7879 * - We must include any properties which are not represented specifically by
7880 *   a service manifest, e.g., properties created by an admin post-import.  To
7881 *   do so we'll iterate through all properties and deal with each
7882 *   apropriately.
7883 *
7884 * - Children of services and instances must must be in the order set by the
7885 *   DTD, but we iterate over the properties in undefined order.  The elements
7886 *   are not easily (or efficiently) sortable by name.  Since there's a fixed
7887 *   number of classes of them, however, we'll keep the classes separate and
7888 *   assemble them in order.
7889 */
7890
7891/*
7892 * Convenience function to handle xmlSetProp errors (and type casting).
7893 */
7894static void
7895safe_setprop(xmlNodePtr n, const char *name, const char *val)
7896{
7897	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
7898		uu_die(gettext("Could not set XML property.\n"));
7899}
7900
7901/*
7902 * Convenience function to set an XML attribute to the single value of an
7903 * astring property.  If the value happens to be the default, don't set the
7904 * attribute.  "dval" should be the default value supplied by the DTD, or
7905 * NULL for no default.
7906 */
7907static int
7908set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
7909    const char *name, const char *dval)
7910{
7911	scf_value_t *val;
7912	ssize_t len;
7913	char *str;
7914
7915	val = scf_value_create(g_hndl);
7916	if (val == NULL)
7917		scfdie();
7918
7919	if (prop_get_val(prop, val) != 0) {
7920		scf_value_destroy(val);
7921		return (-1);
7922	}
7923
7924	len = scf_value_get_as_string(val, NULL, 0);
7925	if (len < 0)
7926		scfdie();
7927
7928	str = safe_malloc(len + 1);
7929
7930	if (scf_value_get_as_string(val, str, len + 1) < 0)
7931		scfdie();
7932
7933	scf_value_destroy(val);
7934
7935	if (dval == NULL || strcmp(str, dval) != 0)
7936		safe_setprop(n, name, str);
7937
7938	free(str);
7939
7940	return (0);
7941}
7942
7943/*
7944 * As above, but the attribute is always set.
7945 */
7946static int
7947set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
7948{
7949	return (set_attr_from_prop_default(prop, n, name, NULL));
7950}
7951
7952/*
7953 * Dump the given document onto f, with "'s replaced by ''s.
7954 */
7955static int
7956write_service_bundle(xmlDocPtr doc, FILE *f)
7957{
7958	xmlChar *mem;
7959	int sz, i;
7960
7961	mem = NULL;
7962	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
7963
7964	if (mem == NULL) {
7965		semerr(gettext("Could not dump XML tree.\n"));
7966		return (-1);
7967	}
7968
7969	/*
7970	 * Fortunately libxml produces &quot; instead of ", so we can blindly
7971	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
7972	 * &apos; code?!
7973	 */
7974	for (i = 0; i < sz; ++i) {
7975		char c = (char)mem[i];
7976
7977		if (c == '"')
7978			(void) fputc('\'', f);
7979		else if (c == '\'')
7980			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
7981		else
7982			(void) fputc(c, f);
7983	}
7984
7985	return (0);
7986}
7987
7988/*
7989 * Create the DOM elements in elts necessary to (generically) represent prop
7990 * (i.e., a property or propval element).  If the name of the property is
7991 * known, it should be passed as name_arg.  Otherwise, pass NULL.
7992 */
7993static void
7994export_property(scf_property_t *prop, const char *name_arg,
7995    struct pg_elts *elts, int flags)
7996{
7997	const char *type;
7998	scf_error_t err = 0;
7999	xmlNodePtr pnode, lnode;
8000	char *lnname;
8001	int ret;
8002
8003	/* name */
8004	if (name_arg != NULL) {
8005		(void) strcpy(exp_str, name_arg);
8006	} else {
8007		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8008			scfdie();
8009	}
8010
8011	/* type */
8012	type = prop_to_typestr(prop);
8013	if (type == NULL)
8014		uu_die(gettext("Can't export property %s: unknown type.\n"),
8015		    exp_str);
8016
8017	/* If we're exporting values, and there's just one, export it here. */
8018	if (!(flags & SCE_ALL_VALUES))
8019		goto empty;
8020
8021	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8022		xmlNodePtr n;
8023
8024		/* Single value, so use propval */
8025		n = xmlNewNode(NULL, (xmlChar *)"propval");
8026		if (n == NULL)
8027			uu_die(emsg_create_xml);
8028
8029		safe_setprop(n, name_attr, exp_str);
8030		safe_setprop(n, type_attr, type);
8031
8032		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8033			scfdie();
8034		safe_setprop(n, value_attr, exp_str);
8035
8036		if (elts->propvals == NULL)
8037			elts->propvals = n;
8038		else
8039			(void) xmlAddSibling(elts->propvals, n);
8040
8041		return;
8042	}
8043
8044	err = scf_error();
8045
8046	if (err == SCF_ERROR_PERMISSION_DENIED) {
8047		semerr(emsg_permission_denied);
8048		return;
8049	}
8050
8051	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8052	    err != SCF_ERROR_NOT_FOUND &&
8053	    err != SCF_ERROR_PERMISSION_DENIED)
8054		scfdie();
8055
8056empty:
8057	/* Multiple (or no) values, so use property */
8058	pnode = xmlNewNode(NULL, (xmlChar *)"property");
8059	if (pnode == NULL)
8060		uu_die(emsg_create_xml);
8061
8062	safe_setprop(pnode, name_attr, exp_str);
8063	safe_setprop(pnode, type_attr, type);
8064
8065	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8066		lnname = uu_msprintf("%s_list", type);
8067		if (lnname == NULL)
8068			uu_die(gettext("Could not create string"));
8069
8070		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8071		if (lnode == NULL)
8072			uu_die(emsg_create_xml);
8073
8074		uu_free(lnname);
8075
8076		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8077			scfdie();
8078
8079		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8080		    1) {
8081			xmlNodePtr vn;
8082
8083			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8084			    NULL);
8085			if (vn == NULL)
8086				uu_die(emsg_create_xml);
8087
8088			if (scf_value_get_as_string(exp_val, exp_str,
8089			    exp_str_sz) < 0)
8090				scfdie();
8091			safe_setprop(vn, value_attr, exp_str);
8092		}
8093		if (ret != 0)
8094			scfdie();
8095	}
8096
8097	if (elts->properties == NULL)
8098		elts->properties = pnode;
8099	else
8100		(void) xmlAddSibling(elts->properties, pnode);
8101}
8102
8103/*
8104 * Add a property_group element for this property group to elts.
8105 */
8106static void
8107export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8108{
8109	xmlNodePtr n;
8110	struct pg_elts elts;
8111	int ret;
8112	boolean_t read_protected;
8113
8114	n = xmlNewNode(NULL, (xmlChar *)"property_group");
8115
8116	/* name */
8117	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8118		scfdie();
8119	safe_setprop(n, name_attr, exp_str);
8120
8121	/* type */
8122	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8123		scfdie();
8124	safe_setprop(n, type_attr, exp_str);
8125
8126	/* properties */
8127	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8128		scfdie();
8129
8130	(void) memset(&elts, 0, sizeof (elts));
8131
8132	/*
8133	 * If this property group is not read protected, we always want to
8134	 * output all the values.  Otherwise, we only output the values if the
8135	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8136	 */
8137	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8138		scfdie();
8139
8140	if (!read_protected)
8141		flags |= SCE_ALL_VALUES;
8142
8143	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8144		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8145			scfdie();
8146
8147		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8148			xmlNodePtr m;
8149
8150			m = xmlNewNode(NULL, (xmlChar *)"stability");
8151			if (m == NULL)
8152				uu_die(emsg_create_xml);
8153
8154			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8155				elts.stability = m;
8156				continue;
8157			}
8158
8159			xmlFreeNode(m);
8160		}
8161
8162		export_property(exp_prop, NULL, &elts, flags);
8163	}
8164	if (ret == -1)
8165		scfdie();
8166
8167	(void) xmlAddChild(n, elts.stability);
8168	(void) xmlAddChildList(n, elts.propvals);
8169	(void) xmlAddChildList(n, elts.properties);
8170
8171	if (eelts->property_groups == NULL)
8172		eelts->property_groups = n;
8173	else
8174		(void) xmlAddSibling(eelts->property_groups, n);
8175}
8176
8177/*
8178 * Create an XML node representing the dependency described by the given
8179 * property group and put it in eelts.  Unless the dependency is not valid, in
8180 * which case create a generic property_group element which represents it and
8181 * put it in eelts.
8182 */
8183static void
8184export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8185{
8186	xmlNodePtr n;
8187	int err = 0, ret;
8188	struct pg_elts elts;
8189
8190	n = xmlNewNode(NULL, (xmlChar *)"dependency");
8191	if (n == NULL)
8192		uu_die(emsg_create_xml);
8193
8194	/*
8195	 * If the external flag is present, skip this dependency because it
8196	 * should have been created by another manifest.
8197	 */
8198	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
8199		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8200		    prop_get_val(exp_prop, exp_val) == 0) {
8201			uint8_t b;
8202
8203			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
8204				scfdie();
8205
8206			if (b)
8207				return;
8208		}
8209	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
8210		scfdie();
8211
8212	/* Get the required attributes. */
8213
8214	/* name */
8215	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8216		scfdie();
8217	safe_setprop(n, name_attr, exp_str);
8218
8219	/* grouping */
8220	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8221	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8222		err = 1;
8223
8224	/* restart_on */
8225	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8226	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8227		err = 1;
8228
8229	/* type */
8230	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8231	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8232		err = 1;
8233
8234	/*
8235	 * entities: Not required, but if we create no children, it will be
8236	 * created as empty on import, so fail if it's missing.
8237	 */
8238	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8239	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
8240		scf_iter_t *eiter;
8241		int ret2;
8242
8243		eiter = scf_iter_create(g_hndl);
8244		if (eiter == NULL)
8245			scfdie();
8246
8247		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
8248			scfdie();
8249
8250		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
8251			xmlNodePtr ch;
8252
8253			if (scf_value_get_astring(exp_val, exp_str,
8254			    exp_str_sz) < 0)
8255				scfdie();
8256
8257			/*
8258			 * service_fmri's must be first, so we can add them
8259			 * here.
8260			 */
8261			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
8262			    NULL);
8263			if (ch == NULL)
8264				uu_die(emsg_create_xml);
8265
8266			safe_setprop(ch, value_attr, exp_str);
8267		}
8268		if (ret2 == -1)
8269			scfdie();
8270
8271		scf_iter_destroy(eiter);
8272	} else
8273		err = 1;
8274
8275	if (err) {
8276		xmlFreeNode(n);
8277
8278		export_pg(pg, eelts, 0);
8279
8280		return;
8281	}
8282
8283	/* Iterate through the properties & handle each. */
8284	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8285		scfdie();
8286
8287	(void) memset(&elts, 0, sizeof (elts));
8288
8289	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8290		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8291			scfdie();
8292
8293		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8294		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8295		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8296		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8297			continue;
8298		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8299			xmlNodePtr m;
8300
8301			m = xmlNewNode(NULL, (xmlChar *)"stability");
8302			if (m == NULL)
8303				uu_die(emsg_create_xml);
8304
8305			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8306				elts.stability = m;
8307				continue;
8308			}
8309
8310			xmlFreeNode(m);
8311		}
8312
8313		export_property(exp_prop, exp_str, &elts, 0);
8314	}
8315	if (ret == -1)
8316		scfdie();
8317
8318	(void) xmlAddChild(n, elts.stability);
8319	(void) xmlAddChildList(n, elts.propvals);
8320	(void) xmlAddChildList(n, elts.properties);
8321
8322	if (eelts->dependencies == NULL)
8323		eelts->dependencies = n;
8324	else
8325		(void) xmlAddSibling(eelts->dependencies, n);
8326}
8327
8328static xmlNodePtr
8329export_method_environment(scf_propertygroup_t *pg)
8330{
8331	xmlNodePtr env;
8332	int ret;
8333	int children = 0;
8334
8335	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
8336		return (NULL);
8337
8338	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
8339	if (env == NULL)
8340		uu_die(emsg_create_xml);
8341
8342	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
8343		scfdie();
8344
8345	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
8346		scfdie();
8347
8348	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
8349		xmlNodePtr ev;
8350		char *cp;
8351
8352		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8353			scfdie();
8354
8355		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
8356			warn(gettext("Invalid environment variable \"%s\".\n"),
8357			    exp_str);
8358			continue;
8359		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
8360			warn(gettext("Invalid environment variable \"%s\"; "
8361			    "\"SMF_\" prefix is reserved.\n"), exp_str);
8362			continue;
8363		}
8364
8365		*cp = '\0';
8366		cp++;
8367
8368		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
8369		if (ev == NULL)
8370			uu_die(emsg_create_xml);
8371
8372		safe_setprop(ev, name_attr, exp_str);
8373		safe_setprop(ev, value_attr, cp);
8374		children++;
8375	}
8376
8377	if (ret != 0)
8378		scfdie();
8379
8380	if (children == 0) {
8381		xmlFreeNode(env);
8382		return (NULL);
8383	}
8384
8385	return (env);
8386}
8387
8388/*
8389 * As above, but for a method property group.
8390 */
8391static void
8392export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
8393{
8394	xmlNodePtr n, env;
8395	char *str;
8396	int err = 0, nonenv, ret;
8397	uint8_t use_profile;
8398	struct pg_elts elts;
8399	xmlNodePtr ctxt = NULL;
8400
8401	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
8402
8403	/* Get the required attributes. */
8404
8405	/* name */
8406	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8407		scfdie();
8408	safe_setprop(n, name_attr, exp_str);
8409
8410	/* type */
8411	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8412	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8413		err = 1;
8414
8415	/* exec */
8416	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
8417	    set_attr_from_prop(exp_prop, n, "exec") != 0)
8418		err = 1;
8419
8420	/* timeout */
8421	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
8422	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
8423	    prop_get_val(exp_prop, exp_val) == 0) {
8424		uint64_t c;
8425
8426		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
8427			scfdie();
8428
8429		str = uu_msprintf("%llu", c);
8430		if (str == NULL)
8431			uu_die(gettext("Could not create string"));
8432
8433		safe_setprop(n, "timeout_seconds", str);
8434		free(str);
8435	} else
8436		err = 1;
8437
8438	if (err) {
8439		xmlFreeNode(n);
8440
8441		export_pg(pg, eelts, 0);
8442
8443		return;
8444	}
8445
8446
8447	/*
8448	 * If we're going to have a method_context child, we need to know
8449	 * before we iterate through the properties.  Since method_context's
8450	 * are optional, we don't want to complain about any properties
8451	 * missing if none of them are there.  Thus we can't use the
8452	 * convenience functions.
8453	 */
8454	nonenv =
8455	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
8456	    SCF_SUCCESS ||
8457	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
8458	    SCF_SUCCESS ||
8459	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
8460	    SCF_SUCCESS ||
8461	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
8462	    SCF_SUCCESS;
8463
8464	if (nonenv) {
8465		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8466		if (ctxt == NULL)
8467			uu_die(emsg_create_xml);
8468
8469		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
8470		    0 &&
8471		    set_attr_from_prop_default(exp_prop, ctxt,
8472		    "working_directory", ":default") != 0)
8473			err = 1;
8474
8475		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
8476		    set_attr_from_prop_default(exp_prop, ctxt, "project",
8477		    ":default") != 0)
8478			err = 1;
8479
8480		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
8481		    0 &&
8482		    set_attr_from_prop_default(exp_prop, ctxt,
8483		    "resource_pool", ":default") != 0)
8484			err = 1;
8485		/*
8486		 * We only want to complain about profile or credential
8487		 * properties if we will use them.  To determine that we must
8488		 * examine USE_PROFILE.
8489		 */
8490		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8491		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8492		    prop_get_val(exp_prop, exp_val) == 0) {
8493			if (scf_value_get_boolean(exp_val, &use_profile) !=
8494			    SCF_SUCCESS) {
8495				scfdie();
8496			}
8497
8498			if (use_profile) {
8499				xmlNodePtr prof;
8500
8501				prof = xmlNewChild(ctxt, NULL,
8502				    (xmlChar *)"method_profile", NULL);
8503				if (prof == NULL)
8504					uu_die(emsg_create_xml);
8505
8506				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
8507				    exp_prop) != 0 ||
8508				    set_attr_from_prop(exp_prop, prof,
8509				    name_attr) != 0)
8510					err = 1;
8511			} else {
8512				xmlNodePtr cred;
8513
8514				cred = xmlNewChild(ctxt, NULL,
8515				    (xmlChar *)"method_credential", NULL);
8516				if (cred == NULL)
8517					uu_die(emsg_create_xml);
8518
8519				if (pg_get_prop(pg, SCF_PROPERTY_USER,
8520				    exp_prop) != 0 ||
8521				    set_attr_from_prop(exp_prop, cred,
8522				    "user") != 0) {
8523					err = 1;
8524				}
8525
8526				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
8527				    exp_prop) == 0 &&
8528				    set_attr_from_prop_default(exp_prop, cred,
8529				    "group", ":default") != 0)
8530					err = 1;
8531
8532				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
8533				    exp_prop) == 0 &&
8534				    set_attr_from_prop_default(exp_prop, cred,
8535				    "supp_groups", ":default") != 0)
8536					err = 1;
8537
8538				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
8539				    exp_prop) == 0 &&
8540				    set_attr_from_prop_default(exp_prop, cred,
8541				    "privileges", ":default") != 0)
8542					err = 1;
8543
8544				if (pg_get_prop(pg,
8545				    SCF_PROPERTY_LIMIT_PRIVILEGES,
8546				    exp_prop) == 0 &&
8547				    set_attr_from_prop_default(exp_prop, cred,
8548				    "limit_privileges", ":default") != 0)
8549					err = 1;
8550			}
8551		}
8552	}
8553
8554	if ((env = export_method_environment(pg)) != NULL) {
8555		if (ctxt == NULL) {
8556			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8557			if (ctxt == NULL)
8558				uu_die(emsg_create_xml);
8559		}
8560		(void) xmlAddChild(ctxt, env);
8561	}
8562
8563	if (env != NULL || (nonenv && err == 0))
8564		(void) xmlAddChild(n, ctxt);
8565	else
8566		xmlFreeNode(ctxt);
8567
8568	nonenv = (err == 0);
8569
8570	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8571		scfdie();
8572
8573	(void) memset(&elts, 0, sizeof (elts));
8574
8575	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8576		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8577			scfdie();
8578
8579		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8580		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
8581		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
8582			continue;
8583		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8584			xmlNodePtr m;
8585
8586			m = xmlNewNode(NULL, (xmlChar *)"stability");
8587			if (m == NULL)
8588				uu_die(emsg_create_xml);
8589
8590			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8591				elts.stability = m;
8592				continue;
8593			}
8594
8595			xmlFreeNode(m);
8596		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
8597		    0 ||
8598		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
8599		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
8600		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8601			if (nonenv)
8602				continue;
8603		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
8604		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
8605		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
8606		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
8607		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
8608			if (nonenv && !use_profile)
8609				continue;
8610		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8611			if (nonenv && use_profile)
8612				continue;
8613		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
8614			if (env != NULL)
8615				continue;
8616		}
8617
8618		export_property(exp_prop, exp_str, &elts, 0);
8619	}
8620	if (ret == -1)
8621		scfdie();
8622
8623	(void) xmlAddChild(n, elts.stability);
8624	(void) xmlAddChildList(n, elts.propvals);
8625	(void) xmlAddChildList(n, elts.properties);
8626
8627	if (eelts->exec_methods == NULL)
8628		eelts->exec_methods = n;
8629	else
8630		(void) xmlAddSibling(eelts->exec_methods, n);
8631}
8632
8633static void
8634export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
8635    struct entity_elts *eelts)
8636{
8637	xmlNodePtr pgnode;
8638
8639	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
8640	if (pgnode == NULL)
8641		uu_die(emsg_create_xml);
8642
8643	safe_setprop(pgnode, name_attr, name);
8644	safe_setprop(pgnode, type_attr, type);
8645
8646	(void) xmlAddChildList(pgnode, elts->propvals);
8647	(void) xmlAddChildList(pgnode, elts->properties);
8648
8649	if (eelts->property_groups == NULL)
8650		eelts->property_groups = pgnode;
8651	else
8652		(void) xmlAddSibling(eelts->property_groups, pgnode);
8653}
8654
8655/*
8656 * Process the general property group for a service.  This is the one with the
8657 * goodies.
8658 */
8659static void
8660export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
8661{
8662	struct pg_elts elts;
8663	int ret;
8664
8665	/*
8666	 * In case there are properties which don't correspond to child
8667	 * entities of the service entity, we'll set up a pg_elts structure to
8668	 * put them in.
8669	 */
8670	(void) memset(&elts, 0, sizeof (elts));
8671
8672	/* Walk the properties, looking for special ones. */
8673	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8674		scfdie();
8675
8676	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8677		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8678			scfdie();
8679
8680		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
8681			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8682			    prop_get_val(exp_prop, exp_val) == 0) {
8683				uint8_t b;
8684
8685				if (scf_value_get_boolean(exp_val, &b) !=
8686				    SCF_SUCCESS)
8687					scfdie();
8688
8689				if (b) {
8690					selts->single_instance =
8691					    xmlNewNode(NULL,
8692					    (xmlChar *)"single_instance");
8693					if (selts->single_instance == NULL)
8694						uu_die(emsg_create_xml);
8695				}
8696
8697				continue;
8698			}
8699		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8700			xmlNodePtr rnode, sfnode;
8701
8702			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8703			if (rnode == NULL)
8704				uu_die(emsg_create_xml);
8705
8706			sfnode = xmlNewChild(rnode, NULL,
8707			    (xmlChar *)"service_fmri", NULL);
8708			if (sfnode == NULL)
8709				uu_die(emsg_create_xml);
8710
8711			if (set_attr_from_prop(exp_prop, sfnode,
8712			    value_attr) == 0) {
8713				selts->restarter = rnode;
8714				continue;
8715			}
8716
8717			xmlFreeNode(rnode);
8718		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
8719		    0) {
8720			xmlNodePtr s;
8721
8722			s = xmlNewNode(NULL, (xmlChar *)"stability");
8723			if (s == NULL)
8724				uu_die(emsg_create_xml);
8725
8726			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8727				selts->stability = s;
8728				continue;
8729			}
8730
8731			xmlFreeNode(s);
8732		}
8733
8734		export_property(exp_prop, exp_str, &elts, 0);
8735	}
8736	if (ret == -1)
8737		scfdie();
8738
8739	if (elts.propvals != NULL || elts.properties != NULL)
8740		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
8741		    selts);
8742}
8743
8744static void
8745export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
8746{
8747	xmlNodePtr n, prof, cred, env;
8748	uint8_t use_profile;
8749	int ret, err = 0;
8750
8751	n = xmlNewNode(NULL, (xmlChar *)"method_context");
8752
8753	env = export_method_environment(pg);
8754
8755	/* Need to know whether we'll use a profile or not. */
8756	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8757	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8758	    prop_get_val(exp_prop, exp_val) == 0) {
8759		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
8760			scfdie();
8761
8762		if (use_profile)
8763			prof =
8764			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
8765			    NULL);
8766		else
8767			cred =
8768			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
8769			    NULL);
8770	}
8771
8772	if (env != NULL)
8773		(void) xmlAddChild(n, env);
8774
8775	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8776		scfdie();
8777
8778	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8779		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8780			scfdie();
8781
8782		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
8783			if (set_attr_from_prop(exp_prop, n,
8784			    "working_directory") != 0)
8785				err = 1;
8786		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
8787			if (set_attr_from_prop(exp_prop, n, "project") != 0)
8788				err = 1;
8789		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
8790			if (set_attr_from_prop(exp_prop, n,
8791			    "resource_pool") != 0)
8792				err = 1;
8793		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8794			/* EMPTY */
8795		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
8796			if (use_profile ||
8797			    set_attr_from_prop(exp_prop, cred, "user") != 0)
8798				err = 1;
8799		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
8800			if (use_profile ||
8801			    set_attr_from_prop(exp_prop, cred, "group") != 0)
8802				err = 1;
8803		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
8804			if (use_profile || set_attr_from_prop(exp_prop, cred,
8805			    "supp_groups") != 0)
8806				err = 1;
8807		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
8808			if (use_profile || set_attr_from_prop(exp_prop, cred,
8809			    "privileges") != 0)
8810				err = 1;
8811		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
8812		    0) {
8813			if (use_profile || set_attr_from_prop(exp_prop, cred,
8814			    "limit_privileges") != 0)
8815				err = 1;
8816		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8817			if (!use_profile || set_attr_from_prop(exp_prop,
8818			    prof, name_attr) != 0)
8819				err = 1;
8820		} else {
8821			/* Can't have generic properties in method_context's */
8822			err = 1;
8823		}
8824	}
8825	if (ret == -1)
8826		scfdie();
8827
8828	if (err && env == NULL) {
8829		xmlFreeNode(n);
8830		export_pg(pg, elts, 0);
8831		return;
8832	}
8833
8834	elts->method_context = n;
8835}
8836
8837/*
8838 * Given a dependency property group in the tfmri entity (target fmri), return
8839 * a dependent element which represents it.
8840 */
8841static xmlNodePtr
8842export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
8843{
8844	uint8_t b;
8845	xmlNodePtr n, sf;
8846	int err = 0, ret;
8847	struct pg_elts pgelts;
8848
8849	/*
8850	 * If external isn't set to true then exporting the service will
8851	 * export this as a normal dependency, so we should stop to avoid
8852	 * duplication.
8853	 */
8854	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
8855	    scf_property_get_value(exp_prop, exp_val) != 0 ||
8856	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
8857		if (g_verbose) {
8858			warn(gettext("Dependent \"%s\" cannot be exported "
8859			    "properly because the \"%s\" property of the "
8860			    "\"%s\" dependency of %s is not set to true.\n"),
8861			    name, scf_property_external, name, tfmri);
8862		}
8863
8864		return (NULL);
8865	}
8866
8867	n = xmlNewNode(NULL, (xmlChar *)"dependent");
8868	if (n == NULL)
8869		uu_die(emsg_create_xml);
8870
8871	safe_setprop(n, name_attr, name);
8872
8873	/* Get the required attributes */
8874	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8875	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8876		err = 1;
8877
8878	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8879	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8880		err = 1;
8881
8882	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8883	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
8884	    prop_get_val(exp_prop, exp_val) == 0) {
8885		/* EMPTY */
8886	} else
8887		err = 1;
8888
8889	if (err) {
8890		xmlFreeNode(n);
8891		return (NULL);
8892	}
8893
8894	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
8895	if (sf == NULL)
8896		uu_die(emsg_create_xml);
8897
8898	safe_setprop(sf, value_attr, tfmri);
8899
8900	/*
8901	 * Now add elements for the other properties.
8902	 */
8903	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8904		scfdie();
8905
8906	(void) memset(&pgelts, 0, sizeof (pgelts));
8907
8908	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8909		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8910			scfdie();
8911
8912		if (strcmp(exp_str, scf_property_external) == 0 ||
8913		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8914		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8915		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8916			continue;
8917		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
8918			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
8919			    prop_get_val(exp_prop, exp_val) == 0) {
8920				char type[sizeof ("service") + 1];
8921
8922				if (scf_value_get_astring(exp_val, type,
8923				    sizeof (type)) < 0)
8924					scfdie();
8925
8926				if (strcmp(type, "service") == 0)
8927					continue;
8928			}
8929		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8930			xmlNodePtr s;
8931
8932			s = xmlNewNode(NULL, (xmlChar *)"stability");
8933			if (s == NULL)
8934				uu_die(emsg_create_xml);
8935
8936			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8937				pgelts.stability = s;
8938				continue;
8939			}
8940
8941			xmlFreeNode(s);
8942		}
8943
8944		export_property(exp_prop, exp_str, &pgelts, 0);
8945	}
8946	if (ret == -1)
8947		scfdie();
8948
8949	(void) xmlAddChild(n, pgelts.stability);
8950	(void) xmlAddChildList(n, pgelts.propvals);
8951	(void) xmlAddChildList(n, pgelts.properties);
8952
8953	return (n);
8954}
8955
8956static void
8957export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
8958{
8959	scf_propertygroup_t *opg;
8960	scf_iter_t *iter;
8961	char *type, *fmri;
8962	int ret;
8963	struct pg_elts pgelts;
8964	xmlNodePtr n;
8965	scf_error_t serr;
8966
8967	if ((opg = scf_pg_create(g_hndl)) == NULL ||
8968	    (iter = scf_iter_create(g_hndl)) == NULL)
8969		scfdie();
8970
8971	/* Can't use exp_prop_iter due to export_dependent(). */
8972	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
8973		scfdie();
8974
8975	type = safe_malloc(max_scf_pg_type_len + 1);
8976
8977	/* Get an extra byte so we can tell if values are too long. */
8978	fmri = safe_malloc(max_scf_fmri_len + 2);
8979
8980	(void) memset(&pgelts, 0, sizeof (pgelts));
8981
8982	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
8983		void *entity;
8984		int isservice;
8985		scf_type_t ty;
8986
8987		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
8988			scfdie();
8989
8990		if ((ty != SCF_TYPE_ASTRING &&
8991		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
8992		    prop_get_val(exp_prop, exp_val) != 0) {
8993			export_property(exp_prop, NULL, &pgelts, 0);
8994			continue;
8995		}
8996
8997		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8998			scfdie();
8999
9000		if (scf_value_get_astring(exp_val, fmri,
9001		    max_scf_fmri_len + 2) < 0)
9002			scfdie();
9003
9004		/* Look for a dependency group in the target fmri. */
9005		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9006		switch (serr) {
9007		case SCF_ERROR_NONE:
9008			break;
9009
9010		case SCF_ERROR_NO_MEMORY:
9011			uu_die(gettext("Out of memory.\n"));
9012			/* NOTREACHED */
9013
9014		case SCF_ERROR_INVALID_ARGUMENT:
9015			if (g_verbose) {
9016				if (scf_property_to_fmri(exp_prop, fmri,
9017				    max_scf_fmri_len + 2) < 0)
9018					scfdie();
9019
9020				warn(gettext("The value of %s is not a valid "
9021				    "FMRI.\n"), fmri);
9022			}
9023
9024			export_property(exp_prop, exp_str, &pgelts, 0);
9025			continue;
9026
9027		case SCF_ERROR_CONSTRAINT_VIOLATED:
9028			if (g_verbose) {
9029				if (scf_property_to_fmri(exp_prop, fmri,
9030				    max_scf_fmri_len + 2) < 0)
9031					scfdie();
9032
9033				warn(gettext("The value of %s does not specify "
9034				    "a service or an instance.\n"), fmri);
9035			}
9036
9037			export_property(exp_prop, exp_str, &pgelts, 0);
9038			continue;
9039
9040		case SCF_ERROR_NOT_FOUND:
9041			if (g_verbose) {
9042				if (scf_property_to_fmri(exp_prop, fmri,
9043				    max_scf_fmri_len + 2) < 0)
9044					scfdie();
9045
9046				warn(gettext("The entity specified by %s does "
9047				    "not exist.\n"), fmri);
9048			}
9049
9050			export_property(exp_prop, exp_str, &pgelts, 0);
9051			continue;
9052
9053		default:
9054#ifndef NDEBUG
9055			(void) fprintf(stderr, "%s:%d: %s() failed with "
9056			    "unexpected error %d.\n", __FILE__, __LINE__,
9057			    "fmri_to_entity", serr);
9058#endif
9059			abort();
9060		}
9061
9062		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9063			if (scf_error() != SCF_ERROR_NOT_FOUND)
9064				scfdie();
9065
9066			warn(gettext("Entity %s is missing dependency property "
9067			    "group %s.\n"), fmri, exp_str);
9068
9069			export_property(exp_prop, NULL, &pgelts, 0);
9070			continue;
9071		}
9072
9073		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9074			scfdie();
9075
9076		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9077			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9078				scfdie();
9079
9080			warn(gettext("Property group %s is not of "
9081			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9082
9083			export_property(exp_prop, NULL, &pgelts, 0);
9084			continue;
9085		}
9086
9087		n = export_dependent(opg, exp_str, fmri);
9088		if (n == NULL)
9089			export_property(exp_prop, exp_str, &pgelts, 0);
9090		else {
9091			if (eelts->dependents == NULL)
9092				eelts->dependents = n;
9093			else
9094				(void) xmlAddSibling(eelts->dependents,
9095				    n);
9096		}
9097	}
9098	if (ret == -1)
9099		scfdie();
9100
9101	free(fmri);
9102	free(type);
9103
9104	scf_iter_destroy(iter);
9105	scf_pg_destroy(opg);
9106
9107	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9108		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9109		    eelts);
9110}
9111
9112static void
9113make_node(xmlNodePtr *nodep, const char *name)
9114{
9115	if (*nodep == NULL) {
9116		*nodep = xmlNewNode(NULL, (xmlChar *)name);
9117		if (*nodep == NULL)
9118			uu_die(emsg_create_xml);
9119	}
9120}
9121
9122static xmlNodePtr
9123export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9124{
9125	int ret;
9126	xmlNodePtr parent = NULL;
9127	xmlNodePtr loctext = NULL;
9128
9129	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9130		scfdie();
9131
9132	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9133		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9134		    prop_get_val(exp_prop, exp_val) != 0)
9135			continue;
9136
9137		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9138			scfdie();
9139
9140		make_node(&parent, parname);
9141		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9142		    (xmlChar *)exp_str);
9143		if (loctext == NULL)
9144			uu_die(emsg_create_xml);
9145
9146		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9147			scfdie();
9148
9149		safe_setprop(loctext, "xml:lang", exp_str);
9150	}
9151
9152	if (ret == -1)
9153		scfdie();
9154
9155	return (parent);
9156}
9157
9158static xmlNodePtr
9159export_tm_manpage(scf_propertygroup_t *pg)
9160{
9161	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9162	if (manpage == NULL)
9163		uu_die(emsg_create_xml);
9164
9165	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9166	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9167	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9168	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9169		xmlFreeNode(manpage);
9170		return (NULL);
9171	}
9172
9173	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9174		(void) set_attr_from_prop_default(exp_prop,
9175		    manpage, "manpath", ":default");
9176
9177	return (manpage);
9178}
9179
9180static xmlNodePtr
9181export_tm_doc_link(scf_propertygroup_t *pg)
9182{
9183	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9184	if (doc_link == NULL)
9185		uu_die(emsg_create_xml);
9186
9187	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9188	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9189	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9190	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9191		xmlFreeNode(doc_link);
9192		return (NULL);
9193	}
9194	return (doc_link);
9195}
9196
9197/*
9198 * Process template information for a service or instances.
9199 */
9200static void
9201export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
9202    struct template_elts *telts)
9203{
9204	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
9205	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
9206	xmlNodePtr child = NULL;
9207
9208	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
9209		scfdie();
9210
9211	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
9212		telts->common_name = export_tm_loctext(pg, "common_name");
9213		if (telts->common_name == NULL)
9214			export_pg(pg, elts, 0);
9215		return;
9216	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
9217		telts->description = export_tm_loctext(pg, "description");
9218		if (telts->description == NULL)
9219			export_pg(pg, elts, 0);
9220		return;
9221	}
9222
9223	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
9224		child = export_tm_manpage(pg);
9225	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
9226		child = export_tm_doc_link(pg);
9227	}
9228
9229	if (child != NULL) {
9230		make_node(&telts->documentation, "documentation");
9231		(void) xmlAddChild(telts->documentation, child);
9232	} else {
9233		export_pg(pg, elts, 0);
9234	}
9235}
9236
9237/*
9238 * Process the general property group for an instance.
9239 */
9240static void
9241export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
9242    struct entity_elts *elts)
9243{
9244	uint8_t enabled;
9245	struct pg_elts pgelts;
9246	int ret;
9247
9248	/* enabled */
9249	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
9250	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9251	    prop_get_val(exp_prop, exp_val) == 0) {
9252		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
9253			scfdie();
9254	} else {
9255		enabled = 0;
9256	}
9257
9258	safe_setprop(inode, enabled_attr, enabled ? true : false);
9259
9260	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9261		scfdie();
9262
9263	(void) memset(&pgelts, 0, sizeof (pgelts));
9264
9265	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9266		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9267			scfdie();
9268
9269		if (strcmp(exp_str, scf_property_enabled) == 0) {
9270			continue;
9271		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9272			xmlNodePtr rnode, sfnode;
9273
9274			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9275			if (rnode == NULL)
9276				uu_die(emsg_create_xml);
9277
9278			sfnode = xmlNewChild(rnode, NULL,
9279			    (xmlChar *)"service_fmri", NULL);
9280			if (sfnode == NULL)
9281				uu_die(emsg_create_xml);
9282
9283			if (set_attr_from_prop(exp_prop, sfnode,
9284			    value_attr) == 0) {
9285				elts->restarter = rnode;
9286				continue;
9287			}
9288
9289			xmlFreeNode(rnode);
9290		}
9291
9292		export_property(exp_prop, exp_str, &pgelts, 0);
9293	}
9294	if (ret == -1)
9295		scfdie();
9296
9297	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9298		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
9299		    elts);
9300}
9301
9302/*
9303 * Put an instance element for the given instance into selts.
9304 */
9305static void
9306export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
9307{
9308	xmlNodePtr n;
9309	boolean_t isdefault;
9310	struct entity_elts elts;
9311	struct template_elts template_elts;
9312	int ret;
9313
9314	n = xmlNewNode(NULL, (xmlChar *)"instance");
9315	if (n == NULL)
9316		uu_die(emsg_create_xml);
9317
9318	/* name */
9319	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
9320		scfdie();
9321	safe_setprop(n, name_attr, exp_str);
9322	isdefault = strcmp(exp_str, "default") == 0;
9323
9324	/* check existance of general pg (since general/enabled is required) */
9325	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
9326		if (scf_error() != SCF_ERROR_NOT_FOUND)
9327			scfdie();
9328
9329		if (g_verbose) {
9330			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
9331				scfdie();
9332
9333			warn(gettext("Instance %s has no general property "
9334			    "group; it will be marked disabled.\n"), exp_str);
9335		}
9336
9337		safe_setprop(n, enabled_attr, false);
9338	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
9339	    strcmp(exp_str, scf_group_framework) != 0) {
9340		if (g_verbose) {
9341			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
9342				scfdie();
9343
9344			warn(gettext("Property group %s is not of type "
9345			    "framework; the instance will be marked "
9346			    "disabled.\n"), exp_str);
9347		}
9348
9349		safe_setprop(n, enabled_attr, false);
9350	}
9351
9352	/* property groups */
9353	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
9354		scfdie();
9355
9356	(void) memset(&elts, 0, sizeof (elts));
9357	(void) memset(&template_elts, 0, sizeof (template_elts));
9358
9359	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9360		uint32_t pgflags;
9361
9362		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9363			scfdie();
9364
9365		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9366			continue;
9367
9368		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9369			scfdie();
9370
9371		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9372			export_dependency(exp_pg, &elts);
9373			continue;
9374		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9375			export_method(exp_pg, &elts);
9376			continue;
9377		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9378			if (scf_pg_get_name(exp_pg, exp_str,
9379			    max_scf_name_len + 1) < 0)
9380				scfdie();
9381
9382			if (strcmp(exp_str, scf_pg_general) == 0) {
9383				export_inst_general(exp_pg, n, &elts);
9384				continue;
9385			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9386			    0) {
9387				export_method_context(exp_pg, &elts);
9388				continue;
9389			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9390				export_dependents(exp_pg, &elts);
9391				continue;
9392			}
9393		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9394			export_template(exp_pg, &elts, &template_elts);
9395			continue;
9396		}
9397
9398		/* Ordinary pg. */
9399		export_pg(exp_pg, &elts, flags);
9400	}
9401	if (ret == -1)
9402		scfdie();
9403
9404	if (template_elts.common_name != NULL) {
9405		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9406		(void) xmlAddChild(elts.template, template_elts.common_name);
9407		(void) xmlAddChild(elts.template, template_elts.description);
9408		(void) xmlAddChild(elts.template, template_elts.documentation);
9409	} else {
9410		xmlFreeNode(template_elts.description);
9411		xmlFreeNode(template_elts.documentation);
9412	}
9413
9414	if (isdefault && elts.restarter == NULL &&
9415	    elts.dependencies == NULL && elts.method_context == NULL &&
9416	    elts.exec_methods == NULL && elts.property_groups == NULL &&
9417	    elts.template == NULL) {
9418		xmlChar *eval;
9419
9420		/* This is a default instance */
9421		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
9422
9423		xmlFreeNode(n);
9424
9425		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
9426		if (n == NULL)
9427			uu_die(emsg_create_xml);
9428
9429		safe_setprop(n, enabled_attr, (char *)eval);
9430		xmlFree(eval);
9431
9432		selts->create_default_instance = n;
9433	} else {
9434		/* Assemble the children in order. */
9435		(void) xmlAddChild(n, elts.restarter);
9436		(void) xmlAddChildList(n, elts.dependencies);
9437		(void) xmlAddChildList(n, elts.dependents);
9438		(void) xmlAddChild(n, elts.method_context);
9439		(void) xmlAddChildList(n, elts.exec_methods);
9440		(void) xmlAddChildList(n, elts.property_groups);
9441		(void) xmlAddChild(n, elts.template);
9442
9443		if (selts->instances == NULL)
9444			selts->instances = n;
9445		else
9446			(void) xmlAddSibling(selts->instances, n);
9447	}
9448}
9449
9450/*
9451 * Return a service element for the given service.
9452 */
9453static xmlNodePtr
9454export_service(scf_service_t *svc, int flags)
9455{
9456	xmlNodePtr snode;
9457	struct entity_elts elts;
9458	struct template_elts template_elts;
9459	int ret;
9460
9461	snode = xmlNewNode(NULL, (xmlChar *)"service");
9462	if (snode == NULL)
9463		uu_die(emsg_create_xml);
9464
9465	/* Get & set name attribute */
9466	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
9467		scfdie();
9468	safe_setprop(snode, name_attr, exp_str);
9469
9470	safe_setprop(snode, type_attr, "service");
9471	safe_setprop(snode, "version", "0");
9472
9473	/* Acquire child elements. */
9474	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
9475		scfdie();
9476
9477	(void) memset(&elts, 0, sizeof (elts));
9478	(void) memset(&template_elts, 0, sizeof (template_elts));
9479
9480	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9481		uint32_t pgflags;
9482
9483		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9484			scfdie();
9485
9486		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9487			continue;
9488
9489		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9490			scfdie();
9491
9492		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9493			export_dependency(exp_pg, &elts);
9494			continue;
9495		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9496			export_method(exp_pg, &elts);
9497			continue;
9498		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9499			if (scf_pg_get_name(exp_pg, exp_str,
9500			    max_scf_name_len + 1) < 0)
9501				scfdie();
9502
9503			if (strcmp(exp_str, scf_pg_general) == 0) {
9504				export_svc_general(exp_pg, &elts);
9505				continue;
9506			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9507			    0) {
9508				export_method_context(exp_pg, &elts);
9509				continue;
9510			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9511				export_dependents(exp_pg, &elts);
9512				continue;
9513			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
9514				continue;
9515			}
9516		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9517			export_template(exp_pg, &elts, &template_elts);
9518			continue;
9519		}
9520
9521		export_pg(exp_pg, &elts, flags);
9522	}
9523	if (ret == -1)
9524		scfdie();
9525
9526	if (template_elts.common_name != NULL) {
9527		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9528		(void) xmlAddChild(elts.template, template_elts.common_name);
9529		(void) xmlAddChild(elts.template, template_elts.description);
9530		(void) xmlAddChild(elts.template, template_elts.documentation);
9531	} else {
9532		xmlFreeNode(template_elts.description);
9533		xmlFreeNode(template_elts.documentation);
9534	}
9535
9536	/* Iterate instances */
9537	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
9538		scfdie();
9539
9540	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
9541		export_instance(exp_inst, &elts, flags);
9542	if (ret == -1)
9543		scfdie();
9544
9545	/* Now add all of the accumulated elements in order. */
9546	(void) xmlAddChild(snode, elts.create_default_instance);
9547	(void) xmlAddChild(snode, elts.single_instance);
9548	(void) xmlAddChild(snode, elts.restarter);
9549	(void) xmlAddChildList(snode, elts.dependencies);
9550	(void) xmlAddChildList(snode, elts.dependents);
9551	(void) xmlAddChild(snode, elts.method_context);
9552	(void) xmlAddChildList(snode, elts.exec_methods);
9553	(void) xmlAddChildList(snode, elts.property_groups);
9554	(void) xmlAddChildList(snode, elts.instances);
9555	(void) xmlAddChild(snode, elts.stability);
9556	(void) xmlAddChild(snode, elts.template);
9557
9558	return (snode);
9559}
9560
9561static int
9562export_callback(void *data, scf_walkinfo_t *wip)
9563{
9564	FILE *f;
9565	xmlDocPtr doc;
9566	xmlNodePtr sb;
9567	int result;
9568	struct export_args *argsp = (struct export_args *)data;
9569
9570	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
9571	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9572	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9573	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9574	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9575	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9576	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9577	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9578		scfdie();
9579
9580	exp_str_sz = max_scf_len + 1;
9581	exp_str = safe_malloc(exp_str_sz);
9582
9583	if (argsp->filename != NULL) {
9584		errno = 0;
9585		f = fopen(argsp->filename, "wb");
9586		if (f == NULL) {
9587			if (errno == 0)
9588				uu_die(gettext("Could not open \"%s\": no free "
9589				    "stdio streams.\n"), argsp->filename);
9590			else
9591				uu_die(gettext("Could not open \"%s\""),
9592				    argsp->filename);
9593		}
9594	} else
9595		f = stdout;
9596
9597	doc = xmlNewDoc((xmlChar *)"1.0");
9598	if (doc == NULL)
9599		uu_die(gettext("Could not create XML document.\n"));
9600
9601	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9602	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9603		uu_die(emsg_create_xml);
9604
9605	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9606	if (sb == NULL)
9607		uu_die(emsg_create_xml);
9608	safe_setprop(sb, type_attr, "manifest");
9609	safe_setprop(sb, name_attr, "export");
9610	(void) xmlAddSibling(doc->children, sb);
9611
9612	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
9613
9614	result = write_service_bundle(doc, f);
9615
9616	free(exp_str);
9617	scf_iter_destroy(exp_val_iter);
9618	scf_iter_destroy(exp_prop_iter);
9619	scf_iter_destroy(exp_pg_iter);
9620	scf_iter_destroy(exp_inst_iter);
9621	scf_value_destroy(exp_val);
9622	scf_property_destroy(exp_prop);
9623	scf_pg_destroy(exp_pg);
9624	scf_instance_destroy(exp_inst);
9625
9626	xmlFreeDoc(doc);
9627
9628	if (f != stdout)
9629		(void) fclose(f);
9630
9631	return (result);
9632}
9633
9634/*
9635 * Get the service named by fmri, build an XML tree which represents it, and
9636 * dump it into filename (or stdout if filename is NULL).
9637 */
9638int
9639lscf_service_export(char *fmri, const char *filename, int flags)
9640{
9641	struct export_args args;
9642	int ret, err;
9643
9644	lscf_prep_hndl();
9645
9646	bzero(&args, sizeof (args));
9647	args.filename = filename;
9648	args.flags = flags;
9649
9650	err = 0;
9651	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
9652	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
9653	    &args, &err, semerr)) != 0) {
9654		if (ret != -1)
9655			semerr(gettext("Failed to walk instances: %s\n"),
9656			    scf_strerror(ret));
9657		return (-1);
9658	}
9659
9660	/*
9661	 * Error message has already been printed.
9662	 */
9663	if (err != 0)
9664		return (-1);
9665
9666	return (0);
9667}
9668
9669
9670/*
9671 * Archive
9672 */
9673
9674static xmlNodePtr
9675make_archive(int flags)
9676{
9677	xmlNodePtr sb;
9678	scf_scope_t *scope;
9679	scf_service_t *svc;
9680	scf_iter_t *iter;
9681	int r;
9682
9683	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9684	    (svc = scf_service_create(g_hndl)) == NULL ||
9685	    (iter = scf_iter_create(g_hndl)) == NULL ||
9686	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
9687	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9688	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9689	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9690	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9691	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9692	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9693	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9694		scfdie();
9695
9696	exp_str_sz = max_scf_len + 1;
9697	exp_str = safe_malloc(exp_str_sz);
9698
9699	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9700	if (sb == NULL)
9701		uu_die(emsg_create_xml);
9702	safe_setprop(sb, type_attr, "archive");
9703	safe_setprop(sb, name_attr, "none");
9704
9705	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
9706		scfdie();
9707	if (scf_iter_scope_services(iter, scope) != 0)
9708		scfdie();
9709
9710	for (;;) {
9711		r = scf_iter_next_service(iter, svc);
9712		if (r == 0)
9713			break;
9714		if (r != 1)
9715			scfdie();
9716
9717		if (scf_service_get_name(svc, exp_str,
9718		    max_scf_name_len + 1) < 0)
9719			scfdie();
9720
9721		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
9722			continue;
9723
9724		(void) xmlAddChild(sb, export_service(svc, flags));
9725	}
9726
9727	free(exp_str);
9728
9729	scf_iter_destroy(exp_val_iter);
9730	scf_iter_destroy(exp_prop_iter);
9731	scf_iter_destroy(exp_pg_iter);
9732	scf_iter_destroy(exp_inst_iter);
9733	scf_value_destroy(exp_val);
9734	scf_property_destroy(exp_prop);
9735	scf_pg_destroy(exp_pg);
9736	scf_instance_destroy(exp_inst);
9737	scf_iter_destroy(iter);
9738	scf_service_destroy(svc);
9739	scf_scope_destroy(scope);
9740
9741	return (sb);
9742}
9743
9744int
9745lscf_archive(const char *filename, int flags)
9746{
9747	FILE *f;
9748	xmlDocPtr doc;
9749	int result;
9750
9751	lscf_prep_hndl();
9752
9753	if (filename != NULL) {
9754		errno = 0;
9755		f = fopen(filename, "wb");
9756		if (f == NULL) {
9757			if (errno == 0)
9758				uu_die(gettext("Could not open \"%s\": no free "
9759				    "stdio streams.\n"), filename);
9760			else
9761				uu_die(gettext("Could not open \"%s\""),
9762				    filename);
9763		}
9764	} else
9765		f = stdout;
9766
9767	doc = xmlNewDoc((xmlChar *)"1.0");
9768	if (doc == NULL)
9769		uu_die(gettext("Could not create XML document.\n"));
9770
9771	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9772	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9773		uu_die(emsg_create_xml);
9774
9775	(void) xmlAddSibling(doc->children, make_archive(flags));
9776
9777	result = write_service_bundle(doc, f);
9778
9779	xmlFreeDoc(doc);
9780
9781	if (f != stdout)
9782		(void) fclose(f);
9783
9784	return (result);
9785}
9786
9787
9788/*
9789 * "Extract" a profile.
9790 */
9791int
9792lscf_profile_extract(const char *filename)
9793{
9794	FILE *f;
9795	xmlDocPtr doc;
9796	xmlNodePtr sb, snode, inode;
9797	scf_scope_t *scope;
9798	scf_service_t *svc;
9799	scf_instance_t *inst;
9800	scf_propertygroup_t *pg;
9801	scf_property_t *prop;
9802	scf_value_t *val;
9803	scf_iter_t *siter, *iiter;
9804	int r, s;
9805	char *namebuf;
9806	uint8_t b;
9807	int result;
9808
9809	lscf_prep_hndl();
9810
9811	if (filename != NULL) {
9812		errno = 0;
9813		f = fopen(filename, "wb");
9814		if (f == NULL) {
9815			if (errno == 0)
9816				uu_die(gettext("Could not open \"%s\": no "
9817				    "free stdio streams.\n"), filename);
9818			else
9819				uu_die(gettext("Could not open \"%s\""),
9820				    filename);
9821		}
9822	} else
9823		f = stdout;
9824
9825	doc = xmlNewDoc((xmlChar *)"1.0");
9826	if (doc == NULL)
9827		uu_die(gettext("Could not create XML document.\n"));
9828
9829	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9830	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9831		uu_die(emsg_create_xml);
9832
9833	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9834	if (sb == NULL)
9835		uu_die(emsg_create_xml);
9836	safe_setprop(sb, type_attr, "profile");
9837	safe_setprop(sb, name_attr, "extract");
9838	(void) xmlAddSibling(doc->children, sb);
9839
9840	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9841	    (svc = scf_service_create(g_hndl)) == NULL ||
9842	    (inst = scf_instance_create(g_hndl)) == NULL ||
9843	    (pg = scf_pg_create(g_hndl)) == NULL ||
9844	    (prop = scf_property_create(g_hndl)) == NULL ||
9845	    (val = scf_value_create(g_hndl)) == NULL ||
9846	    (siter = scf_iter_create(g_hndl)) == NULL ||
9847	    (iiter = scf_iter_create(g_hndl)) == NULL)
9848		scfdie();
9849
9850	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
9851		scfdie();
9852
9853	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
9854		scfdie();
9855
9856	namebuf = safe_malloc(max_scf_name_len + 1);
9857
9858	while ((r = scf_iter_next_service(siter, svc)) == 1) {
9859		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
9860			scfdie();
9861
9862		snode = xmlNewNode(NULL, (xmlChar *)"service");
9863		if (snode == NULL)
9864			uu_die(emsg_create_xml);
9865
9866		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
9867		    0)
9868			scfdie();
9869
9870		safe_setprop(snode, name_attr, namebuf);
9871
9872		safe_setprop(snode, type_attr, "service");
9873		safe_setprop(snode, "version", "0");
9874
9875		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
9876			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
9877			    SCF_SUCCESS) {
9878				if (scf_error() != SCF_ERROR_NOT_FOUND)
9879					scfdie();
9880
9881				if (g_verbose) {
9882					ssize_t len;
9883					char *fmri;
9884
9885					len =
9886					    scf_instance_to_fmri(inst, NULL, 0);
9887					if (len < 0)
9888						scfdie();
9889
9890					fmri = safe_malloc(len + 1);
9891
9892					if (scf_instance_to_fmri(inst, fmri,
9893					    len + 1) < 0)
9894						scfdie();
9895
9896					warn("Instance %s has no \"%s\" "
9897					    "property group.\n", fmri,
9898					    scf_pg_general);
9899
9900					free(fmri);
9901				}
9902
9903				continue;
9904			}
9905
9906			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
9907			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
9908			    prop_get_val(prop, val) != 0)
9909				continue;
9910
9911			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
9912			    NULL);
9913			if (inode == NULL)
9914				uu_die(emsg_create_xml);
9915
9916			if (scf_instance_get_name(inst, namebuf,
9917			    max_scf_name_len + 1) < 0)
9918				scfdie();
9919
9920			safe_setprop(inode, name_attr, namebuf);
9921
9922			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
9923				scfdie();
9924
9925			safe_setprop(inode, enabled_attr, b ? true : false);
9926		}
9927		if (s < 0)
9928			scfdie();
9929
9930		if (snode->children != NULL)
9931			(void) xmlAddChild(sb, snode);
9932		else
9933			xmlFreeNode(snode);
9934	}
9935	if (r < 0)
9936		scfdie();
9937
9938	free(namebuf);
9939
9940	result = write_service_bundle(doc, f);
9941
9942	xmlFreeDoc(doc);
9943
9944	if (f != stdout)
9945		(void) fclose(f);
9946
9947	return (result);
9948}
9949
9950
9951/*
9952 * Entity manipulation commands
9953 */
9954
9955/*
9956 * Entity selection.  If no entity is selected, then the current scope is in
9957 * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
9958 * only cur_inst is NULL, and when an instance is selected, none are NULL.
9959 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
9960 * cur_inst will be non-NULL.
9961 */
9962
9963/* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
9964static int
9965select_inst(const char *name)
9966{
9967	scf_instance_t *inst;
9968	scf_error_t err;
9969
9970	assert(cur_svc != NULL);
9971
9972	inst = scf_instance_create(g_hndl);
9973	if (inst == NULL)
9974		scfdie();
9975
9976	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
9977		cur_inst = inst;
9978		return (0);
9979	}
9980
9981	err = scf_error();
9982	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9983		scfdie();
9984
9985	scf_instance_destroy(inst);
9986	return (1);
9987}
9988
9989/* Returns as above. */
9990static int
9991select_svc(const char *name)
9992{
9993	scf_service_t *svc;
9994	scf_error_t err;
9995
9996	assert(cur_scope != NULL);
9997
9998	svc = scf_service_create(g_hndl);
9999	if (svc == NULL)
10000		scfdie();
10001
10002	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10003		cur_svc = svc;
10004		return (0);
10005	}
10006
10007	err = scf_error();
10008	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10009		scfdie();
10010
10011	scf_service_destroy(svc);
10012	return (1);
10013}
10014
10015/* ARGSUSED */
10016static int
10017select_callback(void *unused, scf_walkinfo_t *wip)
10018{
10019	scf_instance_t *inst;
10020	scf_service_t *svc;
10021	scf_scope_t *scope;
10022
10023	if (wip->inst != NULL) {
10024		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10025		    (svc = scf_service_create(g_hndl)) == NULL ||
10026		    (inst = scf_instance_create(g_hndl)) == NULL)
10027			scfdie();
10028
10029		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10030		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10031			scfdie();
10032	} else {
10033		assert(wip->svc != NULL);
10034
10035		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10036		    (svc = scf_service_create(g_hndl)) == NULL)
10037			scfdie();
10038
10039		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10040		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10041			scfdie();
10042
10043		inst = NULL;
10044	}
10045
10046	/* Clear out the current selection */
10047	assert(cur_scope != NULL);
10048	scf_scope_destroy(cur_scope);
10049	scf_service_destroy(cur_svc);
10050	scf_instance_destroy(cur_inst);
10051
10052	cur_scope = scope;
10053	cur_svc = svc;
10054	cur_inst = inst;
10055
10056	return (0);
10057}
10058
10059static int
10060validate_callback(void *fmri_p, scf_walkinfo_t *wip)
10061{
10062	char **fmri = fmri_p;
10063
10064	*fmri = strdup(wip->fmri);
10065	if (*fmri == NULL)
10066		uu_die(gettext("Out of memory.\n"));
10067
10068	return (0);
10069}
10070
10071/*
10072 * validate [fmri]
10073 * Perform the validation of an FMRI instance.
10074 */
10075void
10076lscf_validate_fmri(const char *fmri)
10077{
10078	int ret = 0;
10079	size_t inst_sz;
10080	char *inst_fmri = NULL;
10081	scf_tmpl_errors_t *errs = NULL;
10082	char *snapbuf = NULL;
10083
10084	lscf_prep_hndl();
10085
10086	if (fmri == NULL) {
10087		inst_sz = max_scf_fmri_len + 1;
10088		inst_fmri = safe_malloc(inst_sz);
10089
10090		if (cur_snap != NULL) {
10091			snapbuf = safe_malloc(max_scf_name_len + 1);
10092			if (scf_snapshot_get_name(cur_snap, snapbuf,
10093			    max_scf_name_len + 1) < 0)
10094				scfdie();
10095		}
10096		if (cur_inst == NULL) {
10097			semerr(gettext("No instance selected\n"));
10098			goto cleanup;
10099		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
10100		    inst_sz) >= inst_sz) {
10101			/* sanity check. Should never get here */
10102			uu_die(gettext("Unexpected error! file %s, line %d\n"),
10103			    __FILE__, __LINE__);
10104		}
10105	} else {
10106		scf_error_t scf_err;
10107		int err = 0;
10108
10109		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
10110		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
10111			uu_warn("Failed to walk instances: %s\n",
10112			    scf_strerror(scf_err));
10113			goto cleanup;
10114		}
10115		if (err != 0) {
10116			/* error message displayed by scf_walk_fmri */
10117			goto cleanup;
10118		}
10119	}
10120
10121	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
10122	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
10123	if (ret == -1) {
10124		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
10125			warn(gettext("Template data for %s is invalid. "
10126			    "Consider reverting to a previous snapshot or "
10127			    "restoring original configuration.\n"), inst_fmri);
10128		} else {
10129			uu_warn("%s: %s\n",
10130			    gettext("Error validating the instance"),
10131			    scf_strerror(scf_error()));
10132		}
10133	} else if (ret == 1 && errs != NULL) {
10134		scf_tmpl_error_t *err = NULL;
10135		char *msg;
10136		size_t len = 256;	/* initial error buffer size */
10137		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
10138		    SCF_TMPL_STRERROR_HUMAN : 0;
10139
10140		msg = safe_malloc(len);
10141
10142		while ((err = scf_tmpl_next_error(errs)) != NULL) {
10143			int ret;
10144
10145			if ((ret = scf_tmpl_strerror(err, msg, len,
10146			    flag)) >= len) {
10147				len = ret + 1;
10148				msg = realloc(msg, len);
10149				if (msg == NULL)
10150					uu_die(gettext(
10151					    "Out of memory.\n"));
10152				(void) scf_tmpl_strerror(err, msg, len,
10153				    flag);
10154			}
10155			(void) fprintf(stderr, "%s\n", msg);
10156		}
10157		if (msg != NULL)
10158			free(msg);
10159	}
10160	if (errs != NULL)
10161		scf_tmpl_errors_destroy(errs);
10162
10163cleanup:
10164	free(inst_fmri);
10165	free(snapbuf);
10166}
10167
10168static void
10169lscf_validate_file(const char *filename)
10170{
10171	tmpl_errors_t *errs;
10172
10173	bundle_t *b = internal_bundle_new();
10174	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
10175		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
10176			tmpl_errors_print(stderr, errs, "");
10177			semerr(gettext("Validation failed.\n"));
10178		}
10179		tmpl_errors_destroy(errs);
10180	}
10181	(void) internal_bundle_free(b);
10182}
10183
10184/*
10185 * validate [fmri|file]
10186 */
10187void
10188lscf_validate(const char *arg)
10189{
10190	const char *str;
10191
10192	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
10193	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
10194		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
10195		lscf_validate_file(str);
10196	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
10197	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
10198		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
10199		lscf_validate_fmri(str);
10200	} else if (access(arg, R_OK | F_OK) == 0) {
10201		lscf_validate_file(arg);
10202	} else {
10203		lscf_validate_fmri(arg);
10204	}
10205}
10206
10207void
10208lscf_select(const char *fmri)
10209{
10210	int ret, err;
10211
10212	lscf_prep_hndl();
10213
10214	if (cur_snap != NULL) {
10215		struct snaplevel *elt;
10216		char *buf;
10217
10218		/* Error unless name is that of the next level. */
10219		elt = uu_list_next(cur_levels, cur_elt);
10220		if (elt == NULL) {
10221			semerr(gettext("No children.\n"));
10222			return;
10223		}
10224
10225		buf = safe_malloc(max_scf_name_len + 1);
10226
10227		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10228		    max_scf_name_len + 1) < 0)
10229			scfdie();
10230
10231		if (strcmp(buf, fmri) != 0) {
10232			semerr(gettext("No such child.\n"));
10233			free(buf);
10234			return;
10235		}
10236
10237		free(buf);
10238
10239		cur_elt = elt;
10240		cur_level = elt->sl;
10241		return;
10242	}
10243
10244	/*
10245	 * Special case for 'svc:', which takes the user to the scope level.
10246	 */
10247	if (strcmp(fmri, "svc:") == 0) {
10248		scf_instance_destroy(cur_inst);
10249		scf_service_destroy(cur_svc);
10250		cur_inst = NULL;
10251		cur_svc = NULL;
10252		return;
10253	}
10254
10255	/*
10256	 * Special case for ':properties'.  This appears as part of 'list' but
10257	 * can't be selected.  Give a more helpful error message in this case.
10258	 */
10259	if (strcmp(fmri, ":properties") == 0) {
10260		semerr(gettext(":properties is not an entity.  Try 'listprop' "
10261		    "to list properties.\n"));
10262		return;
10263	}
10264
10265	/*
10266	 * First try the argument as relative to the current selection.
10267	 */
10268	if (cur_inst != NULL) {
10269		/* EMPTY */;
10270	} else if (cur_svc != NULL) {
10271		if (select_inst(fmri) != 1)
10272			return;
10273	} else {
10274		if (select_svc(fmri) != 1)
10275			return;
10276	}
10277
10278	err = 0;
10279	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
10280	    select_callback, NULL, &err, semerr)) != 0) {
10281		semerr(gettext("Failed to walk instances: %s\n"),
10282		    scf_strerror(ret));
10283	}
10284}
10285
10286void
10287lscf_unselect(void)
10288{
10289	lscf_prep_hndl();
10290
10291	if (cur_snap != NULL) {
10292		struct snaplevel *elt;
10293
10294		elt = uu_list_prev(cur_levels, cur_elt);
10295		if (elt == NULL) {
10296			semerr(gettext("No parent levels.\n"));
10297		} else {
10298			cur_elt = elt;
10299			cur_level = elt->sl;
10300		}
10301	} else if (cur_inst != NULL) {
10302		scf_instance_destroy(cur_inst);
10303		cur_inst = NULL;
10304	} else if (cur_svc != NULL) {
10305		scf_service_destroy(cur_svc);
10306		cur_svc = NULL;
10307	} else {
10308		semerr(gettext("Cannot unselect at scope level.\n"));
10309	}
10310}
10311
10312/*
10313 * Return the FMRI of the current selection, for the prompt.
10314 */
10315void
10316lscf_get_selection_str(char *buf, size_t bufsz)
10317{
10318	char *cp;
10319	ssize_t fmrilen, szret;
10320	boolean_t deleted = B_FALSE;
10321
10322	if (g_hndl == NULL) {
10323		(void) strlcpy(buf, "svc:", bufsz);
10324		return;
10325	}
10326
10327	if (cur_level != NULL) {
10328		assert(cur_snap != NULL);
10329
10330		/* [ snapshot ] FMRI [: instance ] */
10331		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
10332		    + 2 + max_scf_name_len + 1 + 1);
10333
10334		buf[0] = '[';
10335
10336		szret = scf_snapshot_get_name(cur_snap, buf + 1,
10337		    max_scf_name_len + 1);
10338		if (szret < 0) {
10339			if (scf_error() != SCF_ERROR_DELETED)
10340				scfdie();
10341
10342			goto snap_deleted;
10343		}
10344
10345		(void) strcat(buf, "]svc:/");
10346
10347		cp = strchr(buf, '\0');
10348
10349		szret = scf_snaplevel_get_service_name(cur_level, cp,
10350		    max_scf_name_len + 1);
10351		if (szret < 0) {
10352			if (scf_error() != SCF_ERROR_DELETED)
10353				scfdie();
10354
10355			goto snap_deleted;
10356		}
10357
10358		cp = strchr(cp, '\0');
10359
10360		if (snaplevel_is_instance(cur_level)) {
10361			*cp++ = ':';
10362
10363			if (scf_snaplevel_get_instance_name(cur_level, cp,
10364			    max_scf_name_len + 1) < 0) {
10365				if (scf_error() != SCF_ERROR_DELETED)
10366					scfdie();
10367
10368				goto snap_deleted;
10369			}
10370		} else {
10371			*cp++ = '[';
10372			*cp++ = ':';
10373
10374			if (scf_instance_get_name(cur_inst, cp,
10375			    max_scf_name_len + 1) < 0) {
10376				if (scf_error() != SCF_ERROR_DELETED)
10377					scfdie();
10378
10379				goto snap_deleted;
10380			}
10381
10382			(void) strcat(buf, "]");
10383		}
10384
10385		return;
10386
10387snap_deleted:
10388		deleted = B_TRUE;
10389		free(buf);
10390		unselect_cursnap();
10391	}
10392
10393	assert(cur_snap == NULL);
10394
10395	if (cur_inst != NULL) {
10396		assert(cur_svc != NULL);
10397		assert(cur_scope != NULL);
10398
10399		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
10400		if (fmrilen >= 0) {
10401			assert(fmrilen < bufsz);
10402			if (deleted)
10403				warn(emsg_deleted);
10404			return;
10405		}
10406
10407		if (scf_error() != SCF_ERROR_DELETED)
10408			scfdie();
10409
10410		deleted = B_TRUE;
10411
10412		scf_instance_destroy(cur_inst);
10413		cur_inst = NULL;
10414	}
10415
10416	if (cur_svc != NULL) {
10417		assert(cur_scope != NULL);
10418
10419		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
10420		if (szret >= 0) {
10421			assert(szret < bufsz);
10422			if (deleted)
10423				warn(emsg_deleted);
10424			return;
10425		}
10426
10427		if (scf_error() != SCF_ERROR_DELETED)
10428			scfdie();
10429
10430		deleted = B_TRUE;
10431		scf_service_destroy(cur_svc);
10432		cur_svc = NULL;
10433	}
10434
10435	assert(cur_scope != NULL);
10436	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
10437
10438	if (fmrilen < 0)
10439		scfdie();
10440
10441	assert(fmrilen < bufsz);
10442	if (deleted)
10443		warn(emsg_deleted);
10444}
10445
10446/*
10447 * Entity listing.  Entities and colon namespaces (e.g., :properties and
10448 * :statistics) are listed for the current selection.
10449 */
10450void
10451lscf_list(const char *pattern)
10452{
10453	scf_iter_t *iter;
10454	char *buf;
10455	int ret;
10456
10457	lscf_prep_hndl();
10458
10459	if (cur_level != NULL) {
10460		struct snaplevel *elt;
10461
10462		(void) fputs(COLON_NAMESPACES, stdout);
10463
10464		elt = uu_list_next(cur_levels, cur_elt);
10465		if (elt == NULL)
10466			return;
10467
10468		/*
10469		 * For now, we know that the next level is an instance.  But
10470		 * if we ever have multiple scopes, this could be complicated.
10471		 */
10472		buf = safe_malloc(max_scf_name_len + 1);
10473		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10474		    max_scf_name_len + 1) >= 0) {
10475			(void) puts(buf);
10476		} else {
10477			if (scf_error() != SCF_ERROR_DELETED)
10478				scfdie();
10479		}
10480
10481		free(buf);
10482
10483		return;
10484	}
10485
10486	if (cur_inst != NULL) {
10487		(void) fputs(COLON_NAMESPACES, stdout);
10488		return;
10489	}
10490
10491	iter = scf_iter_create(g_hndl);
10492	if (iter == NULL)
10493		scfdie();
10494
10495	buf = safe_malloc(max_scf_name_len + 1);
10496
10497	if (cur_svc != NULL) {
10498		/* List the instances in this service. */
10499		scf_instance_t *inst;
10500
10501		inst = scf_instance_create(g_hndl);
10502		if (inst == NULL)
10503			scfdie();
10504
10505		if (scf_iter_service_instances(iter, cur_svc) == 0) {
10506			safe_printf(COLON_NAMESPACES);
10507
10508			for (;;) {
10509				ret = scf_iter_next_instance(iter, inst);
10510				if (ret == 0)
10511					break;
10512				if (ret != 1) {
10513					if (scf_error() != SCF_ERROR_DELETED)
10514						scfdie();
10515
10516					break;
10517				}
10518
10519				if (scf_instance_get_name(inst, buf,
10520				    max_scf_name_len + 1) >= 0) {
10521					if (pattern == NULL ||
10522					    fnmatch(pattern, buf, 0) == 0)
10523						(void) puts(buf);
10524				} else {
10525					if (scf_error() != SCF_ERROR_DELETED)
10526						scfdie();
10527				}
10528			}
10529		} else {
10530			if (scf_error() != SCF_ERROR_DELETED)
10531				scfdie();
10532		}
10533
10534		scf_instance_destroy(inst);
10535	} else {
10536		/* List the services in this scope. */
10537		scf_service_t *svc;
10538
10539		assert(cur_scope != NULL);
10540
10541		svc = scf_service_create(g_hndl);
10542		if (svc == NULL)
10543			scfdie();
10544
10545		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
10546			scfdie();
10547
10548		for (;;) {
10549			ret = scf_iter_next_service(iter, svc);
10550			if (ret == 0)
10551				break;
10552			if (ret != 1)
10553				scfdie();
10554
10555			if (scf_service_get_name(svc, buf,
10556			    max_scf_name_len + 1) >= 0) {
10557				if (pattern == NULL ||
10558				    fnmatch(pattern, buf, 0) == 0)
10559					safe_printf("%s\n", buf);
10560			} else {
10561				if (scf_error() != SCF_ERROR_DELETED)
10562					scfdie();
10563			}
10564		}
10565
10566		scf_service_destroy(svc);
10567	}
10568
10569	free(buf);
10570	scf_iter_destroy(iter);
10571}
10572
10573/*
10574 * Entity addition.  Creates an empty entity in the current selection.
10575 */
10576void
10577lscf_add(const char *name)
10578{
10579	lscf_prep_hndl();
10580
10581	if (cur_snap != NULL) {
10582		semerr(emsg_cant_modify_snapshots);
10583	} else if (cur_inst != NULL) {
10584		semerr(gettext("Cannot add entities to an instance.\n"));
10585	} else if (cur_svc != NULL) {
10586
10587		if (scf_service_add_instance(cur_svc, name, NULL) !=
10588		    SCF_SUCCESS) {
10589			switch (scf_error()) {
10590			case SCF_ERROR_INVALID_ARGUMENT:
10591				semerr(gettext("Invalid name.\n"));
10592				break;
10593
10594			case SCF_ERROR_EXISTS:
10595				semerr(gettext("Instance already exists.\n"));
10596				break;
10597
10598			case SCF_ERROR_PERMISSION_DENIED:
10599				semerr(emsg_permission_denied);
10600				break;
10601
10602			default:
10603				scfdie();
10604			}
10605		}
10606	} else {
10607		assert(cur_scope != NULL);
10608
10609		if (scf_scope_add_service(cur_scope, name, NULL) !=
10610		    SCF_SUCCESS) {
10611			switch (scf_error()) {
10612			case SCF_ERROR_INVALID_ARGUMENT:
10613				semerr(gettext("Invalid name.\n"));
10614				break;
10615
10616			case SCF_ERROR_EXISTS:
10617				semerr(gettext("Service already exists.\n"));
10618				break;
10619
10620			case SCF_ERROR_PERMISSION_DENIED:
10621				semerr(emsg_permission_denied);
10622				break;
10623
10624			case SCF_ERROR_BACKEND_READONLY:
10625				semerr(emsg_read_only);
10626				break;
10627
10628			default:
10629				scfdie();
10630			}
10631		}
10632	}
10633}
10634
10635/* return 1 if the entity has no persistent pgs, else return 0 */
10636static int
10637entity_has_no_pgs(void *ent, int isservice)
10638{
10639	scf_iter_t *iter = NULL;
10640	scf_propertygroup_t *pg = NULL;
10641	uint32_t flags;
10642	int err;
10643	int ret = 1;
10644
10645	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10646	    (pg = scf_pg_create(g_hndl)) == NULL)
10647		scfdie();
10648
10649	if (isservice) {
10650		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
10651			scfdie();
10652	} else {
10653		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
10654			scfdie();
10655	}
10656
10657	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10658		if (scf_pg_get_flags(pg, &flags) != 0)
10659			scfdie();
10660
10661		/* skip nonpersistent pgs */
10662		if (flags & SCF_PG_FLAG_NONPERSISTENT)
10663			continue;
10664
10665		ret = 0;
10666		break;
10667	}
10668
10669	if (err == -1)
10670		scfdie();
10671
10672	scf_pg_destroy(pg);
10673	scf_iter_destroy(iter);
10674
10675	return (ret);
10676}
10677
10678/* return 1 if the service has no instances, else return 0 */
10679static int
10680svc_has_no_insts(scf_service_t *svc)
10681{
10682	scf_instance_t *inst;
10683	scf_iter_t *iter;
10684	int r;
10685	int ret = 1;
10686
10687	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10688	    (iter = scf_iter_create(g_hndl)) == NULL)
10689		scfdie();
10690
10691	if (scf_iter_service_instances(iter, svc) != 0)
10692		scfdie();
10693
10694	r = scf_iter_next_instance(iter, inst);
10695	if (r == 1) {
10696		ret = 0;
10697	} else if (r == 0) {
10698		ret = 1;
10699	} else if (r == -1) {
10700		scfdie();
10701	} else {
10702		bad_error("scf_iter_next_instance", r);
10703	}
10704
10705	scf_iter_destroy(iter);
10706	scf_instance_destroy(inst);
10707
10708	return (ret);
10709}
10710
10711/*
10712 * Entity deletion.
10713 */
10714
10715/*
10716 * Delete the property group <fmri>/:properties/<name>.  Returns
10717 * SCF_ERROR_NONE on success (or if the entity is not found),
10718 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
10719 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
10720 * denied.
10721 */
10722static scf_error_t
10723delete_dependency_pg(const char *fmri, const char *name)
10724{
10725	void *entity = NULL;
10726	int isservice;
10727	scf_propertygroup_t *pg = NULL;
10728	scf_error_t result;
10729	char *pgty;
10730	scf_service_t *svc = NULL;
10731	scf_instance_t *inst = NULL;
10732	scf_iter_t *iter = NULL;
10733	char *name_buf = NULL;
10734
10735	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10736	switch (result) {
10737	case SCF_ERROR_NONE:
10738		break;
10739
10740	case SCF_ERROR_NO_MEMORY:
10741		uu_die(gettext("Out of memory.\n"));
10742		/* NOTREACHED */
10743
10744	case SCF_ERROR_INVALID_ARGUMENT:
10745	case SCF_ERROR_CONSTRAINT_VIOLATED:
10746		return (SCF_ERROR_INVALID_ARGUMENT);
10747
10748	case SCF_ERROR_NOT_FOUND:
10749		result = SCF_ERROR_NONE;
10750		goto out;
10751
10752	default:
10753		bad_error("fmri_to_entity", result);
10754	}
10755
10756	pg = scf_pg_create(g_hndl);
10757	if (pg == NULL)
10758		scfdie();
10759
10760	if (entity_get_pg(entity, isservice, name, pg) != 0) {
10761		if (scf_error() != SCF_ERROR_NOT_FOUND)
10762			scfdie();
10763
10764		result = SCF_ERROR_NONE;
10765		goto out;
10766	}
10767
10768	pgty = safe_malloc(max_scf_pg_type_len + 1);
10769
10770	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10771		scfdie();
10772
10773	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
10774		result = SCF_ERROR_TYPE_MISMATCH;
10775		free(pgty);
10776		goto out;
10777	}
10778
10779	free(pgty);
10780
10781	if (scf_pg_delete(pg) != 0) {
10782		result = scf_error();
10783		if (result != SCF_ERROR_PERMISSION_DENIED)
10784			scfdie();
10785		goto out;
10786	}
10787
10788	/*
10789	 * We have to handle the case where we've just deleted the last
10790	 * property group of a "dummy" entity (instance or service).
10791	 * A "dummy" entity is an entity only present to hold an
10792	 * external dependency.
10793	 * So, in the case we deleted the last property group then we
10794	 * can also delete the entity. If the entity is an instance then
10795	 * we must verify if this was the last instance for the service
10796	 * and if it is, we can also delete the service if it doesn't
10797	 * have any property group either.
10798	 */
10799
10800	result = SCF_ERROR_NONE;
10801
10802	if (isservice) {
10803		svc = (scf_service_t *)entity;
10804
10805		if ((inst = scf_instance_create(g_hndl)) == NULL ||
10806		    (iter = scf_iter_create(g_hndl)) == NULL)
10807			scfdie();
10808
10809		name_buf = safe_malloc(max_scf_name_len + 1);
10810	} else {
10811		inst = (scf_instance_t *)entity;
10812	}
10813
10814	/*
10815	 * If the entity is an instance and we've just deleted its last
10816	 * property group then we should delete it.
10817	 */
10818	if (!isservice && entity_has_no_pgs(entity, isservice)) {
10819		/* find the service before deleting the inst. - needed later */
10820		if ((svc = scf_service_create(g_hndl)) == NULL)
10821			scfdie();
10822
10823		if (scf_instance_get_parent(inst, svc) != 0)
10824			scfdie();
10825
10826		/* delete the instance */
10827		if (scf_instance_delete(inst) != 0) {
10828			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10829				scfdie();
10830
10831			result = SCF_ERROR_PERMISSION_DENIED;
10832			goto out;
10833		}
10834		/* no need to refresh the instance */
10835		inst = NULL;
10836	}
10837
10838	/*
10839	 * If the service has no more instances and pgs or we just deleted the
10840	 * last instance and the service doesn't have anymore propery groups
10841	 * then the service should be deleted.
10842	 */
10843	if (svc != NULL &&
10844	    svc_has_no_insts(svc) &&
10845	    entity_has_no_pgs((void *)svc, 1)) {
10846		if (scf_service_delete(svc) == 0) {
10847			if (isservice) {
10848				/* no need to refresh the service */
10849				svc = NULL;
10850			}
10851
10852			goto out;
10853		}
10854
10855		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10856			scfdie();
10857
10858		result = SCF_ERROR_PERMISSION_DENIED;
10859	}
10860
10861	/* if the entity has not been deleted, refresh it */
10862	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
10863		(void) refresh_entity(isservice, entity, fmri, inst, iter,
10864		    name_buf);
10865	}
10866
10867out:
10868	if (isservice && (inst != NULL && iter != NULL)) {
10869		free(name_buf);
10870		scf_iter_destroy(iter);
10871		scf_instance_destroy(inst);
10872	}
10873
10874	if (!isservice && svc != NULL) {
10875		scf_service_destroy(svc);
10876	}
10877
10878	scf_pg_destroy(pg);
10879	if (entity != NULL)
10880		entity_destroy(entity, isservice);
10881
10882	return (result);
10883}
10884
10885static int
10886delete_dependents(scf_propertygroup_t *pg)
10887{
10888	char *pgty, *name, *fmri;
10889	scf_property_t *prop;
10890	scf_value_t *val;
10891	scf_iter_t *iter;
10892	int r;
10893	scf_error_t err;
10894
10895	/* Verify that the pg has the correct type. */
10896	pgty = safe_malloc(max_scf_pg_type_len + 1);
10897	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10898		scfdie();
10899
10900	if (strcmp(pgty, scf_group_framework) != 0) {
10901		if (g_verbose) {
10902			fmri = safe_malloc(max_scf_fmri_len + 1);
10903			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
10904				scfdie();
10905
10906			warn(gettext("Property group %s is not of expected "
10907			    "type %s.\n"), fmri, scf_group_framework);
10908
10909			free(fmri);
10910		}
10911
10912		free(pgty);
10913		return (-1);
10914	}
10915
10916	free(pgty);
10917
10918	/* map delete_dependency_pg onto the properties. */
10919	if ((prop = scf_property_create(g_hndl)) == NULL ||
10920	    (val = scf_value_create(g_hndl)) == NULL ||
10921	    (iter = scf_iter_create(g_hndl)) == NULL)
10922		scfdie();
10923
10924	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10925		scfdie();
10926
10927	name = safe_malloc(max_scf_name_len + 1);
10928	fmri = safe_malloc(max_scf_fmri_len + 2);
10929
10930	while ((r = scf_iter_next_property(iter, prop)) == 1) {
10931		scf_type_t ty;
10932
10933		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
10934			scfdie();
10935
10936		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
10937			scfdie();
10938
10939		if ((ty != SCF_TYPE_ASTRING &&
10940		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
10941		    prop_get_val(prop, val) != 0)
10942			continue;
10943
10944		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
10945			scfdie();
10946
10947		err = delete_dependency_pg(fmri, name);
10948		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
10949			if (scf_property_to_fmri(prop, fmri,
10950			    max_scf_fmri_len + 2) < 0)
10951				scfdie();
10952
10953			warn(gettext("Value of %s is not a valid FMRI.\n"),
10954			    fmri);
10955		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
10956			warn(gettext("Property group \"%s\" of entity \"%s\" "
10957			    "does not have dependency type.\n"), name, fmri);
10958		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
10959			warn(gettext("Could not delete property group \"%s\" "
10960			    "of entity \"%s\" (permission denied).\n"), name,
10961			    fmri);
10962		}
10963	}
10964	if (r == -1)
10965		scfdie();
10966
10967	scf_value_destroy(val);
10968	scf_property_destroy(prop);
10969
10970	return (0);
10971}
10972
10973/*
10974 * Returns 1 if the instance may be running, and 0 otherwise.
10975 */
10976static int
10977inst_is_running(scf_instance_t *inst)
10978{
10979	scf_propertygroup_t *pg;
10980	scf_property_t *prop;
10981	scf_value_t *val;
10982	char buf[MAX_SCF_STATE_STRING_SZ];
10983	int ret = 0;
10984	ssize_t szret;
10985
10986	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10987	    (prop = scf_property_create(g_hndl)) == NULL ||
10988	    (val = scf_value_create(g_hndl)) == NULL)
10989		scfdie();
10990
10991	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
10992		if (scf_error() != SCF_ERROR_NOT_FOUND)
10993			scfdie();
10994		goto out;
10995	}
10996
10997	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
10998	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
10999	    prop_get_val(prop, val) != 0)
11000		goto out;
11001
11002	szret = scf_value_get_astring(val, buf, sizeof (buf));
11003	assert(szret >= 0);
11004
11005	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11006	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11007
11008out:
11009	scf_value_destroy(val);
11010	scf_property_destroy(prop);
11011	scf_pg_destroy(pg);
11012	return (ret);
11013}
11014
11015static uint8_t
11016pg_is_external_dependency(scf_propertygroup_t *pg)
11017{
11018	char *type;
11019	scf_value_t *val;
11020	scf_property_t *prop;
11021	uint8_t b = B_FALSE;
11022
11023	type = safe_malloc(max_scf_pg_type_len + 1);
11024
11025	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
11026		scfdie();
11027
11028	if ((prop = scf_property_create(g_hndl)) == NULL ||
11029	    (val = scf_value_create(g_hndl)) == NULL)
11030		scfdie();
11031
11032	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
11033		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
11034			if (scf_property_get_value(prop, val) != 0)
11035				scfdie();
11036			if (scf_value_get_boolean(val, &b) != 0)
11037				scfdie();
11038		}
11039	}
11040
11041	free(type);
11042	(void) scf_value_destroy(val);
11043	(void) scf_property_destroy(prop);
11044
11045	return (b);
11046}
11047
11048#define	DELETE_FAILURE			-1
11049#define	DELETE_SUCCESS_NOEXTDEPS	0
11050#define	DELETE_SUCCESS_EXTDEPS		1
11051
11052/*
11053 * lscf_instance_delete() deletes an instance.  Before calling
11054 * scf_instance_delete(), though, we make sure the instance isn't
11055 * running and delete dependencies in other entities which the instance
11056 * declared as "dependents".  If there are dependencies which were
11057 * created for other entities, then instead of deleting the instance we
11058 * make it "empty" by deleting all other property groups and all
11059 * snapshots.
11060 *
11061 * lscf_instance_delete() verifies that there is no external dependency pgs
11062 * before suppressing the instance. If there is, then we must not remove them
11063 * now in case the instance is re-created otherwise the dependencies would be
11064 * lost. The external dependency pgs will be removed if the dependencies are
11065 * removed.
11066 *
11067 * Returns:
11068 *  DELETE_FAILURE		on failure
11069 *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11070 *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11071 */
11072static int
11073lscf_instance_delete(scf_instance_t *inst, int force)
11074{
11075	scf_propertygroup_t *pg;
11076	scf_snapshot_t *snap;
11077	scf_iter_t *iter;
11078	int err;
11079	int external = 0;
11080
11081	/* If we're not forcing and the instance is running, refuse. */
11082	if (!force && inst_is_running(inst)) {
11083		char *fmri;
11084
11085		fmri = safe_malloc(max_scf_fmri_len + 1);
11086
11087		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
11088			scfdie();
11089
11090		semerr(gettext("Instance %s may be running.  "
11091		    "Use delete -f if it is not.\n"), fmri);
11092
11093		free(fmri);
11094		return (DELETE_FAILURE);
11095	}
11096
11097	pg = scf_pg_create(g_hndl);
11098	if (pg == NULL)
11099		scfdie();
11100
11101	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
11102		(void) delete_dependents(pg);
11103	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11104		scfdie();
11105
11106	scf_pg_destroy(pg);
11107
11108	/*
11109	 * If the instance has some external dependencies then we must
11110	 * keep them in case the instance is reimported otherwise the
11111	 * dependencies would be lost on reimport.
11112	 */
11113	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11114	    (pg = scf_pg_create(g_hndl)) == NULL)
11115		scfdie();
11116
11117	if (scf_iter_instance_pgs(iter, inst) < 0)
11118		scfdie();
11119
11120	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11121		if (pg_is_external_dependency(pg)) {
11122			external = 1;
11123			continue;
11124		}
11125
11126		if (scf_pg_delete(pg) != 0) {
11127			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11128				scfdie();
11129			else {
11130				semerr(emsg_permission_denied);
11131
11132				(void) scf_iter_destroy(iter);
11133				(void) scf_pg_destroy(pg);
11134				return (DELETE_FAILURE);
11135			}
11136		}
11137	}
11138
11139	if (err == -1)
11140		scfdie();
11141
11142	(void) scf_iter_destroy(iter);
11143	(void) scf_pg_destroy(pg);
11144
11145	if (external) {
11146		/*
11147		 * All the pgs have been deleted for the instance except
11148		 * the ones holding the external dependencies.
11149		 * For the job to be complete, we must also delete the
11150		 * snapshots associated with the instance.
11151		 */
11152		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
11153		    NULL)
11154			scfdie();
11155		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
11156			scfdie();
11157
11158		if (scf_iter_instance_snapshots(iter, inst) == -1)
11159			scfdie();
11160
11161		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
11162			if (_scf_snapshot_delete(snap) != 0) {
11163				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11164					scfdie();
11165
11166				semerr(emsg_permission_denied);
11167
11168				(void) scf_iter_destroy(iter);
11169				(void) scf_snapshot_destroy(snap);
11170				return (DELETE_FAILURE);
11171			}
11172		}
11173
11174		if (err == -1)
11175			scfdie();
11176
11177		(void) scf_iter_destroy(iter);
11178		(void) scf_snapshot_destroy(snap);
11179		return (DELETE_SUCCESS_EXTDEPS);
11180	}
11181
11182	if (scf_instance_delete(inst) != 0) {
11183		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11184			scfdie();
11185
11186		semerr(emsg_permission_denied);
11187
11188		return (DELETE_FAILURE);
11189	}
11190
11191	return (DELETE_SUCCESS_NOEXTDEPS);
11192}
11193
11194/*
11195 * lscf_service_delete() deletes a service.  Before calling
11196 * scf_service_delete(), though, we call lscf_instance_delete() for
11197 * each of the instances and delete dependencies in other entities
11198 * which were created as "dependents" of this service.  If there are
11199 * dependencies which were created for other entities, then we delete
11200 * all other property groups in the service and leave it as "empty".
11201 *
11202 * lscf_service_delete() verifies that there is no external dependency
11203 * pgs at the instance & service level before suppressing the service.
11204 * If there is, then we must not remove them now in case the service
11205 * is re-imported otherwise the dependencies would be lost. The external
11206 * dependency pgs will be removed if the dependencies are removed.
11207 *
11208 * Returns:
11209 *   DELETE_FAILURE		on failure
11210 *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11211 *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11212 */
11213static int
11214lscf_service_delete(scf_service_t *svc, int force)
11215{
11216	int r;
11217	scf_instance_t *inst;
11218	scf_propertygroup_t *pg;
11219	scf_iter_t *iter;
11220	int ret;
11221	int external = 0;
11222
11223	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11224	    (pg = scf_pg_create(g_hndl)) == NULL ||
11225	    (iter = scf_iter_create(g_hndl)) == NULL)
11226		scfdie();
11227
11228	if (scf_iter_service_instances(iter, svc) != 0)
11229		scfdie();
11230
11231	for (r = scf_iter_next_instance(iter, inst);
11232	    r == 1;
11233	    r = scf_iter_next_instance(iter, inst)) {
11234
11235		ret = lscf_instance_delete(inst, force);
11236		if (ret == DELETE_FAILURE) {
11237			scf_iter_destroy(iter);
11238			scf_pg_destroy(pg);
11239			scf_instance_destroy(inst);
11240			return (DELETE_FAILURE);
11241		}
11242
11243		/*
11244		 * Record the fact that there is some external dependencies
11245		 * at the instance level.
11246		 */
11247		if (ret == DELETE_SUCCESS_EXTDEPS)
11248			external |= 1;
11249	}
11250
11251	if (r != 0)
11252		scfdie();
11253
11254	/* Delete dependency property groups in dependent services. */
11255	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
11256		(void) delete_dependents(pg);
11257	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11258		scfdie();
11259
11260	scf_iter_destroy(iter);
11261	scf_pg_destroy(pg);
11262	scf_instance_destroy(inst);
11263
11264	/*
11265	 * If the service has some external dependencies then we don't
11266	 * want to remove them in case the service is re-imported.
11267	 */
11268	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11269	    (iter = scf_iter_create(g_hndl)) == NULL)
11270		scfdie();
11271
11272	if (scf_iter_service_pgs(iter, svc) < 0)
11273		scfdie();
11274
11275	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
11276		if (pg_is_external_dependency(pg)) {
11277			external |= 2;
11278			continue;
11279		}
11280
11281		if (scf_pg_delete(pg) != 0) {
11282			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11283				scfdie();
11284			else {
11285				semerr(emsg_permission_denied);
11286
11287				(void) scf_iter_destroy(iter);
11288				(void) scf_pg_destroy(pg);
11289				return (DELETE_FAILURE);
11290			}
11291		}
11292	}
11293
11294	if (r == -1)
11295		scfdie();
11296
11297	(void) scf_iter_destroy(iter);
11298	(void) scf_pg_destroy(pg);
11299
11300	if (external != 0)
11301		return (DELETE_SUCCESS_EXTDEPS);
11302
11303	if (scf_service_delete(svc) == 0)
11304		return (DELETE_SUCCESS_NOEXTDEPS);
11305
11306	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11307		scfdie();
11308
11309	semerr(emsg_permission_denied);
11310	return (DELETE_FAILURE);
11311}
11312
11313static int
11314delete_callback(void *data, scf_walkinfo_t *wip)
11315{
11316	int force = (int)data;
11317
11318	if (wip->inst != NULL)
11319		(void) lscf_instance_delete(wip->inst, force);
11320	else
11321		(void) lscf_service_delete(wip->svc, force);
11322
11323	return (0);
11324}
11325
11326void
11327lscf_delete(const char *fmri, int force)
11328{
11329	scf_service_t *svc;
11330	scf_instance_t *inst;
11331	int ret;
11332
11333	lscf_prep_hndl();
11334
11335	if (cur_snap != NULL) {
11336		if (!snaplevel_is_instance(cur_level)) {
11337			char *buf;
11338
11339			buf = safe_malloc(max_scf_name_len + 1);
11340			if (scf_instance_get_name(cur_inst, buf,
11341			    max_scf_name_len + 1) >= 0) {
11342				if (strcmp(buf, fmri) == 0) {
11343					semerr(emsg_cant_modify_snapshots);
11344					free(buf);
11345					return;
11346				}
11347			} else if (scf_error() != SCF_ERROR_DELETED) {
11348				scfdie();
11349			}
11350			free(buf);
11351		}
11352	} else if (cur_inst != NULL) {
11353		/* EMPTY */;
11354	} else if (cur_svc != NULL) {
11355		inst = scf_instance_create(g_hndl);
11356		if (inst == NULL)
11357			scfdie();
11358
11359		if (scf_service_get_instance(cur_svc, fmri, inst) ==
11360		    SCF_SUCCESS) {
11361			(void) lscf_instance_delete(inst, force);
11362			scf_instance_destroy(inst);
11363			return;
11364		}
11365
11366		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11367		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11368			scfdie();
11369
11370		scf_instance_destroy(inst);
11371	} else {
11372		assert(cur_scope != NULL);
11373
11374		svc = scf_service_create(g_hndl);
11375		if (svc == NULL)
11376			scfdie();
11377
11378		if (scf_scope_get_service(cur_scope, fmri, svc) ==
11379		    SCF_SUCCESS) {
11380			(void) lscf_service_delete(svc, force);
11381			scf_service_destroy(svc);
11382			return;
11383		}
11384
11385		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11386		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11387			scfdie();
11388
11389		scf_service_destroy(svc);
11390	}
11391
11392	/*
11393	 * Match FMRI to entity.
11394	 */
11395	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11396	    delete_callback, (void *)force, NULL, semerr)) != 0) {
11397		semerr(gettext("Failed to walk instances: %s\n"),
11398		    scf_strerror(ret));
11399	}
11400}
11401
11402
11403
11404/*
11405 * :properties commands.  These all end with "pg" or "prop" and generally
11406 * operate on the currently selected entity.
11407 */
11408
11409/*
11410 * Property listing.  List the property groups, properties, their types and
11411 * their values for the currently selected entity.
11412 */
11413static void
11414list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
11415{
11416	char *buf;
11417	uint32_t flags;
11418
11419	buf = safe_malloc(max_scf_pg_type_len + 1);
11420
11421	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
11422		scfdie();
11423
11424	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
11425		scfdie();
11426
11427	safe_printf("%-*s  %s", namewidth, name, buf);
11428
11429	if (flags & SCF_PG_FLAG_NONPERSISTENT)
11430		safe_printf("\tNONPERSISTENT");
11431
11432	safe_printf("\n");
11433
11434	free(buf);
11435}
11436
11437static boolean_t
11438prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
11439{
11440	if (scf_property_get_value(prop, val) == 0) {
11441		return (B_FALSE);
11442	} else {
11443		switch (scf_error()) {
11444		case SCF_ERROR_NOT_FOUND:
11445			return (B_FALSE);
11446		case SCF_ERROR_PERMISSION_DENIED:
11447		case SCF_ERROR_CONSTRAINT_VIOLATED:
11448			return (B_TRUE);
11449		default:
11450			scfdie();
11451			/*NOTREACHED*/
11452		}
11453	}
11454}
11455
11456static void
11457list_prop_info(const scf_property_t *prop, const char *name, size_t len)
11458{
11459	scf_iter_t *iter;
11460	scf_value_t *val;
11461	const char *type;
11462	int multiple_strings = 0;
11463	int ret;
11464
11465	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11466	    (val = scf_value_create(g_hndl)) == NULL)
11467		scfdie();
11468
11469	type = prop_to_typestr(prop);
11470	assert(type != NULL);
11471
11472	safe_printf("%-*s  %-7s ", len, name, type);
11473
11474	if (prop_has_multiple_values(prop, val) &&
11475	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
11476	    scf_value_type(val) == SCF_TYPE_USTRING))
11477		multiple_strings = 1;
11478
11479	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11480		scfdie();
11481
11482	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11483		char *buf;
11484		ssize_t vlen, szret;
11485
11486		vlen = scf_value_get_as_string(val, NULL, 0);
11487		if (vlen < 0)
11488			scfdie();
11489
11490		buf = safe_malloc(vlen + 1);
11491
11492		szret = scf_value_get_as_string(val, buf, vlen + 1);
11493		if (szret < 0)
11494			scfdie();
11495		assert(szret <= vlen);
11496
11497		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11498		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
11499			safe_printf(" \"");
11500			(void) quote_and_print(buf, stdout, 0);
11501			(void) putchar('"');
11502			if (ferror(stdout)) {
11503				(void) putchar('\n');
11504				uu_die(gettext("Error writing to stdout.\n"));
11505			}
11506		} else {
11507			safe_printf(" %s", buf);
11508		}
11509
11510		free(buf);
11511	}
11512	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11513		scfdie();
11514
11515	if (putchar('\n') != '\n')
11516		uu_die(gettext("Could not output newline"));
11517}
11518
11519/*
11520 * Outputs template property group info for the describe subcommand.
11521 * If 'templates' == 2, verbose output is printed in the format expected
11522 * for describe -v, which includes all templates fields.  If pg is
11523 * not NULL, we're describing the template data, not an existing property
11524 * group, and formatting should be appropriate for describe -t.
11525 */
11526static void
11527list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
11528{
11529	char *buf;
11530	uint8_t required;
11531	scf_property_t *stability_prop;
11532	scf_value_t *stability_val;
11533
11534	if (templates == 0)
11535		return;
11536
11537	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
11538	    (stability_val = scf_value_create(g_hndl)) == NULL)
11539		scfdie();
11540
11541	if (templates == 2 && pg != NULL) {
11542		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
11543		    stability_prop) == 0) {
11544			if (prop_check_type(stability_prop,
11545			    SCF_TYPE_ASTRING) == 0 &&
11546			    prop_get_val(stability_prop, stability_val) == 0) {
11547				char *stability;
11548
11549				stability = safe_malloc(max_scf_value_len + 1);
11550
11551				if (scf_value_get_astring(stability_val,
11552				    stability, max_scf_value_len + 1) == -1 &&
11553				    scf_error() != SCF_ERROR_NOT_FOUND)
11554					scfdie();
11555
11556				safe_printf("%s%s: %s\n", TMPL_INDENT,
11557				    gettext("stability"), stability);
11558
11559				free(stability);
11560			}
11561		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
11562			scfdie();
11563	}
11564
11565	scf_property_destroy(stability_prop);
11566	scf_value_destroy(stability_val);
11567
11568	if (pgt == NULL)
11569		return;
11570
11571	if (pg == NULL || templates == 2) {
11572		/* print type info only if scf_tmpl_pg_name succeeds */
11573		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
11574			if (pg != NULL)
11575				safe_printf("%s", TMPL_INDENT);
11576			safe_printf("%s: ", gettext("name"));
11577			safe_printf("%s\n", buf);
11578			free(buf);
11579		}
11580
11581		/* print type info only if scf_tmpl_pg_type succeeds */
11582		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
11583			if (pg != NULL)
11584				safe_printf("%s", TMPL_INDENT);
11585			safe_printf("%s: ", gettext("type"));
11586			safe_printf("%s\n", buf);
11587			free(buf);
11588		}
11589	}
11590
11591	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
11592		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11593		    required ? "true" : "false");
11594
11595	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
11596		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
11597		    buf);
11598		free(buf);
11599	}
11600
11601	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
11602		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11603		    buf);
11604		free(buf);
11605	}
11606
11607	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
11608		if (templates == 2)
11609			safe_printf("%s%s: %s\n", TMPL_INDENT,
11610			    gettext("description"), buf);
11611		else
11612			safe_printf("%s%s\n", TMPL_INDENT, buf);
11613		free(buf);
11614	}
11615
11616}
11617
11618/*
11619 * With as_value set to true, indent as appropriate for the value level.
11620 * If false, indent to appropriate level for inclusion in constraint
11621 * or choice printout.
11622 */
11623static void
11624print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
11625    int as_value)
11626{
11627	char *buf;
11628
11629	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
11630		if (as_value == 0)
11631			safe_printf("%s", TMPL_CHOICE_INDENT);
11632		else
11633			safe_printf("%s", TMPL_INDENT);
11634		safe_printf("%s: %s\n", gettext("value common name"), buf);
11635		free(buf);
11636	}
11637
11638	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
11639		if (as_value == 0)
11640			safe_printf("%s", TMPL_CHOICE_INDENT);
11641		else
11642			safe_printf("%s", TMPL_INDENT);
11643		safe_printf("%s: %s\n", gettext("value description"), buf);
11644		free(buf);
11645	}
11646}
11647
11648static void
11649print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
11650{
11651	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
11652	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11653	safe_printf("%s\n", val_buf);
11654
11655	print_template_value_details(prt, val_buf, 1);
11656}
11657
11658static void
11659print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
11660{
11661	int i, printed = 0;
11662	scf_values_t values;
11663	scf_count_ranges_t c_ranges;
11664	scf_int_ranges_t i_ranges;
11665
11666	printed = 0;
11667	i = 0;
11668	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
11669		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11670		    gettext("value constraints"));
11671		printed++;
11672		for (i = 0; i < values.value_count; ++i) {
11673			safe_printf("%s%s: %s\n", TMPL_INDENT,
11674			    gettext("value name"), values.values_as_strings[i]);
11675			if (verbose == 1)
11676				print_template_value_details(prt,
11677				    values.values_as_strings[i], 0);
11678		}
11679
11680		scf_values_destroy(&values);
11681	}
11682
11683	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
11684		if (printed++ == 0)
11685			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11686			    gettext("value constraints"));
11687		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11688			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11689			    gettext("range"), c_ranges.scr_min[i],
11690			    c_ranges.scr_max[i]);
11691		}
11692		scf_count_ranges_destroy(&c_ranges);
11693	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11694	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
11695		if (printed++ == 0)
11696			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11697			    gettext("value constraints"));
11698		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11699			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11700			    gettext("range"), i_ranges.sir_min[i],
11701			    i_ranges.sir_max[i]);
11702		}
11703		scf_int_ranges_destroy(&i_ranges);
11704	}
11705}
11706
11707static void
11708print_template_choices(scf_prop_tmpl_t *prt, int verbose)
11709{
11710	int i = 0, printed = 0;
11711	scf_values_t values;
11712	scf_count_ranges_t c_ranges;
11713	scf_int_ranges_t i_ranges;
11714
11715	printed = 0;
11716	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
11717		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11718		    gettext("value constraints"));
11719		printed++;
11720		for (i = 0; i < values.value_count; i++) {
11721			safe_printf("%s%s: %s\n", TMPL_INDENT,
11722			    gettext("value name"), values.values_as_strings[i]);
11723			if (verbose == 1)
11724				print_template_value_details(prt,
11725				    values.values_as_strings[i], 0);
11726		}
11727
11728		scf_values_destroy(&values);
11729	}
11730
11731	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
11732		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11733			if (printed++ == 0)
11734				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11735				    gettext("value choices"));
11736			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11737			    gettext("range"), c_ranges.scr_min[i],
11738			    c_ranges.scr_max[i]);
11739		}
11740		scf_count_ranges_destroy(&c_ranges);
11741	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11742	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
11743		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11744			if (printed++ == 0)
11745				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11746				    gettext("value choices"));
11747			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11748			    gettext("range"), i_ranges.sir_min[i],
11749			    i_ranges.sir_max[i]);
11750		}
11751		scf_int_ranges_destroy(&i_ranges);
11752	}
11753}
11754
11755static void
11756list_values_by_template(scf_prop_tmpl_t *prt)
11757{
11758	print_template_constraints(prt, 1);
11759	print_template_choices(prt, 1);
11760}
11761
11762static void
11763list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
11764{
11765	char *val_buf;
11766	scf_iter_t *iter;
11767	scf_value_t *val;
11768	int ret;
11769
11770	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11771	    (val = scf_value_create(g_hndl)) == NULL)
11772		scfdie();
11773
11774	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11775		scfdie();
11776
11777	val_buf = safe_malloc(max_scf_value_len + 1);
11778
11779	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11780		if (scf_value_get_as_string(val, val_buf,
11781		    max_scf_value_len + 1) < 0)
11782			scfdie();
11783
11784		print_template_value(prt, val_buf);
11785	}
11786	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11787		scfdie();
11788	free(val_buf);
11789
11790	print_template_constraints(prt, 0);
11791	print_template_choices(prt, 0);
11792
11793}
11794
11795/*
11796 * Outputs property info for the describe subcommand
11797 * Verbose output if templates == 2, -v option of svccfg describe
11798 * Displays template data if prop is not NULL, -t option of svccfg describe
11799 */
11800static void
11801list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
11802{
11803	char *buf;
11804	uint8_t u_buf;
11805	int i;
11806	uint64_t min, max;
11807	scf_values_t values;
11808
11809	if (prt == NULL || templates == 0)
11810		return;
11811
11812	if (prop == NULL) {
11813		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
11814		if (scf_tmpl_prop_name(prt, &buf) > 0) {
11815			safe_printf("%s\n", buf);
11816			free(buf);
11817		} else
11818			safe_printf("(%s)\n", gettext("any"));
11819	}
11820
11821	if (prop == NULL || templates == 2) {
11822		if (prop != NULL)
11823			safe_printf("%s", TMPL_INDENT);
11824		else
11825			safe_printf("%s", TMPL_VALUE_INDENT);
11826		safe_printf("%s: ", gettext("type"));
11827		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
11828			safe_printf("%s\n", buf);
11829			free(buf);
11830		} else
11831			safe_printf("(%s)\n", gettext("any"));
11832	}
11833
11834	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
11835		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11836		    u_buf ? "true" : "false");
11837
11838	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
11839		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11840		    buf);
11841		free(buf);
11842	}
11843
11844	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
11845		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
11846		    buf);
11847		free(buf);
11848	}
11849
11850	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
11851		safe_printf("%s%s\n", TMPL_INDENT, buf);
11852		free(buf);
11853	}
11854
11855	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
11856		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
11857		    scf_tmpl_visibility_to_string(u_buf));
11858
11859	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
11860		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11861		    gettext("minimum number of values"), min);
11862		if (max == ULLONG_MAX) {
11863			safe_printf("%s%s: %s\n", TMPL_INDENT,
11864			    gettext("maximum number of values"),
11865			    gettext("unlimited"));
11866		} else {
11867			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11868			    gettext("maximum number of values"), max);
11869		}
11870	}
11871
11872	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
11873		for (i = 0; i < values.value_count; i++) {
11874			if (i == 0) {
11875				safe_printf("%s%s:", TMPL_INDENT,
11876				    gettext("internal separators"));
11877			}
11878			safe_printf(" \"%s\"", values.values_as_strings[i]);
11879		}
11880		safe_printf("\n");
11881	}
11882
11883	if (templates != 2)
11884		return;
11885
11886	if (prop != NULL)
11887		list_values_tmpl(prt, prop);
11888	else
11889		list_values_by_template(prt);
11890}
11891
11892static char *
11893read_astring(scf_propertygroup_t *pg, const char *prop_name)
11894{
11895	char *rv;
11896
11897	rv = _scf_read_single_astring_from_pg(pg, prop_name);
11898	if (rv == NULL) {
11899		switch (scf_error()) {
11900		case SCF_ERROR_NOT_FOUND:
11901			break;
11902		default:
11903			scfdie();
11904		}
11905	}
11906	return (rv);
11907}
11908
11909static void
11910display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
11911{
11912	size_t doc_len;
11913	size_t man_len;
11914	char *pg_name;
11915	char *text = NULL;
11916	int rv;
11917
11918	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
11919	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
11920	pg_name = safe_malloc(max_scf_name_len + 1);
11921	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
11922		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
11923			scfdie();
11924		}
11925		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
11926			/* Display doc_link and and uri */
11927			safe_printf("%s%s:\n", TMPL_INDENT,
11928			    gettext("doc_link"));
11929			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
11930			if (text != NULL) {
11931				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11932				    TMPL_INDENT, gettext("name"), text);
11933				uu_free(text);
11934			}
11935			text = read_astring(pg, SCF_PROPERTY_TM_URI);
11936			if (text != NULL) {
11937				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
11938				    gettext("uri"), text);
11939				uu_free(text);
11940			}
11941		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
11942		    man_len) == 0) {
11943			/* Display manpage title, section and path */
11944			safe_printf("%s%s:\n", TMPL_INDENT,
11945			    gettext("manpage"));
11946			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
11947			if (text != NULL) {
11948				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11949				    TMPL_INDENT, gettext("title"), text);
11950				uu_free(text);
11951			}
11952			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
11953			if (text != NULL) {
11954				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11955				    TMPL_INDENT, gettext("section"), text);
11956				uu_free(text);
11957			}
11958			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
11959			if (text != NULL) {
11960				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11961				    TMPL_INDENT, gettext("manpath"), text);
11962				uu_free(text);
11963			}
11964		}
11965	}
11966	if (rv == -1)
11967		scfdie();
11968
11969done:
11970	free(pg_name);
11971}
11972
11973static void
11974list_entity_tmpl(int templates)
11975{
11976	char *common_name = NULL;
11977	char *description = NULL;
11978	char *locale = NULL;
11979	scf_iter_t *iter;
11980	scf_propertygroup_t *pg;
11981	scf_property_t *prop;
11982	int r;
11983	scf_value_t *val;
11984
11985	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11986	    (prop = scf_property_create(g_hndl)) == NULL ||
11987	    (val = scf_value_create(g_hndl)) == NULL ||
11988	    (iter = scf_iter_create(g_hndl)) == NULL)
11989		scfdie();
11990
11991	locale = setlocale(LC_MESSAGES, NULL);
11992
11993	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
11994		common_name = safe_malloc(max_scf_value_len + 1);
11995
11996		/* Try both the current locale and the "C" locale. */
11997		if (scf_pg_get_property(pg, locale, prop) == 0 ||
11998		    (scf_error() == SCF_ERROR_NOT_FOUND &&
11999		    scf_pg_get_property(pg, "C", prop) == 0)) {
12000			if (prop_get_val(prop, val) == 0 &&
12001			    scf_value_get_ustring(val, common_name,
12002			    max_scf_value_len + 1) != -1) {
12003				safe_printf("%s%s: %s\n", TMPL_INDENT,
12004				    gettext("common name"), common_name);
12005			}
12006		}
12007	}
12008
12009	/*
12010	 * Do description, manpages, and doc links if templates == 2.
12011	 */
12012	if (templates == 2) {
12013		/* Get the description. */
12014		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12015			description = safe_malloc(max_scf_value_len + 1);
12016
12017			/* Try both the current locale and the "C" locale. */
12018			if (scf_pg_get_property(pg, locale, prop) == 0 ||
12019			    (scf_error() == SCF_ERROR_NOT_FOUND &&
12020			    scf_pg_get_property(pg, "C", prop) == 0)) {
12021				if (prop_get_val(prop, val) == 0 &&
12022				    scf_value_get_ustring(val, description,
12023				    max_scf_value_len + 1) != -1) {
12024					safe_printf("%s%s: %s\n", TMPL_INDENT,
12025					    gettext("description"),
12026					    description);
12027				}
12028			}
12029		}
12030
12031		/* Process doc_link & manpage elements. */
12032		if (cur_level != NULL) {
12033			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
12034			    SCF_GROUP_TEMPLATE);
12035		} else if (cur_inst != NULL) {
12036			r = scf_iter_instance_pgs_typed(iter, cur_inst,
12037			    SCF_GROUP_TEMPLATE);
12038		} else {
12039			r = scf_iter_service_pgs_typed(iter, cur_svc,
12040			    SCF_GROUP_TEMPLATE);
12041		}
12042		if (r == 0) {
12043			display_documentation(iter, pg);
12044		}
12045	}
12046
12047	free(common_name);
12048	free(description);
12049	scf_pg_destroy(pg);
12050	scf_property_destroy(prop);
12051	scf_value_destroy(val);
12052	scf_iter_destroy(iter);
12053}
12054
12055static void
12056listtmpl(const char *pattern, int templates)
12057{
12058	scf_pg_tmpl_t *pgt;
12059	scf_prop_tmpl_t *prt;
12060	char *snapbuf = NULL;
12061	char *fmribuf;
12062	char *pg_name = NULL, *prop_name = NULL;
12063	ssize_t prop_name_size;
12064	char *qual_prop_name;
12065	char *search_name;
12066	int listed = 0;
12067
12068	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12069	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
12070		scfdie();
12071
12072	fmribuf = safe_malloc(max_scf_name_len + 1);
12073	qual_prop_name = safe_malloc(max_scf_name_len + 1);
12074
12075	if (cur_snap != NULL) {
12076		snapbuf = safe_malloc(max_scf_name_len + 1);
12077		if (scf_snapshot_get_name(cur_snap, snapbuf,
12078		    max_scf_name_len + 1) < 0)
12079			scfdie();
12080	}
12081
12082	if (cur_inst != NULL) {
12083		if (scf_instance_to_fmri(cur_inst, fmribuf,
12084		    max_scf_name_len + 1) < 0)
12085			scfdie();
12086	} else if (cur_svc != NULL) {
12087		if (scf_service_to_fmri(cur_svc, fmribuf,
12088		    max_scf_name_len + 1) < 0)
12089			scfdie();
12090	} else
12091		abort();
12092
12093	/* If pattern is specified, we want to list only those items. */
12094	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
12095		listed = 0;
12096		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
12097		    fnmatch(pattern, pg_name, 0) == 0)) {
12098			list_pg_tmpl(pgt, NULL, templates);
12099			listed++;
12100		}
12101
12102		scf_tmpl_prop_reset(prt);
12103
12104		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
12105			search_name = NULL;
12106			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
12107			if ((prop_name_size > 0) && (pg_name != NULL)) {
12108				if (snprintf(qual_prop_name,
12109				    max_scf_name_len + 1, "%s/%s",
12110				    pg_name, prop_name) >=
12111				    max_scf_name_len + 1) {
12112					prop_name_size = -1;
12113				} else {
12114					search_name = qual_prop_name;
12115				}
12116			}
12117			if (listed > 0 || pattern == NULL ||
12118			    (prop_name_size > 0 &&
12119			    fnmatch(pattern, search_name,
12120			    FNM_PATHNAME) == 0))
12121				list_prop_tmpl(prt, NULL, templates);
12122			if (prop_name != NULL) {
12123				free(prop_name);
12124				prop_name = NULL;
12125			}
12126		}
12127		if (pg_name != NULL) {
12128			free(pg_name);
12129			pg_name = NULL;
12130		}
12131	}
12132
12133	scf_tmpl_prop_destroy(prt);
12134	scf_tmpl_pg_destroy(pgt);
12135	free(snapbuf);
12136	free(fmribuf);
12137	free(qual_prop_name);
12138}
12139
12140static void
12141listprop(const char *pattern, int only_pgs, int templates)
12142{
12143	scf_propertygroup_t *pg;
12144	scf_property_t *prop;
12145	scf_iter_t *iter, *piter;
12146	char *pgnbuf, *prnbuf, *ppnbuf;
12147	scf_pg_tmpl_t *pgt, *pgtp;
12148	scf_prop_tmpl_t *prt;
12149
12150	void **objects;
12151	char **names;
12152	void **tmpls;
12153	int allocd, i;
12154
12155	int ret;
12156	ssize_t pgnlen, prnlen, szret;
12157	size_t max_len = 0;
12158
12159	if (cur_svc == NULL && cur_inst == NULL) {
12160		semerr(emsg_entity_not_selected);
12161		return;
12162	}
12163
12164	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12165	    (prop = scf_property_create(g_hndl)) == NULL ||
12166	    (iter = scf_iter_create(g_hndl)) == NULL ||
12167	    (piter = scf_iter_create(g_hndl)) == NULL ||
12168	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12169	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
12170		scfdie();
12171
12172	prnbuf = safe_malloc(max_scf_name_len + 1);
12173
12174	if (cur_level != NULL)
12175		ret = scf_iter_snaplevel_pgs(iter, cur_level);
12176	else if (cur_inst != NULL)
12177		ret = scf_iter_instance_pgs(iter, cur_inst);
12178	else
12179		ret = scf_iter_service_pgs(iter, cur_svc);
12180	if (ret != 0) {
12181		return;
12182	}
12183
12184	/*
12185	 * We want to only list items which match pattern, and we want the
12186	 * second column to line up, so during the first pass we'll save
12187	 * matching items, their names, and their templates in objects,
12188	 * names, and tmpls, computing the maximum name length as we go,
12189	 * and then we'll print them out.
12190	 *
12191	 * Note: We always keep an extra slot available so the array can be
12192	 * NULL-terminated.
12193	 */
12194	i = 0;
12195	allocd = 1;
12196	objects = safe_malloc(sizeof (*objects));
12197	names = safe_malloc(sizeof (*names));
12198	tmpls = safe_malloc(sizeof (*tmpls));
12199
12200	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12201		int new_pg = 0;
12202		int print_props = 0;
12203		pgtp = NULL;
12204
12205		pgnlen = scf_pg_get_name(pg, NULL, 0);
12206		if (pgnlen < 0)
12207			scfdie();
12208
12209		pgnbuf = safe_malloc(pgnlen + 1);
12210
12211		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
12212		if (szret < 0)
12213			scfdie();
12214		assert(szret <= pgnlen);
12215
12216		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
12217			if (scf_error() != SCF_ERROR_NOT_FOUND)
12218				scfdie();
12219			pgtp = NULL;
12220		} else {
12221			pgtp = pgt;
12222		}
12223
12224		if (pattern == NULL ||
12225		    fnmatch(pattern, pgnbuf, 0) == 0) {
12226			if (i+1 >= allocd) {
12227				allocd *= 2;
12228				objects = realloc(objects,
12229				    sizeof (*objects) * allocd);
12230				names =
12231				    realloc(names, sizeof (*names) * allocd);
12232				tmpls = realloc(tmpls,
12233				    sizeof (*tmpls) * allocd);
12234				if (objects == NULL || names == NULL ||
12235				    tmpls == NULL)
12236					uu_die(gettext("Out of memory"));
12237			}
12238			objects[i] = pg;
12239			names[i] = pgnbuf;
12240
12241			if (pgtp == NULL)
12242				tmpls[i] = NULL;
12243			else
12244				tmpls[i] = pgt;
12245
12246			++i;
12247
12248			if (pgnlen > max_len)
12249				max_len = pgnlen;
12250
12251			new_pg = 1;
12252			print_props = 1;
12253		}
12254
12255		if (only_pgs) {
12256			if (new_pg) {
12257				pg = scf_pg_create(g_hndl);
12258				if (pg == NULL)
12259					scfdie();
12260				pgt = scf_tmpl_pg_create(g_hndl);
12261				if (pgt == NULL)
12262					scfdie();
12263			} else
12264				free(pgnbuf);
12265
12266			continue;
12267		}
12268
12269		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12270			scfdie();
12271
12272		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
12273			prnlen = scf_property_get_name(prop, prnbuf,
12274			    max_scf_name_len + 1);
12275			if (prnlen < 0)
12276				scfdie();
12277
12278			/* Will prepend the property group name and a slash. */
12279			prnlen += pgnlen + 1;
12280
12281			ppnbuf = safe_malloc(prnlen + 1);
12282
12283			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
12284			    prnbuf) < 0)
12285				uu_die("snprintf");
12286
12287			if (pattern == NULL || print_props == 1 ||
12288			    fnmatch(pattern, ppnbuf, 0) == 0) {
12289				if (i+1 >= allocd) {
12290					allocd *= 2;
12291					objects = realloc(objects,
12292					    sizeof (*objects) * allocd);
12293					names = realloc(names,
12294					    sizeof (*names) * allocd);
12295					tmpls = realloc(tmpls,
12296					    sizeof (*tmpls) * allocd);
12297					if (objects == NULL || names == NULL ||
12298					    tmpls == NULL)
12299						uu_die(gettext(
12300						    "Out of memory"));
12301				}
12302
12303				objects[i] = prop;
12304				names[i] = ppnbuf;
12305
12306				if (pgtp != NULL) {
12307					if (scf_tmpl_get_by_prop(pgt, prnbuf,
12308					    prt, NULL) < 0) {
12309						if (scf_error() !=
12310						    SCF_ERROR_NOT_FOUND)
12311							scfdie();
12312						tmpls[i] = NULL;
12313					} else {
12314						tmpls[i] = prt;
12315					}
12316				} else {
12317					tmpls[i] = NULL;
12318				}
12319
12320				++i;
12321
12322				if (prnlen > max_len)
12323					max_len = prnlen;
12324
12325				prop = scf_property_create(g_hndl);
12326				prt = scf_tmpl_prop_create(g_hndl);
12327			} else {
12328				free(ppnbuf);
12329			}
12330		}
12331
12332		if (new_pg) {
12333			pg = scf_pg_create(g_hndl);
12334			if (pg == NULL)
12335				scfdie();
12336			pgt = scf_tmpl_pg_create(g_hndl);
12337			if (pgt == NULL)
12338				scfdie();
12339		} else
12340			free(pgnbuf);
12341	}
12342	if (ret != 0)
12343		scfdie();
12344
12345	objects[i] = NULL;
12346
12347	scf_pg_destroy(pg);
12348	scf_tmpl_pg_destroy(pgt);
12349	scf_property_destroy(prop);
12350	scf_tmpl_prop_destroy(prt);
12351
12352	for (i = 0; objects[i] != NULL; ++i) {
12353		if (strchr(names[i], '/') == NULL) {
12354			/* property group */
12355			pg = (scf_propertygroup_t *)objects[i];
12356			pgt = (scf_pg_tmpl_t *)tmpls[i];
12357			list_pg_info(pg, names[i], max_len);
12358			list_pg_tmpl(pgt, pg, templates);
12359			free(names[i]);
12360			scf_pg_destroy(pg);
12361			if (pgt != NULL)
12362				scf_tmpl_pg_destroy(pgt);
12363		} else {
12364			/* property */
12365			prop = (scf_property_t *)objects[i];
12366			prt = (scf_prop_tmpl_t *)tmpls[i];
12367			list_prop_info(prop, names[i], max_len);
12368			list_prop_tmpl(prt, prop, templates);
12369			free(names[i]);
12370			scf_property_destroy(prop);
12371			if (prt != NULL)
12372				scf_tmpl_prop_destroy(prt);
12373		}
12374	}
12375
12376	free(names);
12377	free(objects);
12378	free(tmpls);
12379}
12380
12381void
12382lscf_listpg(const char *pattern)
12383{
12384	lscf_prep_hndl();
12385
12386	listprop(pattern, 1, 0);
12387}
12388
12389/*
12390 * Property group and property creation, setting, and deletion.  setprop (and
12391 * its alias, addprop) can either create a property group of a given type, or
12392 * it can create or set a property to a given type and list of values.
12393 */
12394void
12395lscf_addpg(const char *name, const char *type, const char *flags)
12396{
12397	scf_propertygroup_t *pg;
12398	int ret;
12399	uint32_t flgs = 0;
12400	const char *cp;
12401
12402
12403	lscf_prep_hndl();
12404
12405	if (cur_snap != NULL) {
12406		semerr(emsg_cant_modify_snapshots);
12407		return;
12408	}
12409
12410	if (cur_inst == NULL && cur_svc == NULL) {
12411		semerr(emsg_entity_not_selected);
12412		return;
12413	}
12414
12415	if (flags != NULL) {
12416		for (cp = flags; *cp != '\0'; ++cp) {
12417			switch (*cp) {
12418			case 'P':
12419				flgs |= SCF_PG_FLAG_NONPERSISTENT;
12420				break;
12421
12422			case 'p':
12423				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
12424				break;
12425
12426			default:
12427				semerr(gettext("Invalid property group flag "
12428				    "%c."), *cp);
12429				return;
12430			}
12431		}
12432	}
12433
12434	pg = scf_pg_create(g_hndl);
12435	if (pg == NULL)
12436		scfdie();
12437
12438	if (cur_inst != NULL)
12439		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
12440	else
12441		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
12442
12443	if (ret != SCF_SUCCESS) {
12444		switch (scf_error()) {
12445		case SCF_ERROR_INVALID_ARGUMENT:
12446			semerr(gettext("Name, type, or flags are invalid.\n"));
12447			break;
12448
12449		case SCF_ERROR_EXISTS:
12450			semerr(gettext("Property group already exists.\n"));
12451			break;
12452
12453		case SCF_ERROR_PERMISSION_DENIED:
12454			semerr(emsg_permission_denied);
12455			break;
12456
12457		case SCF_ERROR_BACKEND_ACCESS:
12458			semerr(gettext("Backend refused access.\n"));
12459			break;
12460
12461		default:
12462			scfdie();
12463		}
12464	}
12465
12466	scf_pg_destroy(pg);
12467
12468	private_refresh();
12469}
12470
12471void
12472lscf_delpg(char *name)
12473{
12474	lscf_prep_hndl();
12475
12476	if (cur_snap != NULL) {
12477		semerr(emsg_cant_modify_snapshots);
12478		return;
12479	}
12480
12481	if (cur_inst == NULL && cur_svc == NULL) {
12482		semerr(emsg_entity_not_selected);
12483		return;
12484	}
12485
12486	if (strchr(name, '/') != NULL) {
12487		semerr(emsg_invalid_pg_name, name);
12488		return;
12489	}
12490
12491	lscf_delprop(name);
12492}
12493
12494/*
12495 * scf_delhash() is used to remove the property group related to the
12496 * hash entry for a specific manifest in the repository. pgname will be
12497 * constructed from the location of the manifest file. If deathrow isn't 0,
12498 * manifest file doesn't need to exist (manifest string will be used as
12499 * an absolute path).
12500 */
12501void
12502lscf_delhash(char *manifest, int deathrow)
12503{
12504	char *pgname;
12505
12506	if (cur_snap != NULL ||
12507	    cur_inst != NULL || cur_svc != NULL) {
12508		warn(gettext("error, an entity is selected\n"));
12509		return;
12510	}
12511
12512	/* select smf/manifest */
12513	lscf_select(HASH_SVC);
12514	/*
12515	 * Translate the manifest file name to property name. In the deathrow
12516	 * case, the manifest file does not need to exist.
12517	 */
12518	pgname = mhash_filename_to_propname(manifest,
12519	    deathrow ? B_TRUE : B_FALSE);
12520	if (pgname == NULL) {
12521		warn(gettext("cannot resolve pathname for %s\n"), manifest);
12522		return;
12523	}
12524	/* delete the hash property name */
12525	lscf_delpg(pgname);
12526}
12527
12528void
12529lscf_listprop(const char *pattern)
12530{
12531	lscf_prep_hndl();
12532
12533	listprop(pattern, 0, 0);
12534}
12535
12536int
12537lscf_setprop(const char *pgname, const char *type, const char *value,
12538    const uu_list_t *values)
12539{
12540	scf_type_t ty, current_ty;
12541	scf_service_t *svc;
12542	scf_propertygroup_t *pg, *parent_pg;
12543	scf_property_t *prop, *parent_prop;
12544	scf_pg_tmpl_t *pgt;
12545	scf_prop_tmpl_t *prt;
12546	int ret, result = 0;
12547	scf_transaction_t *tx;
12548	scf_transaction_entry_t *e;
12549	scf_value_t *v;
12550	uu_list_walk_t *walk;
12551	string_list_t *sp;
12552	char *propname;
12553	int req_quotes = 0;
12554
12555	lscf_prep_hndl();
12556
12557	if ((e = scf_entry_create(g_hndl)) == NULL ||
12558	    (svc = scf_service_create(g_hndl)) == NULL ||
12559	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
12560	    (pg = scf_pg_create(g_hndl)) == NULL ||
12561	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
12562	    (prop = scf_property_create(g_hndl)) == NULL ||
12563	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12564	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12565	    (tx = scf_transaction_create(g_hndl)) == NULL)
12566		scfdie();
12567
12568	if (cur_snap != NULL) {
12569		semerr(emsg_cant_modify_snapshots);
12570		goto fail;
12571	}
12572
12573	if (cur_inst == NULL && cur_svc == NULL) {
12574		semerr(emsg_entity_not_selected);
12575		goto fail;
12576	}
12577
12578	propname = strchr(pgname, '/');
12579	if (propname == NULL) {
12580		semerr(gettext("Property names must contain a `/'.\n"));
12581		goto fail;
12582	}
12583
12584	*propname = '\0';
12585	++propname;
12586
12587	if (type != NULL) {
12588		ty = string_to_type(type);
12589		if (ty == SCF_TYPE_INVALID) {
12590			semerr(gettext("Unknown type \"%s\".\n"), type);
12591			goto fail;
12592		}
12593	}
12594
12595	if (cur_inst != NULL)
12596		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12597	else
12598		ret = scf_service_get_pg(cur_svc, pgname, pg);
12599	if (ret != SCF_SUCCESS) {
12600		switch (scf_error()) {
12601		case SCF_ERROR_NOT_FOUND:
12602			semerr(emsg_no_such_pg, pgname);
12603			goto fail;
12604
12605		case SCF_ERROR_INVALID_ARGUMENT:
12606			semerr(emsg_invalid_pg_name, pgname);
12607			goto fail;
12608
12609		default:
12610			scfdie();
12611			break;
12612		}
12613	}
12614
12615	do {
12616		if (scf_pg_update(pg) == -1)
12617			scfdie();
12618		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12619			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12620				scfdie();
12621
12622			semerr(emsg_permission_denied);
12623			goto fail;
12624		}
12625
12626		ret = scf_pg_get_property(pg, propname, prop);
12627		if (ret == SCF_SUCCESS) {
12628			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
12629				scfdie();
12630
12631			if (type == NULL)
12632				ty = current_ty;
12633			if (scf_transaction_property_change_type(tx, e,
12634			    propname, ty) == -1)
12635				scfdie();
12636
12637		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12638			/* Infer the type, if possible. */
12639			if (type == NULL) {
12640				/*
12641				 * First check if we're an instance and the
12642				 * property is set on the service.
12643				 */
12644				if (cur_inst != NULL &&
12645				    scf_instance_get_parent(cur_inst,
12646				    svc) == 0 &&
12647				    scf_service_get_pg(cur_svc, pgname,
12648				    parent_pg) == 0 &&
12649				    scf_pg_get_property(parent_pg, propname,
12650				    parent_prop) == 0 &&
12651				    scf_property_type(parent_prop,
12652				    &current_ty) == 0) {
12653					ty = current_ty;
12654
12655				/* Then check for a type set in a template. */
12656				} else if (scf_tmpl_get_by_pg(pg, pgt,
12657				    NULL) == 0 &&
12658				    scf_tmpl_get_by_prop(pgt, propname, prt,
12659				    NULL) == 0 &&
12660				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
12661					ty = current_ty;
12662
12663				/* If type can't be inferred, fail. */
12664				} else {
12665					semerr(gettext("Type required for new "
12666					    "properties.\n"));
12667					goto fail;
12668				}
12669			}
12670			if (scf_transaction_property_new(tx, e, propname,
12671			    ty) == -1)
12672				scfdie();
12673		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12674			semerr(emsg_invalid_prop_name, propname);
12675			goto fail;
12676		} else {
12677			scfdie();
12678		}
12679
12680		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
12681			req_quotes = 1;
12682
12683		if (value != NULL) {
12684			v = string_to_value(value, ty, 0);
12685
12686			if (v == NULL)
12687				goto fail;
12688
12689			ret = scf_entry_add_value(e, v);
12690			assert(ret == SCF_SUCCESS);
12691		} else {
12692			assert(values != NULL);
12693
12694			walk = uu_list_walk_start((uu_list_t *)values,
12695			    UU_DEFAULT);
12696			if (walk == NULL)
12697				uu_die(gettext("Could not walk list"));
12698
12699			for (sp = uu_list_walk_next(walk); sp != NULL;
12700			    sp = uu_list_walk_next(walk)) {
12701				v = string_to_value(sp->str, ty, req_quotes);
12702
12703				if (v == NULL) {
12704					scf_entry_destroy_children(e);
12705					goto fail;
12706				}
12707
12708				ret = scf_entry_add_value(e, v);
12709				assert(ret == SCF_SUCCESS);
12710			}
12711			uu_list_walk_end(walk);
12712		}
12713		result = scf_transaction_commit(tx);
12714
12715		scf_transaction_reset(tx);
12716		scf_entry_destroy_children(e);
12717	} while (result == 0);
12718
12719	if (result < 0) {
12720		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12721			scfdie();
12722
12723		semerr(emsg_permission_denied);
12724		goto fail;
12725	}
12726
12727	ret = 0;
12728
12729	private_refresh();
12730
12731	goto cleanup;
12732
12733fail:
12734	ret = -1;
12735
12736cleanup:
12737	scf_transaction_destroy(tx);
12738	scf_entry_destroy(e);
12739	scf_service_destroy(svc);
12740	scf_pg_destroy(parent_pg);
12741	scf_pg_destroy(pg);
12742	scf_property_destroy(parent_prop);
12743	scf_property_destroy(prop);
12744	scf_tmpl_pg_destroy(pgt);
12745	scf_tmpl_prop_destroy(prt);
12746
12747	return (ret);
12748}
12749
12750void
12751lscf_delprop(char *pgn)
12752{
12753	char *slash, *pn;
12754	scf_propertygroup_t *pg;
12755	scf_transaction_t *tx;
12756	scf_transaction_entry_t *e;
12757	int ret;
12758
12759
12760	lscf_prep_hndl();
12761
12762	if (cur_snap != NULL) {
12763		semerr(emsg_cant_modify_snapshots);
12764		return;
12765	}
12766
12767	if (cur_inst == NULL && cur_svc == NULL) {
12768		semerr(emsg_entity_not_selected);
12769		return;
12770	}
12771
12772	pg = scf_pg_create(g_hndl);
12773	if (pg == NULL)
12774		scfdie();
12775
12776	slash = strchr(pgn, '/');
12777	if (slash == NULL) {
12778		pn = NULL;
12779	} else {
12780		*slash = '\0';
12781		pn = slash + 1;
12782	}
12783
12784	if (cur_inst != NULL)
12785		ret = scf_instance_get_pg(cur_inst, pgn, pg);
12786	else
12787		ret = scf_service_get_pg(cur_svc, pgn, pg);
12788	if (ret != SCF_SUCCESS) {
12789		switch (scf_error()) {
12790		case SCF_ERROR_NOT_FOUND:
12791			semerr(emsg_no_such_pg, pgn);
12792			break;
12793
12794		case SCF_ERROR_INVALID_ARGUMENT:
12795			semerr(emsg_invalid_pg_name, pgn);
12796			break;
12797
12798		default:
12799			scfdie();
12800		}
12801
12802		scf_pg_destroy(pg);
12803
12804		return;
12805	}
12806
12807	if (pn == NULL) {
12808		/* Try to delete the property group. */
12809		if (scf_pg_delete(pg) != SCF_SUCCESS) {
12810			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12811				scfdie();
12812
12813			semerr(emsg_permission_denied);
12814		} else {
12815			private_refresh();
12816		}
12817
12818		scf_pg_destroy(pg);
12819		return;
12820	}
12821
12822	e = scf_entry_create(g_hndl);
12823	tx = scf_transaction_create(g_hndl);
12824
12825	do {
12826		if (scf_pg_update(pg) == -1)
12827			scfdie();
12828		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12829			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12830				scfdie();
12831
12832			semerr(emsg_permission_denied);
12833			break;
12834		}
12835
12836		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
12837			if (scf_error() == SCF_ERROR_NOT_FOUND) {
12838				semerr(gettext("No such property %s/%s.\n"),
12839				    pgn, pn);
12840				break;
12841			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12842				semerr(emsg_invalid_prop_name, pn);
12843				break;
12844			} else {
12845				scfdie();
12846			}
12847		}
12848
12849		ret = scf_transaction_commit(tx);
12850
12851		if (ret == 0)
12852			scf_transaction_reset(tx);
12853	} while (ret == 0);
12854
12855	if (ret < 0) {
12856		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12857			scfdie();
12858
12859		semerr(emsg_permission_denied);
12860	} else {
12861		private_refresh();
12862	}
12863
12864	scf_transaction_destroy(tx);
12865	scf_entry_destroy(e);
12866	scf_pg_destroy(pg);
12867}
12868
12869/*
12870 * Property editing.
12871 */
12872
12873static int
12874write_edit_script(FILE *strm)
12875{
12876	char *fmribuf;
12877	ssize_t fmrilen;
12878
12879	scf_propertygroup_t *pg;
12880	scf_property_t *prop;
12881	scf_value_t *val;
12882	scf_type_t ty;
12883	int ret, result = 0;
12884	scf_iter_t *iter, *piter, *viter;
12885	char *buf, *tybuf, *pname;
12886	const char *emsg_write_error;
12887
12888
12889	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
12890
12891
12892	/* select fmri */
12893	if (cur_inst != NULL) {
12894		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
12895		if (fmrilen < 0)
12896			scfdie();
12897		fmribuf = safe_malloc(fmrilen + 1);
12898		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
12899			scfdie();
12900	} else {
12901		assert(cur_svc != NULL);
12902		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
12903		if (fmrilen < 0)
12904			scfdie();
12905		fmribuf = safe_malloc(fmrilen + 1);
12906		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
12907			scfdie();
12908	}
12909
12910	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
12911		warn(emsg_write_error, strerror(errno));
12912		free(fmribuf);
12913		return (-1);
12914	}
12915
12916	free(fmribuf);
12917
12918
12919	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12920	    (prop = scf_property_create(g_hndl)) == NULL ||
12921	    (val = scf_value_create(g_hndl)) == NULL ||
12922	    (iter = scf_iter_create(g_hndl)) == NULL ||
12923	    (piter = scf_iter_create(g_hndl)) == NULL ||
12924	    (viter = scf_iter_create(g_hndl)) == NULL)
12925		scfdie();
12926
12927	buf = safe_malloc(max_scf_name_len + 1);
12928	tybuf = safe_malloc(max_scf_pg_type_len + 1);
12929	pname = safe_malloc(max_scf_name_len + 1);
12930
12931	if (cur_inst != NULL)
12932		ret = scf_iter_instance_pgs(iter, cur_inst);
12933	else
12934		ret = scf_iter_service_pgs(iter, cur_svc);
12935	if (ret != SCF_SUCCESS)
12936		scfdie();
12937
12938	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12939		int ret2;
12940
12941		/*
12942		 * # delprop pg
12943		 * # addpg pg type
12944		 */
12945		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
12946			scfdie();
12947
12948		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
12949			scfdie();
12950
12951		if (fprintf(strm, "# Property group \"%s\"\n"
12952		    "# delprop %s\n"
12953		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
12954			warn(emsg_write_error, strerror(errno));
12955			result = -1;
12956			goto out;
12957		}
12958
12959		/* # setprop pg/prop = (values) */
12960
12961		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12962			scfdie();
12963
12964		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
12965			int first = 1;
12966			int ret3;
12967			int multiple;
12968			int is_str;
12969			scf_type_t bty;
12970
12971			if (scf_property_get_name(prop, pname,
12972			    max_scf_name_len + 1) < 0)
12973				scfdie();
12974
12975			if (scf_property_type(prop, &ty) != 0)
12976				scfdie();
12977
12978			multiple = prop_has_multiple_values(prop, val);
12979
12980			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
12981			    pname, scf_type_to_string(ty), multiple ? "(" : "")
12982			    < 0) {
12983				warn(emsg_write_error, strerror(errno));
12984				result = -1;
12985				goto out;
12986			}
12987
12988			(void) scf_type_base_type(ty, &bty);
12989			is_str = (bty == SCF_TYPE_ASTRING);
12990
12991			if (scf_iter_property_values(viter, prop) !=
12992			    SCF_SUCCESS)
12993				scfdie();
12994
12995			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
12996				char *buf;
12997				ssize_t buflen;
12998
12999				buflen = scf_value_get_as_string(val, NULL, 0);
13000				if (buflen < 0)
13001					scfdie();
13002
13003				buf = safe_malloc(buflen + 1);
13004
13005				if (scf_value_get_as_string(val, buf,
13006				    buflen + 1) < 0)
13007					scfdie();
13008
13009				if (first)
13010					first = 0;
13011				else {
13012					if (putc(' ', strm) != ' ') {
13013						warn(emsg_write_error,
13014						    strerror(errno));
13015						result = -1;
13016						goto out;
13017					}
13018				}
13019
13020				if ((is_str && multiple) ||
13021				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
13022					(void) putc('"', strm);
13023					(void) quote_and_print(buf, strm, 1);
13024					(void) putc('"', strm);
13025
13026					if (ferror(strm)) {
13027						warn(emsg_write_error,
13028						    strerror(errno));
13029						result = -1;
13030						goto out;
13031					}
13032				} else {
13033					if (fprintf(strm, "%s", buf) < 0) {
13034						warn(emsg_write_error,
13035						    strerror(errno));
13036						result = -1;
13037						goto out;
13038					}
13039				}
13040
13041				free(buf);
13042			}
13043			if (ret3 < 0 &&
13044			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
13045				scfdie();
13046
13047			/* Write closing paren if mult-value property */
13048			if ((multiple && putc(')', strm) == EOF) ||
13049
13050			    /* Write final newline */
13051			    fputc('\n', strm) == EOF) {
13052				warn(emsg_write_error, strerror(errno));
13053				result = -1;
13054				goto out;
13055			}
13056		}
13057		if (ret2 < 0)
13058			scfdie();
13059
13060		if (fputc('\n', strm) == EOF) {
13061			warn(emsg_write_error, strerror(errno));
13062			result = -1;
13063			goto out;
13064		}
13065	}
13066	if (ret < 0)
13067		scfdie();
13068
13069out:
13070	free(pname);
13071	free(tybuf);
13072	free(buf);
13073	scf_iter_destroy(viter);
13074	scf_iter_destroy(piter);
13075	scf_iter_destroy(iter);
13076	scf_value_destroy(val);
13077	scf_property_destroy(prop);
13078	scf_pg_destroy(pg);
13079
13080	if (result == 0) {
13081		if (fflush(strm) != 0) {
13082			warn(emsg_write_error, strerror(errno));
13083			return (-1);
13084		}
13085	}
13086
13087	return (result);
13088}
13089
13090int
13091lscf_editprop()
13092{
13093	char *buf, *editor;
13094	size_t bufsz;
13095	int tmpfd;
13096	char tempname[] = TEMP_FILE_PATTERN;
13097
13098	lscf_prep_hndl();
13099
13100	if (cur_snap != NULL) {
13101		semerr(emsg_cant_modify_snapshots);
13102		return (-1);
13103	}
13104
13105	if (cur_svc == NULL && cur_inst == NULL) {
13106		semerr(emsg_entity_not_selected);
13107		return (-1);
13108	}
13109
13110	tmpfd = mkstemp(tempname);
13111	if (tmpfd == -1) {
13112		semerr(gettext("Could not create temporary file.\n"));
13113		return (-1);
13114	}
13115
13116	(void) strcpy(tempfilename, tempname);
13117
13118	tempfile = fdopen(tmpfd, "r+");
13119	if (tempfile == NULL) {
13120		warn(gettext("Could not create temporary file.\n"));
13121		if (close(tmpfd) == -1)
13122			warn(gettext("Could not close temporary file: %s.\n"),
13123			    strerror(errno));
13124
13125		remove_tempfile();
13126
13127		return (-1);
13128	}
13129
13130	if (write_edit_script(tempfile) == -1) {
13131		remove_tempfile();
13132		return (-1);
13133	}
13134
13135	editor = getenv("EDITOR");
13136	if (editor == NULL)
13137		editor = "vi";
13138
13139	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
13140	buf = safe_malloc(bufsz);
13141
13142	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
13143		uu_die(gettext("Error creating editor command"));
13144
13145	if (system(buf) == -1) {
13146		semerr(gettext("Could not launch editor %s: %s\n"), editor,
13147		    strerror(errno));
13148		free(buf);
13149		remove_tempfile();
13150		return (-1);
13151	}
13152
13153	free(buf);
13154
13155	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
13156
13157	remove_tempfile();
13158
13159	return (0);
13160}
13161
13162static void
13163add_string(uu_list_t *strlist, const char *str)
13164{
13165	string_list_t *elem;
13166	elem = safe_malloc(sizeof (*elem));
13167	uu_list_node_init(elem, &elem->node, string_pool);
13168	elem->str = safe_strdup(str);
13169	if (uu_list_append(strlist, elem) != 0)
13170		uu_die(gettext("libuutil error: %s\n"),
13171		    uu_strerror(uu_error()));
13172}
13173
13174static int
13175remove_string(uu_list_t *strlist, const char *str)
13176{
13177	uu_list_walk_t	*elems;
13178	string_list_t	*sp;
13179
13180	/*
13181	 * Find the element that needs to be removed.
13182	 */
13183	elems = uu_list_walk_start(strlist, UU_DEFAULT);
13184	while ((sp = uu_list_walk_next(elems)) != NULL) {
13185		if (strcmp(sp->str, str) == 0)
13186			break;
13187	}
13188	uu_list_walk_end(elems);
13189
13190	/*
13191	 * Returning 1 here as the value was not found, this
13192	 * might not be an error.  Leave it to the caller to
13193	 * decide.
13194	 */
13195	if (sp == NULL) {
13196		return (1);
13197	}
13198
13199	uu_list_remove(strlist, sp);
13200
13201	free(sp->str);
13202	free(sp);
13203
13204	return (0);
13205}
13206
13207/*
13208 * Get all property values that don't match the given glob pattern,
13209 * if a pattern is specified.
13210 */
13211static void
13212get_prop_values(scf_property_t *prop, uu_list_t *values,
13213    const char *pattern)
13214{
13215	scf_iter_t *iter;
13216	scf_value_t *val;
13217	int ret;
13218
13219	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13220	    (val = scf_value_create(g_hndl)) == NULL)
13221		scfdie();
13222
13223	if (scf_iter_property_values(iter, prop) != 0)
13224		scfdie();
13225
13226	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13227		char *buf;
13228		ssize_t vlen, szret;
13229
13230		vlen = scf_value_get_as_string(val, NULL, 0);
13231		if (vlen < 0)
13232			scfdie();
13233
13234		buf = safe_malloc(vlen + 1);
13235
13236		szret = scf_value_get_as_string(val, buf, vlen + 1);
13237		if (szret < 0)
13238			scfdie();
13239		assert(szret <= vlen);
13240
13241		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
13242			add_string(values, buf);
13243
13244		free(buf);
13245	}
13246
13247	if (ret == -1)
13248		scfdie();
13249
13250	scf_value_destroy(val);
13251	scf_iter_destroy(iter);
13252}
13253
13254static int
13255lscf_setpropvalue(const char *pgname, const char *type,
13256    const char *arg, int isadd, int isnotfoundok)
13257{
13258	scf_type_t ty;
13259	scf_propertygroup_t *pg;
13260	scf_property_t *prop;
13261	int ret, result = 0;
13262	scf_transaction_t *tx;
13263	scf_transaction_entry_t *e;
13264	scf_value_t *v;
13265	string_list_t *sp;
13266	char *propname;
13267	uu_list_t *values;
13268	uu_list_walk_t *walk;
13269	void *cookie = NULL;
13270	char *pattern = NULL;
13271
13272	lscf_prep_hndl();
13273
13274	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
13275		uu_die(gettext("Could not create property list: %s\n"),
13276		    uu_strerror(uu_error()));
13277
13278	if (!isadd)
13279		pattern = safe_strdup(arg);
13280
13281	if ((e = scf_entry_create(g_hndl)) == NULL ||
13282	    (pg = scf_pg_create(g_hndl)) == NULL ||
13283	    (prop = scf_property_create(g_hndl)) == NULL ||
13284	    (tx = scf_transaction_create(g_hndl)) == NULL)
13285		scfdie();
13286
13287	if (cur_snap != NULL) {
13288		semerr(emsg_cant_modify_snapshots);
13289		goto fail;
13290	}
13291
13292	if (cur_inst == NULL && cur_svc == NULL) {
13293		semerr(emsg_entity_not_selected);
13294		goto fail;
13295	}
13296
13297	propname = strchr(pgname, '/');
13298	if (propname == NULL) {
13299		semerr(gettext("Property names must contain a `/'.\n"));
13300		goto fail;
13301	}
13302
13303	*propname = '\0';
13304	++propname;
13305
13306	if (type != NULL) {
13307		ty = string_to_type(type);
13308		if (ty == SCF_TYPE_INVALID) {
13309			semerr(gettext("Unknown type \"%s\".\n"), type);
13310			goto fail;
13311		}
13312	}
13313
13314	if (cur_inst != NULL)
13315		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13316	else
13317		ret = scf_service_get_pg(cur_svc, pgname, pg);
13318	if (ret != 0) {
13319		switch (scf_error()) {
13320		case SCF_ERROR_NOT_FOUND:
13321			if (isnotfoundok) {
13322				result = 0;
13323			} else {
13324				semerr(emsg_no_such_pg, pgname);
13325				result = -1;
13326			}
13327			goto out;
13328
13329		case SCF_ERROR_INVALID_ARGUMENT:
13330			semerr(emsg_invalid_pg_name, pgname);
13331			goto fail;
13332
13333		default:
13334			scfdie();
13335		}
13336	}
13337
13338	do {
13339		if (scf_pg_update(pg) == -1)
13340			scfdie();
13341		if (scf_transaction_start(tx, pg) != 0) {
13342			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13343				scfdie();
13344
13345			semerr(emsg_permission_denied);
13346			goto fail;
13347		}
13348
13349		ret = scf_pg_get_property(pg, propname, prop);
13350		if (ret == 0) {
13351			scf_type_t ptype;
13352			char *pat = pattern;
13353
13354			if (scf_property_type(prop, &ptype) != 0)
13355				scfdie();
13356
13357			if (isadd) {
13358				if (type != NULL && ptype != ty) {
13359					semerr(gettext("Property \"%s\" is not "
13360					    "of type \"%s\".\n"), propname,
13361					    type);
13362					goto fail;
13363				}
13364
13365				pat = NULL;
13366			} else {
13367				size_t len = strlen(pat);
13368				if (len > 0 && pat[len - 1] == '\"')
13369					pat[len - 1] = '\0';
13370				if (len > 0 && pat[0] == '\"')
13371					pat++;
13372			}
13373
13374			ty = ptype;
13375
13376			get_prop_values(prop, values, pat);
13377
13378			if (isadd)
13379				add_string(values, arg);
13380
13381			if (scf_transaction_property_change(tx, e,
13382			    propname, ty) == -1)
13383				scfdie();
13384		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13385			if (isadd) {
13386				if (type == NULL) {
13387					semerr(gettext("Type required "
13388					    "for new properties.\n"));
13389					goto fail;
13390				}
13391
13392				add_string(values, arg);
13393
13394				if (scf_transaction_property_new(tx, e,
13395				    propname, ty) == -1)
13396					scfdie();
13397			} else if (isnotfoundok) {
13398				result = 0;
13399				goto out;
13400			} else {
13401				semerr(gettext("No such property %s/%s.\n"),
13402				    pgname, propname);
13403				result = -1;
13404				goto out;
13405			}
13406		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13407			semerr(emsg_invalid_prop_name, propname);
13408			goto fail;
13409		} else {
13410			scfdie();
13411		}
13412
13413		walk = uu_list_walk_start(values, UU_DEFAULT);
13414		if (walk == NULL)
13415			uu_die(gettext("Could not walk property list.\n"));
13416
13417		for (sp = uu_list_walk_next(walk); sp != NULL;
13418		    sp = uu_list_walk_next(walk)) {
13419			v = string_to_value(sp->str, ty, 0);
13420
13421			if (v == NULL) {
13422				scf_entry_destroy_children(e);
13423				goto fail;
13424			}
13425			ret = scf_entry_add_value(e, v);
13426			assert(ret == 0);
13427		}
13428		uu_list_walk_end(walk);
13429
13430		result = scf_transaction_commit(tx);
13431
13432		scf_transaction_reset(tx);
13433		scf_entry_destroy_children(e);
13434	} while (result == 0);
13435
13436	if (result < 0) {
13437		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13438			scfdie();
13439
13440		semerr(emsg_permission_denied);
13441		goto fail;
13442	}
13443
13444	result = 0;
13445
13446	private_refresh();
13447
13448out:
13449	scf_transaction_destroy(tx);
13450	scf_entry_destroy(e);
13451	scf_pg_destroy(pg);
13452	scf_property_destroy(prop);
13453	free(pattern);
13454
13455	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
13456		free(sp->str);
13457		free(sp);
13458	}
13459
13460	uu_list_destroy(values);
13461
13462	return (result);
13463
13464fail:
13465	result = -1;
13466	goto out;
13467}
13468
13469int
13470lscf_addpropvalue(const char *pgname, const char *type, const char *value)
13471{
13472	return (lscf_setpropvalue(pgname, type, value, 1, 0));
13473}
13474
13475int
13476lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
13477{
13478	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
13479}
13480
13481/*
13482 * Look for a standard start method, first in the instance (if any),
13483 * then the service.
13484 */
13485static const char *
13486start_method_name(int *in_instance)
13487{
13488	scf_propertygroup_t *pg;
13489	char **p;
13490	int ret;
13491	scf_instance_t *inst = cur_inst;
13492
13493	if ((pg = scf_pg_create(g_hndl)) == NULL)
13494		scfdie();
13495
13496again:
13497	for (p = start_method_names; *p != NULL; p++) {
13498		if (inst != NULL)
13499			ret = scf_instance_get_pg(inst, *p, pg);
13500		else
13501			ret = scf_service_get_pg(cur_svc, *p, pg);
13502
13503		if (ret == 0) {
13504			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
13505			char *buf = safe_malloc(bufsz);
13506
13507			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
13508				free(buf);
13509				continue;
13510			}
13511			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
13512				free(buf);
13513				continue;
13514			}
13515
13516			free(buf);
13517			*in_instance = (inst != NULL);
13518			scf_pg_destroy(pg);
13519			return (*p);
13520		}
13521
13522		if (scf_error() == SCF_ERROR_NOT_FOUND)
13523			continue;
13524
13525		scfdie();
13526	}
13527
13528	if (inst != NULL) {
13529		inst = NULL;
13530		goto again;
13531	}
13532
13533	scf_pg_destroy(pg);
13534	return (NULL);
13535}
13536
13537static int
13538addpg(const char *name, const char *type)
13539{
13540	scf_propertygroup_t *pg;
13541	int ret;
13542
13543	pg = scf_pg_create(g_hndl);
13544	if (pg == NULL)
13545		scfdie();
13546
13547	if (cur_inst != NULL)
13548		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
13549	else
13550		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
13551
13552	if (ret != 0) {
13553		switch (scf_error()) {
13554		case SCF_ERROR_EXISTS:
13555			ret = 0;
13556			break;
13557
13558		case SCF_ERROR_PERMISSION_DENIED:
13559			semerr(emsg_permission_denied);
13560			break;
13561
13562		default:
13563			scfdie();
13564		}
13565	}
13566
13567	scf_pg_destroy(pg);
13568	return (ret);
13569}
13570
13571int
13572lscf_setenv(uu_list_t *args, int isunset)
13573{
13574	int ret = 0;
13575	size_t i;
13576	int argc;
13577	char **argv = NULL;
13578	string_list_t *slp;
13579	char *pattern;
13580	char *prop;
13581	int do_service = 0;
13582	int do_instance = 0;
13583	const char *method = NULL;
13584	const char *name = NULL;
13585	const char *value = NULL;
13586	scf_instance_t *saved_cur_inst = cur_inst;
13587
13588	lscf_prep_hndl();
13589
13590	argc = uu_list_numnodes(args);
13591	if (argc < 1)
13592		goto usage;
13593
13594	argv = calloc(argc + 1, sizeof (char *));
13595	if (argv == NULL)
13596		uu_die(gettext("Out of memory.\n"));
13597
13598	for (slp = uu_list_first(args), i = 0;
13599	    slp != NULL;
13600	    slp = uu_list_next(args, slp), ++i)
13601		argv[i] = slp->str;
13602
13603	argv[i] = NULL;
13604
13605	opterr = 0;
13606	optind = 0;
13607	for (;;) {
13608		ret = getopt(argc, argv, "sim:");
13609		if (ret == -1)
13610			break;
13611
13612		switch (ret) {
13613		case 's':
13614			do_service = 1;
13615			cur_inst = NULL;
13616			break;
13617
13618		case 'i':
13619			do_instance = 1;
13620			break;
13621
13622		case 'm':
13623			method = optarg;
13624			break;
13625
13626		case '?':
13627			goto usage;
13628
13629		default:
13630			bad_error("getopt", ret);
13631		}
13632	}
13633
13634	argc -= optind;
13635	if ((do_service && do_instance) ||
13636	    (isunset && argc != 1) ||
13637	    (!isunset && argc != 2))
13638		goto usage;
13639
13640	name = argv[optind];
13641	if (!isunset)
13642		value = argv[optind + 1];
13643
13644	if (cur_snap != NULL) {
13645		semerr(emsg_cant_modify_snapshots);
13646		ret = -1;
13647		goto out;
13648	}
13649
13650	if (cur_inst == NULL && cur_svc == NULL) {
13651		semerr(emsg_entity_not_selected);
13652		ret = -1;
13653		goto out;
13654	}
13655
13656	if (do_instance && cur_inst == NULL) {
13657		semerr(gettext("No instance is selected.\n"));
13658		ret = -1;
13659		goto out;
13660	}
13661
13662	if (do_service && cur_svc == NULL) {
13663		semerr(gettext("No service is selected.\n"));
13664		ret = -1;
13665		goto out;
13666	}
13667
13668	if (method == NULL) {
13669		if (do_instance || do_service) {
13670			method = "method_context";
13671			if (!isunset) {
13672				ret = addpg("method_context",
13673				    SCF_GROUP_FRAMEWORK);
13674				if (ret != 0)
13675					goto out;
13676			}
13677		} else {
13678			int in_instance;
13679			method = start_method_name(&in_instance);
13680			if (method == NULL) {
13681				semerr(gettext(
13682				    "Couldn't find start method; please "
13683				    "specify a method with '-m'.\n"));
13684				ret = -1;
13685				goto out;
13686			}
13687			if (!in_instance)
13688				cur_inst = NULL;
13689		}
13690	} else {
13691		scf_propertygroup_t *pg;
13692		size_t bufsz;
13693		char *buf;
13694		int ret;
13695
13696		if ((pg = scf_pg_create(g_hndl)) == NULL)
13697			scfdie();
13698
13699		if (cur_inst != NULL)
13700			ret = scf_instance_get_pg(cur_inst, method, pg);
13701		else
13702			ret = scf_service_get_pg(cur_svc, method, pg);
13703
13704		if (ret != 0) {
13705			scf_pg_destroy(pg);
13706			switch (scf_error()) {
13707			case SCF_ERROR_NOT_FOUND:
13708				semerr(gettext("Couldn't find the method "
13709				    "\"%s\".\n"), method);
13710				goto out;
13711
13712			case SCF_ERROR_INVALID_ARGUMENT:
13713				semerr(gettext("Invalid method name \"%s\".\n"),
13714				    method);
13715				goto out;
13716
13717			default:
13718				scfdie();
13719			}
13720		}
13721
13722		bufsz = strlen(SCF_GROUP_METHOD) + 1;
13723		buf = safe_malloc(bufsz);
13724
13725		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
13726		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
13727			semerr(gettext("Property group \"%s\" is not of type "
13728			    "\"method\".\n"), method);
13729			ret = -1;
13730			free(buf);
13731			scf_pg_destroy(pg);
13732			goto out;
13733		}
13734
13735		free(buf);
13736		scf_pg_destroy(pg);
13737	}
13738
13739	prop = uu_msprintf("%s/environment", method);
13740	pattern = uu_msprintf("%s=*", name);
13741
13742	if (prop == NULL || pattern == NULL)
13743		uu_die(gettext("Out of memory.\n"));
13744
13745	ret = lscf_delpropvalue(prop, pattern, !isunset);
13746
13747	if (ret == 0 && !isunset) {
13748		uu_free(pattern);
13749		uu_free(prop);
13750		prop = uu_msprintf("%s/environment", method);
13751		pattern = uu_msprintf("%s=%s", name, value);
13752		if (prop == NULL || pattern == NULL)
13753			uu_die(gettext("Out of memory.\n"));
13754		ret = lscf_addpropvalue(prop, "astring:", pattern);
13755	}
13756	uu_free(pattern);
13757	uu_free(prop);
13758
13759out:
13760	cur_inst = saved_cur_inst;
13761
13762	free(argv);
13763	return (ret);
13764usage:
13765	ret = -2;
13766	goto out;
13767}
13768
13769/*
13770 * Snapshot commands
13771 */
13772
13773void
13774lscf_listsnap()
13775{
13776	scf_snapshot_t *snap;
13777	scf_iter_t *iter;
13778	char *nb;
13779	int r;
13780
13781	lscf_prep_hndl();
13782
13783	if (cur_inst == NULL) {
13784		semerr(gettext("Instance not selected.\n"));
13785		return;
13786	}
13787
13788	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13789	    (iter = scf_iter_create(g_hndl)) == NULL)
13790		scfdie();
13791
13792	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
13793		scfdie();
13794
13795	nb = safe_malloc(max_scf_name_len + 1);
13796
13797	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
13798		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
13799			scfdie();
13800
13801		(void) puts(nb);
13802	}
13803	if (r < 0)
13804		scfdie();
13805
13806	free(nb);
13807	scf_iter_destroy(iter);
13808	scf_snapshot_destroy(snap);
13809}
13810
13811void
13812lscf_selectsnap(const char *name)
13813{
13814	scf_snapshot_t *snap;
13815	scf_snaplevel_t *level;
13816
13817	lscf_prep_hndl();
13818
13819	if (cur_inst == NULL) {
13820		semerr(gettext("Instance not selected.\n"));
13821		return;
13822	}
13823
13824	if (cur_snap != NULL) {
13825		if (name != NULL) {
13826			char *cur_snap_name;
13827			boolean_t nochange;
13828
13829			cur_snap_name = safe_malloc(max_scf_name_len + 1);
13830
13831			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
13832			    max_scf_name_len + 1) < 0)
13833				scfdie();
13834
13835			nochange = strcmp(name, cur_snap_name) == 0;
13836
13837			free(cur_snap_name);
13838
13839			if (nochange)
13840				return;
13841		}
13842
13843		unselect_cursnap();
13844	}
13845
13846	if (name == NULL)
13847		return;
13848
13849	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13850	    (level = scf_snaplevel_create(g_hndl)) == NULL)
13851		scfdie();
13852
13853	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
13854	    SCF_SUCCESS) {
13855		switch (scf_error()) {
13856		case SCF_ERROR_INVALID_ARGUMENT:
13857			semerr(gettext("Invalid name \"%s\".\n"), name);
13858			break;
13859
13860		case SCF_ERROR_NOT_FOUND:
13861			semerr(gettext("No such snapshot \"%s\".\n"), name);
13862			break;
13863
13864		default:
13865			scfdie();
13866		}
13867
13868		scf_snaplevel_destroy(level);
13869		scf_snapshot_destroy(snap);
13870		return;
13871	}
13872
13873	/* Load the snaplevels into our list. */
13874	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
13875	if (cur_levels == NULL)
13876		uu_die(gettext("Could not create list: %s\n"),
13877		    uu_strerror(uu_error()));
13878
13879	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13880		if (scf_error() != SCF_ERROR_NOT_FOUND)
13881			scfdie();
13882
13883		semerr(gettext("Snapshot has no snaplevels.\n"));
13884
13885		scf_snaplevel_destroy(level);
13886		scf_snapshot_destroy(snap);
13887		return;
13888	}
13889
13890	cur_snap = snap;
13891
13892	for (;;) {
13893		cur_elt = safe_malloc(sizeof (*cur_elt));
13894		uu_list_node_init(cur_elt, &cur_elt->list_node,
13895		    snaplevel_pool);
13896		cur_elt->sl = level;
13897		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
13898			uu_die(gettext("libuutil error: %s\n"),
13899			    uu_strerror(uu_error()));
13900
13901		level = scf_snaplevel_create(g_hndl);
13902		if (level == NULL)
13903			scfdie();
13904
13905		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
13906		    level) != SCF_SUCCESS) {
13907			if (scf_error() != SCF_ERROR_NOT_FOUND)
13908				scfdie();
13909
13910			scf_snaplevel_destroy(level);
13911			break;
13912		}
13913	}
13914
13915	cur_elt = uu_list_last(cur_levels);
13916	cur_level = cur_elt->sl;
13917}
13918
13919/*
13920 * Copies the properties & values in src to dst.  Assumes src won't change.
13921 * Returns -1 if permission is denied, -2 if another transaction interrupts,
13922 * and 0 on success.
13923 *
13924 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
13925 * property, if it is copied and has type boolean.  (See comment in
13926 * lscf_revert()).
13927 */
13928static int
13929pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
13930    uint8_t enabled)
13931{
13932	scf_transaction_t *tx;
13933	scf_iter_t *iter, *viter;
13934	scf_property_t *prop;
13935	scf_value_t *v;
13936	char *nbuf;
13937	int r;
13938
13939	tx = scf_transaction_create(g_hndl);
13940	if (tx == NULL)
13941		scfdie();
13942
13943	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
13944		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13945			scfdie();
13946
13947		scf_transaction_destroy(tx);
13948
13949		return (-1);
13950	}
13951
13952	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13953	    (prop = scf_property_create(g_hndl)) == NULL ||
13954	    (viter = scf_iter_create(g_hndl)) == NULL)
13955		scfdie();
13956
13957	nbuf = safe_malloc(max_scf_name_len + 1);
13958
13959	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
13960		scfdie();
13961
13962	for (;;) {
13963		scf_transaction_entry_t *e;
13964		scf_type_t ty;
13965
13966		r = scf_iter_next_property(iter, prop);
13967		if (r == -1)
13968			scfdie();
13969		if (r == 0)
13970			break;
13971
13972		e = scf_entry_create(g_hndl);
13973		if (e == NULL)
13974			scfdie();
13975
13976		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
13977			scfdie();
13978
13979		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
13980			scfdie();
13981
13982		if (scf_transaction_property_new(tx, e, nbuf,
13983		    ty) != SCF_SUCCESS)
13984			scfdie();
13985
13986		if ((enabled == 0 || enabled == 1) &&
13987		    strcmp(nbuf, scf_property_enabled) == 0 &&
13988		    ty == SCF_TYPE_BOOLEAN) {
13989			v = scf_value_create(g_hndl);
13990			if (v == NULL)
13991				scfdie();
13992
13993			scf_value_set_boolean(v, enabled);
13994
13995			if (scf_entry_add_value(e, v) != 0)
13996				scfdie();
13997		} else {
13998			if (scf_iter_property_values(viter, prop) != 0)
13999				scfdie();
14000
14001			for (;;) {
14002				v = scf_value_create(g_hndl);
14003				if (v == NULL)
14004					scfdie();
14005
14006				r = scf_iter_next_value(viter, v);
14007				if (r == -1)
14008					scfdie();
14009				if (r == 0) {
14010					scf_value_destroy(v);
14011					break;
14012				}
14013
14014				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14015					scfdie();
14016			}
14017		}
14018	}
14019
14020	free(nbuf);
14021	scf_iter_destroy(viter);
14022	scf_property_destroy(prop);
14023	scf_iter_destroy(iter);
14024
14025	r = scf_transaction_commit(tx);
14026	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
14027		scfdie();
14028
14029	scf_transaction_destroy_children(tx);
14030	scf_transaction_destroy(tx);
14031
14032	switch (r) {
14033	case 1:		return (0);
14034	case 0:		return (-2);
14035	case -1:	return (-1);
14036
14037	default:
14038		abort();
14039	}
14040
14041	/* NOTREACHED */
14042}
14043
14044void
14045lscf_revert(const char *snapname)
14046{
14047	scf_snapshot_t *snap, *prev;
14048	scf_snaplevel_t *level, *nlevel;
14049	scf_iter_t *iter;
14050	scf_propertygroup_t *pg, *npg;
14051	scf_property_t *prop;
14052	scf_value_t *val;
14053	char *nbuf, *tbuf;
14054	uint8_t enabled;
14055
14056	lscf_prep_hndl();
14057
14058	if (cur_inst == NULL) {
14059		semerr(gettext("Instance not selected.\n"));
14060		return;
14061	}
14062
14063	if (snapname != NULL) {
14064		snap = scf_snapshot_create(g_hndl);
14065		if (snap == NULL)
14066			scfdie();
14067
14068		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
14069		    SCF_SUCCESS) {
14070			switch (scf_error()) {
14071			case SCF_ERROR_INVALID_ARGUMENT:
14072				semerr(gettext("Invalid snapshot name "
14073				    "\"%s\".\n"), snapname);
14074				break;
14075
14076			case SCF_ERROR_NOT_FOUND:
14077				semerr(gettext("No such snapshot.\n"));
14078				break;
14079
14080			default:
14081				scfdie();
14082			}
14083
14084			scf_snapshot_destroy(snap);
14085			return;
14086		}
14087	} else {
14088		if (cur_snap != NULL) {
14089			snap = cur_snap;
14090		} else {
14091			semerr(gettext("No snapshot selected.\n"));
14092			return;
14093		}
14094	}
14095
14096	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
14097	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
14098	    (iter = scf_iter_create(g_hndl)) == NULL ||
14099	    (pg = scf_pg_create(g_hndl)) == NULL ||
14100	    (npg = scf_pg_create(g_hndl)) == NULL ||
14101	    (prop = scf_property_create(g_hndl)) == NULL ||
14102	    (val = scf_value_create(g_hndl)) == NULL)
14103		scfdie();
14104
14105	nbuf = safe_malloc(max_scf_name_len + 1);
14106	tbuf = safe_malloc(max_scf_pg_type_len + 1);
14107
14108	/* Take the "previous" snapshot before we blow away the properties. */
14109	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
14110		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
14111			scfdie();
14112	} else {
14113		if (scf_error() != SCF_ERROR_NOT_FOUND)
14114			scfdie();
14115
14116		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
14117			scfdie();
14118	}
14119
14120	/* Save general/enabled, since we're probably going to replace it. */
14121	enabled = 2;
14122	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
14123	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
14124	    scf_property_get_value(prop, val) == 0)
14125		(void) scf_value_get_boolean(val, &enabled);
14126
14127	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14128		if (scf_error() != SCF_ERROR_NOT_FOUND)
14129			scfdie();
14130
14131		goto out;
14132	}
14133
14134	for (;;) {
14135		boolean_t isinst;
14136		uint32_t flags;
14137		int r;
14138
14139		/* Clear the properties from the corresponding entity. */
14140		isinst = snaplevel_is_instance(level);
14141
14142		if (!isinst)
14143			r = scf_iter_service_pgs(iter, cur_svc);
14144		else
14145			r = scf_iter_instance_pgs(iter, cur_inst);
14146		if (r != SCF_SUCCESS)
14147			scfdie();
14148
14149		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14150			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14151				scfdie();
14152
14153			/* Skip nonpersistent pgs. */
14154			if (flags & SCF_PG_FLAG_NONPERSISTENT)
14155				continue;
14156
14157			if (scf_pg_delete(pg) != SCF_SUCCESS) {
14158				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14159					scfdie();
14160
14161				semerr(emsg_permission_denied);
14162				goto out;
14163			}
14164		}
14165		if (r == -1)
14166			scfdie();
14167
14168		/* Copy the properties to the corresponding entity. */
14169		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
14170			scfdie();
14171
14172		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14173			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
14174				scfdie();
14175
14176			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
14177			    0)
14178				scfdie();
14179
14180			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14181				scfdie();
14182
14183			if (!isinst)
14184				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
14185				    flags, npg);
14186			else
14187				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
14188				    flags, npg);
14189			if (r != SCF_SUCCESS) {
14190				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14191					scfdie();
14192
14193				semerr(emsg_permission_denied);
14194				goto out;
14195			}
14196
14197			if ((enabled == 0 || enabled == 1) &&
14198			    strcmp(nbuf, scf_pg_general) == 0)
14199				r = pg_copy(pg, npg, enabled);
14200			else
14201				r = pg_copy(pg, npg, 2);
14202
14203			switch (r) {
14204			case 0:
14205				break;
14206
14207			case -1:
14208				semerr(emsg_permission_denied);
14209				goto out;
14210
14211			case -2:
14212				semerr(gettext(
14213				    "Interrupted by another change.\n"));
14214				goto out;
14215
14216			default:
14217				abort();
14218			}
14219		}
14220		if (r == -1)
14221			scfdie();
14222
14223		/* Get next level. */
14224		nlevel = scf_snaplevel_create(g_hndl);
14225		if (nlevel == NULL)
14226			scfdie();
14227
14228		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
14229		    SCF_SUCCESS) {
14230			if (scf_error() != SCF_ERROR_NOT_FOUND)
14231				scfdie();
14232
14233			scf_snaplevel_destroy(nlevel);
14234			break;
14235		}
14236
14237		scf_snaplevel_destroy(level);
14238		level = nlevel;
14239	}
14240
14241	if (snapname == NULL) {
14242		lscf_selectsnap(NULL);
14243		snap = NULL;		/* cur_snap has been destroyed */
14244	}
14245
14246out:
14247	free(tbuf);
14248	free(nbuf);
14249	scf_value_destroy(val);
14250	scf_property_destroy(prop);
14251	scf_pg_destroy(npg);
14252	scf_pg_destroy(pg);
14253	scf_iter_destroy(iter);
14254	scf_snaplevel_destroy(level);
14255	scf_snapshot_destroy(prev);
14256	if (snap != cur_snap)
14257		scf_snapshot_destroy(snap);
14258}
14259
14260void
14261lscf_refresh(void)
14262{
14263	ssize_t fmrilen;
14264	size_t bufsz;
14265	char *fmribuf;
14266	int r;
14267
14268	lscf_prep_hndl();
14269
14270	if (cur_inst == NULL) {
14271		semerr(gettext("Instance not selected.\n"));
14272		return;
14273	}
14274
14275	bufsz = max_scf_fmri_len + 1;
14276	fmribuf = safe_malloc(bufsz);
14277	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
14278	if (fmrilen < 0) {
14279		free(fmribuf);
14280		if (scf_error() != SCF_ERROR_DELETED)
14281			scfdie();
14282		scf_instance_destroy(cur_inst);
14283		cur_inst = NULL;
14284		warn(emsg_deleted);
14285		return;
14286	}
14287	assert(fmrilen < bufsz);
14288
14289	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
14290	switch (r) {
14291	case 0:
14292		break;
14293
14294	case ECONNABORTED:
14295		warn(gettext("Could not refresh %s "
14296		    "(repository connection broken).\n"), fmribuf);
14297		break;
14298
14299	case ECANCELED:
14300		warn(emsg_deleted);
14301		break;
14302
14303	case EPERM:
14304		warn(gettext("Could not refresh %s "
14305		    "(permission denied).\n"), fmribuf);
14306		break;
14307
14308	case ENOSPC:
14309		warn(gettext("Could not refresh %s "
14310		    "(repository server out of resources).\n"),
14311		    fmribuf);
14312		break;
14313
14314	case EACCES:
14315	default:
14316		bad_error("refresh_entity", scf_error());
14317	}
14318
14319	free(fmribuf);
14320}
14321
14322/*
14323 * describe [-v] [-t] [pg/prop]
14324 */
14325int
14326lscf_describe(uu_list_t *args, int hasargs)
14327{
14328	int ret = 0;
14329	size_t i;
14330	int argc;
14331	char **argv = NULL;
14332	string_list_t *slp;
14333	int do_verbose = 0;
14334	int do_templates = 0;
14335	char *pattern = NULL;
14336
14337	lscf_prep_hndl();
14338
14339	if (hasargs != 0)  {
14340		argc = uu_list_numnodes(args);
14341		if (argc < 1)
14342			goto usage;
14343
14344		argv = calloc(argc + 1, sizeof (char *));
14345		if (argv == NULL)
14346			uu_die(gettext("Out of memory.\n"));
14347
14348		for (slp = uu_list_first(args), i = 0;
14349		    slp != NULL;
14350		    slp = uu_list_next(args, slp), ++i)
14351			argv[i] = slp->str;
14352
14353		argv[i] = NULL;
14354
14355		/*
14356		 * We start optind = 0 because our list of arguments
14357		 * starts at argv[0]
14358		 */
14359		optind = 0;
14360		opterr = 0;
14361		for (;;) {
14362			ret = getopt(argc, argv, "vt");
14363			if (ret == -1)
14364				break;
14365
14366			switch (ret) {
14367			case 'v':
14368				do_verbose = 1;
14369				break;
14370
14371			case 't':
14372				do_templates = 1;
14373				break;
14374
14375			case '?':
14376				goto usage;
14377
14378			default:
14379				bad_error("getopt", ret);
14380			}
14381		}
14382
14383		pattern = argv[optind];
14384	}
14385
14386	if (cur_inst == NULL && cur_svc == NULL) {
14387		semerr(emsg_entity_not_selected);
14388		ret = -1;
14389		goto out;
14390	}
14391
14392	/*
14393	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
14394	 * output if their last parameter is set to 2.  Less information is
14395	 * produced if the parameter is set to 1.
14396	 */
14397	if (pattern == NULL) {
14398		if (do_verbose == 1)
14399			list_entity_tmpl(2);
14400		else
14401			list_entity_tmpl(1);
14402	}
14403
14404	if (do_templates == 0) {
14405		if (do_verbose == 1)
14406			listprop(pattern, 0, 2);
14407		else
14408			listprop(pattern, 0, 1);
14409	} else {
14410		if (do_verbose == 1)
14411			listtmpl(pattern, 2);
14412		else
14413			listtmpl(pattern, 1);
14414	}
14415
14416	ret = 0;
14417out:
14418	if (argv != NULL)
14419		free(argv);
14420	return (ret);
14421usage:
14422	ret = -2;
14423	goto out;
14424}
14425
14426/*
14427 * Creates a list of instance name strings associated with a service. If
14428 * wohandcrafted flag is set, get only instances that have a last-import
14429 * snapshot, instances that were imported via svccfg.
14430 */
14431static uu_list_t *
14432create_instance_list(scf_service_t *svc, int wohandcrafted)
14433{
14434	scf_snapshot_t  *snap = NULL;
14435	scf_instance_t  *inst;
14436	scf_iter_t	*inst_iter;
14437	uu_list_t	*instances;
14438	char		*instname;
14439	int		r;
14440
14441	inst_iter = scf_iter_create(g_hndl);
14442	inst = scf_instance_create(g_hndl);
14443	if (inst_iter == NULL || inst == NULL) {
14444		uu_warn(gettext("Could not create instance or iterator\n"));
14445		scfdie();
14446	}
14447
14448	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
14449		return (instances);
14450
14451	if (scf_iter_service_instances(inst_iter, svc) != 0) {
14452		switch (scf_error()) {
14453		case SCF_ERROR_CONNECTION_BROKEN:
14454		case SCF_ERROR_DELETED:
14455			uu_list_destroy(instances);
14456			instances = NULL;
14457			goto out;
14458
14459		case SCF_ERROR_HANDLE_MISMATCH:
14460		case SCF_ERROR_NOT_BOUND:
14461		case SCF_ERROR_NOT_SET:
14462		default:
14463			bad_error("scf_iter_service_instances", scf_error());
14464		}
14465	}
14466
14467	instname = safe_malloc(max_scf_name_len + 1);
14468	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
14469		if (r == -1) {
14470			(void) uu_warn(gettext("Unable to iterate through "
14471			    "instances to create instance list : %s\n"),
14472			    scf_strerror(scf_error()));
14473
14474			uu_list_destroy(instances);
14475			instances = NULL;
14476			goto out;
14477		}
14478
14479		/*
14480		 * If the instance does not have a last-import snapshot
14481		 * then do not add it to the list as it is a hand-crafted
14482		 * instance that should not be managed.
14483		 */
14484		if (wohandcrafted) {
14485			if (snap == NULL &&
14486			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
14487				uu_warn(gettext("Unable to create snapshot "
14488				    "entity\n"));
14489				scfdie();
14490			}
14491
14492			if (scf_instance_get_snapshot(inst,
14493			    snap_lastimport, snap) != 0) {
14494				switch (scf_error()) {
14495				case SCF_ERROR_NOT_FOUND :
14496				case SCF_ERROR_DELETED:
14497					continue;
14498
14499				case SCF_ERROR_CONNECTION_BROKEN:
14500					uu_list_destroy(instances);
14501					instances = NULL;
14502					goto out;
14503
14504				case SCF_ERROR_HANDLE_MISMATCH:
14505				case SCF_ERROR_NOT_BOUND:
14506				case SCF_ERROR_NOT_SET:
14507				default:
14508					bad_error("scf_iter_service_instances",
14509					    scf_error());
14510				}
14511			}
14512		}
14513
14514		if (scf_instance_get_name(inst, instname,
14515		    max_scf_name_len + 1) < 0) {
14516			switch (scf_error()) {
14517			case SCF_ERROR_NOT_FOUND :
14518				continue;
14519
14520			case SCF_ERROR_CONNECTION_BROKEN:
14521			case SCF_ERROR_DELETED:
14522				uu_list_destroy(instances);
14523				instances = NULL;
14524				goto out;
14525
14526			case SCF_ERROR_HANDLE_MISMATCH:
14527			case SCF_ERROR_NOT_BOUND:
14528			case SCF_ERROR_NOT_SET:
14529			default:
14530				bad_error("scf_iter_service_instances",
14531				    scf_error());
14532			}
14533		}
14534
14535		add_string(instances, instname);
14536	}
14537
14538out:
14539	if (snap)
14540		scf_snapshot_destroy(snap);
14541
14542	scf_instance_destroy(inst);
14543	scf_iter_destroy(inst_iter);
14544	free(instname);
14545	return (instances);
14546}
14547
14548/*
14549 * disable an instance but wait for the instance to
14550 * move out of the running state.
14551 *
14552 * Returns 0 : if the instance did not disable
14553 * Returns non-zero : if the instance disabled.
14554 *
14555 */
14556static int
14557disable_instance(scf_instance_t *instance)
14558{
14559	char	*fmribuf;
14560	int	enabled = 10000;
14561
14562	if (inst_is_running(instance)) {
14563		fmribuf = safe_malloc(max_scf_name_len + 1);
14564		if (scf_instance_to_fmri(instance, fmribuf,
14565		    max_scf_name_len + 1) < 0) {
14566			free(fmribuf);
14567			return (0);
14568		}
14569
14570		/*
14571		 * If the instance cannot be disabled then return
14572		 * failure to disable and let the caller decide
14573		 * if that is of importance.
14574		 */
14575		if (smf_disable_instance(fmribuf, 0) != 0) {
14576			free(fmribuf);
14577			return (0);
14578		}
14579
14580		while (enabled) {
14581			if (!inst_is_running(instance))
14582				break;
14583
14584			(void) poll(NULL, 0, 5);
14585			enabled = enabled - 5;
14586		}
14587
14588		free(fmribuf);
14589	}
14590
14591	return (enabled);
14592}
14593
14594/*
14595 * Function to compare two service_manifest structures.
14596 */
14597/* ARGSUSED2 */
14598static int
14599service_manifest_compare(const void *left, const void *right, void *unused)
14600{
14601	service_manifest_t *l = (service_manifest_t *)left;
14602	service_manifest_t *r = (service_manifest_t *)right;
14603	int rc;
14604
14605	rc = strcmp(l->servicename, r->servicename);
14606
14607	return (rc);
14608}
14609
14610/*
14611 * Look for the provided service in the service to manifest
14612 * tree.  If the service exists, and a manifest was provided
14613 * then add the manifest to that service.  If the service
14614 * does not exist, then add the service and manifest to the
14615 * list.
14616 *
14617 * If the manifest is NULL, return the element if found.  If
14618 * the service is not found return NULL.
14619 */
14620service_manifest_t *
14621find_add_svc_mfst(const char *svnbuf, const char *mfst)
14622{
14623	service_manifest_t	elem;
14624	service_manifest_t	*fnelem;
14625	uu_avl_index_t		marker;
14626
14627	elem.servicename = svnbuf;
14628	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
14629
14630	if (mfst) {
14631		if (fnelem) {
14632			add_string(fnelem->mfstlist, strdup(mfst));
14633		} else {
14634			fnelem = safe_malloc(sizeof (*fnelem));
14635			fnelem->servicename = safe_strdup(svnbuf);
14636			if ((fnelem->mfstlist =
14637			    uu_list_create(string_pool, NULL, 0)) == NULL)
14638				uu_die(gettext("Could not create property "
14639				    "list: %s\n"), uu_strerror(uu_error()));
14640
14641			add_string(fnelem->mfstlist, safe_strdup(mfst));
14642
14643			uu_avl_insert(service_manifest_tree, fnelem, marker);
14644		}
14645	}
14646
14647	return (fnelem);
14648}
14649
14650/*
14651 * Create the service to manifest avl tree.
14652 *
14653 * Walk each of the manifests currently installed in the supported
14654 * directories, /lib/svc/manifests and /var/svc/manifests.  For
14655 * each of the manifests, inventory the services and add them to
14656 * the tree.
14657 *
14658 * Code that calls this function should make sure fileystem/minimal is online,
14659 * /var is available, since this function walks the /var/svc/manifest directory.
14660 */
14661static void
14662create_manifest_tree(void)
14663{
14664	manifest_info_t **entry;
14665	manifest_info_t **manifests;
14666	uu_list_walk_t	*svcs;
14667	bundle_t	*b;
14668	entity_t	*mfsvc;
14669	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
14670	int		c, status;
14671
14672	if (service_manifest_pool)
14673		return;
14674
14675	/*
14676	 * Create the list pool for the service manifest list
14677	 */
14678	service_manifest_pool = uu_avl_pool_create("service_manifest",
14679	    sizeof (service_manifest_t),
14680	    offsetof(service_manifest_t, svcmfst_node),
14681	    service_manifest_compare, UU_DEFAULT);
14682	if (service_manifest_pool == NULL)
14683		uu_die(gettext("service_manifest pool creation failed: %s\n"),
14684		    uu_strerror(uu_error()));
14685
14686	/*
14687	 * Create the list
14688	 */
14689	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
14690	    UU_DEFAULT);
14691	if (service_manifest_tree == NULL)
14692		uu_die(gettext("service_manifest tree creation failed: %s\n"),
14693		    uu_strerror(uu_error()));
14694
14695	/*
14696	 * Walk the manifests adding the service(s) from each manifest.
14697	 *
14698	 * If a service already exists add the manifest to the manifest
14699	 * list for that service.  This covers the case of a service that
14700	 * is supported by multiple manifest files.
14701	 */
14702	for (c = 0; dirs[c]; c++) {
14703		status = find_manifests(dirs[c], &manifests, CHECKEXT);
14704		if (status < 0) {
14705			uu_warn(gettext("file tree walk of %s encountered "
14706			    "error %s\n"), dirs[c], strerror(errno));
14707
14708			uu_avl_destroy(service_manifest_tree);
14709			service_manifest_tree = NULL;
14710			return;
14711		}
14712
14713		/*
14714		 * If a manifest that was in the list is not found
14715		 * then skip and go to the next manifest file.
14716		 */
14717		if (manifests != NULL) {
14718			for (entry = manifests; *entry != NULL; entry++) {
14719				b = internal_bundle_new();
14720				if (lxml_get_bundle_file(b, (*entry)->mi_path,
14721				    SVCCFG_OP_IMPORT) != 0) {
14722					internal_bundle_free(b);
14723					continue;
14724				}
14725
14726				svcs = uu_list_walk_start(b->sc_bundle_services,
14727				    0);
14728				if (svcs == NULL) {
14729					internal_bundle_free(b);
14730					continue;
14731				}
14732
14733				while ((mfsvc = uu_list_walk_next(svcs)) !=
14734				    NULL) {
14735					/* Add manifest to service */
14736					(void) find_add_svc_mfst(mfsvc->sc_name,
14737					    (*entry)->mi_path);
14738				}
14739
14740				uu_list_walk_end(svcs);
14741				internal_bundle_free(b);
14742			}
14743
14744			free_manifest_array(manifests);
14745		}
14746	}
14747}
14748
14749/*
14750 * Check the manifest history file to see
14751 * if the service was ever installed from
14752 * one of the supported directories.
14753 *
14754 * Return Values :
14755 * 	-1 - if there's error reading manifest history file
14756 *	 1 - if the service is not found
14757 *	 0 - if the service is found
14758 */
14759static int
14760check_mfst_history(const char *svcname)
14761{
14762	struct stat	st;
14763	caddr_t		mfsthist_start;
14764	char		*svnbuf;
14765	int		fd;
14766	int		r = 1;
14767
14768	fd = open(MFSTHISTFILE, O_RDONLY);
14769	if (fd == -1) {
14770		uu_warn(gettext("Unable to open the history file\n"));
14771		return (-1);
14772	}
14773
14774	if (fstat(fd, &st) == -1) {
14775		uu_warn(gettext("Unable to stat the history file\n"));
14776		return (-1);
14777	}
14778
14779	mfsthist_start = mmap(0, st.st_size, PROT_READ,
14780	    MAP_PRIVATE, fd, 0);
14781
14782	(void) close(fd);
14783	if (mfsthist_start == MAP_FAILED ||
14784	    *(mfsthist_start + st.st_size) != '\0') {
14785		(void) munmap(mfsthist_start, st.st_size);
14786		return (-1);
14787	}
14788
14789	/*
14790	 * The manifest history file is a space delimited list
14791	 * of service and instance to manifest linkage.  Adding
14792	 * a space to the end of the service name so to get only
14793	 * the service that is being searched for.
14794	 */
14795	svnbuf = uu_msprintf("%s ", svcname);
14796	if (svnbuf == NULL)
14797		uu_die(gettext("Out of memory"));
14798
14799	if (strstr(mfsthist_start, svnbuf) != NULL)
14800		r = 0;
14801
14802	(void) munmap(mfsthist_start, st.st_size);
14803	uu_free(svnbuf);
14804	return (r);
14805}
14806
14807/*
14808 * Take down each of the instances in the service
14809 * and remove them, then delete the service.
14810 */
14811static void
14812teardown_service(scf_service_t *svc, const char *svnbuf)
14813{
14814	scf_instance_t	*instance;
14815	scf_iter_t	*iter;
14816	int		r;
14817
14818	safe_printf(gettext("Delete service %s as there are no "
14819	    "supporting manifests\n"), svnbuf);
14820
14821	instance = scf_instance_create(g_hndl);
14822	iter = scf_iter_create(g_hndl);
14823	if (iter == NULL || instance == NULL) {
14824		uu_warn(gettext("Unable to create supporting entities to "
14825		    "teardown the service\n"));
14826		uu_warn(gettext("scf error is : %s\n"),
14827		    scf_strerror(scf_error()));
14828		scfdie();
14829	}
14830
14831	if (scf_iter_service_instances(iter, svc) != 0) {
14832		switch (scf_error()) {
14833		case SCF_ERROR_CONNECTION_BROKEN:
14834		case SCF_ERROR_DELETED:
14835			goto out;
14836
14837		case SCF_ERROR_HANDLE_MISMATCH:
14838		case SCF_ERROR_NOT_BOUND:
14839		case SCF_ERROR_NOT_SET:
14840		default:
14841			bad_error("scf_iter_service_instances",
14842			    scf_error());
14843		}
14844	}
14845
14846	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
14847		if (r == -1) {
14848			uu_warn(gettext("Error - %s\n"),
14849			    scf_strerror(scf_error()));
14850			goto out;
14851		}
14852
14853		(void) disable_instance(instance);
14854	}
14855
14856	/*
14857	 * Delete the service... forcing the deletion in case
14858	 * any of the instances did not disable.
14859	 */
14860	(void) lscf_service_delete(svc, 1);
14861out:
14862	scf_instance_destroy(instance);
14863	scf_iter_destroy(iter);
14864}
14865
14866/*
14867 * Get the list of instances supported by the manifest
14868 * file.
14869 *
14870 * Return 0 if there are no instances.
14871 *
14872 * Return -1 if there are errors attempting to collect instances.
14873 *
14874 * Return the count of instances found if there are no errors.
14875 *
14876 */
14877static int
14878check_instance_support(char *mfstfile, const char *svcname,
14879    uu_list_t *instances)
14880{
14881	uu_list_walk_t	*svcs, *insts;
14882	uu_list_t	*ilist;
14883	bundle_t	*b;
14884	entity_t	*mfsvc, *mfinst;
14885	const char	*svcn;
14886	int		rminstcnt = 0;
14887
14888
14889	b = internal_bundle_new();
14890
14891	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
14892		/*
14893		 * Unable to process the manifest file for
14894		 * instance support, so just return as
14895		 * don't want to remove instances that could
14896		 * not be accounted for that might exist here.
14897		 */
14898		internal_bundle_free(b);
14899		return (0);
14900	}
14901
14902	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
14903	if (svcs == NULL) {
14904		internal_bundle_free(b);
14905		return (0);
14906	}
14907
14908	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
14909	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
14910
14911	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
14912		if (strcmp(mfsvc->sc_name, svcn) == 0)
14913			break;
14914	}
14915	uu_list_walk_end(svcs);
14916
14917	if (mfsvc == NULL) {
14918		internal_bundle_free(b);
14919		return (-1);
14920	}
14921
14922	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
14923	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
14924		internal_bundle_free(b);
14925		return (0);
14926	}
14927
14928	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
14929		/*
14930		 * Remove the instance from the instances list.
14931		 * The unaccounted for instances will be removed
14932		 * from the service once all manifests are
14933		 * processed.
14934		 */
14935		(void) remove_string(instances,
14936		    mfinst->sc_name);
14937		rminstcnt++;
14938	}
14939
14940	uu_list_walk_end(insts);
14941	internal_bundle_free(b);
14942
14943	return (rminstcnt);
14944}
14945
14946/*
14947 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
14948 * 'false' to indicate there's no manifest file(s) found for the service.
14949 */
14950static void
14951svc_add_no_support(scf_service_t *svc)
14952{
14953	char	*pname;
14954
14955	/* Add no support */
14956	cur_svc = svc;
14957	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
14958		return;
14959
14960	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
14961	if (pname == NULL)
14962		uu_die(gettext("Out of memory.\n"));
14963
14964	(void) lscf_addpropvalue(pname, "boolean:", "0");
14965
14966	uu_free(pname);
14967	cur_svc = NULL;
14968}
14969
14970/*
14971 * This function handles all upgrade scenarios for a service that doesn't have
14972 * SCF_PG_MANIFESTFILES pg. The function creates and populates
14973 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
14974 * manifest(s) mapping. Manifests under supported directories are inventoried
14975 * and a property is added for each file that delivers configuration to the
14976 * service.  A service that has no corresponding manifest files (deleted) are
14977 * removed from repository.
14978 *
14979 * Unsupported services:
14980 *
14981 * A service is considered unsupported if there is no corresponding manifest
14982 * in the supported directories for that service and the service isn't in the
14983 * history file list.  The history file, MFSTHISTFILE, contains a list of all
14984 * services and instances that were delivered by Solaris before the introduction
14985 * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
14986 * the path to the manifest file that defined the service or instance.
14987 *
14988 * Another type of unsupported services is 'handcrafted' services,
14989 * programmatically created services or services created by dependent entries
14990 * in other manifests. A handcrafted service is identified by its lack of any
14991 * instance containing last-import snapshot which is created during svccfg
14992 * import.
14993 *
14994 * This function sets a flag for unsupported services by setting services'
14995 * SCF_PG_MANIFESTFILES/support property to false.
14996 */
14997static void
14998upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
14999{
15000	service_manifest_t	*elem;
15001	uu_list_walk_t		*mfwalk;
15002	string_list_t		*mfile;
15003	uu_list_t		*instances;
15004	const char		*sname;
15005	char			*pname;
15006	int			r;
15007
15008	/*
15009	 * Since there's no guarantee manifests under /var are available during
15010	 * early import, don't perform any upgrade during early import.
15011	 */
15012	if (IGNORE_VAR)
15013		return;
15014
15015	if (service_manifest_tree == NULL) {
15016		create_manifest_tree();
15017	}
15018
15019	/*
15020	 * Find service's supporting manifest(s) after
15021	 * stripping off the svc:/ prefix that is part
15022	 * of the fmri that is not used in the service
15023	 * manifest bundle list.
15024	 */
15025	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
15026	    strlen(SCF_FMRI_SERVICE_PREFIX);
15027	elem = find_add_svc_mfst(sname, NULL);
15028	if (elem == NULL) {
15029
15030		/*
15031		 * A handcrafted service, one that has no instance containing
15032		 * last-import snapshot, should get unsupported flag.
15033		 */
15034		instances = create_instance_list(svc, 1);
15035		if (instances == NULL) {
15036			uu_warn(gettext("Unable to create instance list %s\n"),
15037			    svcname);
15038			return;
15039		}
15040
15041		if (uu_list_numnodes(instances) == 0) {
15042			svc_add_no_support(svc);
15043			return;
15044		}
15045
15046		/*
15047		 * If the service is in the history file, and its supporting
15048		 * manifests are not found, we can safely delete the service
15049		 * because its manifests are removed from the system.
15050		 *
15051		 * Services not found in the history file are not delivered by
15052		 * Solaris and/or delivered outside supported directories, set
15053		 * unsupported flag for these services.
15054		 */
15055		r = check_mfst_history(svcname);
15056		if (r == -1)
15057			return;
15058
15059		if (r) {
15060			/* Set unsupported flag for service  */
15061			svc_add_no_support(svc);
15062		} else {
15063			/* Delete the service */
15064			teardown_service(svc, svcname);
15065		}
15066
15067		return;
15068	}
15069
15070	/*
15071	 * Walk through the list of manifests and add them
15072	 * to the service.
15073	 *
15074	 * Create a manifestfiles pg and add the property.
15075	 */
15076	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
15077	if (mfwalk == NULL)
15078		return;
15079
15080	cur_svc = svc;
15081	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
15082	if (r != 0) {
15083		cur_svc = NULL;
15084		return;
15085	}
15086
15087	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
15088		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
15089		    mhash_filename_to_propname(mfile->str, 0));
15090		if (pname == NULL)
15091			uu_die(gettext("Out of memory.\n"));
15092
15093		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
15094		uu_free(pname);
15095	}
15096	uu_list_walk_end(mfwalk);
15097
15098	cur_svc = NULL;
15099}
15100
15101/*
15102 * Take a service and process the manifest file entires to see if
15103 * there is continued support for the service and instances.  If
15104 * not cleanup as appropriate.
15105 *
15106 * If a service does not have a manifest files entry flag it for
15107 * upgrade and return.
15108 *
15109 * For each manifestfiles property check if the manifest file is
15110 * under the supported /lib/svc/manifest or /var/svc/manifest path
15111 * and if not then return immediately as this service is not supported
15112 * by the cleanup mechanism and should be ignored.
15113 *
15114 * For each manifest file that is supported, check to see if the
15115 * file exists.  If not then remove the manifest file property
15116 * from the service and the smf/manifest hash table.  If the manifest
15117 * file exists then verify that it supports the instances that are
15118 * part of the service.
15119 *
15120 * Once all manifest files have been accounted for remove any instances
15121 * that are no longer supported in the service.
15122 *
15123 * Return values :
15124 * 0 - Successfully processed the service
15125 * non-zero - failed to process the service
15126 *
15127 * On most errors, will just return to wait and get the next service,
15128 * unless in case of unable to create the needed structures which is
15129 * most likely a fatal error that is not going to be recoverable.
15130 */
15131int
15132lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
15133{
15134	struct mpg_mfile	*mpntov;
15135	struct mpg_mfile	**mpvarry = NULL;
15136	scf_service_t		*svc;
15137	scf_propertygroup_t	*mpg;
15138	scf_property_t		*mp;
15139	scf_value_t		*mv;
15140	scf_iter_t		*mi;
15141	scf_instance_t		*instance;
15142	uu_list_walk_t		*insts;
15143	uu_list_t		*instances = NULL;
15144	boolean_t		activity = (boolean_t)act;
15145	char			*mpnbuf;
15146	char			*mpvbuf;
15147	char			*pgpropbuf;
15148	int			mfstcnt, rminstct, instct, mfstmax;
15149	int			index;
15150	int			r = 0;
15151
15152	assert(g_hndl != NULL);
15153	assert(wip->svc != NULL);
15154	assert(wip->fmri != NULL);
15155
15156	svc = wip->svc;
15157
15158	mpg = scf_pg_create(g_hndl);
15159	mp = scf_property_create(g_hndl);
15160	mi = scf_iter_create(g_hndl);
15161	mv = scf_value_create(g_hndl);
15162	instance = scf_instance_create(g_hndl);
15163
15164	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
15165	    instance == NULL) {
15166		uu_warn(gettext("Unable to create the supporting entities\n"));
15167		uu_warn(gettext("scf error is : %s\n"),
15168		    scf_strerror(scf_error()));
15169		scfdie();
15170	}
15171
15172	/*
15173	 * Get the manifestfiles property group to be parsed for
15174	 * files existence.
15175	 */
15176	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
15177		switch (scf_error()) {
15178		case SCF_ERROR_NOT_FOUND:
15179			upgrade_svc_mfst_connection(svc, wip->fmri);
15180			break;
15181		case SCF_ERROR_DELETED:
15182		case SCF_ERROR_CONNECTION_BROKEN:
15183			goto out;
15184
15185		case SCF_ERROR_HANDLE_MISMATCH:
15186		case SCF_ERROR_NOT_BOUND:
15187		case SCF_ERROR_NOT_SET:
15188		default:
15189			bad_error("scf_iter_pg_properties",
15190			    scf_error());
15191		}
15192
15193		goto out;
15194	}
15195
15196	/*
15197	 * Iterate through each of the manifestfiles properties
15198	 * to determine what manifestfiles are available.
15199	 *
15200	 * If a manifest file is supported then increment the
15201	 * count and therefore the service is safe.
15202	 */
15203	if (scf_iter_pg_properties(mi, mpg) != 0) {
15204		switch (scf_error()) {
15205		case SCF_ERROR_DELETED:
15206		case SCF_ERROR_CONNECTION_BROKEN:
15207			goto out;
15208
15209		case SCF_ERROR_HANDLE_MISMATCH:
15210		case SCF_ERROR_NOT_BOUND:
15211		case SCF_ERROR_NOT_SET:
15212		default:
15213			bad_error("scf_iter_pg_properties",
15214			    scf_error());
15215		}
15216	}
15217
15218	mfstcnt = 0;
15219	mfstmax = MFSTFILE_MAX;
15220	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
15221	while ((r = scf_iter_next_property(mi, mp)) != 0) {
15222		if (r == -1)
15223			bad_error(gettext("Unable to iterate through "
15224			    "manifestfiles properties : %s"),
15225			    scf_error());
15226
15227		mpntov = safe_malloc(sizeof (struct mpg_mfile));
15228		mpnbuf = safe_malloc(max_scf_name_len + 1);
15229		mpvbuf = safe_malloc(max_scf_value_len + 1);
15230		mpntov->mpg = mpnbuf;
15231		mpntov->mfile = mpvbuf;
15232		mpntov->access = 1;
15233		if (scf_property_get_name(mp, mpnbuf,
15234		    max_scf_name_len + 1) < 0) {
15235			uu_warn(gettext("Unable to get manifest file "
15236			    "property : %s\n"),
15237			    scf_strerror(scf_error()));
15238
15239			switch (scf_error()) {
15240			case SCF_ERROR_DELETED:
15241			case SCF_ERROR_CONNECTION_BROKEN:
15242				r = scferror2errno(scf_error());
15243				goto out_free;
15244
15245			case SCF_ERROR_HANDLE_MISMATCH:
15246			case SCF_ERROR_NOT_BOUND:
15247			case SCF_ERROR_NOT_SET:
15248			default:
15249				bad_error("scf_iter_pg_properties",
15250				    scf_error());
15251			}
15252		}
15253
15254		/*
15255		 * The support property is a boolean value that indicates
15256		 * if the service is supported for manifest file deletion.
15257		 * Currently at this time there is no code that sets this
15258		 * value to true.  So while we could just let this be caught
15259		 * by the support check below, in the future this by be set
15260		 * to true and require processing.  So for that, go ahead
15261		 * and check here, and just return if false.  Otherwise,
15262		 * fall through expecting that other support checks will
15263		 * handle the entries.
15264		 */
15265		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
15266			uint8_t	support;
15267
15268			if (scf_property_get_value(mp, mv) != 0 ||
15269			    scf_value_get_boolean(mv, &support) != 0) {
15270				uu_warn(gettext("Unable to get the manifest "
15271				    "support value: %s\n"),
15272				    scf_strerror(scf_error()));
15273
15274				switch (scf_error()) {
15275				case SCF_ERROR_DELETED:
15276				case SCF_ERROR_CONNECTION_BROKEN:
15277					r = scferror2errno(scf_error());
15278					goto out_free;
15279
15280				case SCF_ERROR_HANDLE_MISMATCH:
15281				case SCF_ERROR_NOT_BOUND:
15282				case SCF_ERROR_NOT_SET:
15283				default:
15284					bad_error("scf_iter_pg_properties",
15285					    scf_error());
15286				}
15287			}
15288
15289			if (support == B_FALSE)
15290				goto out_free;
15291		}
15292
15293		/*
15294		 * Anything with a manifest outside of the supported
15295		 * directories, immediately bail out because that makes
15296		 * this service non-supported.  We don't even want
15297		 * to do instance processing in this case because the
15298		 * instances could be part of the non-supported manifest.
15299		 */
15300		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
15301			/*
15302			 * Manifest is not in /lib/svc, so we need to
15303			 * consider the /var/svc case.
15304			 */
15305			if (strncmp(mpnbuf, VARSVC_PR,
15306			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
15307				/*
15308				 * Either the manifest is not in /var/svc or
15309				 * /var is not yet mounted.  We ignore the
15310				 * manifest either because it is not in a
15311				 * standard location or because we cannot
15312				 * currently access the manifest.
15313				 */
15314				goto out_free;
15315			}
15316		}
15317
15318		/*
15319		 * Get the value to of the manifest file for this entry
15320		 * for access verification and instance support
15321		 * verification if it still exists.
15322		 *
15323		 * During Early Manifest Import if the manifest is in
15324		 * /var/svc then it may not yet be available for checking
15325		 * so we must determine if /var/svc is available.  If not
15326		 * then defer until Late Manifest Import to cleanup.
15327		 */
15328		if (scf_property_get_value(mp, mv) != 0) {
15329			uu_warn(gettext("Unable to get the manifest file "
15330			    "value: %s\n"),
15331			    scf_strerror(scf_error()));
15332
15333			switch (scf_error()) {
15334			case SCF_ERROR_DELETED:
15335			case SCF_ERROR_CONNECTION_BROKEN:
15336				r = scferror2errno(scf_error());
15337				goto out_free;
15338
15339			case SCF_ERROR_HANDLE_MISMATCH:
15340			case SCF_ERROR_NOT_BOUND:
15341			case SCF_ERROR_NOT_SET:
15342			default:
15343				bad_error("scf_property_get_value",
15344				    scf_error());
15345			}
15346		}
15347
15348		if (scf_value_get_astring(mv, mpvbuf,
15349		    max_scf_value_len + 1) < 0) {
15350			uu_warn(gettext("Unable to get the manifest "
15351			    "file : %s\n"),
15352			    scf_strerror(scf_error()));
15353
15354			switch (scf_error()) {
15355			case SCF_ERROR_DELETED:
15356			case SCF_ERROR_CONNECTION_BROKEN:
15357				r = scferror2errno(scf_error());
15358				goto out_free;
15359
15360			case SCF_ERROR_HANDLE_MISMATCH:
15361			case SCF_ERROR_NOT_BOUND:
15362			case SCF_ERROR_NOT_SET:
15363			default:
15364				bad_error("scf_value_get_astring",
15365				    scf_error());
15366			}
15367		}
15368
15369		mpvarry[mfstcnt] = mpntov;
15370		mfstcnt++;
15371
15372		/*
15373		 * Check for the need to reallocate array
15374		 */
15375		if (mfstcnt >= (mfstmax - 1)) {
15376			struct mpg_mfile **newmpvarry;
15377
15378			mfstmax = mfstmax * 2;
15379			newmpvarry = realloc(mpvarry,
15380			    sizeof (struct mpg_mfile *) * mfstmax);
15381
15382			if (newmpvarry == NULL)
15383				goto out_free;
15384
15385			mpvarry = newmpvarry;
15386		}
15387
15388		mpvarry[mfstcnt] = NULL;
15389	}
15390
15391	for (index = 0; mpvarry[index]; index++) {
15392		mpntov = mpvarry[index];
15393
15394		/*
15395		 * Check to see if the manifestfile is accessable, if so hand
15396		 * this service and manifestfile off to be processed for
15397		 * instance support.
15398		 */
15399		mpnbuf = mpntov->mpg;
15400		mpvbuf = mpntov->mfile;
15401		if (access(mpvbuf, F_OK) != 0) {
15402			mpntov->access = 0;
15403			activity++;
15404			mfstcnt--;
15405			/* Remove the entry from the service */
15406			cur_svc = svc;
15407			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
15408			    mpnbuf);
15409			if (pgpropbuf == NULL)
15410				uu_die(gettext("Out of memory.\n"));
15411
15412			lscf_delprop(pgpropbuf);
15413			cur_svc = NULL;
15414
15415			uu_free(pgpropbuf);
15416		}
15417	}
15418
15419	/*
15420	 * If mfstcnt is 0, none of the manifests that supported the service
15421	 * existed so remove the service.
15422	 */
15423	if (mfstcnt == 0) {
15424		teardown_service(svc, wip->fmri);
15425
15426		goto out_free;
15427	}
15428
15429	if (activity) {
15430		int	nosvcsupport = 0;
15431
15432		/*
15433		 * If the list of service instances is NULL then
15434		 * create the list.
15435		 */
15436		instances = create_instance_list(svc, 1);
15437		if (instances == NULL) {
15438			uu_warn(gettext("Unable to create instance list %s\n"),
15439			    wip->fmri);
15440			goto out_free;
15441		}
15442
15443		rminstct = uu_list_numnodes(instances);
15444		instct = rminstct;
15445
15446		for (index = 0; mpvarry[index]; index++) {
15447			mpntov = mpvarry[index];
15448			if (mpntov->access == 0)
15449				continue;
15450
15451			mpnbuf = mpntov->mpg;
15452			mpvbuf = mpntov->mfile;
15453			r = check_instance_support(mpvbuf, wip->fmri,
15454			    instances);
15455			if (r == -1) {
15456				nosvcsupport++;
15457			} else {
15458				rminstct -= r;
15459			}
15460		}
15461
15462		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
15463			teardown_service(svc, wip->fmri);
15464
15465			goto out_free;
15466		}
15467	}
15468
15469	/*
15470	 * If there are instances left on the instance list, then
15471	 * we must remove them.
15472	 */
15473	if (instances != NULL && uu_list_numnodes(instances)) {
15474		string_list_t *sp;
15475
15476		insts = uu_list_walk_start(instances, 0);
15477		while ((sp = uu_list_walk_next(insts)) != NULL) {
15478			/*
15479			 * Remove the instance from the instances list.
15480			 */
15481			safe_printf(gettext("Delete instance %s from "
15482			    "service %s\n"), sp->str, wip->fmri);
15483			if (scf_service_get_instance(svc, sp->str,
15484			    instance) != SCF_SUCCESS) {
15485				(void) uu_warn("scf_error - %s\n",
15486				    scf_strerror(scf_error()));
15487
15488				continue;
15489			}
15490
15491			(void) disable_instance(instance);
15492
15493			(void) lscf_instance_delete(instance, 1);
15494		}
15495		scf_instance_destroy(instance);
15496		uu_list_walk_end(insts);
15497	}
15498
15499out_free:
15500	if (mpvarry) {
15501		struct mpg_mfile *fmpntov;
15502
15503		for (index = 0; mpvarry[index]; index++) {
15504			fmpntov  = mpvarry[index];
15505			if (fmpntov->mpg == mpnbuf)
15506				mpnbuf = NULL;
15507			free(fmpntov->mpg);
15508
15509			if (fmpntov->mfile == mpvbuf)
15510				mpvbuf = NULL;
15511			free(fmpntov->mfile);
15512
15513			if (fmpntov == mpntov)
15514				mpntov = NULL;
15515			free(fmpntov);
15516		}
15517		if (mpnbuf)
15518			free(mpnbuf);
15519		if (mpvbuf)
15520			free(mpvbuf);
15521		if (mpntov)
15522			free(mpntov);
15523
15524		free(mpvarry);
15525	}
15526out:
15527	scf_pg_destroy(mpg);
15528	scf_property_destroy(mp);
15529	scf_iter_destroy(mi);
15530	scf_value_destroy(mv);
15531
15532	return (0);
15533}
15534
15535/*
15536 * Take the service and search for the manifestfiles property
15537 * in each of the property groups.  If the manifest file
15538 * associated with the property does not exist then remove
15539 * the property group.
15540 */
15541int
15542lscf_hash_cleanup()
15543{
15544	scf_service_t		*svc;
15545	scf_scope_t		*scope;
15546	scf_propertygroup_t	*pg;
15547	scf_property_t		*prop;
15548	scf_value_t		*val;
15549	scf_iter_t		*iter;
15550	char			*pgname;
15551	char			*mfile;
15552	int			r;
15553
15554	svc = scf_service_create(g_hndl);
15555	scope = scf_scope_create(g_hndl);
15556	pg = scf_pg_create(g_hndl);
15557	prop = scf_property_create(g_hndl);
15558	val = scf_value_create(g_hndl);
15559	iter = scf_iter_create(g_hndl);
15560	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
15561	    svc == NULL || scope == NULL) {
15562		uu_warn(gettext("Unable to create a property group, or "
15563		    "property\n"));
15564		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
15565		    "pg is not NULL");
15566		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
15567		    "prop is not NULL");
15568		uu_warn("%s\n", val == NULL ? "val is NULL" :
15569		    "val is not NULL");
15570		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
15571		    "iter is not NULL");
15572		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
15573		    "svc is not NULL");
15574		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
15575		    "scope is not NULL");
15576		uu_warn(gettext("scf error is : %s\n"),
15577		    scf_strerror(scf_error()));
15578		scfdie();
15579	}
15580
15581	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
15582		switch (scf_error()) {
15583		case SCF_ERROR_CONNECTION_BROKEN:
15584		case SCF_ERROR_NOT_FOUND:
15585			goto out;
15586
15587		case SCF_ERROR_HANDLE_MISMATCH:
15588		case SCF_ERROR_NOT_BOUND:
15589		case SCF_ERROR_INVALID_ARGUMENT:
15590		default:
15591			bad_error("scf_handle_get_scope", scf_error());
15592		}
15593	}
15594
15595	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
15596		uu_warn(gettext("Unable to process the hash service, %s\n"),
15597		    HASH_SVC);
15598		goto out;
15599	}
15600
15601	pgname = safe_malloc(max_scf_name_len + 1);
15602	mfile = safe_malloc(max_scf_value_len + 1);
15603
15604	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
15605		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
15606		    scf_strerror(scf_error()));
15607		goto out;
15608	}
15609
15610	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
15611		if (r == -1)
15612			goto out;
15613
15614		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
15615			switch (scf_error()) {
15616			case SCF_ERROR_DELETED:
15617				return (ENODEV);
15618
15619			case SCF_ERROR_CONNECTION_BROKEN:
15620				return (ECONNABORTED);
15621
15622			case SCF_ERROR_NOT_SET:
15623			case SCF_ERROR_NOT_BOUND:
15624			default:
15625				bad_error("scf_pg_get_name", scf_error());
15626			}
15627		}
15628		if (IGNORE_VAR) {
15629			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
15630				continue;
15631		}
15632
15633		/*
15634		 * If unable to get the property continue as this is an
15635		 * entry that has no location to check against.
15636		 */
15637		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
15638			continue;
15639		}
15640
15641		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
15642			uu_warn(gettext("Unable to get value from %s\n"),
15643			    pgname);
15644			goto error_handle;
15645		}
15646
15647		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) ==
15648		    -1) {
15649			uu_warn(gettext("Unable to get astring from %s : %s\n"),
15650			    pgname, scf_strerror(scf_error()));
15651			goto error_handle;
15652		}
15653
15654		if (access(mfile, F_OK) == 0)
15655			continue;
15656
15657		(void) scf_pg_delete(pg);
15658
15659error_handle:
15660		switch (scf_error()) {
15661		case SCF_ERROR_DELETED:
15662		case SCF_ERROR_CONSTRAINT_VIOLATED:
15663		case SCF_ERROR_NOT_FOUND:
15664		case SCF_ERROR_NOT_SET:
15665			continue;
15666
15667		case SCF_ERROR_CONNECTION_BROKEN:
15668			r = scferror2errno(scf_error());
15669			goto out;
15670
15671		case SCF_ERROR_HANDLE_MISMATCH:
15672		case SCF_ERROR_NOT_BOUND:
15673		default:
15674			bad_error("scf_value_get_astring",
15675			    scf_error());
15676		}
15677	}
15678
15679out:
15680	scf_scope_destroy(scope);
15681	scf_service_destroy(svc);
15682	scf_pg_destroy(pg);
15683	scf_property_destroy(prop);
15684	scf_value_destroy(val);
15685	scf_iter_destroy(iter);
15686	free(pgname);
15687	free(mfile);
15688
15689	return (0);
15690}
15691
15692#ifndef NATIVE_BUILD
15693/* ARGSUSED */
15694CPL_MATCH_FN(complete_select)
15695{
15696	const char *arg0, *arg1, *arg1end;
15697	int word_start, err = 0, r;
15698	size_t len;
15699	char *buf;
15700
15701	lscf_prep_hndl();
15702
15703	arg0 = line + strspn(line, " \t");
15704	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
15705
15706	arg1 = arg0 + sizeof ("select") - 1;
15707	arg1 += strspn(arg1, " \t");
15708	word_start = arg1 - line;
15709
15710	arg1end = arg1 + strcspn(arg1, " \t");
15711	if (arg1end < line + word_end)
15712		return (0);
15713
15714	len = line + word_end - arg1;
15715
15716	buf = safe_malloc(max_scf_name_len + 1);
15717
15718	if (cur_snap != NULL) {
15719		return (0);
15720	} else if (cur_inst != NULL) {
15721		return (0);
15722	} else if (cur_svc != NULL) {
15723		scf_instance_t *inst;
15724		scf_iter_t *iter;
15725
15726		if ((inst = scf_instance_create(g_hndl)) == NULL ||
15727		    (iter = scf_iter_create(g_hndl)) == NULL)
15728			scfdie();
15729
15730		if (scf_iter_service_instances(iter, cur_svc) != 0)
15731			scfdie();
15732
15733		for (;;) {
15734			r = scf_iter_next_instance(iter, inst);
15735			if (r == 0)
15736				break;
15737			if (r != 1)
15738				scfdie();
15739
15740			if (scf_instance_get_name(inst, buf,
15741			    max_scf_name_len + 1) < 0)
15742				scfdie();
15743
15744			if (strncmp(buf, arg1, len) == 0) {
15745				err = cpl_add_completion(cpl, line, word_start,
15746				    word_end, buf + len, "", " ");
15747				if (err != 0)
15748					break;
15749			}
15750		}
15751
15752		scf_iter_destroy(iter);
15753		scf_instance_destroy(inst);
15754
15755		return (err);
15756	} else {
15757		scf_service_t *svc;
15758		scf_iter_t *iter;
15759
15760		assert(cur_scope != NULL);
15761
15762		if ((svc = scf_service_create(g_hndl)) == NULL ||
15763		    (iter = scf_iter_create(g_hndl)) == NULL)
15764			scfdie();
15765
15766		if (scf_iter_scope_services(iter, cur_scope) != 0)
15767			scfdie();
15768
15769		for (;;) {
15770			r = scf_iter_next_service(iter, svc);
15771			if (r == 0)
15772				break;
15773			if (r != 1)
15774				scfdie();
15775
15776			if (scf_service_get_name(svc, buf,
15777			    max_scf_name_len + 1) < 0)
15778				scfdie();
15779
15780			if (strncmp(buf, arg1, len) == 0) {
15781				err = cpl_add_completion(cpl, line, word_start,
15782				    word_end, buf + len, "", " ");
15783				if (err != 0)
15784					break;
15785			}
15786		}
15787
15788		scf_iter_destroy(iter);
15789		scf_service_destroy(svc);
15790
15791		return (err);
15792	}
15793}
15794
15795/* ARGSUSED */
15796CPL_MATCH_FN(complete_command)
15797{
15798	uint32_t scope = 0;
15799
15800	if (cur_snap != NULL)
15801		scope = CS_SNAP;
15802	else if (cur_inst != NULL)
15803		scope = CS_INST;
15804	else if (cur_svc != NULL)
15805		scope = CS_SVC;
15806	else
15807		scope = CS_SCOPE;
15808
15809	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
15810}
15811#endif	/* NATIVE_BUILD */
15812