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