10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*407Sjwadams  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * This is the main implementation file for the low-level repository
310Sstevel@tonic-gate  * interface.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include "lowlevel_impl.h"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include "repcache_protocol.h"
370Sstevel@tonic-gate #include "scf_type.h"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include <assert.h>
400Sstevel@tonic-gate #include <alloca.h>
410Sstevel@tonic-gate #include <door.h>
420Sstevel@tonic-gate #include <errno.h>
430Sstevel@tonic-gate #include <fcntl.h>
440Sstevel@tonic-gate #include <fnmatch.h>
450Sstevel@tonic-gate #include <libuutil.h>
460Sstevel@tonic-gate #include <poll.h>
470Sstevel@tonic-gate #include <pthread.h>
480Sstevel@tonic-gate #include <stddef.h>
490Sstevel@tonic-gate #include <stdio.h>
500Sstevel@tonic-gate #include <stdlib.h>
510Sstevel@tonic-gate #include <string.h>
520Sstevel@tonic-gate #include <sys/mman.h>
530Sstevel@tonic-gate #include <sys/sysmacros.h>
540Sstevel@tonic-gate #include <unistd.h>
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #define	ENV_SCF_DEBUG		"LIBSCF_DEBUG"
570Sstevel@tonic-gate #define	ENV_SCF_DOORPATH	"LIBSCF_DOORPATH"
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static uint32_t default_debug = 0;
600Sstevel@tonic-gate static const char *default_door_path = REPOSITORY_DOOR_NAME;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #define	CALL_FAILED		-1
630Sstevel@tonic-gate #define	RESULT_TOO_BIG		-2
640Sstevel@tonic-gate #define	NOT_BOUND		-3
650Sstevel@tonic-gate 
660Sstevel@tonic-gate static pthread_mutex_t	lowlevel_init_lock;
670Sstevel@tonic-gate static int32_t		lowlevel_inited;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static uu_list_pool_t	*tran_entry_pool;
700Sstevel@tonic-gate static uu_list_pool_t	*datael_pool;
710Sstevel@tonic-gate static uu_list_pool_t	*iter_pool;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * We want MUTEX_HELD, but we also want pthreads.
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate struct _lwp_mutex;
770Sstevel@tonic-gate extern int _mutex_held(struct _lwp_mutex *);
780Sstevel@tonic-gate #define	MUTEX_HELD(m)		_mutex_held((struct _lwp_mutex *)(m))
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * no cancellation, please
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate struct _lwp_cond;
840Sstevel@tonic-gate extern int _cond_wait(struct _lwp_cond *, struct _lwp_mutex *);
850Sstevel@tonic-gate #define	PTHREAD_COND_WAIT(cv, mx) \
860Sstevel@tonic-gate 	    _cond_wait((struct _lwp_cond *)(cv), (struct _lwp_mutex *)(mx))
870Sstevel@tonic-gate 
880Sstevel@tonic-gate #ifdef lint
890Sstevel@tonic-gate #define	assert_nolint(x) (void)0
900Sstevel@tonic-gate #else
910Sstevel@tonic-gate #define	assert_nolint(x) assert(x)
920Sstevel@tonic-gate #endif
930Sstevel@tonic-gate 
940Sstevel@tonic-gate static void scf_iter_reset_locked(scf_iter_t *iter);
950Sstevel@tonic-gate static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define	TYPE_VALUE	(-100)
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * Hold and release subhandles.  We only allow one thread access to the
1010Sstevel@tonic-gate  * subhandles at a time, and he can use any subset, grabbing and releasing
1020Sstevel@tonic-gate  * them in any order.  The only restrictions are that you cannot hold an
1030Sstevel@tonic-gate  * already-held subhandle, and all subhandles must be released before
1040Sstevel@tonic-gate  * returning to the original caller.
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate static void
1070Sstevel@tonic-gate handle_hold_subhandles(scf_handle_t *h, int mask)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1120Sstevel@tonic-gate 	while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self())
1130Sstevel@tonic-gate 		(void) PTHREAD_COND_WAIT(&h->rh_cv, &h->rh_lock);
1140Sstevel@tonic-gate 	if (h->rh_hold_flags == 0)
1150Sstevel@tonic-gate 		h->rh_holder = pthread_self();
1160Sstevel@tonic-gate 	assert(!(h->rh_hold_flags & mask));
1170Sstevel@tonic-gate 	h->rh_hold_flags |= mask;
1180Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate static void
1220Sstevel@tonic-gate handle_rele_subhandles(scf_handle_t *h, int mask)
1230Sstevel@tonic-gate {
1240Sstevel@tonic-gate 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1270Sstevel@tonic-gate 	assert(h->rh_holder == pthread_self());
1280Sstevel@tonic-gate 	assert((h->rh_hold_flags & mask));
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	h->rh_hold_flags &= ~mask;
1310Sstevel@tonic-gate 	if (h->rh_hold_flags == 0)
1320Sstevel@tonic-gate 		(void) pthread_cond_signal(&h->rh_cv);
1330Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate #define	HOLD_HANDLE(h, flag, field) \
1370Sstevel@tonic-gate 	(handle_hold_subhandles((h), (flag)), (h)->field)
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate #define	RELE_HANDLE(h, flag) \
1400Sstevel@tonic-gate 	(handle_rele_subhandles((h), (flag)))
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate /*
1430Sstevel@tonic-gate  * convenience macros, for functions that only need a one or two handles at
1440Sstevel@tonic-gate  * any given time
1450Sstevel@tonic-gate  */
1460Sstevel@tonic-gate #define	HANDLE_HOLD_ITER(h)	HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
1470Sstevel@tonic-gate #define	HANDLE_HOLD_SCOPE(h)	HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
1480Sstevel@tonic-gate #define	HANDLE_HOLD_SERVICE(h)	HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
1490Sstevel@tonic-gate #define	HANDLE_HOLD_INSTANCE(h)	HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
1500Sstevel@tonic-gate #define	HANDLE_HOLD_SNAPSHOT(h)	HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
1510Sstevel@tonic-gate #define	HANDLE_HOLD_SNAPLVL(h)	HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
1520Sstevel@tonic-gate #define	HANDLE_HOLD_PG(h)	HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
1530Sstevel@tonic-gate #define	HANDLE_HOLD_PROPERTY(h)	HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
1540Sstevel@tonic-gate #define	HANDLE_HOLD_VALUE(h)	HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate #define	HANDLE_RELE_ITER(h)	RELE_HANDLE((h), RH_HOLD_ITER)
1570Sstevel@tonic-gate #define	HANDLE_RELE_SCOPE(h)	RELE_HANDLE((h), RH_HOLD_SCOPE)
1580Sstevel@tonic-gate #define	HANDLE_RELE_SERVICE(h)	RELE_HANDLE((h), RH_HOLD_SERVICE)
1590Sstevel@tonic-gate #define	HANDLE_RELE_INSTANCE(h)	RELE_HANDLE((h), RH_HOLD_INSTANCE)
1600Sstevel@tonic-gate #define	HANDLE_RELE_SNAPSHOT(h)	RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
1610Sstevel@tonic-gate #define	HANDLE_RELE_SNAPLVL(h)	RELE_HANDLE((h), RH_HOLD_SNAPLVL)
1620Sstevel@tonic-gate #define	HANDLE_RELE_PG(h)	RELE_HANDLE((h), RH_HOLD_PG)
1630Sstevel@tonic-gate #define	HANDLE_RELE_PROPERTY(h)	RELE_HANDLE((h), RH_HOLD_PROPERTY)
1640Sstevel@tonic-gate #define	HANDLE_RELE_VALUE(h)	RELE_HANDLE((h), RH_HOLD_VALUE)
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /*ARGSUSED*/
1670Sstevel@tonic-gate static int
1680Sstevel@tonic-gate transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
1690Sstevel@tonic-gate {
1700Sstevel@tonic-gate 	const char *l_prop =
1710Sstevel@tonic-gate 	    ((scf_transaction_entry_t *)l_arg)->entry_property;
1720Sstevel@tonic-gate 	const char *r_prop =
1730Sstevel@tonic-gate 	    ((scf_transaction_entry_t *)r_arg)->entry_property;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	int ret;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	ret = strcmp(l_prop, r_prop);
1780Sstevel@tonic-gate 	if (ret > 0)
1790Sstevel@tonic-gate 		return (1);
180*407Sjwadams 	if (ret < 0)
181*407Sjwadams 		return (-1);
182*407Sjwadams 	return (0);
183*407Sjwadams }
184*407Sjwadams 
185*407Sjwadams static int
186*407Sjwadams datael_compare(const void *l_arg, const void *r_arg, void *private)
187*407Sjwadams {
188*407Sjwadams 	uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
189*407Sjwadams 	uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
190*407Sjwadams 	    *(uint32_t *)private;
191*407Sjwadams 
192*407Sjwadams 	if (l_id > r_id)
193*407Sjwadams 		return (1);
194*407Sjwadams 	if (l_id < r_id)
195*407Sjwadams 		return (-1);
196*407Sjwadams 	return (0);
197*407Sjwadams }
198*407Sjwadams 
199*407Sjwadams static int
200*407Sjwadams iter_compare(const void *l_arg, const void *r_arg, void *private)
201*407Sjwadams {
202*407Sjwadams 	uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
203*407Sjwadams 	uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
204*407Sjwadams 	    *(uint32_t *)private;
205*407Sjwadams 
206*407Sjwadams 	if (l_id > r_id)
207*407Sjwadams 		return (1);
208*407Sjwadams 	if (l_id < r_id)
2090Sstevel@tonic-gate 		return (-1);
2100Sstevel@tonic-gate 	return (0);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate static int
2140Sstevel@tonic-gate lowlevel_init(void)
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate 	const char *debug;
2170Sstevel@tonic-gate 	const char *door_path;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	(void) pthread_mutex_lock(&lowlevel_init_lock);
2200Sstevel@tonic-gate 	if (lowlevel_inited == 0) {
2210Sstevel@tonic-gate 		if (!issetugid() &&
2220Sstevel@tonic-gate 		    (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
2230Sstevel@tonic-gate 		    uu_strtoint(debug, &default_debug, sizeof (default_debug),
2240Sstevel@tonic-gate 		    0, 0, 0) == -1) {
2250Sstevel@tonic-gate 			(void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
2260Sstevel@tonic-gate 			    ENV_SCF_DEBUG, debug,
2270Sstevel@tonic-gate 			    uu_strerror(uu_error()));
2280Sstevel@tonic-gate 		}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 		if (!issetugid() &&
2310Sstevel@tonic-gate 		    (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
2320Sstevel@tonic-gate 		    door_path[0] != 0) {
2330Sstevel@tonic-gate 			default_door_path = strdup(door_path);
2340Sstevel@tonic-gate 			if (default_door_path == NULL)
2350Sstevel@tonic-gate 				default_door_path = door_path;
2360Sstevel@tonic-gate 		}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 		datael_pool = uu_list_pool_create("SUNW,libscf_datael",
2390Sstevel@tonic-gate 		    sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
240*407Sjwadams 		    datael_compare, UU_LIST_POOL_DEBUG);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		iter_pool = uu_list_pool_create("SUNW,libscf_iter",
2430Sstevel@tonic-gate 		    sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
244*407Sjwadams 		    iter_compare, UU_LIST_POOL_DEBUG);
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		assert_nolint(offsetof(scf_transaction_entry_t,
2470Sstevel@tonic-gate 		    entry_property) == 0);
2480Sstevel@tonic-gate 		tran_entry_pool = uu_list_pool_create(
2490Sstevel@tonic-gate 		    "SUNW,libscf_transaction_entity",
2500Sstevel@tonic-gate 		    sizeof (scf_transaction_entry_t),
2510Sstevel@tonic-gate 		    offsetof(scf_transaction_entry_t, entry_link),
2520Sstevel@tonic-gate 		    transaction_entry_compare, UU_LIST_POOL_DEBUG);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		if (datael_pool == NULL || iter_pool == NULL ||
2550Sstevel@tonic-gate 		    tran_entry_pool == NULL) {
2560Sstevel@tonic-gate 			lowlevel_inited = -1;
2570Sstevel@tonic-gate 			goto end;
2580Sstevel@tonic-gate 		}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		if (!scf_setup_error()) {
2610Sstevel@tonic-gate 			lowlevel_inited = -1;
2620Sstevel@tonic-gate 			goto end;
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 		lowlevel_inited = 1;
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate end:
2670Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&lowlevel_init_lock);
2680Sstevel@tonic-gate 	if (lowlevel_inited > 0)
2690Sstevel@tonic-gate 		return (1);
2700Sstevel@tonic-gate 	return (0);
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate static const struct {
2740Sstevel@tonic-gate 	scf_type_t ti_type;
2750Sstevel@tonic-gate 	rep_protocol_value_type_t ti_proto_type;
2760Sstevel@tonic-gate 	const char *ti_name;
2770Sstevel@tonic-gate } scf_type_info[] = {
2780Sstevel@tonic-gate 	{SCF_TYPE_BOOLEAN,	REP_PROTOCOL_TYPE_BOOLEAN,	"boolean"},
2790Sstevel@tonic-gate 	{SCF_TYPE_COUNT,	REP_PROTOCOL_TYPE_COUNT,	"count"},
2800Sstevel@tonic-gate 	{SCF_TYPE_INTEGER,	REP_PROTOCOL_TYPE_INTEGER,	"integer"},
2810Sstevel@tonic-gate 	{SCF_TYPE_TIME,		REP_PROTOCOL_TYPE_TIME,		"time"},
2820Sstevel@tonic-gate 	{SCF_TYPE_ASTRING,	REP_PROTOCOL_TYPE_STRING,	"astring"},
2830Sstevel@tonic-gate 	{SCF_TYPE_OPAQUE,	REP_PROTOCOL_TYPE_OPAQUE,	"opaque"},
2840Sstevel@tonic-gate 	{SCF_TYPE_USTRING,	REP_PROTOCOL_SUBTYPE_USTRING,	"ustring"},
2850Sstevel@tonic-gate 	{SCF_TYPE_URI,		REP_PROTOCOL_SUBTYPE_URI,	"uri"},
2860Sstevel@tonic-gate 	{SCF_TYPE_FMRI,		REP_PROTOCOL_SUBTYPE_FMRI,	"fmri"},
2870Sstevel@tonic-gate 	{SCF_TYPE_HOST,		REP_PROTOCOL_SUBTYPE_HOST,	"host"},
2880Sstevel@tonic-gate 	{SCF_TYPE_HOSTNAME,	REP_PROTOCOL_SUBTYPE_HOSTNAME,	"hostname"},
2890Sstevel@tonic-gate 	{SCF_TYPE_NET_ADDR_V4,	REP_PROTOCOL_SUBTYPE_NETADDR_V4,
2900Sstevel@tonic-gate 	    "net_address_v4"},
2910Sstevel@tonic-gate 	{SCF_TYPE_NET_ADDR_V6,	REP_PROTOCOL_SUBTYPE_NETADDR_V6,
2920Sstevel@tonic-gate 	    "net_address_v6"}
2930Sstevel@tonic-gate };
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate #define	SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
2960Sstevel@tonic-gate static rep_protocol_value_type_t
2970Sstevel@tonic-gate scf_type_to_protocol_type(scf_type_t t)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate 	int i;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
3020Sstevel@tonic-gate 		if (scf_type_info[i].ti_type == t)
3030Sstevel@tonic-gate 			return (scf_type_info[i].ti_proto_type);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	return (REP_PROTOCOL_TYPE_INVALID);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate static scf_type_t
3090Sstevel@tonic-gate scf_protocol_type_to_type(rep_protocol_value_type_t t)
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate 	int i;
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
3140Sstevel@tonic-gate 		if (scf_type_info[i].ti_proto_type == t)
3150Sstevel@tonic-gate 			return (scf_type_info[i].ti_type);
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	return (SCF_TYPE_INVALID);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate const char *
3210Sstevel@tonic-gate scf_type_to_string(scf_type_t ty)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate 	int i;
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
3260Sstevel@tonic-gate 		if (scf_type_info[i].ti_type == ty)
3270Sstevel@tonic-gate 			return (scf_type_info[i].ti_name);
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	return ("unknown");
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate scf_type_t
3330Sstevel@tonic-gate scf_string_to_type(const char *name)
3340Sstevel@tonic-gate {
3350Sstevel@tonic-gate 	int i;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
3380Sstevel@tonic-gate 		if (strcmp(scf_type_info[i].ti_name, name) == 0)
3390Sstevel@tonic-gate 			return (scf_type_info[i].ti_type);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	return (SCF_TYPE_INVALID);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate int
3450Sstevel@tonic-gate scf_type_base_type(scf_type_t type, scf_type_t *out)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate 	rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
3480Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_INVALID)
3490Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	*out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
3520Sstevel@tonic-gate 	return (SCF_SUCCESS);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate /*
3560Sstevel@tonic-gate  * Convert a protocol error code into an SCF_ERROR_* code.
3570Sstevel@tonic-gate  */
3580Sstevel@tonic-gate static scf_error_t
3590Sstevel@tonic-gate proto_error(rep_protocol_responseid_t e)
3600Sstevel@tonic-gate {
3610Sstevel@tonic-gate 	switch (e) {
3620Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_MISORDERED:
3630Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_UNKNOWN_ID:
3640Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_INVALID_TYPE:
3650Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_TRUNCATED:
3660Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
3670Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
3680Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_UNKNOWN:
3690Sstevel@tonic-gate 		return (SCF_ERROR_INTERNAL);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BAD_TX:
3720Sstevel@tonic-gate 		return (SCF_ERROR_INVALID_ARGUMENT);
3730Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BAD_REQUEST:
3740Sstevel@tonic-gate 		return (SCF_ERROR_INVALID_ARGUMENT);
3750Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
3760Sstevel@tonic-gate 		return (SCF_ERROR_NO_RESOURCES);
3770Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_FOUND:
3780Sstevel@tonic-gate 		return (SCF_ERROR_NOT_FOUND);
3790Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_DELETED:
3800Sstevel@tonic-gate 		return (SCF_ERROR_DELETED);
3810Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_SET:
3820Sstevel@tonic-gate 		return (SCF_ERROR_NOT_SET);
3830Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_EXISTS:
3840Sstevel@tonic-gate 		return (SCF_ERROR_EXISTS);
3850Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_DUPLICATE_ID:
3860Sstevel@tonic-gate 		return (SCF_ERROR_EXISTS);
3870Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
3880Sstevel@tonic-gate 		return (SCF_ERROR_PERMISSION_DENIED);
3890Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
3900Sstevel@tonic-gate 		return (SCF_ERROR_BACKEND_ACCESS);
3910Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BACKEND_READONLY:
3920Sstevel@tonic-gate 		return (SCF_ERROR_BACKEND_READONLY);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	case REP_PROTOCOL_SUCCESS:
3950Sstevel@tonic-gate 	case REP_PROTOCOL_DONE:
3960Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_LATEST:	/* TX code should handle this */
3970Sstevel@tonic-gate 	default:
3980Sstevel@tonic-gate #ifndef NDEBUG
3990Sstevel@tonic-gate 		uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
4000Sstevel@tonic-gate 		    __FILE__, __LINE__, e);
4010Sstevel@tonic-gate #endif
4020Sstevel@tonic-gate 		abort();
4030Sstevel@tonic-gate 		/*NOTREACHED*/
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate ssize_t
4080Sstevel@tonic-gate scf_limit(uint32_t limit)
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate 	switch (limit) {
4110Sstevel@tonic-gate 	case SCF_LIMIT_MAX_NAME_LENGTH:
4120Sstevel@tonic-gate 	case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
4130Sstevel@tonic-gate 		return (REP_PROTOCOL_NAME_LEN - 1);
4140Sstevel@tonic-gate 	case SCF_LIMIT_MAX_VALUE_LENGTH:
4150Sstevel@tonic-gate 		return (REP_PROTOCOL_VALUE_LEN - 1);
4160Sstevel@tonic-gate 	case SCF_LIMIT_MAX_FMRI_LENGTH:
4170Sstevel@tonic-gate 		return (SCF_FMRI_PREFIX_MAX_LEN +
4180Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
4190Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
4200Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
4210Sstevel@tonic-gate 		    sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
4220Sstevel@tonic-gate 		    sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
4230Sstevel@tonic-gate 		    sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
4240Sstevel@tonic-gate 		    5 * (REP_PROTOCOL_NAME_LEN - 1));
4250Sstevel@tonic-gate 	default:
4260Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate static size_t
4310Sstevel@tonic-gate scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate 	char a, b;
4340Sstevel@tonic-gate 	char *out = out_arg;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
4370Sstevel@tonic-gate 		in += 2;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 		if (a >= '0' && a <= '9')
4400Sstevel@tonic-gate 			a -= '0';
4410Sstevel@tonic-gate 		else if (a >= 'a' && a <= 'f')
4420Sstevel@tonic-gate 			a = a - 'a' + 10;
4430Sstevel@tonic-gate 		else if (a >= 'A' && a <= 'F')
4440Sstevel@tonic-gate 			a = a - 'A' + 10;
4450Sstevel@tonic-gate 		else
4460Sstevel@tonic-gate 			break;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 		if (b >= '0' && b <= '9')
4490Sstevel@tonic-gate 			b -= '0';
4500Sstevel@tonic-gate 		else if (b >= 'a' && b <= 'f')
4510Sstevel@tonic-gate 			b = b - 'a' + 10;
4520Sstevel@tonic-gate 		else if (b >= 'A' && b <= 'F')
4530Sstevel@tonic-gate 			b = b - 'A' + 10;
4540Sstevel@tonic-gate 		else
4550Sstevel@tonic-gate 			break;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 		*out++ = (a << 4) | b;
4580Sstevel@tonic-gate 		max_out--;
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	return (out - out_arg);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate static size_t
4650Sstevel@tonic-gate scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
4660Sstevel@tonic-gate {
4670Sstevel@tonic-gate 	uint8_t *in = (uint8_t *)in_arg;
4680Sstevel@tonic-gate 	uint8_t *end = in + in_sz;
4690Sstevel@tonic-gate 	char *out = out_arg;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	if (out == NULL)
4720Sstevel@tonic-gate 		return (2 * in_sz);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	while (in < end) {
4750Sstevel@tonic-gate 		uint8_t c = *in++;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 		uint8_t a = (c & 0xf0) >> 4;
4780Sstevel@tonic-gate 		uint8_t b = (c & 0x0f);
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 		if (a <= 9)
4810Sstevel@tonic-gate 			*out++ = a + '0';
4820Sstevel@tonic-gate 		else
4830Sstevel@tonic-gate 			*out++ = a + 'a' - 10;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 		if (b <= 9)
4860Sstevel@tonic-gate 			*out++ = b + '0';
4870Sstevel@tonic-gate 		else
4880Sstevel@tonic-gate 			*out++ = b + 'a' - 10;
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	*out = 0;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	return (out - out_arg);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate static void
4970Sstevel@tonic-gate handle_do_close(scf_handle_t *h)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
5000Sstevel@tonic-gate 	assert(h->rh_doorfd != -1);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	/*
5030Sstevel@tonic-gate 	 * if there are any active FD users, we just move the FD over
5040Sstevel@tonic-gate 	 * to rh_doorfd_old -- they'll close it when they finish.
5050Sstevel@tonic-gate 	 */
5060Sstevel@tonic-gate 	if (h->rh_fd_users > 0) {
5070Sstevel@tonic-gate 		h->rh_doorfd_old = h->rh_doorfd;
5080Sstevel@tonic-gate 		h->rh_doorfd = -1;
5090Sstevel@tonic-gate 	} else {
5100Sstevel@tonic-gate 		assert(h->rh_doorfd_old == -1);
5110Sstevel@tonic-gate 		(void) close(h->rh_doorfd);
5120Sstevel@tonic-gate 		h->rh_doorfd = -1;
5130Sstevel@tonic-gate 	}
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate  * Check if a handle is currently bound.  fork()ing implicitly unbinds
5180Sstevel@tonic-gate  * the handle in the child.
5190Sstevel@tonic-gate  */
5200Sstevel@tonic-gate static int
5210Sstevel@tonic-gate handle_is_bound(scf_handle_t *h)
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	if (h->rh_doorfd == -1)
5260Sstevel@tonic-gate 		return (0);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	if (getpid() == h->rh_doorpid)
5290Sstevel@tonic-gate 		return (1);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	/* forked since our last bind -- initiate handle close */
5320Sstevel@tonic-gate 	handle_do_close(h);
5330Sstevel@tonic-gate 	return (0);
5340Sstevel@tonic-gate }
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate static int
537*407Sjwadams handle_has_server_locked(scf_handle_t *h)
5380Sstevel@tonic-gate {
5390Sstevel@tonic-gate 	door_info_t i;
540*407Sjwadams 	assert(MUTEX_HELD(&h->rh_lock));
541*407Sjwadams 
542*407Sjwadams 	return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
543*407Sjwadams 	    i.di_target != -1);
544*407Sjwadams }
545*407Sjwadams 
546*407Sjwadams static int
547*407Sjwadams handle_has_server(scf_handle_t *h)
548*407Sjwadams {
5490Sstevel@tonic-gate 	int ret;
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
552*407Sjwadams 	ret = handle_has_server_locked(h);
5530Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	return (ret);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate /*
5590Sstevel@tonic-gate  * This makes a door request on the client door associated with handle h.
5600Sstevel@tonic-gate  * It will automatically retry calls which fail on EINTR.  If h is not bound,
5610Sstevel@tonic-gate  * returns NOT_BOUND.  If the door call fails or the server response is too
5620Sstevel@tonic-gate  * small, returns CALL_FAILED.  If the server response is too big, truncates the
5630Sstevel@tonic-gate  * response and returns RESULT_TOO_BIG.  Otherwise, the size of the result is
5640Sstevel@tonic-gate  * returned.
5650Sstevel@tonic-gate  */
5660Sstevel@tonic-gate static ssize_t
5670Sstevel@tonic-gate make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
5680Sstevel@tonic-gate     void *res, size_t res_sz)
5690Sstevel@tonic-gate {
5700Sstevel@tonic-gate 	door_arg_t arg;
5710Sstevel@tonic-gate 	int r;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
5760Sstevel@tonic-gate 		return (NOT_BOUND);
5770Sstevel@tonic-gate 	}
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	arg.data_ptr = (void *)req;
5800Sstevel@tonic-gate 	arg.data_size = req_sz;
5810Sstevel@tonic-gate 	arg.desc_ptr = NULL;
5820Sstevel@tonic-gate 	arg.desc_num = 0;
5830Sstevel@tonic-gate 	arg.rbuf = res;
5840Sstevel@tonic-gate 	arg.rsize = res_sz;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
5870Sstevel@tonic-gate 		if (errno != EINTR)
5880Sstevel@tonic-gate 			break;
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	if (r < 0) {
5920Sstevel@tonic-gate 		return (CALL_FAILED);
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	if (arg.desc_num > 0) {
5960Sstevel@tonic-gate 		while (arg.desc_num > 0) {
5970Sstevel@tonic-gate 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
5980Sstevel@tonic-gate 				int cfd = arg.desc_ptr->d_data.d_desc.d_id;
5990Sstevel@tonic-gate 				(void) close(cfd);
6000Sstevel@tonic-gate 			}
6010Sstevel@tonic-gate 			arg.desc_ptr++;
6020Sstevel@tonic-gate 			arg.desc_num--;
6030Sstevel@tonic-gate 		}
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 	if (arg.data_ptr != res && arg.data_size > 0)
6060Sstevel@tonic-gate 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if (arg.rbuf != res)
6090Sstevel@tonic-gate 		(void) munmap(arg.rbuf, arg.rsize);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	if (arg.data_size > res_sz)
6120Sstevel@tonic-gate 		return (RESULT_TOO_BIG);
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	if (arg.data_size < sizeof (uint32_t))
6150Sstevel@tonic-gate 		return (CALL_FAILED);
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	return (arg.data_size);
6180Sstevel@tonic-gate }
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate /*
6210Sstevel@tonic-gate  * Should only be used when r < 0.
6220Sstevel@tonic-gate  */
6230Sstevel@tonic-gate #define	DOOR_ERRORS_BLOCK(r)	{					\
6240Sstevel@tonic-gate 	switch (r) {							\
6250Sstevel@tonic-gate 	case NOT_BOUND:							\
6260Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_BOUND));		\
6270Sstevel@tonic-gate 									\
6280Sstevel@tonic-gate 	case CALL_FAILED:						\
6290Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));	\
6300Sstevel@tonic-gate 									\
6310Sstevel@tonic-gate 	case RESULT_TOO_BIG:						\
6320Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));		\
6330Sstevel@tonic-gate 									\
6340Sstevel@tonic-gate 	default:							\
6350Sstevel@tonic-gate 		assert(r == NOT_BOUND || r == CALL_FAILED ||		\
6360Sstevel@tonic-gate 		    r == RESULT_TOO_BIG);				\
6370Sstevel@tonic-gate 		abort();						\
6380Sstevel@tonic-gate 	}								\
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate /*
6420Sstevel@tonic-gate  * Like make_door_call(), but takes an fd instead of a handle, and expects
6430Sstevel@tonic-gate  * a single file descriptor, returned via res_fd.
6440Sstevel@tonic-gate  *
6450Sstevel@tonic-gate  * If no file descriptor is returned, *res_fd == -1.
6460Sstevel@tonic-gate  */
6470Sstevel@tonic-gate static int
6480Sstevel@tonic-gate make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
6490Sstevel@tonic-gate     size_t res_sz, int *res_fd)
6500Sstevel@tonic-gate {
6510Sstevel@tonic-gate 	door_arg_t arg;
6520Sstevel@tonic-gate 	int r;
6530Sstevel@tonic-gate 	char rbuf[256];
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	*res_fd = -1;
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	if (fd == -1)
6580Sstevel@tonic-gate 		return (NOT_BOUND);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	arg.data_ptr = (void *)req;
6610Sstevel@tonic-gate 	arg.data_size = req_sz;
6620Sstevel@tonic-gate 	arg.desc_ptr = NULL;
6630Sstevel@tonic-gate 	arg.desc_num = 0;
6640Sstevel@tonic-gate 	arg.rbuf = rbuf;
6650Sstevel@tonic-gate 	arg.rsize = sizeof (rbuf);
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	while ((r = door_call(fd, &arg)) < 0) {
6680Sstevel@tonic-gate 		if (errno != EINTR)
6690Sstevel@tonic-gate 			break;
6700Sstevel@tonic-gate 	}
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	if (r < 0)
6730Sstevel@tonic-gate 		return (CALL_FAILED);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (arg.desc_num > 1) {
6760Sstevel@tonic-gate 		while (arg.desc_num > 0) {
6770Sstevel@tonic-gate 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
6780Sstevel@tonic-gate 				int cfd =
6790Sstevel@tonic-gate 				    arg.desc_ptr->d_data.d_desc.d_descriptor;
6800Sstevel@tonic-gate 				(void) close(cfd);
6810Sstevel@tonic-gate 			}
6820Sstevel@tonic-gate 			arg.desc_ptr++;
6830Sstevel@tonic-gate 			arg.desc_num--;
6840Sstevel@tonic-gate 		}
6850Sstevel@tonic-gate 	}
6860Sstevel@tonic-gate 	if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
6870Sstevel@tonic-gate 		*res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (arg.data_size > 0)
6900Sstevel@tonic-gate 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	if (arg.rbuf != rbuf)
6930Sstevel@tonic-gate 		(void) munmap(arg.rbuf, arg.rsize);
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	if (arg.data_size > res_sz)
6960Sstevel@tonic-gate 		return (RESULT_TOO_BIG);
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	if (arg.data_size < sizeof (uint32_t))
6990Sstevel@tonic-gate 		return (CALL_FAILED);
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	return (arg.data_size);
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate /*
7050Sstevel@tonic-gate  * Fails with
7060Sstevel@tonic-gate  *   _VERSION_MISMATCH
7070Sstevel@tonic-gate  *   _NO_MEMORY
7080Sstevel@tonic-gate  */
7090Sstevel@tonic-gate scf_handle_t *
7100Sstevel@tonic-gate scf_handle_create(scf_version_t v)
7110Sstevel@tonic-gate {
7120Sstevel@tonic-gate 	scf_handle_t *ret;
7130Sstevel@tonic-gate 	int failed;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	/*
7160Sstevel@tonic-gate 	 * This will need to be revisited when we bump SCF_VERSION
7170Sstevel@tonic-gate 	 */
7180Sstevel@tonic-gate 	if (v != SCF_VERSION) {
7190Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
7200Sstevel@tonic-gate 		return (NULL);
7210Sstevel@tonic-gate 	}
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if (!lowlevel_init()) {
7240Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7250Sstevel@tonic-gate 		return (NULL);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
7290Sstevel@tonic-gate 	if (ret == NULL) {
7300Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7310Sstevel@tonic-gate 		return (NULL);
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
7350Sstevel@tonic-gate 	ret->rh_iters = uu_list_create(iter_pool, ret, 0);
7360Sstevel@tonic-gate 	if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
7370Sstevel@tonic-gate 		if (ret->rh_dataels != NULL)
7380Sstevel@tonic-gate 			uu_list_destroy(ret->rh_dataels);
7390Sstevel@tonic-gate 		if (ret->rh_iters != NULL)
7400Sstevel@tonic-gate 			uu_list_destroy(ret->rh_iters);
7410Sstevel@tonic-gate 		uu_free(ret);
7420Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7430Sstevel@tonic-gate 		return (NULL);
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	ret->rh_doorfd = -1;
7470Sstevel@tonic-gate 	ret->rh_doorfd_old = -1;
7480Sstevel@tonic-gate 	(void) pthread_mutex_init(&ret->rh_lock, NULL);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	handle_hold_subhandles(ret, RH_HOLD_ALL);
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
7530Sstevel@tonic-gate 	    (ret->rh_scope = scf_scope_create(ret)) == NULL ||
7540Sstevel@tonic-gate 	    (ret->rh_service = scf_service_create(ret)) == NULL ||
7550Sstevel@tonic-gate 	    (ret->rh_instance = scf_instance_create(ret)) == NULL ||
7560Sstevel@tonic-gate 	    (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
7570Sstevel@tonic-gate 	    (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
7580Sstevel@tonic-gate 	    (ret->rh_pg = scf_pg_create(ret)) == NULL ||
7590Sstevel@tonic-gate 	    (ret->rh_property = scf_property_create(ret)) == NULL ||
7600Sstevel@tonic-gate 	    (ret->rh_value = scf_value_create(ret)) == NULL);
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	/*
7630Sstevel@tonic-gate 	 * these subhandles count as internal references, not external ones.
7640Sstevel@tonic-gate 	 */
7650Sstevel@tonic-gate 	ret->rh_intrefs = ret->rh_extrefs;
7660Sstevel@tonic-gate 	ret->rh_extrefs = 0;
7670Sstevel@tonic-gate 	handle_rele_subhandles(ret, RH_HOLD_ALL);
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	if (failed) {
7700Sstevel@tonic-gate 		scf_handle_destroy(ret);
7710Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7720Sstevel@tonic-gate 		return (NULL);
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	scf_value_set_count(ret->rh_value, default_debug);
7760Sstevel@tonic-gate 	(void) scf_handle_decorate(ret, "debug", ret->rh_value);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	return (ret);
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate int
7820Sstevel@tonic-gate scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
7830Sstevel@tonic-gate {
7840Sstevel@tonic-gate 	if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
7850Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
7880Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
7890Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
7900Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	if (strcmp(name, "debug") == 0) {
7950Sstevel@tonic-gate 		if (v == SCF_DECORATE_CLEAR) {
7960Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
7970Sstevel@tonic-gate 			handle->rh_debug = 0;
7980Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
7990Sstevel@tonic-gate 		} else {
8000Sstevel@tonic-gate 			uint64_t val;
8010Sstevel@tonic-gate 			if (scf_value_get_count(v, &val) < 0)
8020Sstevel@tonic-gate 				return (-1);		/* error already set */
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8050Sstevel@tonic-gate 			handle->rh_debug = (uid_t)val;
8060Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8070Sstevel@tonic-gate 		}
8080Sstevel@tonic-gate 		return (0);
8090Sstevel@tonic-gate 	}
8100Sstevel@tonic-gate 	if (strcmp(name, "door_path") == 0) {
8110Sstevel@tonic-gate 		char name[sizeof (handle->rh_doorpath)];
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 		if (v == SCF_DECORATE_CLEAR) {
8140Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8150Sstevel@tonic-gate 			handle->rh_doorpath[0] = 0;
8160Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8170Sstevel@tonic-gate 		} else {
8180Sstevel@tonic-gate 			ssize_t len;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 			if ((len = scf_value_get_astring(v, name,
8210Sstevel@tonic-gate 			    sizeof (name))) < 0) {
8220Sstevel@tonic-gate 				return (-1);		/* error already set */
8230Sstevel@tonic-gate 			}
8240Sstevel@tonic-gate 			if (len == 0 || len >= sizeof (name)) {
8250Sstevel@tonic-gate 				return (scf_set_error(
8260Sstevel@tonic-gate 				    SCF_ERROR_INVALID_ARGUMENT));
8270Sstevel@tonic-gate 			}
8280Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8290Sstevel@tonic-gate 			(void) strlcpy(handle->rh_doorpath, name,
8300Sstevel@tonic-gate 			    sizeof (handle->rh_doorpath));
8310Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8320Sstevel@tonic-gate 		}
8330Sstevel@tonic-gate 		return (0);
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate /*
8390Sstevel@tonic-gate  * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
8400Sstevel@tonic-gate  */
8410Sstevel@tonic-gate int
8420Sstevel@tonic-gate _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f,
8430Sstevel@tonic-gate     scf_value_t *v, void *data)
8440Sstevel@tonic-gate {
8450Sstevel@tonic-gate 	scf_decoration_info_t i;
8460Sstevel@tonic-gate 	char name[sizeof (handle->rh_doorpath)];
8470Sstevel@tonic-gate 	uint64_t debug;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	if (f == NULL || v == NULL)
8500Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	if (v->value_handle != handle)
8530Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	i.sdi_name = (const char *)"debug";
8560Sstevel@tonic-gate 	i.sdi_type = SCF_TYPE_COUNT;
8570Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
8580Sstevel@tonic-gate 	debug = handle->rh_debug;
8590Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
8600Sstevel@tonic-gate 	if (debug != 0) {
8610Sstevel@tonic-gate 		scf_value_set_count(v, debug);
8620Sstevel@tonic-gate 		i.sdi_value = v;
8630Sstevel@tonic-gate 	} else {
8640Sstevel@tonic-gate 		i.sdi_value = SCF_DECORATE_CLEAR;
8650Sstevel@tonic-gate 	}
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	if ((*f)(&i, data) == 0)
8680Sstevel@tonic-gate 		return (0);
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	i.sdi_name = (const char *)"door_path";
8710Sstevel@tonic-gate 	i.sdi_type = SCF_TYPE_ASTRING;
8720Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
8730Sstevel@tonic-gate 	(void) strlcpy(name, handle->rh_doorpath, sizeof (name));
8740Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
8750Sstevel@tonic-gate 	if (name[0] != 0) {
8760Sstevel@tonic-gate 		(void) scf_value_set_astring(v, name);
8770Sstevel@tonic-gate 		i.sdi_value = v;
8780Sstevel@tonic-gate 	} else {
8790Sstevel@tonic-gate 		i.sdi_value = SCF_DECORATE_CLEAR;
8800Sstevel@tonic-gate 	}
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	if ((*f)(&i, data) == 0)
8830Sstevel@tonic-gate 		return (0);
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	return (1);
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate /*
8890Sstevel@tonic-gate  * Fails if handle is not bound.
8900Sstevel@tonic-gate  */
8910Sstevel@tonic-gate static int
8920Sstevel@tonic-gate handle_unbind_unlocked(scf_handle_t *handle)
8930Sstevel@tonic-gate {
8940Sstevel@tonic-gate 	rep_protocol_request_t request;
8950Sstevel@tonic-gate 	rep_protocol_response_t response;
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	if (!handle_is_bound(handle))
8980Sstevel@tonic-gate 		return (-1);
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_CLOSE;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	(void) make_door_call(handle, &request, sizeof (request),
9030Sstevel@tonic-gate 	    &response, sizeof (response));
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	handle_do_close(handle);
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	return (SCF_SUCCESS);
9080Sstevel@tonic-gate }
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate /*
9110Sstevel@tonic-gate  * Fails with
9120Sstevel@tonic-gate  *   _HANDLE_DESTROYED - dp's handle has been destroyed
9130Sstevel@tonic-gate  *   _INTERNAL - server response too big
9140Sstevel@tonic-gate  *		 entity already set up with different type
9150Sstevel@tonic-gate  *   _NO_RESOURCES - server out of memory
9160Sstevel@tonic-gate  */
9170Sstevel@tonic-gate static int
9180Sstevel@tonic-gate datael_attach(scf_datael_t *dp)
9190Sstevel@tonic-gate {
9200Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	struct rep_protocol_entity_setup request;
9230Sstevel@tonic-gate 	rep_protocol_response_t response;
9240Sstevel@tonic-gate 	ssize_t r;
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	dp->rd_reset = 0;		/* setup implicitly resets */
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD)
9310Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	if (!handle_is_bound(h))
9340Sstevel@tonic-gate 		return (SCF_SUCCESS);		/* nothing to do */
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_SETUP;
9370Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
9380Sstevel@tonic-gate 	request.rpr_entitytype = dp->rd_type;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
9410Sstevel@tonic-gate 	    &response, sizeof (response));
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	if (r == NOT_BOUND || r == CALL_FAILED)
9440Sstevel@tonic-gate 		return (SCF_SUCCESS);
9450Sstevel@tonic-gate 	if (r == RESULT_TOO_BIG)
9460Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
9490Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	return (SCF_SUCCESS);
9520Sstevel@tonic-gate }
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate /*
9550Sstevel@tonic-gate  * Fails with
9560Sstevel@tonic-gate  *   _HANDLE_DESTROYED - iter's handle has been destroyed
9570Sstevel@tonic-gate  *   _INTERNAL - server response too big
9580Sstevel@tonic-gate  *		 iter already existed
9590Sstevel@tonic-gate  *   _NO_RESOURCES
9600Sstevel@tonic-gate  */
9610Sstevel@tonic-gate static int
9620Sstevel@tonic-gate iter_attach(scf_iter_t *iter)
9630Sstevel@tonic-gate {
9640Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
9650Sstevel@tonic-gate 	struct rep_protocol_iter_request request;
9660Sstevel@tonic-gate 	struct rep_protocol_response response;
9670Sstevel@tonic-gate 	int r;
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD)
9720Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	if (!handle_is_bound(h))
9750Sstevel@tonic-gate 		return (SCF_SUCCESS);		/* nothing to do */
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_SETUP;
9780Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
9810Sstevel@tonic-gate 	    &response, sizeof (response));
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	if (r == NOT_BOUND || r == CALL_FAILED)
9840Sstevel@tonic-gate 		return (SCF_SUCCESS);
9850Sstevel@tonic-gate 	if (r == RESULT_TOO_BIG)
9860Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
9890Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	return (SCF_SUCCESS);
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate /*
9950Sstevel@tonic-gate  * Fails with
9960Sstevel@tonic-gate  *   _IN_USE - handle already bound
9970Sstevel@tonic-gate  *   _NO_SERVER - server door could not be open()ed
9980Sstevel@tonic-gate  *		  door call failed
9990Sstevel@tonic-gate  *		  door_info() failed
10000Sstevel@tonic-gate  *   _VERSION_MISMATCH - server returned bad file descriptor
10010Sstevel@tonic-gate  *			 server claimed bad request
10020Sstevel@tonic-gate  *			 server reported version mismatch
10030Sstevel@tonic-gate  *			 server refused with unknown reason
10040Sstevel@tonic-gate  *   _INVALID_ARGUMENT
10050Sstevel@tonic-gate  *   _NO_RESOURCES - server is out of memory
10060Sstevel@tonic-gate  *   _PERMISSION_DENIED
10070Sstevel@tonic-gate  *   _INTERNAL - could not set up entities or iters
10080Sstevel@tonic-gate  *		 server response too big
10090Sstevel@tonic-gate  *
10100Sstevel@tonic-gate  * perhaps this should try multiple times.
10110Sstevel@tonic-gate  */
10120Sstevel@tonic-gate int
10130Sstevel@tonic-gate scf_handle_bind(scf_handle_t *handle)
10140Sstevel@tonic-gate {
10150Sstevel@tonic-gate 	scf_datael_t *el;
10160Sstevel@tonic-gate 	scf_iter_t *iter;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	pid_t pid;
10190Sstevel@tonic-gate 	int fd;
10200Sstevel@tonic-gate 	int res;
10210Sstevel@tonic-gate 	door_info_t info;
10220Sstevel@tonic-gate 	repository_door_request_t request;
10230Sstevel@tonic-gate 	repository_door_response_t response;
10240Sstevel@tonic-gate 	const char *door_name = default_door_path;
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
10270Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
10280Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
10290Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	/* wait until any active fd users have cleared out */
10330Sstevel@tonic-gate 	while (handle->rh_fd_users > 0)
10340Sstevel@tonic-gate 		(void) PTHREAD_COND_WAIT(&handle->rh_cv, &handle->rh_lock);
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	/* check again, since we had to drop the lock */
10370Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
10380Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
10390Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1);
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	if (handle->rh_doorpath[0] != 0)
10450Sstevel@tonic-gate 		door_name = handle->rh_doorpath;
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	fd = open(door_name, O_RDONLY, 0);
10480Sstevel@tonic-gate 	if (fd == -1) {
10490Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
10500Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NO_SERVER));
10510Sstevel@tonic-gate 	}
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	request.rdr_version = REPOSITORY_DOOR_VERSION;
10540Sstevel@tonic-gate 	request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT;
10550Sstevel@tonic-gate 	request.rdr_flags = handle->rh_flags;
10560Sstevel@tonic-gate 	request.rdr_debug = handle->rh_debug;
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	pid = getpid();
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	res = make_door_call_retfd(fd, &request, sizeof (request),
10610Sstevel@tonic-gate 	    &response, sizeof (response), &handle->rh_doorfd);
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	(void) close(fd);
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	if (res < 0) {
10660Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 		assert(res != NOT_BOUND);
10690Sstevel@tonic-gate 		if (res == CALL_FAILED)
10700Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_NO_SERVER));
10710Sstevel@tonic-gate 		assert(res == RESULT_TOO_BIG);
10720Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	if (handle->rh_doorfd < 0) {
10760Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 		switch (response.rdr_status) {
10790Sstevel@tonic-gate 		case REPOSITORY_DOOR_SUCCESS:
10800Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_BAD_REQUEST:
10830Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH:
10860Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_BAD_FLAG:
10890Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_NO_RESOURCES:
10920Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_NO_RESOURCES));
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED:
10950Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 		default:
10980Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
10990Sstevel@tonic-gate 		}
11000Sstevel@tonic-gate 	}
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	(void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC);
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	if (door_info(handle->rh_doorfd, &info) < 0) {
11050Sstevel@tonic-gate 		(void) close(handle->rh_doorfd);
11060Sstevel@tonic-gate 		handle->rh_doorfd = -1;
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
11090Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NO_SERVER));
11100Sstevel@tonic-gate 	}
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	handle->rh_doorpid = pid;
11130Sstevel@tonic-gate 	handle->rh_doorid = info.di_uniquifier;
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	/*
11160Sstevel@tonic-gate 	 * Now, re-attach everything
11170Sstevel@tonic-gate 	 */
11180Sstevel@tonic-gate 	for (el = uu_list_first(handle->rh_dataels); el != NULL;
11190Sstevel@tonic-gate 	    el = uu_list_next(handle->rh_dataels, el)) {
11200Sstevel@tonic-gate 		if (datael_attach(el) == -1) {
11210Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
11220Sstevel@tonic-gate 			(void) handle_unbind_unlocked(handle);
11230Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
11240Sstevel@tonic-gate 			return (-1);
11250Sstevel@tonic-gate 		}
11260Sstevel@tonic-gate 	}
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	for (iter = uu_list_first(handle->rh_iters); iter != NULL;
11290Sstevel@tonic-gate 	    iter = uu_list_next(handle->rh_iters, iter)) {
11300Sstevel@tonic-gate 		if (iter_attach(iter) == -1) {
11310Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
11320Sstevel@tonic-gate 			(void) handle_unbind_unlocked(handle);
11330Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
11340Sstevel@tonic-gate 			return (-1);
11350Sstevel@tonic-gate 		}
11360Sstevel@tonic-gate 	}
11370Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
11380Sstevel@tonic-gate 	return (SCF_SUCCESS);
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate int
11420Sstevel@tonic-gate scf_handle_unbind(scf_handle_t *handle)
11430Sstevel@tonic-gate {
11440Sstevel@tonic-gate 	int ret;
11450Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
11460Sstevel@tonic-gate 	ret = handle_unbind_unlocked(handle);
11470Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
11480Sstevel@tonic-gate 	return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND));
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate static scf_handle_t *
11520Sstevel@tonic-gate handle_get(scf_handle_t *h)
11530Sstevel@tonic-gate {
11540Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
11550Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD) {
11560Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
11570Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
11580Sstevel@tonic-gate 		return (NULL);
11590Sstevel@tonic-gate 	}
11600Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
11610Sstevel@tonic-gate 	return (h);
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate  * Called when an object is removed from the handle.  On the last remove,
11660Sstevel@tonic-gate  * cleans up and frees the handle.
11670Sstevel@tonic-gate  */
11680Sstevel@tonic-gate static void
11690Sstevel@tonic-gate handle_unrefed(scf_handle_t *handle)
11700Sstevel@tonic-gate {
11710Sstevel@tonic-gate 	scf_iter_t *iter;
11720Sstevel@tonic-gate 	scf_value_t *v;
11730Sstevel@tonic-gate 	scf_scope_t *sc;
11740Sstevel@tonic-gate 	scf_service_t *svc;
11750Sstevel@tonic-gate 	scf_instance_t *inst;
11760Sstevel@tonic-gate 	scf_snapshot_t *snap;
11770Sstevel@tonic-gate 	scf_snaplevel_t *snaplvl;
11780Sstevel@tonic-gate 	scf_propertygroup_t *pg;
11790Sstevel@tonic-gate 	scf_property_t *prop;
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	/*
11840Sstevel@tonic-gate 	 * Don't do anything if the handle has not yet been destroyed, there
11850Sstevel@tonic-gate 	 * are still external references, or we're already doing unrefed
11860Sstevel@tonic-gate 	 * handling.
11870Sstevel@tonic-gate 	 */
11880Sstevel@tonic-gate 	if (!(handle->rh_flags & HANDLE_DEAD) ||
11890Sstevel@tonic-gate 	    handle->rh_extrefs > 0 ||
11900Sstevel@tonic-gate 	    handle->rh_fd_users > 0 ||
11910Sstevel@tonic-gate 	    (handle->rh_flags & HANDLE_UNREFED)) {
11920Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
11930Sstevel@tonic-gate 		return;
11940Sstevel@tonic-gate 	}
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	handle->rh_flags |= HANDLE_UNREFED;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	/*
11990Sstevel@tonic-gate 	 * Now that we know that there are no external references, and the
12000Sstevel@tonic-gate 	 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
12010Sstevel@tonic-gate 	 * our subhandles and destroy the handle completely.
12020Sstevel@tonic-gate 	 */
12030Sstevel@tonic-gate 	assert(handle->rh_intrefs >= 0);
12040Sstevel@tonic-gate 	handle->rh_extrefs = handle->rh_intrefs;
12050Sstevel@tonic-gate 	handle->rh_intrefs = 0;
12060Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 	handle_hold_subhandles(handle, RH_HOLD_ALL);
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	iter = handle->rh_iter;
12110Sstevel@tonic-gate 	sc = handle->rh_scope;
12120Sstevel@tonic-gate 	svc = handle->rh_service;
12130Sstevel@tonic-gate 	inst = handle->rh_instance;
12140Sstevel@tonic-gate 	snap = handle->rh_snapshot;
12150Sstevel@tonic-gate 	snaplvl = handle->rh_snaplvl;
12160Sstevel@tonic-gate 	pg = handle->rh_pg;
12170Sstevel@tonic-gate 	prop = handle->rh_property;
12180Sstevel@tonic-gate 	v = handle->rh_value;
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 	handle->rh_iter = NULL;
12210Sstevel@tonic-gate 	handle->rh_scope = NULL;
12220Sstevel@tonic-gate 	handle->rh_service = NULL;
12230Sstevel@tonic-gate 	handle->rh_instance = NULL;
12240Sstevel@tonic-gate 	handle->rh_snapshot = NULL;
12250Sstevel@tonic-gate 	handle->rh_snaplvl = NULL;
12260Sstevel@tonic-gate 	handle->rh_pg = NULL;
12270Sstevel@tonic-gate 	handle->rh_property = NULL;
12280Sstevel@tonic-gate 	handle->rh_value = NULL;
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	if (iter != NULL)
12310Sstevel@tonic-gate 		scf_iter_destroy(iter);
12320Sstevel@tonic-gate 	if (sc != NULL)
12330Sstevel@tonic-gate 		scf_scope_destroy(sc);
12340Sstevel@tonic-gate 	if (svc != NULL)
12350Sstevel@tonic-gate 		scf_service_destroy(svc);
12360Sstevel@tonic-gate 	if (inst != NULL)
12370Sstevel@tonic-gate 		scf_instance_destroy(inst);
12380Sstevel@tonic-gate 	if (snap != NULL)
12390Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
12400Sstevel@tonic-gate 	if (snaplvl != NULL)
12410Sstevel@tonic-gate 		scf_snaplevel_destroy(snaplvl);
12420Sstevel@tonic-gate 	if (pg != NULL)
12430Sstevel@tonic-gate 		scf_pg_destroy(pg);
12440Sstevel@tonic-gate 	if (prop != NULL)
12450Sstevel@tonic-gate 		scf_property_destroy(prop);
12460Sstevel@tonic-gate 	if (v != NULL)
12470Sstevel@tonic-gate 		scf_value_destroy(v);
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	/* there should be no outstanding children at this point */
12520Sstevel@tonic-gate 	assert(handle->rh_extrefs == 0);
12530Sstevel@tonic-gate 	assert(handle->rh_intrefs == 0);
12540Sstevel@tonic-gate 	assert(handle->rh_values == 0);
12550Sstevel@tonic-gate 	assert(handle->rh_entries == 0);
12560Sstevel@tonic-gate 	assert(uu_list_numnodes(handle->rh_dataels) == 0);
12570Sstevel@tonic-gate 	assert(uu_list_numnodes(handle->rh_iters) == 0);
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	uu_list_destroy(handle->rh_dataels);
12600Sstevel@tonic-gate 	uu_list_destroy(handle->rh_iters);
12610Sstevel@tonic-gate 	handle->rh_dataels = NULL;
12620Sstevel@tonic-gate 	handle->rh_iters = NULL;
12630Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&handle->rh_lock);
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	uu_free(handle);
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate void
12710Sstevel@tonic-gate scf_handle_destroy(scf_handle_t *handle)
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate 	if (handle == NULL)
12740Sstevel@tonic-gate 		return;
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
12770Sstevel@tonic-gate 	if (handle->rh_flags & HANDLE_DEAD) {
12780Sstevel@tonic-gate 		/*
12790Sstevel@tonic-gate 		 * This is an error (you are not allowed to reference the
12800Sstevel@tonic-gate 		 * handle after it is destroyed), but we can't report it.
12810Sstevel@tonic-gate 		 */
12820Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
12830Sstevel@tonic-gate 		return;
12840Sstevel@tonic-gate 	}
12850Sstevel@tonic-gate 	handle->rh_flags |= HANDLE_DEAD;
12860Sstevel@tonic-gate 	(void) handle_unbind_unlocked(handle);
12870Sstevel@tonic-gate 	handle_unrefed(handle);
12880Sstevel@tonic-gate }
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate ssize_t
12910Sstevel@tonic-gate scf_myname(scf_handle_t *h, char *out, size_t len)
12920Sstevel@tonic-gate {
12930Sstevel@tonic-gate 	char *cp;
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 	if (!handle_has_server(h))
12960Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	cp = getenv("SMF_FMRI");
12990Sstevel@tonic-gate 	if (cp == NULL)
13000Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	return (strlcpy(out, cp, len));
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate static uint32_t
1306*407Sjwadams handle_alloc_entityid(scf_handle_t *h)
1307*407Sjwadams {
1308*407Sjwadams 	uint32_t nextid;
1309*407Sjwadams 
1310*407Sjwadams 	assert(MUTEX_HELD(&h->rh_lock));
1311*407Sjwadams 
1312*407Sjwadams 	if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX)
1313*407Sjwadams 		return (0);		/* no ids available */
1314*407Sjwadams 
1315*407Sjwadams 	/*
1316*407Sjwadams 	 * The following loop assumes that there are not a huge number of
1317*407Sjwadams 	 * outstanding entities when we've wrapped.  If that ends up not
1318*407Sjwadams 	 * being the case, the O(N^2) nature of this search will hurt a lot,
1319*407Sjwadams 	 * and the data structure should be switched to an AVL tree.
1320*407Sjwadams 	 */
1321*407Sjwadams 	nextid = h->rh_nextentity + 1;
1322*407Sjwadams 	for (;;) {
1323*407Sjwadams 		scf_datael_t *cur;
1324*407Sjwadams 
1325*407Sjwadams 		if (nextid == 0) {
1326*407Sjwadams 			nextid++;
1327*407Sjwadams 			h->rh_flags |= HANDLE_WRAPPED_ENTITY;
1328*407Sjwadams 		}
1329*407Sjwadams 		if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
1330*407Sjwadams 			break;
1331*407Sjwadams 
1332*407Sjwadams 		cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL);
1333*407Sjwadams 		if (cur == NULL)
1334*407Sjwadams 			break;		/* not in use */
1335*407Sjwadams 
1336*407Sjwadams 		if (nextid == h->rh_nextentity)
1337*407Sjwadams 			return (0);	/* wrapped around; no ids available */
1338*407Sjwadams 		nextid++;
1339*407Sjwadams 	}
1340*407Sjwadams 
1341*407Sjwadams 	h->rh_nextentity = nextid;
1342*407Sjwadams 	return (nextid);
13430Sstevel@tonic-gate }
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate static uint32_t
1346*407Sjwadams handle_alloc_iterid(scf_handle_t *h)
1347*407Sjwadams {
1348*407Sjwadams 	uint32_t nextid;
1349*407Sjwadams 
1350*407Sjwadams 	assert(MUTEX_HELD(&h->rh_lock));
1351*407Sjwadams 
1352*407Sjwadams 	if (uu_list_numnodes(h->rh_iters) == UINT32_MAX)
1353*407Sjwadams 		return (0);		/* no ids available */
1354*407Sjwadams 
1355*407Sjwadams 	/* see the comment in handle_alloc_entityid */
1356*407Sjwadams 	nextid = h->rh_nextiter + 1;
1357*407Sjwadams 	for (;;) {
1358*407Sjwadams 		scf_iter_t *cur;
1359*407Sjwadams 
1360*407Sjwadams 		if (nextid == 0) {
1361*407Sjwadams 			nextid++;
1362*407Sjwadams 			h->rh_flags |= HANDLE_WRAPPED_ITER;
1363*407Sjwadams 		}
1364*407Sjwadams 		if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
1365*407Sjwadams 			break;			/* not yet wrapped */
1366*407Sjwadams 
1367*407Sjwadams 		cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL);
1368*407Sjwadams 		if (cur == NULL)
1369*407Sjwadams 			break;		/* not in use */
1370*407Sjwadams 
1371*407Sjwadams 		if (nextid == h->rh_nextiter)
1372*407Sjwadams 			return (0);	/* wrapped around; no ids available */
1373*407Sjwadams 		nextid++;
1374*407Sjwadams 	}
1375*407Sjwadams 
1376*407Sjwadams 	h->rh_nextiter = nextid;
1377*407Sjwadams 	return (nextid);
13780Sstevel@tonic-gate }
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate static uint32_t
1381*407Sjwadams handle_next_changeid(scf_handle_t *handle)
1382*407Sjwadams {
1383*407Sjwadams 	uint32_t nextid;
1384*407Sjwadams 
13850Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
1386*407Sjwadams 
1387*407Sjwadams 	nextid = ++handle->rh_nextchangeid;
1388*407Sjwadams 	if (nextid == 0)
1389*407Sjwadams 		nextid = ++handle->rh_nextchangeid;
1390*407Sjwadams 	return (nextid);
13910Sstevel@tonic-gate }
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate /*
13940Sstevel@tonic-gate  * Fails with
13950Sstevel@tonic-gate  *   _INVALID_ARGUMENT - h is NULL
13960Sstevel@tonic-gate  *   _HANDLE_DESTROYED
13970Sstevel@tonic-gate  *   _INTERNAL - server response too big
13980Sstevel@tonic-gate  *		 entity already set up with different type
13990Sstevel@tonic-gate  *   _NO_RESOURCES
14000Sstevel@tonic-gate  */
14010Sstevel@tonic-gate static int
14020Sstevel@tonic-gate datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
14030Sstevel@tonic-gate {
14040Sstevel@tonic-gate 	int ret;
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	if (h == NULL)
14070Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 	uu_list_node_init(dp, &dp->rd_node, datael_pool);
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	dp->rd_handle = h;
14120Sstevel@tonic-gate 	dp->rd_type = type;
14130Sstevel@tonic-gate 	dp->rd_reset = 0;
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
14160Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD) {
14170Sstevel@tonic-gate 		/*
14180Sstevel@tonic-gate 		 * we're in undefined territory (the user cannot use a handle
14190Sstevel@tonic-gate 		 * directly after it has been destroyed), but we don't want
14200Sstevel@tonic-gate 		 * to allow any new references to happen, so we fail here.
14210Sstevel@tonic-gate 		 */
14220Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
14230Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
14240Sstevel@tonic-gate 	}
14250Sstevel@tonic-gate 	dp->rd_entity = handle_alloc_entityid(h);
1426*407Sjwadams 	if (dp->rd_entity == 0) {
1427*407Sjwadams 		(void) pthread_mutex_unlock(&h->rh_lock);
1428*407Sjwadams 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1429*407Sjwadams 		return (scf_set_error(SCF_ERROR_NO_MEMORY));
1430*407Sjwadams 	}
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate 	ret = datael_attach(dp);
14330Sstevel@tonic-gate 	if (ret == 0) {
14340Sstevel@tonic-gate 		(void) uu_list_insert_before(h->rh_dataels, NULL, dp);
14350Sstevel@tonic-gate 		h->rh_extrefs++;
14360Sstevel@tonic-gate 	} else {
14370Sstevel@tonic-gate 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
14380Sstevel@tonic-gate 	}
14390Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	return (ret);
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate static void
14450Sstevel@tonic-gate datael_destroy(scf_datael_t *dp)
14460Sstevel@tonic-gate {
14470Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	struct rep_protocol_entity_teardown request;
14500Sstevel@tonic-gate 	rep_protocol_response_t response;
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
14530Sstevel@tonic-gate 	uu_list_remove(h->rh_dataels, dp);
14540Sstevel@tonic-gate 	--h->rh_extrefs;
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	if (handle_is_bound(h)) {
14570Sstevel@tonic-gate 		request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN;
14580Sstevel@tonic-gate 		request.rpr_entityid = dp->rd_entity;
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 		(void) make_door_call(h, &request, sizeof (request),
14610Sstevel@tonic-gate 		    &response, sizeof (response));
14620Sstevel@tonic-gate 	}
14630Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	dp->rd_handle = NULL;
14660Sstevel@tonic-gate }
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate static scf_handle_t *
14690Sstevel@tonic-gate datael_handle(const scf_datael_t *dp)
14700Sstevel@tonic-gate {
14710Sstevel@tonic-gate 	return (handle_get(dp->rd_handle));
14720Sstevel@tonic-gate }
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate /*
14750Sstevel@tonic-gate  * We delay ENTITY_RESETs until right before the entity is used.  By doing
14760Sstevel@tonic-gate  * them lazily, we remove quite a few unnecessary calls.
14770Sstevel@tonic-gate  */
14780Sstevel@tonic-gate static void
14790Sstevel@tonic-gate datael_do_reset_locked(scf_datael_t *dp)
14800Sstevel@tonic-gate {
14810Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	struct rep_protocol_entity_reset request;
14840Sstevel@tonic-gate 	rep_protocol_response_t response;
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_RESET;
14890Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	(void) make_door_call(h, &request, sizeof (request),
14920Sstevel@tonic-gate 	    &response, sizeof (response));
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	dp->rd_reset = 0;
14950Sstevel@tonic-gate }
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate static void
14980Sstevel@tonic-gate datael_reset_locked(scf_datael_t *dp)
14990Sstevel@tonic-gate {
15000Sstevel@tonic-gate 	assert(MUTEX_HELD(&dp->rd_handle->rh_lock));
15010Sstevel@tonic-gate 	dp->rd_reset = 1;
15020Sstevel@tonic-gate }
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate static void
15050Sstevel@tonic-gate datael_reset(scf_datael_t *dp)
15060Sstevel@tonic-gate {
15070Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
15100Sstevel@tonic-gate 	dp->rd_reset = 1;
15110Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
15120Sstevel@tonic-gate }
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate static void
15150Sstevel@tonic-gate datael_finish_reset(const scf_datael_t *dp_arg)
15160Sstevel@tonic-gate {
15170Sstevel@tonic-gate 	scf_datael_t *dp = (scf_datael_t *)dp_arg;
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 	if (dp->rd_reset)
15200Sstevel@tonic-gate 		datael_do_reset_locked(dp);
15210Sstevel@tonic-gate }
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate /*
15240Sstevel@tonic-gate  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
15250Sstevel@tonic-gate  * big, bad entity id, request not applicable to entity, name too long for
15260Sstevel@tonic-gate  * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
15270Sstevel@tonic-gate  * instance).
15280Sstevel@tonic-gate  */
15290Sstevel@tonic-gate static ssize_t
15300Sstevel@tonic-gate datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type)
15310Sstevel@tonic-gate {
15320Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	struct rep_protocol_entity_name request;
15350Sstevel@tonic-gate 	struct rep_protocol_name_response response;
15360Sstevel@tonic-gate 	ssize_t r;
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
15390Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_NAME;
15400Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
15410Sstevel@tonic-gate 	request.rpr_answertype = type;
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 	datael_finish_reset(dp);
15440Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
15450Sstevel@tonic-gate 	    &response, sizeof (response));
15460Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	if (r < 0)
15490Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
15520Sstevel@tonic-gate 		assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST);
15530Sstevel@tonic-gate 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND)
15540Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
15550Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
15560Sstevel@tonic-gate 	}
15570Sstevel@tonic-gate 	return (strlcpy(buf, response.rpr_name, size));
15580Sstevel@tonic-gate }
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate /*
15610Sstevel@tonic-gate  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
15620Sstevel@tonic-gate  * (server response too big, bad element id), _EXISTS (elements have same id),
15630Sstevel@tonic-gate  * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
15640Sstevel@tonic-gate  * or _SUCCESS.
15650Sstevel@tonic-gate  */
15660Sstevel@tonic-gate static int
15670Sstevel@tonic-gate datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp)
15680Sstevel@tonic-gate {
15690Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 	struct rep_protocol_entity_parent request;
15720Sstevel@tonic-gate 	struct rep_protocol_response response;
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 	ssize_t r;
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	if (h != pp->rd_handle)
15770Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
15800Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT;
15810Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
15820Sstevel@tonic-gate 	request.rpr_outid = pp->rd_entity;
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 	datael_finish_reset(dp);
15850Sstevel@tonic-gate 	datael_finish_reset(pp);
15860Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
15870Sstevel@tonic-gate 	    &response, sizeof (response));
15880Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	if (r < 0)
15910Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
15940Sstevel@tonic-gate 		if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH)
15950Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
15960Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
15970Sstevel@tonic-gate 	}
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 	return (SCF_SUCCESS);
16000Sstevel@tonic-gate }
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate /*
16030Sstevel@tonic-gate  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
16040Sstevel@tonic-gate  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
16050Sstevel@tonic-gate  * too big, bad id, iter already exists, element cannot have children of type,
16060Sstevel@tonic-gate  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
16070Sstevel@tonic-gate  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
16080Sstevel@tonic-gate  * _BACKEND_ACCESS.
16090Sstevel@tonic-gate  */
16100Sstevel@tonic-gate static int
16110Sstevel@tonic-gate datael_get_child_composed_locked(const scf_datael_t *dp, const char *name,
16120Sstevel@tonic-gate     uint32_t type, scf_datael_t *out, scf_iter_t *iter)
16130Sstevel@tonic-gate {
16140Sstevel@tonic-gate 	struct rep_protocol_iter_start request;
16150Sstevel@tonic-gate 	struct rep_protocol_iter_read read_request;
16160Sstevel@tonic-gate 	struct rep_protocol_response response;
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
16190Sstevel@tonic-gate 	ssize_t r;
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	if (h != out->rd_handle)
16220Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 	if (out->rd_type != type)
16250Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
16280Sstevel@tonic-gate 	assert(iter != NULL);
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
16310Sstevel@tonic-gate 	iter->iter_type = type;
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_START;
16340Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
16350Sstevel@tonic-gate 	request.rpr_entity = dp->rd_entity;
16360Sstevel@tonic-gate 	request.rpr_itertype = type;
16370Sstevel@tonic-gate 	request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED;
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	if (name == NULL || strlcpy(request.rpr_pattern, name,
16400Sstevel@tonic-gate 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
16410Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
16420Sstevel@tonic-gate 	}
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	datael_finish_reset(dp);
16450Sstevel@tonic-gate 	datael_finish_reset(out);
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	/*
16480Sstevel@tonic-gate 	 * We hold the handle lock across both door calls, so that they
16490Sstevel@tonic-gate 	 * appear atomic.
16500Sstevel@tonic-gate 	 */
16510Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
16520Sstevel@tonic-gate 	    &response, sizeof (response));
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	if (r < 0)
16550Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
16580Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 	iter->iter_sequence++;
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 	read_request.rpr_request = REP_PROTOCOL_ITER_READ;
16630Sstevel@tonic-gate 	read_request.rpr_iterid = iter->iter_id;
16640Sstevel@tonic-gate 	read_request.rpr_sequence = iter->iter_sequence;
16650Sstevel@tonic-gate 	read_request.rpr_entityid = out->rd_entity;
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate 	r = make_door_call(h, &read_request, sizeof (read_request),
16680Sstevel@tonic-gate 	    &response, sizeof (response));
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 	if (r < 0)
16730Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE) {
16760Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_FOUND));
16770Sstevel@tonic-gate 	}
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
16800Sstevel@tonic-gate 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET ||
16810Sstevel@tonic-gate 		    response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
16820Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INTERNAL));
16830Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
16840Sstevel@tonic-gate 	}
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate 	return (0);
16870Sstevel@tonic-gate }
16880Sstevel@tonic-gate 
16890Sstevel@tonic-gate /*
16900Sstevel@tonic-gate  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
16910Sstevel@tonic-gate  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
16920Sstevel@tonic-gate  * too big, bad id, element cannot have children of type, type is invalid),
16930Sstevel@tonic-gate  * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
16940Sstevel@tonic-gate  */
16950Sstevel@tonic-gate static int
16960Sstevel@tonic-gate datael_get_child_locked(const scf_datael_t *dp, const char *name,
16970Sstevel@tonic-gate     uint32_t type, scf_datael_t *out)
16980Sstevel@tonic-gate {
16990Sstevel@tonic-gate 	struct rep_protocol_entity_get_child request;
17000Sstevel@tonic-gate 	struct rep_protocol_response response;
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
17030Sstevel@tonic-gate 	ssize_t r;
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	if (h != out->rd_handle)
17060Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
17070Sstevel@tonic-gate 
17080Sstevel@tonic-gate 	if (out->rd_type != type)
17090Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD;
17140Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
17150Sstevel@tonic-gate 	request.rpr_childid = out->rd_entity;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	if (name == NULL || strlcpy(request.rpr_name, name,
17180Sstevel@tonic-gate 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) {
17190Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
17200Sstevel@tonic-gate 	}
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 	datael_finish_reset(dp);
17230Sstevel@tonic-gate 	datael_finish_reset(out);
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
17260Sstevel@tonic-gate 	    &response, sizeof (response));
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	if (r < 0)
17290Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
17320Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
17330Sstevel@tonic-gate 	return (0);
17340Sstevel@tonic-gate }
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate static int
17370Sstevel@tonic-gate datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type,
17380Sstevel@tonic-gate     scf_datael_t *out, boolean_t composed)
17390Sstevel@tonic-gate {
17400Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
17410Sstevel@tonic-gate 	uint32_t held = 0;
17420Sstevel@tonic-gate 	int ret;
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	if (composed)
17470Sstevel@tonic-gate 		iter = HANDLE_HOLD_ITER(h);
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	if (out == NULL) {
17500Sstevel@tonic-gate 		switch (type) {
17510Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SERVICE:
17520Sstevel@tonic-gate 			out = &HANDLE_HOLD_SERVICE(h)->rd_d;
17530Sstevel@tonic-gate 			held = RH_HOLD_SERVICE;
17540Sstevel@tonic-gate 			break;
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_INSTANCE:
17570Sstevel@tonic-gate 			out = &HANDLE_HOLD_INSTANCE(h)->rd_d;
17580Sstevel@tonic-gate 			held = RH_HOLD_INSTANCE;
17590Sstevel@tonic-gate 			break;
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
17620Sstevel@tonic-gate 			out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d;
17630Sstevel@tonic-gate 			held = RH_HOLD_SNAPSHOT;
17640Sstevel@tonic-gate 			break;
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SNAPLEVEL:
17670Sstevel@tonic-gate 			out = &HANDLE_HOLD_SNAPLVL(h)->rd_d;
17680Sstevel@tonic-gate 			held = RH_HOLD_SNAPLVL;
17690Sstevel@tonic-gate 			break;
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_PROPERTYGRP:
17720Sstevel@tonic-gate 			out = &HANDLE_HOLD_PG(h)->rd_d;
17730Sstevel@tonic-gate 			held = RH_HOLD_PG;
17740Sstevel@tonic-gate 			break;
17750Sstevel@tonic-gate 
17760Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_PROPERTY:
17770Sstevel@tonic-gate 			out = &HANDLE_HOLD_PROPERTY(h)->rd_d;
17780Sstevel@tonic-gate 			held = RH_HOLD_PROPERTY;
17790Sstevel@tonic-gate 			break;
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 		default:
17820Sstevel@tonic-gate 			assert(0);
17830Sstevel@tonic-gate 			abort();
17840Sstevel@tonic-gate 		}
17850Sstevel@tonic-gate 	}
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
17880Sstevel@tonic-gate 	if (composed)
17890Sstevel@tonic-gate 		ret = datael_get_child_composed_locked(dp, name, type, out,
17900Sstevel@tonic-gate 		    iter);
17910Sstevel@tonic-gate 	else
17920Sstevel@tonic-gate 		ret = datael_get_child_locked(dp, name, type, out);
17930Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	if (composed)
17960Sstevel@tonic-gate 		HANDLE_RELE_ITER(h);
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 	if (held)
17990Sstevel@tonic-gate 		handle_rele_subhandles(h, held);
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 	return (ret);
18020Sstevel@tonic-gate }
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate /*
18050Sstevel@tonic-gate  * Fails with
18060Sstevel@tonic-gate  *   _HANDLE_MISMATCH
18070Sstevel@tonic-gate  *   _INVALID_ARGUMENT - name is too long
18080Sstevel@tonic-gate  *			 invalid changeid
18090Sstevel@tonic-gate  *			 name is invalid
18100Sstevel@tonic-gate  *			 cannot create children for dp's type of node
18110Sstevel@tonic-gate  *   _NOT_BOUND - handle is not bound
18120Sstevel@tonic-gate  *   _CONNECTION_BROKEN - server is not reachable
18130Sstevel@tonic-gate  *   _INTERNAL - server response too big
18140Sstevel@tonic-gate  *		 dp or cp has unknown id
18150Sstevel@tonic-gate  *		 type is _PROPERTYGRP
18160Sstevel@tonic-gate  *		 type is invalid
18170Sstevel@tonic-gate  *		 dp cannot have children of type type
18180Sstevel@tonic-gate  *		 database is corrupt
18190Sstevel@tonic-gate  *   _EXISTS - dp & cp have the same id
18200Sstevel@tonic-gate  *   _EXISTS - child already exists
18210Sstevel@tonic-gate  *   _DELETED - dp has been deleted
18220Sstevel@tonic-gate  *   _NOT_SET - dp is reset
18230Sstevel@tonic-gate  *   _NO_RESOURCES
18240Sstevel@tonic-gate  *   _PERMISSION_DENIED
18250Sstevel@tonic-gate  *   _BACKEND_ACCESS
18260Sstevel@tonic-gate  *   _BACKEND_READONLY
18270Sstevel@tonic-gate  *   _NOT_FOUND - could not allocate new id
18280Sstevel@tonic-gate  */
18290Sstevel@tonic-gate static int
18300Sstevel@tonic-gate datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
18310Sstevel@tonic-gate     scf_datael_t *cp)
18320Sstevel@tonic-gate {
18330Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 	struct rep_protocol_entity_create_child request;
18360Sstevel@tonic-gate 	struct rep_protocol_response response;
18370Sstevel@tonic-gate 	ssize_t r;
18380Sstevel@tonic-gate 	uint32_t held = 0;
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate 	if (cp == NULL) {
18410Sstevel@tonic-gate 		switch (type) {
18420Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SCOPE:
18430Sstevel@tonic-gate 			cp = &HANDLE_HOLD_SCOPE(h)->rd_d;
18440Sstevel@tonic-gate 			held = RH_HOLD_SCOPE;
18450Sstevel@tonic-gate 			break;
18460Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SERVICE:
18470Sstevel@tonic-gate 			cp = &HANDLE_HOLD_SERVICE(h)->rd_d;
18480Sstevel@tonic-gate 			held = RH_HOLD_SERVICE;
18490Sstevel@tonic-gate 			break;
18500Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_INSTANCE:
18510Sstevel@tonic-gate 			cp = &HANDLE_HOLD_INSTANCE(h)->rd_d;
18520Sstevel@tonic-gate 			held = RH_HOLD_INSTANCE;
18530Sstevel@tonic-gate 			break;
18540Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
18550Sstevel@tonic-gate 		default:
18560Sstevel@tonic-gate 			assert(0);
18570Sstevel@tonic-gate 			abort();
18580Sstevel@tonic-gate 		}
18590Sstevel@tonic-gate 		assert(h == cp->rd_handle);
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	} else if (h != cp->rd_handle) {
18620Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
18630Sstevel@tonic-gate 	}
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
18660Sstevel@tonic-gate 	    sizeof (request.rpr_name)) {
18670Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
18680Sstevel@tonic-gate 		goto err;
18690Sstevel@tonic-gate 	}
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
18720Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD;
18730Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
18740Sstevel@tonic-gate 	request.rpr_childtype = type;
18750Sstevel@tonic-gate 	request.rpr_childid = cp->rd_entity;
18760Sstevel@tonic-gate 
18770Sstevel@tonic-gate 	datael_finish_reset(dp);
1878*407Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
18790Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
18800Sstevel@tonic-gate 	    &response, sizeof (response));
18810Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	if (held)
18840Sstevel@tonic-gate 		handle_rele_subhandles(h, held);
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	if (r < 0)
18870Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
18900Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	return (SCF_SUCCESS);
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate err:
18950Sstevel@tonic-gate 	if (held)
18960Sstevel@tonic-gate 		handle_rele_subhandles(h, held);
18970Sstevel@tonic-gate 	return (r);
18980Sstevel@tonic-gate }
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate static int
19010Sstevel@tonic-gate datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
19020Sstevel@tonic-gate     uint32_t flags, scf_datael_t *cp)
19030Sstevel@tonic-gate {
19040Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 	struct rep_protocol_entity_create_pg request;
19070Sstevel@tonic-gate 	struct rep_protocol_response response;
19080Sstevel@tonic-gate 	ssize_t r;
19090Sstevel@tonic-gate 
19100Sstevel@tonic-gate 	int holding_els = 0;
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate 	if (cp == NULL) {
19130Sstevel@tonic-gate 		holding_els = 1;
19140Sstevel@tonic-gate 		cp = &HANDLE_HOLD_PG(h)->rd_d;
19150Sstevel@tonic-gate 		assert(h == cp->rd_handle);
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 	} else if (h != cp->rd_handle) {
19180Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
19190Sstevel@tonic-gate 	}
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG;
19220Sstevel@tonic-gate 
19230Sstevel@tonic-gate 	if (name == NULL || strlcpy(request.rpr_name, name,
19240Sstevel@tonic-gate 	    sizeof (request.rpr_name)) > sizeof (request.rpr_name)) {
19250Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
19260Sstevel@tonic-gate 		goto err;
19270Sstevel@tonic-gate 	}
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate 	if (type == NULL || strlcpy(request.rpr_type, type,
19300Sstevel@tonic-gate 	    sizeof (request.rpr_type)) > sizeof (request.rpr_type)) {
19310Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
19320Sstevel@tonic-gate 		goto err;
19330Sstevel@tonic-gate 	}
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
19360Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
19370Sstevel@tonic-gate 	request.rpr_childid = cp->rd_entity;
19380Sstevel@tonic-gate 	request.rpr_flags = flags;
19390Sstevel@tonic-gate 
19400Sstevel@tonic-gate 	datael_finish_reset(dp);
19410Sstevel@tonic-gate 	datael_finish_reset(cp);
1942*407Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
19430Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
19440Sstevel@tonic-gate 	    &response, sizeof (response));
19450Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
19460Sstevel@tonic-gate 
19470Sstevel@tonic-gate 	if (holding_els)
19480Sstevel@tonic-gate 		HANDLE_RELE_PG(h);
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate 	if (r < 0)
19510Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
19540Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	return (SCF_SUCCESS);
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate err:
19590Sstevel@tonic-gate 	if (holding_els)
19600Sstevel@tonic-gate 		HANDLE_RELE_PG(h);
19610Sstevel@tonic-gate 	return (r);
19620Sstevel@tonic-gate }
19630Sstevel@tonic-gate 
19640Sstevel@tonic-gate static int
19650Sstevel@tonic-gate datael_delete(const scf_datael_t *dp)
19660Sstevel@tonic-gate {
19670Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate 	struct rep_protocol_entity_delete request;
19700Sstevel@tonic-gate 	struct rep_protocol_response response;
19710Sstevel@tonic-gate 	ssize_t r;
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
19740Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_DELETE;
19750Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	datael_finish_reset(dp);
1978*407Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
19790Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
19800Sstevel@tonic-gate 	    &response, sizeof (response));
19810Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
19820Sstevel@tonic-gate 
19830Sstevel@tonic-gate 	if (r < 0)
19840Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
19870Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 	return (SCF_SUCCESS);
19900Sstevel@tonic-gate }
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate /*
19930Sstevel@tonic-gate  * Fails with
19940Sstevel@tonic-gate  *   _INVALID_ARGUMENT - h is NULL
19950Sstevel@tonic-gate  *   _NO_MEMORY
19960Sstevel@tonic-gate  *   _HANDLE_DESTROYED - h has been destroyed
19970Sstevel@tonic-gate  *   _INTERNAL - server response too big
19980Sstevel@tonic-gate  *		 iter already exists
19990Sstevel@tonic-gate  *   _NO_RESOURCES
20000Sstevel@tonic-gate  */
20010Sstevel@tonic-gate scf_iter_t *
20020Sstevel@tonic-gate scf_iter_create(scf_handle_t *h)
20030Sstevel@tonic-gate {
20040Sstevel@tonic-gate 	scf_iter_t *iter;
20050Sstevel@tonic-gate 
20060Sstevel@tonic-gate 	if (h == NULL) {
20070Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
20080Sstevel@tonic-gate 		return (NULL);
20090Sstevel@tonic-gate 	}
20100Sstevel@tonic-gate 
20110Sstevel@tonic-gate 	iter = uu_zalloc(sizeof (*iter));
20120Sstevel@tonic-gate 	if (iter == NULL) {
20130Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
20140Sstevel@tonic-gate 		return (NULL);
20150Sstevel@tonic-gate 	}
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	uu_list_node_init(iter, &iter->iter_node, iter_pool);
20180Sstevel@tonic-gate 	iter->iter_handle = h;
20190Sstevel@tonic-gate 	iter->iter_sequence = 1;
20200Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
20210Sstevel@tonic-gate 
20220Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
20230Sstevel@tonic-gate 	iter->iter_id = handle_alloc_iterid(h);
2024*407Sjwadams 	if (iter->iter_id == 0) {
2025*407Sjwadams 		(void) pthread_mutex_unlock(&h->rh_lock);
2026*407Sjwadams 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2027*407Sjwadams 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2028*407Sjwadams 		return (NULL);
2029*407Sjwadams 	}
20300Sstevel@tonic-gate 	if (iter_attach(iter) == -1) {
20310Sstevel@tonic-gate 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
20320Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
20330Sstevel@tonic-gate 		uu_free(iter);
20340Sstevel@tonic-gate 		return (NULL);
20350Sstevel@tonic-gate 	}
20360Sstevel@tonic-gate 	(void) uu_list_insert_before(h->rh_iters, NULL, iter);
20370Sstevel@tonic-gate 	h->rh_extrefs++;
20380Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
20390Sstevel@tonic-gate 	return (iter);
20400Sstevel@tonic-gate }
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate scf_handle_t *
20430Sstevel@tonic-gate scf_iter_handle(const scf_iter_t *iter)
20440Sstevel@tonic-gate {
20450Sstevel@tonic-gate 	return (handle_get(iter->iter_handle));
20460Sstevel@tonic-gate }
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate static void
20490Sstevel@tonic-gate scf_iter_reset_locked(scf_iter_t *iter)
20500Sstevel@tonic-gate {
20510Sstevel@tonic-gate 	struct rep_protocol_iter_request request;
20520Sstevel@tonic-gate 	struct rep_protocol_response response;
20530Sstevel@tonic-gate 
20540Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_RESET;
20550Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	assert(MUTEX_HELD(&iter->iter_handle->rh_lock));
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate 	(void) make_door_call(iter->iter_handle,
20600Sstevel@tonic-gate 	    &request, sizeof (request), &response, sizeof (response));
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
20630Sstevel@tonic-gate 	iter->iter_sequence = 1;
20640Sstevel@tonic-gate }
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate void
20670Sstevel@tonic-gate scf_iter_reset(scf_iter_t *iter)
20680Sstevel@tonic-gate {
20690Sstevel@tonic-gate 	(void) pthread_mutex_lock(&iter->iter_handle->rh_lock);
20700Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
20710Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&iter->iter_handle->rh_lock);
20720Sstevel@tonic-gate }
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate void
20750Sstevel@tonic-gate scf_iter_destroy(scf_iter_t *iter)
20760Sstevel@tonic-gate {
20770Sstevel@tonic-gate 	scf_handle_t *handle;
20780Sstevel@tonic-gate 
20790Sstevel@tonic-gate 	struct rep_protocol_iter_request request;
20800Sstevel@tonic-gate 	struct rep_protocol_response response;
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 	if (iter == NULL)
20830Sstevel@tonic-gate 		return;
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate 	handle = iter->iter_handle;
20860Sstevel@tonic-gate 
20870Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
20880Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN;
20890Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
20900Sstevel@tonic-gate 
20910Sstevel@tonic-gate 	(void) make_door_call(handle, &request, sizeof (request),
20920Sstevel@tonic-gate 	    &response, sizeof (response));
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	uu_list_remove(handle->rh_iters, iter);
20950Sstevel@tonic-gate 	--handle->rh_extrefs;
20960Sstevel@tonic-gate 	handle_unrefed(handle);			/* drops h->rh_lock */
20970Sstevel@tonic-gate 	iter->iter_handle = NULL;
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 	uu_list_node_fini(iter, &iter->iter_node, iter_pool);
21000Sstevel@tonic-gate 	uu_free(iter);
21010Sstevel@tonic-gate }
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate static int
21040Sstevel@tonic-gate handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out)
21050Sstevel@tonic-gate {
21060Sstevel@tonic-gate 	struct rep_protocol_entity_get request;
21070Sstevel@tonic-gate 	struct rep_protocol_name_response response;
21080Sstevel@tonic-gate 	ssize_t r;
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate 	if (handle != out->rd_d.rd_handle)
21130Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_GET;
21160Sstevel@tonic-gate 	request.rpr_entityid = out->rd_d.rd_entity;
21170Sstevel@tonic-gate 	request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE;
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 	datael_finish_reset(&out->rd_d);
21200Sstevel@tonic-gate 	r = make_door_call(handle, &request, sizeof (request),
21210Sstevel@tonic-gate 	    &response, sizeof (response));
21220Sstevel@tonic-gate 
21230Sstevel@tonic-gate 	if (r < 0)
21240Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
21270Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 	return (SCF_SUCCESS);
21300Sstevel@tonic-gate }
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate int
21330Sstevel@tonic-gate scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
21340Sstevel@tonic-gate {
21350Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
21360Sstevel@tonic-gate 	if (h != handle)
21370Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
21400Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
21430Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
21440Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_BOUND));
21450Sstevel@tonic-gate 	}
21460Sstevel@tonic-gate 
2147*407Sjwadams 	if (!handle_has_server_locked(h)) {
21480Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
21490Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
21500Sstevel@tonic-gate 	}
21510Sstevel@tonic-gate 
21520Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE;
21530Sstevel@tonic-gate 	iter->iter_sequence = 1;
21540Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
21550Sstevel@tonic-gate 	return (0);
21560Sstevel@tonic-gate }
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate int
21590Sstevel@tonic-gate scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out)
21600Sstevel@tonic-gate {
21610Sstevel@tonic-gate 	int ret;
21620Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
21630Sstevel@tonic-gate 
21640Sstevel@tonic-gate 	if (h != out->rd_d.rd_handle)
21650Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
21680Sstevel@tonic-gate 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
21690Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
21700Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
21710Sstevel@tonic-gate 	}
21720Sstevel@tonic-gate 	if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) {
21730Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
21740Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
21750Sstevel@tonic-gate 	}
21760Sstevel@tonic-gate 	if (iter->iter_sequence == 1) {
21770Sstevel@tonic-gate 		if ((ret = handle_get_local_scope_locked(h, out)) ==
21780Sstevel@tonic-gate 		    SCF_SUCCESS) {
21790Sstevel@tonic-gate 			iter->iter_sequence++;
21800Sstevel@tonic-gate 			ret = 1;
21810Sstevel@tonic-gate 		}
21820Sstevel@tonic-gate 	} else {
21830Sstevel@tonic-gate 		datael_reset_locked(&out->rd_d);
21840Sstevel@tonic-gate 		ret = 0;
21850Sstevel@tonic-gate 	}
21860Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
21870Sstevel@tonic-gate 	return (ret);
21880Sstevel@tonic-gate }
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate int
21910Sstevel@tonic-gate scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out)
21920Sstevel@tonic-gate {
21930Sstevel@tonic-gate 	int ret;
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 	if (h != out->rd_d.rd_handle)
21960Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
21970Sstevel@tonic-gate 
21980Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
21990Sstevel@tonic-gate 	if (strcmp(name, SCF_SCOPE_LOCAL) == 0) {
22000Sstevel@tonic-gate 		ret = handle_get_local_scope_locked(h, out);
22010Sstevel@tonic-gate 	} else {
22020Sstevel@tonic-gate 		datael_reset_locked(&out->rd_d);
22030Sstevel@tonic-gate 		if (uu_check_name(name, 0) == -1)
22040Sstevel@tonic-gate 			ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
22050Sstevel@tonic-gate 		else
22060Sstevel@tonic-gate 			ret = scf_set_error(SCF_ERROR_NOT_FOUND);
22070Sstevel@tonic-gate 	}
22080Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
22090Sstevel@tonic-gate 	return (ret);
22100Sstevel@tonic-gate }
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate static int
22130Sstevel@tonic-gate datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type,
22140Sstevel@tonic-gate     boolean_t composed)
22150Sstevel@tonic-gate {
22160Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate 	struct rep_protocol_iter_start request;
22190Sstevel@tonic-gate 	struct rep_protocol_response response;
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 	ssize_t r;
22220Sstevel@tonic-gate 
22230Sstevel@tonic-gate 	if (h != iter->iter_handle)
22240Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
22270Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
22280Sstevel@tonic-gate 	iter->iter_type = res_type;
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_START;
22310Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
22320Sstevel@tonic-gate 	request.rpr_entity = dp->rd_entity;
22330Sstevel@tonic-gate 	request.rpr_itertype = res_type;
22340Sstevel@tonic-gate 	request.rpr_flags = RP_ITER_START_ALL |
22350Sstevel@tonic-gate 	    (composed ? RP_ITER_START_COMPOSED : 0);
22360Sstevel@tonic-gate 	request.rpr_pattern[0] = 0;
22370Sstevel@tonic-gate 
22380Sstevel@tonic-gate 	datael_finish_reset(dp);
22390Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
22400Sstevel@tonic-gate 	    &response, sizeof (response));
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 	if (r < 0) {
22430Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
22440Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
22450Sstevel@tonic-gate 	}
22460Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
22470Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
22480Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
22490Sstevel@tonic-gate 	}
22500Sstevel@tonic-gate 	iter->iter_sequence++;
22510Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
22520Sstevel@tonic-gate 	return (SCF_SUCCESS);
22530Sstevel@tonic-gate }
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate static int
22560Sstevel@tonic-gate datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp,
22570Sstevel@tonic-gate     const char *pgtype, boolean_t composed)
22580Sstevel@tonic-gate {
22590Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 	struct rep_protocol_iter_start request;
22620Sstevel@tonic-gate 	struct rep_protocol_response response;
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	ssize_t r;
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate 	if (h != iter->iter_handle)
22670Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate 	if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype,
22700Sstevel@tonic-gate 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
22710Sstevel@tonic-gate 		scf_iter_reset(iter);
22720Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
22730Sstevel@tonic-gate 	}
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
22760Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_START;
22770Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
22780Sstevel@tonic-gate 	request.rpr_entity = dp->rd_entity;
22790Sstevel@tonic-gate 	request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP;
22800Sstevel@tonic-gate 	request.rpr_flags = RP_ITER_START_PGTYPE |
22810Sstevel@tonic-gate 	    (composed ? RP_ITER_START_COMPOSED : 0);
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 	datael_finish_reset(dp);
22840Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
22850Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP;
22860Sstevel@tonic-gate 
22870Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
22880Sstevel@tonic-gate 	    &response, sizeof (response));
22890Sstevel@tonic-gate 
22900Sstevel@tonic-gate 	if (r < 0) {
22910Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
22940Sstevel@tonic-gate 	}
22950Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
22960Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
22970Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
22980Sstevel@tonic-gate 	}
22990Sstevel@tonic-gate 	iter->iter_sequence++;
23000Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
23010Sstevel@tonic-gate 	return (SCF_SUCCESS);
23020Sstevel@tonic-gate }
23030Sstevel@tonic-gate 
23040Sstevel@tonic-gate static int
23050Sstevel@tonic-gate datael_iter_next(scf_iter_t *iter, scf_datael_t *out)
23060Sstevel@tonic-gate {
23070Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate 	struct rep_protocol_iter_read request;
23100Sstevel@tonic-gate 	struct rep_protocol_response response;
23110Sstevel@tonic-gate 	ssize_t r;
23120Sstevel@tonic-gate 
23130Sstevel@tonic-gate 	if (h != out->rd_handle)
23140Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
23170Sstevel@tonic-gate 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE ||
23180Sstevel@tonic-gate 	    iter->iter_sequence == 1) {
23190Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
23200Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
23210Sstevel@tonic-gate 	}
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 	if (out->rd_type != iter->iter_type) {
23240Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
23250Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
23260Sstevel@tonic-gate 	}
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_READ;
23290Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
23300Sstevel@tonic-gate 	request.rpr_sequence = iter->iter_sequence;
23310Sstevel@tonic-gate 	request.rpr_entityid = out->rd_entity;
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 	datael_finish_reset(out);
23340Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
23350Sstevel@tonic-gate 	    &response, sizeof (response));
23360Sstevel@tonic-gate 
23370Sstevel@tonic-gate 	if (r < 0) {
23380Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
23390Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
23400Sstevel@tonic-gate 	}
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE) {
23430Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
23440Sstevel@tonic-gate 		return (0);
23450Sstevel@tonic-gate 	}
23460Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
23470Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
23480Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
23490Sstevel@tonic-gate 	}
23500Sstevel@tonic-gate 	iter->iter_sequence++;
23510Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	return (1);
23540Sstevel@tonic-gate }
23550Sstevel@tonic-gate 
23560Sstevel@tonic-gate int
23570Sstevel@tonic-gate scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s)
23580Sstevel@tonic-gate {
23590Sstevel@tonic-gate 	return (datael_setup_iter(iter, &s->rd_d,
23600Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SERVICE, 0));
23610Sstevel@tonic-gate }
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate int
23640Sstevel@tonic-gate scf_iter_next_service(scf_iter_t *iter, scf_service_t *out)
23650Sstevel@tonic-gate {
23660Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
23670Sstevel@tonic-gate }
23680Sstevel@tonic-gate 
23690Sstevel@tonic-gate int
23700Sstevel@tonic-gate scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc)
23710Sstevel@tonic-gate {
23720Sstevel@tonic-gate 	return (datael_setup_iter(iter, &svc->rd_d,
23730Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_INSTANCE, 0));
23740Sstevel@tonic-gate }
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate int
23770Sstevel@tonic-gate scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out)
23780Sstevel@tonic-gate {
23790Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
23800Sstevel@tonic-gate }
23810Sstevel@tonic-gate 
23820Sstevel@tonic-gate int
23830Sstevel@tonic-gate scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc)
23840Sstevel@tonic-gate {
23850Sstevel@tonic-gate 	return (datael_setup_iter(iter, &svc->rd_d,
23860Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
23870Sstevel@tonic-gate }
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate int
23900Sstevel@tonic-gate scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc,
23910Sstevel@tonic-gate     const char *type)
23920Sstevel@tonic-gate {
23930Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0));
23940Sstevel@tonic-gate }
23950Sstevel@tonic-gate 
23960Sstevel@tonic-gate int
23970Sstevel@tonic-gate scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst)
23980Sstevel@tonic-gate {
23990Sstevel@tonic-gate 	return (datael_setup_iter(iter, &inst->rd_d,
24000Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SNAPSHOT, 0));
24010Sstevel@tonic-gate }
24020Sstevel@tonic-gate 
24030Sstevel@tonic-gate int
24040Sstevel@tonic-gate scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out)
24050Sstevel@tonic-gate {
24060Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
24070Sstevel@tonic-gate }
24080Sstevel@tonic-gate 
24090Sstevel@tonic-gate int
24100Sstevel@tonic-gate scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst)
24110Sstevel@tonic-gate {
24120Sstevel@tonic-gate 	return (datael_setup_iter(iter, &inst->rd_d,
24130Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
24140Sstevel@tonic-gate }
24150Sstevel@tonic-gate 
24160Sstevel@tonic-gate int
24170Sstevel@tonic-gate scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst,
24180Sstevel@tonic-gate     const char *type)
24190Sstevel@tonic-gate {
24200Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
24210Sstevel@tonic-gate }
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate int
24240Sstevel@tonic-gate scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst,
24250Sstevel@tonic-gate     const scf_snapshot_t *snap)
24260Sstevel@tonic-gate {
24270Sstevel@tonic-gate 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
24280Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate 	return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d,
24310Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 1));
24320Sstevel@tonic-gate }
24330Sstevel@tonic-gate 
24340Sstevel@tonic-gate int
24350Sstevel@tonic-gate scf_iter_instance_pgs_typed_composed(scf_iter_t *iter,
24360Sstevel@tonic-gate     const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type)
24370Sstevel@tonic-gate {
24380Sstevel@tonic-gate 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
24390Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
24400Sstevel@tonic-gate 
24410Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter,
24420Sstevel@tonic-gate 	    snap ? &snap->rd_d : &inst->rd_d, type, 1));
24430Sstevel@tonic-gate }
24440Sstevel@tonic-gate 
24450Sstevel@tonic-gate int
24460Sstevel@tonic-gate scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst)
24470Sstevel@tonic-gate {
24480Sstevel@tonic-gate 	return (datael_setup_iter(iter, &inst->rd_d,
24490Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
24500Sstevel@tonic-gate }
24510Sstevel@tonic-gate 
24520Sstevel@tonic-gate int
24530Sstevel@tonic-gate scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst,
24540Sstevel@tonic-gate     const char *type)
24550Sstevel@tonic-gate {
24560Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
24570Sstevel@tonic-gate }
24580Sstevel@tonic-gate 
24590Sstevel@tonic-gate int
24600Sstevel@tonic-gate scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out)
24610Sstevel@tonic-gate {
24620Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
24630Sstevel@tonic-gate }
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate int
24660Sstevel@tonic-gate scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg)
24670Sstevel@tonic-gate {
24680Sstevel@tonic-gate 	return (datael_setup_iter(iter, &pg->rd_d,
24690Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTY, 0));
24700Sstevel@tonic-gate }
24710Sstevel@tonic-gate 
24720Sstevel@tonic-gate int
24730Sstevel@tonic-gate scf_iter_next_property(scf_iter_t *iter, scf_property_t *out)
24740Sstevel@tonic-gate {
24750Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
24760Sstevel@tonic-gate }
24770Sstevel@tonic-gate 
24780Sstevel@tonic-gate /*
24790Sstevel@tonic-gate  * Fails with
24800Sstevel@tonic-gate  *   _INVALID_ARGUMENT - handle is NULL
24810Sstevel@tonic-gate  *   _INTERNAL - server response too big
24820Sstevel@tonic-gate  *		 entity already set up with different type
24830Sstevel@tonic-gate  *   _NO_RESOURCES
24840Sstevel@tonic-gate  *   _NO_MEMORY
24850Sstevel@tonic-gate  */
24860Sstevel@tonic-gate scf_scope_t *
24870Sstevel@tonic-gate scf_scope_create(scf_handle_t *handle)
24880Sstevel@tonic-gate {
24890Sstevel@tonic-gate 	scf_scope_t *ret;
24900Sstevel@tonic-gate 
24910Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
24920Sstevel@tonic-gate 	if (ret != NULL) {
24930Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
24940Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SCOPE) == -1) {
24950Sstevel@tonic-gate 			uu_free(ret);
24960Sstevel@tonic-gate 			return (NULL);
24970Sstevel@tonic-gate 		}
24980Sstevel@tonic-gate 	} else {
24990Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
25000Sstevel@tonic-gate 	}
25010Sstevel@tonic-gate 
25020Sstevel@tonic-gate 	return (ret);
25030Sstevel@tonic-gate }
25040Sstevel@tonic-gate 
25050Sstevel@tonic-gate scf_handle_t *
25060Sstevel@tonic-gate scf_scope_handle(const scf_scope_t *val)
25070Sstevel@tonic-gate {
25080Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
25090Sstevel@tonic-gate }
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate void
25120Sstevel@tonic-gate scf_scope_destroy(scf_scope_t *val)
25130Sstevel@tonic-gate {
25140Sstevel@tonic-gate 	if (val == NULL)
25150Sstevel@tonic-gate 		return;
25160Sstevel@tonic-gate 
25170Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
25180Sstevel@tonic-gate 	uu_free(val);
25190Sstevel@tonic-gate }
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate ssize_t
25220Sstevel@tonic-gate scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len)
25230Sstevel@tonic-gate {
25240Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
25250Sstevel@tonic-gate }
25260Sstevel@tonic-gate 
25270Sstevel@tonic-gate /*ARGSUSED*/
25280Sstevel@tonic-gate int
25290Sstevel@tonic-gate scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent)
25300Sstevel@tonic-gate {
25310Sstevel@tonic-gate 	char name[1];
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate 	/* fake up the side-effects */
25340Sstevel@tonic-gate 	datael_reset(&parent->rd_d);
25350Sstevel@tonic-gate 	if (scf_scope_get_name(child, name, sizeof (name)) < 0)
25360Sstevel@tonic-gate 		return (-1);
25370Sstevel@tonic-gate 	return (scf_set_error(SCF_ERROR_NOT_FOUND));
25380Sstevel@tonic-gate }
25390Sstevel@tonic-gate 
25400Sstevel@tonic-gate /*
25410Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
25420Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
25430Sstevel@tonic-gate  */
25440Sstevel@tonic-gate scf_service_t *
25450Sstevel@tonic-gate scf_service_create(scf_handle_t *handle)
25460Sstevel@tonic-gate {
25470Sstevel@tonic-gate 	scf_service_t *ret;
25480Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
25490Sstevel@tonic-gate 	if (ret != NULL) {
25500Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
25510Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SERVICE) == -1) {
25520Sstevel@tonic-gate 			uu_free(ret);
25530Sstevel@tonic-gate 			return (NULL);
25540Sstevel@tonic-gate 		}
25550Sstevel@tonic-gate 	} else {
25560Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
25570Sstevel@tonic-gate 	}
25580Sstevel@tonic-gate 
25590Sstevel@tonic-gate 	return (ret);
25600Sstevel@tonic-gate }
25610Sstevel@tonic-gate 
25620Sstevel@tonic-gate int
25630Sstevel@tonic-gate scf_scope_add_service(const scf_scope_t *scope, const char *name,
25640Sstevel@tonic-gate     scf_service_t *svc)
25650Sstevel@tonic-gate {
25660Sstevel@tonic-gate 	return (datael_add_child(&scope->rd_d, name,
25670Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL));
25680Sstevel@tonic-gate }
25690Sstevel@tonic-gate 
25700Sstevel@tonic-gate int
25710Sstevel@tonic-gate scf_scope_get_service(const scf_scope_t *s, const char *name,
25720Sstevel@tonic-gate     scf_service_t *svc)
25730Sstevel@tonic-gate {
25740Sstevel@tonic-gate 	return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE,
25750Sstevel@tonic-gate 	    svc ? &svc->rd_d : NULL, 0));
25760Sstevel@tonic-gate }
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate scf_handle_t *
25790Sstevel@tonic-gate scf_service_handle(const scf_service_t *val)
25800Sstevel@tonic-gate {
25810Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
25820Sstevel@tonic-gate }
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate int
25850Sstevel@tonic-gate scf_service_delete(scf_service_t *svc)
25860Sstevel@tonic-gate {
25870Sstevel@tonic-gate 	return (datael_delete(&svc->rd_d));
25880Sstevel@tonic-gate }
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate int
25910Sstevel@tonic-gate scf_instance_delete(scf_instance_t *inst)
25920Sstevel@tonic-gate {
25930Sstevel@tonic-gate 	return (datael_delete(&inst->rd_d));
25940Sstevel@tonic-gate }
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate int
25970Sstevel@tonic-gate scf_pg_delete(scf_propertygroup_t *pg)
25980Sstevel@tonic-gate {
25990Sstevel@tonic-gate 	return (datael_delete(&pg->rd_d));
26000Sstevel@tonic-gate }
26010Sstevel@tonic-gate 
26020Sstevel@tonic-gate int
26030Sstevel@tonic-gate _scf_snapshot_delete(scf_snapshot_t *snap)
26040Sstevel@tonic-gate {
26050Sstevel@tonic-gate 	return (datael_delete(&snap->rd_d));
26060Sstevel@tonic-gate }
26070Sstevel@tonic-gate 
26080Sstevel@tonic-gate int
26090Sstevel@tonic-gate scf_service_add_instance(const scf_service_t *svc, const char *name,
26100Sstevel@tonic-gate     scf_instance_t *instance)
26110Sstevel@tonic-gate {
26120Sstevel@tonic-gate 	return (datael_add_child(&svc->rd_d, name,
26130Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_INSTANCE,
26140Sstevel@tonic-gate 	    (instance != NULL)? &instance->rd_d : NULL));
26150Sstevel@tonic-gate }
26160Sstevel@tonic-gate 
26170Sstevel@tonic-gate int
26180Sstevel@tonic-gate scf_service_get_instance(const scf_service_t *svc, const char *name,
26190Sstevel@tonic-gate     scf_instance_t *inst)
26200Sstevel@tonic-gate {
26210Sstevel@tonic-gate 	return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE,
26220Sstevel@tonic-gate 	    inst ? &inst->rd_d : NULL, 0));
26230Sstevel@tonic-gate }
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate int
26260Sstevel@tonic-gate scf_service_add_pg(const scf_service_t *svc, const char *name,
26270Sstevel@tonic-gate     const char *type, uint32_t flags, scf_propertygroup_t *pg)
26280Sstevel@tonic-gate {
26290Sstevel@tonic-gate 	return (datael_add_pg(&svc->rd_d, name, type, flags,
26300Sstevel@tonic-gate 	    (pg != NULL)?&pg->rd_d : NULL));
26310Sstevel@tonic-gate }
26320Sstevel@tonic-gate 
26330Sstevel@tonic-gate int
26340Sstevel@tonic-gate scf_service_get_pg(const scf_service_t *svc, const char *name,
26350Sstevel@tonic-gate     scf_propertygroup_t *pg)
26360Sstevel@tonic-gate {
26370Sstevel@tonic-gate 	return (datael_get_child(&svc->rd_d, name,
26380Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
26390Sstevel@tonic-gate }
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate int
26420Sstevel@tonic-gate scf_instance_add_pg(const scf_instance_t *inst, const char *name,
26430Sstevel@tonic-gate     const char *type, uint32_t flags, scf_propertygroup_t *pg)
26440Sstevel@tonic-gate {
26450Sstevel@tonic-gate 	return (datael_add_pg(&inst->rd_d, name, type, flags,
26460Sstevel@tonic-gate 	    (pg != NULL)?&pg->rd_d : NULL));
26470Sstevel@tonic-gate }
26480Sstevel@tonic-gate 
26490Sstevel@tonic-gate int
26500Sstevel@tonic-gate scf_instance_get_snapshot(const scf_instance_t *inst, const char *name,
26510Sstevel@tonic-gate     scf_snapshot_t *pg)
26520Sstevel@tonic-gate {
26530Sstevel@tonic-gate 	return (datael_get_child(&inst->rd_d, name,
26540Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0));
26550Sstevel@tonic-gate }
26560Sstevel@tonic-gate 
26570Sstevel@tonic-gate int
26580Sstevel@tonic-gate scf_instance_get_pg(const scf_instance_t *inst, const char *name,
26590Sstevel@tonic-gate     scf_propertygroup_t *pg)
26600Sstevel@tonic-gate {
26610Sstevel@tonic-gate 	return (datael_get_child(&inst->rd_d, name,
26620Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
26630Sstevel@tonic-gate }
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate int
26660Sstevel@tonic-gate scf_instance_get_pg_composed(const scf_instance_t *inst,
26670Sstevel@tonic-gate     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
26680Sstevel@tonic-gate {
26690Sstevel@tonic-gate 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
26700Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate 	return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name,
26730Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1));
26740Sstevel@tonic-gate }
26750Sstevel@tonic-gate 
26760Sstevel@tonic-gate int
26770Sstevel@tonic-gate scf_pg_get_property(const scf_propertygroup_t *pg, const char *name,
26780Sstevel@tonic-gate     scf_property_t *prop)
26790Sstevel@tonic-gate {
26800Sstevel@tonic-gate 	return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY,
26810Sstevel@tonic-gate 	    prop ? &prop->rd_d : NULL, 0));
26820Sstevel@tonic-gate }
26830Sstevel@tonic-gate 
26840Sstevel@tonic-gate void
26850Sstevel@tonic-gate scf_service_destroy(scf_service_t *val)
26860Sstevel@tonic-gate {
26870Sstevel@tonic-gate 	if (val == NULL)
26880Sstevel@tonic-gate 		return;
26890Sstevel@tonic-gate 
26900Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
26910Sstevel@tonic-gate 	uu_free(val);
26920Sstevel@tonic-gate }
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate ssize_t
26950Sstevel@tonic-gate scf_service_get_name(const scf_service_t *rep, char *out, size_t len)
26960Sstevel@tonic-gate {
26970Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
26980Sstevel@tonic-gate }
26990Sstevel@tonic-gate 
27000Sstevel@tonic-gate /*
27010Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
27020Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
27030Sstevel@tonic-gate  */
27040Sstevel@tonic-gate scf_instance_t *
27050Sstevel@tonic-gate scf_instance_create(scf_handle_t *handle)
27060Sstevel@tonic-gate {
27070Sstevel@tonic-gate 	scf_instance_t *ret;
27080Sstevel@tonic-gate 
27090Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
27100Sstevel@tonic-gate 	if (ret != NULL) {
27110Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
27120Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
27130Sstevel@tonic-gate 			uu_free(ret);
27140Sstevel@tonic-gate 			return (NULL);
27150Sstevel@tonic-gate 		}
27160Sstevel@tonic-gate 	} else {
27170Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
27180Sstevel@tonic-gate 	}
27190Sstevel@tonic-gate 
27200Sstevel@tonic-gate 	return (ret);
27210Sstevel@tonic-gate }
27220Sstevel@tonic-gate 
27230Sstevel@tonic-gate scf_handle_t *
27240Sstevel@tonic-gate scf_instance_handle(const scf_instance_t *val)
27250Sstevel@tonic-gate {
27260Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
27270Sstevel@tonic-gate }
27280Sstevel@tonic-gate 
27290Sstevel@tonic-gate void
27300Sstevel@tonic-gate scf_instance_destroy(scf_instance_t *val)
27310Sstevel@tonic-gate {
27320Sstevel@tonic-gate 	if (val == NULL)
27330Sstevel@tonic-gate 		return;
27340Sstevel@tonic-gate 
27350Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
27360Sstevel@tonic-gate 	uu_free(val);
27370Sstevel@tonic-gate }
27380Sstevel@tonic-gate 
27390Sstevel@tonic-gate ssize_t
27400Sstevel@tonic-gate scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len)
27410Sstevel@tonic-gate {
27420Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
27430Sstevel@tonic-gate }
27440Sstevel@tonic-gate 
27450Sstevel@tonic-gate /*
27460Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
27470Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
27480Sstevel@tonic-gate  */
27490Sstevel@tonic-gate scf_snapshot_t *
27500Sstevel@tonic-gate scf_snapshot_create(scf_handle_t *handle)
27510Sstevel@tonic-gate {
27520Sstevel@tonic-gate 	scf_snapshot_t *ret;
27530Sstevel@tonic-gate 
27540Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
27550Sstevel@tonic-gate 	if (ret != NULL) {
27560Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
27570Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
27580Sstevel@tonic-gate 			uu_free(ret);
27590Sstevel@tonic-gate 			return (NULL);
27600Sstevel@tonic-gate 		}
27610Sstevel@tonic-gate 	} else {
27620Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
27630Sstevel@tonic-gate 	}
27640Sstevel@tonic-gate 
27650Sstevel@tonic-gate 	return (ret);
27660Sstevel@tonic-gate }
27670Sstevel@tonic-gate 
27680Sstevel@tonic-gate scf_handle_t *
27690Sstevel@tonic-gate scf_snapshot_handle(const scf_snapshot_t *val)
27700Sstevel@tonic-gate {
27710Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
27720Sstevel@tonic-gate }
27730Sstevel@tonic-gate 
27740Sstevel@tonic-gate void
27750Sstevel@tonic-gate scf_snapshot_destroy(scf_snapshot_t *val)
27760Sstevel@tonic-gate {
27770Sstevel@tonic-gate 	if (val == NULL)
27780Sstevel@tonic-gate 		return;
27790Sstevel@tonic-gate 
27800Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
27810Sstevel@tonic-gate 	uu_free(val);
27820Sstevel@tonic-gate }
27830Sstevel@tonic-gate 
27840Sstevel@tonic-gate ssize_t
27850Sstevel@tonic-gate scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len)
27860Sstevel@tonic-gate {
27870Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
27880Sstevel@tonic-gate }
27890Sstevel@tonic-gate 
27900Sstevel@tonic-gate /*
27910Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
27920Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
27930Sstevel@tonic-gate  */
27940Sstevel@tonic-gate scf_snaplevel_t *
27950Sstevel@tonic-gate scf_snaplevel_create(scf_handle_t *handle)
27960Sstevel@tonic-gate {
27970Sstevel@tonic-gate 	scf_snaplevel_t *ret;
27980Sstevel@tonic-gate 
27990Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
28000Sstevel@tonic-gate 	if (ret != NULL) {
28010Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
28020Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
28030Sstevel@tonic-gate 			uu_free(ret);
28040Sstevel@tonic-gate 			return (NULL);
28050Sstevel@tonic-gate 		}
28060Sstevel@tonic-gate 	} else {
28070Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
28080Sstevel@tonic-gate 	}
28090Sstevel@tonic-gate 
28100Sstevel@tonic-gate 	return (ret);
28110Sstevel@tonic-gate }
28120Sstevel@tonic-gate 
28130Sstevel@tonic-gate scf_handle_t *
28140Sstevel@tonic-gate scf_snaplevel_handle(const scf_snaplevel_t *val)
28150Sstevel@tonic-gate {
28160Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
28170Sstevel@tonic-gate }
28180Sstevel@tonic-gate 
28190Sstevel@tonic-gate void
28200Sstevel@tonic-gate scf_snaplevel_destroy(scf_snaplevel_t *val)
28210Sstevel@tonic-gate {
28220Sstevel@tonic-gate 	if (val == NULL)
28230Sstevel@tonic-gate 		return;
28240Sstevel@tonic-gate 
28250Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
28260Sstevel@tonic-gate 	uu_free(val);
28270Sstevel@tonic-gate }
28280Sstevel@tonic-gate 
28290Sstevel@tonic-gate ssize_t
28300Sstevel@tonic-gate scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len)
28310Sstevel@tonic-gate {
28320Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len,
28330Sstevel@tonic-gate 	    RP_ENTITY_NAME_SNAPLEVEL_SCOPE));
28340Sstevel@tonic-gate }
28350Sstevel@tonic-gate 
28360Sstevel@tonic-gate ssize_t
28370Sstevel@tonic-gate scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out,
28380Sstevel@tonic-gate     size_t len)
28390Sstevel@tonic-gate {
28400Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len,
28410Sstevel@tonic-gate 	    RP_ENTITY_NAME_SNAPLEVEL_SERVICE));
28420Sstevel@tonic-gate }
28430Sstevel@tonic-gate 
28440Sstevel@tonic-gate ssize_t
28450Sstevel@tonic-gate scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out,
28460Sstevel@tonic-gate     size_t len)
28470Sstevel@tonic-gate {
28480Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len,
28490Sstevel@tonic-gate 	    RP_ENTITY_NAME_SNAPLEVEL_INSTANCE));
28500Sstevel@tonic-gate }
28510Sstevel@tonic-gate 
28520Sstevel@tonic-gate int
28530Sstevel@tonic-gate scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name,
28540Sstevel@tonic-gate     scf_propertygroup_t *pg)
28550Sstevel@tonic-gate {
28560Sstevel@tonic-gate 	return (datael_get_child(&snap->rd_d, name,
28570Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
28580Sstevel@tonic-gate }
28590Sstevel@tonic-gate 
28600Sstevel@tonic-gate static int
28610Sstevel@tonic-gate snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg)
28620Sstevel@tonic-gate {
28630Sstevel@tonic-gate 	scf_handle_t *h = src->rd_handle;
28640Sstevel@tonic-gate 	scf_snaplevel_t *dst = dst_arg;
28650Sstevel@tonic-gate 	struct rep_protocol_entity_pair request;
28660Sstevel@tonic-gate 	struct rep_protocol_response response;
28670Sstevel@tonic-gate 	int r;
28680Sstevel@tonic-gate 	int dups = 0;
28690Sstevel@tonic-gate 
28700Sstevel@tonic-gate 	if (h != dst->rd_d.rd_handle)
28710Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate 	if (src == &dst->rd_d) {
28740Sstevel@tonic-gate 		dups = 1;
28750Sstevel@tonic-gate 		dst = HANDLE_HOLD_SNAPLVL(h);
28760Sstevel@tonic-gate 	}
28770Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
28780Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL;
28790Sstevel@tonic-gate 	request.rpr_entity_src = src->rd_entity;
28800Sstevel@tonic-gate 	request.rpr_entity_dst = dst->rd_d.rd_entity;
28810Sstevel@tonic-gate 
28820Sstevel@tonic-gate 	datael_finish_reset(src);
28830Sstevel@tonic-gate 	datael_finish_reset(&dst->rd_d);
28840Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
28850Sstevel@tonic-gate 	    &response, sizeof (response));
28860Sstevel@tonic-gate 	/*
28870Sstevel@tonic-gate 	 * if we succeeded, we need to swap dst and dst_arg's identity.  We
28880Sstevel@tonic-gate 	 * take advantage of the fact that the only in-library knowledge is
28890Sstevel@tonic-gate 	 * their entity ids.
28900Sstevel@tonic-gate 	 */
28910Sstevel@tonic-gate 	if (dups && r >= 0 &&
28920Sstevel@tonic-gate 	    (response.rpr_response == REP_PROTOCOL_SUCCESS ||
28930Sstevel@tonic-gate 	    response.rpr_response == REP_PROTOCOL_DONE)) {
28940Sstevel@tonic-gate 		int entity = dst->rd_d.rd_entity;
28950Sstevel@tonic-gate 
28960Sstevel@tonic-gate 		dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity;
28970Sstevel@tonic-gate 		dst_arg->rd_d.rd_entity = entity;
28980Sstevel@tonic-gate 	}
28990Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
29000Sstevel@tonic-gate 
29010Sstevel@tonic-gate 	if (dups)
29020Sstevel@tonic-gate 		HANDLE_RELE_SNAPLVL(h);
29030Sstevel@tonic-gate 
29040Sstevel@tonic-gate 	if (r < 0)
29050Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
29060Sstevel@tonic-gate 
29070Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
29080Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_DONE) {
29090Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
29100Sstevel@tonic-gate 	}
29110Sstevel@tonic-gate 
29120Sstevel@tonic-gate 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
29130Sstevel@tonic-gate 	    SCF_SUCCESS : SCF_COMPLETE;
29140Sstevel@tonic-gate }
29150Sstevel@tonic-gate 
29160Sstevel@tonic-gate int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base,
29170Sstevel@tonic-gate     scf_snaplevel_t *out)
29180Sstevel@tonic-gate {
29190Sstevel@tonic-gate 	return (snaplevel_next(&base->rd_d, out));
29200Sstevel@tonic-gate }
29210Sstevel@tonic-gate 
29220Sstevel@tonic-gate int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base,
29230Sstevel@tonic-gate     scf_snaplevel_t *out)
29240Sstevel@tonic-gate {
29250Sstevel@tonic-gate 	return (snaplevel_next(&base->rd_d, out));
29260Sstevel@tonic-gate }
29270Sstevel@tonic-gate 
29280Sstevel@tonic-gate /*
29290Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
29300Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
29310Sstevel@tonic-gate  */
29320Sstevel@tonic-gate scf_propertygroup_t *
29330Sstevel@tonic-gate scf_pg_create(scf_handle_t *handle)
29340Sstevel@tonic-gate {
29350Sstevel@tonic-gate 	scf_propertygroup_t *ret;
29360Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
29370Sstevel@tonic-gate 	if (ret != NULL) {
29380Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
29390Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
29400Sstevel@tonic-gate 			uu_free(ret);
29410Sstevel@tonic-gate 			return (NULL);
29420Sstevel@tonic-gate 		}
29430Sstevel@tonic-gate 	} else {
29440Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
29450Sstevel@tonic-gate 	}
29460Sstevel@tonic-gate 
29470Sstevel@tonic-gate 	return (ret);
29480Sstevel@tonic-gate }
29490Sstevel@tonic-gate 
29500Sstevel@tonic-gate scf_handle_t *
29510Sstevel@tonic-gate scf_pg_handle(const scf_propertygroup_t *val)
29520Sstevel@tonic-gate {
29530Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
29540Sstevel@tonic-gate }
29550Sstevel@tonic-gate 
29560Sstevel@tonic-gate void
29570Sstevel@tonic-gate scf_pg_destroy(scf_propertygroup_t *val)
29580Sstevel@tonic-gate {
29590Sstevel@tonic-gate 	if (val == NULL)
29600Sstevel@tonic-gate 		return;
29610Sstevel@tonic-gate 
29620Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
29630Sstevel@tonic-gate 	uu_free(val);
29640Sstevel@tonic-gate }
29650Sstevel@tonic-gate 
29660Sstevel@tonic-gate ssize_t
29670Sstevel@tonic-gate scf_pg_get_name(const scf_propertygroup_t *pg,  char *out, size_t len)
29680Sstevel@tonic-gate {
29690Sstevel@tonic-gate 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME));
29700Sstevel@tonic-gate }
29710Sstevel@tonic-gate 
29720Sstevel@tonic-gate ssize_t
29730Sstevel@tonic-gate scf_pg_get_type(const scf_propertygroup_t *pg,  char *out, size_t len)
29740Sstevel@tonic-gate {
29750Sstevel@tonic-gate 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_PGTYPE));
29760Sstevel@tonic-gate }
29770Sstevel@tonic-gate 
29780Sstevel@tonic-gate int
29790Sstevel@tonic-gate scf_pg_get_flags(const scf_propertygroup_t *pg, uint32_t *out)
29800Sstevel@tonic-gate {
29810Sstevel@tonic-gate 	char buf[REP_PROTOCOL_NAME_LEN];
29820Sstevel@tonic-gate 	ssize_t res;
29830Sstevel@tonic-gate 
29840Sstevel@tonic-gate 	res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
29850Sstevel@tonic-gate 	    RP_ENTITY_NAME_PGFLAGS);
29860Sstevel@tonic-gate 
29870Sstevel@tonic-gate 	if (res == -1)
29880Sstevel@tonic-gate 		return (-1);
29890Sstevel@tonic-gate 
29900Sstevel@tonic-gate 	if (uu_strtouint(buf, out, sizeof (*out), 0, 0, UINT32_MAX) == -1)
29910Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
29920Sstevel@tonic-gate 
29930Sstevel@tonic-gate 	return (0);
29940Sstevel@tonic-gate }
29950Sstevel@tonic-gate 
29960Sstevel@tonic-gate static int
29970Sstevel@tonic-gate datael_update(scf_datael_t *dp)
29980Sstevel@tonic-gate {
29990Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
30000Sstevel@tonic-gate 
30010Sstevel@tonic-gate 	struct rep_protocol_entity_update request;
30020Sstevel@tonic-gate 	struct rep_protocol_response response;
30030Sstevel@tonic-gate 
30040Sstevel@tonic-gate 	int r;
30050Sstevel@tonic-gate 
30060Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
30070Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_UPDATE;
30080Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
30090Sstevel@tonic-gate 
30100Sstevel@tonic-gate 	datael_finish_reset(dp);
3011*407Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
30120Sstevel@tonic-gate 
30130Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
30140Sstevel@tonic-gate 	    &response, sizeof (response));
30150Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
30160Sstevel@tonic-gate 
30170Sstevel@tonic-gate 	if (r < 0)
30180Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
30190Sstevel@tonic-gate 
30200Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
30210Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_DONE) {
30220Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
30230Sstevel@tonic-gate 	}
30240Sstevel@tonic-gate 
30250Sstevel@tonic-gate 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
30260Sstevel@tonic-gate 	    SCF_SUCCESS : SCF_COMPLETE;
30270Sstevel@tonic-gate }
30280Sstevel@tonic-gate 
30290Sstevel@tonic-gate int
30300Sstevel@tonic-gate scf_pg_update(scf_propertygroup_t *pg)
30310Sstevel@tonic-gate {
30320Sstevel@tonic-gate 	return (datael_update(&pg->rd_d));
30330Sstevel@tonic-gate }
30340Sstevel@tonic-gate 
30350Sstevel@tonic-gate int
30360Sstevel@tonic-gate scf_snapshot_update(scf_snapshot_t *snap)
30370Sstevel@tonic-gate {
30380Sstevel@tonic-gate 	return (datael_update(&snap->rd_d));
30390Sstevel@tonic-gate }
30400Sstevel@tonic-gate 
30410Sstevel@tonic-gate int
30420Sstevel@tonic-gate _scf_pg_wait(scf_propertygroup_t *pg, int timeout)
30430Sstevel@tonic-gate {
30440Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
30450Sstevel@tonic-gate 
30460Sstevel@tonic-gate 	struct rep_protocol_propertygrp_request request;
30470Sstevel@tonic-gate 	struct rep_protocol_response response;
30480Sstevel@tonic-gate 
30490Sstevel@tonic-gate 	struct pollfd pollfd;
30500Sstevel@tonic-gate 
30510Sstevel@tonic-gate 	int r;
30520Sstevel@tonic-gate 
30530Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
30540Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT;
30550Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
30560Sstevel@tonic-gate 
30570Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
30580Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
30590Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
30600Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
30610Sstevel@tonic-gate 	}
30620Sstevel@tonic-gate 	r = make_door_call_retfd(h->rh_doorfd, &request, sizeof (request),
30630Sstevel@tonic-gate 	    &response, sizeof (response), &pollfd.fd);
30640Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
30650Sstevel@tonic-gate 
30660Sstevel@tonic-gate 	if (r < 0)
30670Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
30680Sstevel@tonic-gate 
30690Sstevel@tonic-gate 	assert((response.rpr_response == REP_PROTOCOL_SUCCESS) ==
30700Sstevel@tonic-gate 	    (pollfd.fd != -1));
30710Sstevel@tonic-gate 
30720Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_LATEST)
30730Sstevel@tonic-gate 		return (SCF_SUCCESS);
30740Sstevel@tonic-gate 
30750Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
30760Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
30770Sstevel@tonic-gate 
30780Sstevel@tonic-gate 	pollfd.events = 0;
30790Sstevel@tonic-gate 	pollfd.revents = 0;
30800Sstevel@tonic-gate 
30810Sstevel@tonic-gate 	r = poll(&pollfd, 1, timeout * MILLISEC);
30820Sstevel@tonic-gate 
30830Sstevel@tonic-gate 	(void) close(pollfd.fd);
30840Sstevel@tonic-gate 	return (pollfd.revents ? SCF_SUCCESS : SCF_COMPLETE);
30850Sstevel@tonic-gate }
30860Sstevel@tonic-gate 
30870Sstevel@tonic-gate static int
30880Sstevel@tonic-gate scf_notify_add_pattern(scf_handle_t *h, int type, const char *name)
30890Sstevel@tonic-gate {
30900Sstevel@tonic-gate 	struct rep_protocol_notify_request request;
30910Sstevel@tonic-gate 	struct rep_protocol_response response;
30920Sstevel@tonic-gate 	int r;
30930Sstevel@tonic-gate 
30940Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
30950Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_CLIENT_ADD_NOTIFY;
30960Sstevel@tonic-gate 	request.rpr_type = type;
30970Sstevel@tonic-gate 	(void) strlcpy(request.rpr_pattern, name, sizeof (request.rpr_pattern));
30980Sstevel@tonic-gate 
30990Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
31000Sstevel@tonic-gate 	    &response, sizeof (response));
31010Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
31020Sstevel@tonic-gate 
31030Sstevel@tonic-gate 	if (r < 0)
31040Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
31050Sstevel@tonic-gate 
31060Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
31070Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
31080Sstevel@tonic-gate 
31090Sstevel@tonic-gate 	return (SCF_SUCCESS);
31100Sstevel@tonic-gate }
31110Sstevel@tonic-gate 
31120Sstevel@tonic-gate int
31130Sstevel@tonic-gate _scf_notify_add_pgname(scf_handle_t *h, const char *name)
31140Sstevel@tonic-gate {
31150Sstevel@tonic-gate 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGNAME, name));
31160Sstevel@tonic-gate }
31170Sstevel@tonic-gate 
31180Sstevel@tonic-gate int
31190Sstevel@tonic-gate _scf_notify_add_pgtype(scf_handle_t *h, const char *type)
31200Sstevel@tonic-gate {
31210Sstevel@tonic-gate 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGTYPE, type));
31220Sstevel@tonic-gate }
31230Sstevel@tonic-gate 
31240Sstevel@tonic-gate int
31250Sstevel@tonic-gate _scf_notify_wait(scf_propertygroup_t *pg, char *out, size_t sz)
31260Sstevel@tonic-gate {
31270Sstevel@tonic-gate 	struct rep_protocol_wait_request request;
31280Sstevel@tonic-gate 	struct rep_protocol_fmri_response response;
31290Sstevel@tonic-gate 
31300Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
31310Sstevel@tonic-gate 	int dummy;
31320Sstevel@tonic-gate 	int fd;
31330Sstevel@tonic-gate 	int r;
31340Sstevel@tonic-gate 
31350Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
31360Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
31370Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
31380Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
31390Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
31400Sstevel@tonic-gate 	}
31410Sstevel@tonic-gate 	fd = h->rh_doorfd;
31420Sstevel@tonic-gate 	++h->rh_fd_users;
31430Sstevel@tonic-gate 	assert(h->rh_fd_users > 0);
31440Sstevel@tonic-gate 
31450Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_CLIENT_WAIT;
31460Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
31470Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
31480Sstevel@tonic-gate 
31490Sstevel@tonic-gate 	r = make_door_call_retfd(fd, &request, sizeof (request),
31500Sstevel@tonic-gate 	    &response, sizeof (response), &dummy);
31510Sstevel@tonic-gate 
31520Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
31530Sstevel@tonic-gate 	assert(h->rh_fd_users > 0);
31540Sstevel@tonic-gate 	if (--h->rh_fd_users == 0) {
31550Sstevel@tonic-gate 		(void) pthread_cond_broadcast(&h->rh_cv);
31560Sstevel@tonic-gate 		/*
31570Sstevel@tonic-gate 		 * check for a delayed close, now that there are no other
31580Sstevel@tonic-gate 		 * users.
31590Sstevel@tonic-gate 		 */
31600Sstevel@tonic-gate 		if (h->rh_doorfd_old != -1) {
31610Sstevel@tonic-gate 			assert(h->rh_doorfd == -1);
31620Sstevel@tonic-gate 			assert(fd == h->rh_doorfd_old);
31630Sstevel@tonic-gate 			(void) close(h->rh_doorfd_old);
31640Sstevel@tonic-gate 			h->rh_doorfd_old = -1;
31650Sstevel@tonic-gate 		}
31660Sstevel@tonic-gate 	}
31670Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
31680Sstevel@tonic-gate 
31690Sstevel@tonic-gate 	if (r < 0)
31700Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
31710Sstevel@tonic-gate 
31720Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE)
31730Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
31740Sstevel@tonic-gate 
31750Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
31760Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
31770Sstevel@tonic-gate 
31780Sstevel@tonic-gate 	/* the following will be non-zero for delete notifications */
31790Sstevel@tonic-gate 	return (strlcpy(out, response.rpr_fmri, sz));
31800Sstevel@tonic-gate }
31810Sstevel@tonic-gate 
31820Sstevel@tonic-gate static int
31830Sstevel@tonic-gate _scf_snapshot_take(scf_instance_t *inst, const char *name,
31840Sstevel@tonic-gate     scf_snapshot_t *snap, int flags)
31850Sstevel@tonic-gate {
31860Sstevel@tonic-gate 	scf_handle_t *h = inst->rd_d.rd_handle;
31870Sstevel@tonic-gate 
31880Sstevel@tonic-gate 	struct rep_protocol_snapshot_take request;
31890Sstevel@tonic-gate 	struct rep_protocol_response response;
31900Sstevel@tonic-gate 
31910Sstevel@tonic-gate 	int r;
31920Sstevel@tonic-gate 
31930Sstevel@tonic-gate 	if (h != snap->rd_d.rd_handle)
31940Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
31950Sstevel@tonic-gate 
31960Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, (name != NULL)? name : "",
31970Sstevel@tonic-gate 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
31980Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
31990Sstevel@tonic-gate 
32000Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
32010Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE;
32020Sstevel@tonic-gate 	request.rpr_entityid_src = inst->rd_d.rd_entity;
32030Sstevel@tonic-gate 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
32040Sstevel@tonic-gate 	request.rpr_flags = flags;
32050Sstevel@tonic-gate 
32060Sstevel@tonic-gate 	datael_finish_reset(&inst->rd_d);
32070Sstevel@tonic-gate 	datael_finish_reset(&snap->rd_d);
32080Sstevel@tonic-gate 
32090Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
32100Sstevel@tonic-gate 	    &response, sizeof (response));
32110Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
32120Sstevel@tonic-gate 
32130Sstevel@tonic-gate 	if (r < 0)
32140Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
32150Sstevel@tonic-gate 
32160Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
32170Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
32180Sstevel@tonic-gate 
32190Sstevel@tonic-gate 	return (SCF_SUCCESS);
32200Sstevel@tonic-gate }
32210Sstevel@tonic-gate 
32220Sstevel@tonic-gate int
32230Sstevel@tonic-gate _scf_snapshot_take_new_named(scf_instance_t *inst,
32240Sstevel@tonic-gate     const char *svcname, const char *instname, const char *snapname,
32250Sstevel@tonic-gate     scf_snapshot_t *snap)
32260Sstevel@tonic-gate {
32270Sstevel@tonic-gate 	scf_handle_t *h = inst->rd_d.rd_handle;
32280Sstevel@tonic-gate 
32290Sstevel@tonic-gate 	struct rep_protocol_snapshot_take_named request;
32300Sstevel@tonic-gate 	struct rep_protocol_response response;
32310Sstevel@tonic-gate 
32320Sstevel@tonic-gate 	int r;
32330Sstevel@tonic-gate 
32340Sstevel@tonic-gate 	if (h != snap->rd_d.rd_handle)
32350Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
32360Sstevel@tonic-gate 
32370Sstevel@tonic-gate 	if (strlcpy(request.rpr_svcname, svcname,
32380Sstevel@tonic-gate 	    sizeof (request.rpr_svcname)) >= sizeof (request.rpr_svcname))
32390Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
32400Sstevel@tonic-gate 
32410Sstevel@tonic-gate 	if (strlcpy(request.rpr_instname, instname,
32420Sstevel@tonic-gate 	    sizeof (request.rpr_instname)) >= sizeof (request.rpr_instname))
32430Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
32440Sstevel@tonic-gate 
32450Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, snapname,
32460Sstevel@tonic-gate 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
32470Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
32480Sstevel@tonic-gate 
32490Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
32500Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE_NAMED;
32510Sstevel@tonic-gate 	request.rpr_entityid_src = inst->rd_d.rd_entity;
32520Sstevel@tonic-gate 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
32530Sstevel@tonic-gate 
32540Sstevel@tonic-gate 	datael_finish_reset(&inst->rd_d);
32550Sstevel@tonic-gate 	datael_finish_reset(&snap->rd_d);
32560Sstevel@tonic-gate 
32570Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
32580Sstevel@tonic-gate 	    &response, sizeof (response));
32590Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
32600Sstevel@tonic-gate 
32610Sstevel@tonic-gate 	if (r < 0)
32620Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
32630Sstevel@tonic-gate 
32640Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
32650Sstevel@tonic-gate 		assert(response.rpr_response !=
32660Sstevel@tonic-gate 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
32670Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
32680Sstevel@tonic-gate 	}
32690Sstevel@tonic-gate 
32700Sstevel@tonic-gate 	return (SCF_SUCCESS);
32710Sstevel@tonic-gate }
32720Sstevel@tonic-gate 
32730Sstevel@tonic-gate int
32740Sstevel@tonic-gate _scf_snapshot_take_new(scf_instance_t *inst, const char *name,
32750Sstevel@tonic-gate     scf_snapshot_t *snap)
32760Sstevel@tonic-gate {
32770Sstevel@tonic-gate 	return (_scf_snapshot_take(inst, name, snap, REP_SNAPSHOT_NEW));
32780Sstevel@tonic-gate }
32790Sstevel@tonic-gate 
32800Sstevel@tonic-gate int
32810Sstevel@tonic-gate _scf_snapshot_take_attach(scf_instance_t *inst, scf_snapshot_t *snap)
32820Sstevel@tonic-gate {
32830Sstevel@tonic-gate 	return (_scf_snapshot_take(inst, NULL, snap, REP_SNAPSHOT_ATTACH));
32840Sstevel@tonic-gate }
32850Sstevel@tonic-gate 
32860Sstevel@tonic-gate int
32870Sstevel@tonic-gate _scf_snapshot_attach(scf_snapshot_t *src, scf_snapshot_t *dest)
32880Sstevel@tonic-gate {
32890Sstevel@tonic-gate 	scf_handle_t *h = dest->rd_d.rd_handle;
32900Sstevel@tonic-gate 
32910Sstevel@tonic-gate 	struct rep_protocol_snapshot_attach request;
32920Sstevel@tonic-gate 	struct rep_protocol_response response;
32930Sstevel@tonic-gate 
32940Sstevel@tonic-gate 	int r;
32950Sstevel@tonic-gate 
32960Sstevel@tonic-gate 	if (h != src->rd_d.rd_handle)
32970Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
32980Sstevel@tonic-gate 
32990Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
33000Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_ATTACH;
33010Sstevel@tonic-gate 	request.rpr_entityid_src = src->rd_d.rd_entity;
33020Sstevel@tonic-gate 	request.rpr_entityid_dest = dest->rd_d.rd_entity;
33030Sstevel@tonic-gate 
33040Sstevel@tonic-gate 	datael_finish_reset(&src->rd_d);
33050Sstevel@tonic-gate 	datael_finish_reset(&dest->rd_d);
33060Sstevel@tonic-gate 
33070Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
33080Sstevel@tonic-gate 	    &response, sizeof (response));
33090Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
33100Sstevel@tonic-gate 
33110Sstevel@tonic-gate 	if (r < 0)
33120Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
33130Sstevel@tonic-gate 
33140Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
33150Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
33160Sstevel@tonic-gate 
33170Sstevel@tonic-gate 	return (SCF_SUCCESS);
33180Sstevel@tonic-gate }
33190Sstevel@tonic-gate 
33200Sstevel@tonic-gate /*
33210Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
33220Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
33230Sstevel@tonic-gate  */
33240Sstevel@tonic-gate scf_property_t *
33250Sstevel@tonic-gate scf_property_create(scf_handle_t *handle)
33260Sstevel@tonic-gate {
33270Sstevel@tonic-gate 	scf_property_t *ret;
33280Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
33290Sstevel@tonic-gate 	if (ret != NULL) {
33300Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
33310Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_PROPERTY) == -1) {
33320Sstevel@tonic-gate 			uu_free(ret);
33330Sstevel@tonic-gate 			return (NULL);
33340Sstevel@tonic-gate 		}
33350Sstevel@tonic-gate 	} else {
33360Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
33370Sstevel@tonic-gate 	}
33380Sstevel@tonic-gate 
33390Sstevel@tonic-gate 	return (ret);
33400Sstevel@tonic-gate }
33410Sstevel@tonic-gate 
33420Sstevel@tonic-gate scf_handle_t *
33430Sstevel@tonic-gate scf_property_handle(const scf_property_t *val)
33440Sstevel@tonic-gate {
33450Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
33460Sstevel@tonic-gate }
33470Sstevel@tonic-gate 
33480Sstevel@tonic-gate void
33490Sstevel@tonic-gate scf_property_destroy(scf_property_t *val)
33500Sstevel@tonic-gate {
33510Sstevel@tonic-gate 	if (val == NULL)
33520Sstevel@tonic-gate 		return;
33530Sstevel@tonic-gate 
33540Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
33550Sstevel@tonic-gate 	uu_free(val);
33560Sstevel@tonic-gate }
33570Sstevel@tonic-gate 
33580Sstevel@tonic-gate static int
33590Sstevel@tonic-gate property_type_locked(const scf_property_t *prop,
33600Sstevel@tonic-gate     rep_protocol_value_type_t *out)
33610Sstevel@tonic-gate {
33620Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
33630Sstevel@tonic-gate 
33640Sstevel@tonic-gate 	struct rep_protocol_property_request request;
33650Sstevel@tonic-gate 	struct rep_protocol_integer_response response;
33660Sstevel@tonic-gate 
33670Sstevel@tonic-gate 	int r;
33680Sstevel@tonic-gate 
33690Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
33700Sstevel@tonic-gate 
33710Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_TYPE;
33720Sstevel@tonic-gate 	request.rpr_entityid = prop->rd_d.rd_entity;
33730Sstevel@tonic-gate 
33740Sstevel@tonic-gate 	datael_finish_reset(&prop->rd_d);
33750Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
33760Sstevel@tonic-gate 	    &response, sizeof (response));
33770Sstevel@tonic-gate 
33780Sstevel@tonic-gate 	if (r < 0)
33790Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
33800Sstevel@tonic-gate 
33810Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
33820Sstevel@tonic-gate 	    r < sizeof (response)) {
33830Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
33840Sstevel@tonic-gate 	}
33850Sstevel@tonic-gate 	*out = response.rpr_value;
33860Sstevel@tonic-gate 	return (SCF_SUCCESS);
33870Sstevel@tonic-gate }
33880Sstevel@tonic-gate 
33890Sstevel@tonic-gate int
33900Sstevel@tonic-gate scf_property_type(const scf_property_t *prop, scf_type_t *out)
33910Sstevel@tonic-gate {
33920Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
33930Sstevel@tonic-gate 	rep_protocol_value_type_t out_raw;
33940Sstevel@tonic-gate 	int ret;
33950Sstevel@tonic-gate 
33960Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
33970Sstevel@tonic-gate 	ret = property_type_locked(prop, &out_raw);
33980Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
33990Sstevel@tonic-gate 
34000Sstevel@tonic-gate 	if (ret == SCF_SUCCESS)
34010Sstevel@tonic-gate 		*out = scf_protocol_type_to_type(out_raw);
34020Sstevel@tonic-gate 
34030Sstevel@tonic-gate 	return (ret);
34040Sstevel@tonic-gate }
34050Sstevel@tonic-gate 
34060Sstevel@tonic-gate int
34070Sstevel@tonic-gate scf_property_is_type(const scf_property_t *prop, scf_type_t base_arg)
34080Sstevel@tonic-gate {
34090Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
34100Sstevel@tonic-gate 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
34110Sstevel@tonic-gate 	rep_protocol_value_type_t type;
34120Sstevel@tonic-gate 	int ret;
34130Sstevel@tonic-gate 
34140Sstevel@tonic-gate 	if (base == REP_PROTOCOL_TYPE_INVALID)
34150Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
34160Sstevel@tonic-gate 
34170Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
34180Sstevel@tonic-gate 	ret = property_type_locked(prop, &type);
34190Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
34200Sstevel@tonic-gate 
34210Sstevel@tonic-gate 	if (ret == SCF_SUCCESS) {
34220Sstevel@tonic-gate 		if (!scf_is_compatible_type(base, type))
34230Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
34240Sstevel@tonic-gate 	}
34250Sstevel@tonic-gate 	return (ret);
34260Sstevel@tonic-gate }
34270Sstevel@tonic-gate 
34280Sstevel@tonic-gate ssize_t
34290Sstevel@tonic-gate scf_property_get_name(const scf_property_t *prop, char *out, size_t len)
34300Sstevel@tonic-gate {
34310Sstevel@tonic-gate 	return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME));
34320Sstevel@tonic-gate }
34330Sstevel@tonic-gate 
34340Sstevel@tonic-gate /*
34350Sstevel@tonic-gate  * transaction functions
34360Sstevel@tonic-gate  */
34370Sstevel@tonic-gate 
34380Sstevel@tonic-gate /*
34390Sstevel@tonic-gate  * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
34400Sstevel@tonic-gate  * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
34410Sstevel@tonic-gate  */
34420Sstevel@tonic-gate scf_transaction_t *
34430Sstevel@tonic-gate scf_transaction_create(scf_handle_t *handle)
34440Sstevel@tonic-gate {
34450Sstevel@tonic-gate 	scf_transaction_t *ret;
34460Sstevel@tonic-gate 
34470Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (scf_transaction_t));
34480Sstevel@tonic-gate 	if (ret == NULL) {
34490Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
34500Sstevel@tonic-gate 		return (NULL);
34510Sstevel@tonic-gate 	}
34520Sstevel@tonic-gate 	if (datael_init(&ret->tran_pg.rd_d, handle,
34530Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
34540Sstevel@tonic-gate 		uu_free(ret);
34550Sstevel@tonic-gate 		return (NULL);			/* error already set */
34560Sstevel@tonic-gate 	}
34570Sstevel@tonic-gate 	ret->tran_state = TRAN_STATE_NEW;
34580Sstevel@tonic-gate 	ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED);
34590Sstevel@tonic-gate 	if (ret->tran_props == NULL) {
34600Sstevel@tonic-gate 		datael_destroy(&ret->tran_pg.rd_d);
34610Sstevel@tonic-gate 		uu_free(ret);
34620Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
34630Sstevel@tonic-gate 		return (NULL);
34640Sstevel@tonic-gate 	}
34650Sstevel@tonic-gate 
34660Sstevel@tonic-gate 	return (ret);
34670Sstevel@tonic-gate }
34680Sstevel@tonic-gate 
34690Sstevel@tonic-gate scf_handle_t *
34700Sstevel@tonic-gate scf_transaction_handle(const scf_transaction_t *val)
34710Sstevel@tonic-gate {
34720Sstevel@tonic-gate 	return (handle_get(val->tran_pg.rd_d.rd_handle));
34730Sstevel@tonic-gate }
34740Sstevel@tonic-gate 
34750Sstevel@tonic-gate int
34760Sstevel@tonic-gate scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg)
34770Sstevel@tonic-gate {
34780Sstevel@tonic-gate 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
34790Sstevel@tonic-gate 
34800Sstevel@tonic-gate 	struct rep_protocol_transaction_start request;
34810Sstevel@tonic-gate 	struct rep_protocol_response response;
34820Sstevel@tonic-gate 	int r;
34830Sstevel@tonic-gate 
34840Sstevel@tonic-gate 	if (h != pg->rd_d.rd_handle)
34850Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
34860Sstevel@tonic-gate 
34870Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
34880Sstevel@tonic-gate 	if (tran->tran_state != TRAN_STATE_NEW) {
34890Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
34900Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
34910Sstevel@tonic-gate 	}
34920Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START;
34930Sstevel@tonic-gate 	request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity;
34940Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
34950Sstevel@tonic-gate 
34960Sstevel@tonic-gate 	datael_finish_reset(&tran->tran_pg.rd_d);
34970Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
34980Sstevel@tonic-gate 
34990Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
35000Sstevel@tonic-gate 	    &response, sizeof (response));
35010Sstevel@tonic-gate 
35020Sstevel@tonic-gate 	if (r < 0) {
35030Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
35040Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
35050Sstevel@tonic-gate 	}
35060Sstevel@tonic-gate 
35070Sstevel@tonic-gate 	/* r < sizeof (response) cannot happen because sizeof (response) == 4 */
35080Sstevel@tonic-gate 
35090Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
35100Sstevel@tonic-gate 	    r < sizeof (response)) {
35110Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
35120Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
35130Sstevel@tonic-gate 	}
35140Sstevel@tonic-gate 
35150Sstevel@tonic-gate 	tran->tran_state = TRAN_STATE_SETUP;
35160Sstevel@tonic-gate 	tran->tran_invalid = 0;
35170Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
35180Sstevel@tonic-gate 	return (SCF_SUCCESS);
35190Sstevel@tonic-gate }
35200Sstevel@tonic-gate 
35210Sstevel@tonic-gate static void
35220Sstevel@tonic-gate entry_invalidate(scf_transaction_entry_t *cur, int and_destroy,
35230Sstevel@tonic-gate     int and_reset_value)
35240Sstevel@tonic-gate {
35250Sstevel@tonic-gate 	scf_value_t *v, *next;
35260Sstevel@tonic-gate 	scf_transaction_t *tx;
35270Sstevel@tonic-gate 	scf_handle_t *h = cur->entry_handle;
35280Sstevel@tonic-gate 
35290Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
35300Sstevel@tonic-gate 
35310Sstevel@tonic-gate 	if ((tx = cur->entry_tx) != NULL) {
35320Sstevel@tonic-gate 		tx->tran_invalid = 1;
35330Sstevel@tonic-gate 		uu_list_remove(tx->tran_props, cur);
35340Sstevel@tonic-gate 		cur->entry_tx = NULL;
35350Sstevel@tonic-gate 	}
35360Sstevel@tonic-gate 
35370Sstevel@tonic-gate 	cur->entry_property = NULL;
35380Sstevel@tonic-gate 	cur->entry_state = ENTRY_STATE_INVALID;
35390Sstevel@tonic-gate 	cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
35400Sstevel@tonic-gate 	cur->entry_type = REP_PROTOCOL_TYPE_INVALID;
35410Sstevel@tonic-gate 
35420Sstevel@tonic-gate 	for (v = cur->entry_head; v != NULL; v = next) {
35430Sstevel@tonic-gate 		next = v->value_next;
35440Sstevel@tonic-gate 		v->value_tx = NULL;
35450Sstevel@tonic-gate 		v->value_next = NULL;
35460Sstevel@tonic-gate 		if (and_destroy || and_reset_value)
35470Sstevel@tonic-gate 			scf_value_reset_locked(v, and_destroy);
35480Sstevel@tonic-gate 	}
35490Sstevel@tonic-gate 	cur->entry_head = NULL;
35500Sstevel@tonic-gate }
35510Sstevel@tonic-gate 
35520Sstevel@tonic-gate static void
35530Sstevel@tonic-gate entry_destroy_locked(scf_transaction_entry_t *entry)
35540Sstevel@tonic-gate {
35550Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
35560Sstevel@tonic-gate 
35570Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
35580Sstevel@tonic-gate 
35590Sstevel@tonic-gate 	entry_invalidate(entry, 0, 0);
35600Sstevel@tonic-gate 
35610Sstevel@tonic-gate 	entry->entry_handle = NULL;
35620Sstevel@tonic-gate 	assert(h->rh_entries > 0);
35630Sstevel@tonic-gate 	--h->rh_entries;
35640Sstevel@tonic-gate 	--h->rh_extrefs;
35650Sstevel@tonic-gate 	uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool);
35660Sstevel@tonic-gate 	uu_free(entry);
35670Sstevel@tonic-gate }
35680Sstevel@tonic-gate 
35690Sstevel@tonic-gate static int
35700Sstevel@tonic-gate transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry,
35710Sstevel@tonic-gate     enum rep_protocol_transaction_action action,
35720Sstevel@tonic-gate     const char *prop, rep_protocol_value_type_t type)
35730Sstevel@tonic-gate {
35740Sstevel@tonic-gate 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
35750Sstevel@tonic-gate 	scf_transaction_entry_t *old;
35760Sstevel@tonic-gate 	scf_property_t *prop_p;
35770Sstevel@tonic-gate 	rep_protocol_value_type_t oldtype;
35780Sstevel@tonic-gate 	scf_error_t error = SCF_ERROR_NONE;
35790Sstevel@tonic-gate 	int ret;
35800Sstevel@tonic-gate 	uu_list_index_t idx;
35810Sstevel@tonic-gate 
35820Sstevel@tonic-gate 	if (h != entry->entry_handle)
35830Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
35840Sstevel@tonic-gate 
35850Sstevel@tonic-gate 	if (action == REP_PROTOCOL_TX_ENTRY_DELETE)
35860Sstevel@tonic-gate 		assert(type == REP_PROTOCOL_TYPE_INVALID);
35870Sstevel@tonic-gate 	else if (type == REP_PROTOCOL_TYPE_INVALID)
35880Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
35890Sstevel@tonic-gate 
35900Sstevel@tonic-gate 	prop_p = HANDLE_HOLD_PROPERTY(h);
35910Sstevel@tonic-gate 
35920Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
35930Sstevel@tonic-gate 	if (tran->tran_state != TRAN_STATE_SETUP) {
35940Sstevel@tonic-gate 		error = SCF_ERROR_NOT_SET;
35950Sstevel@tonic-gate 		goto error;
35960Sstevel@tonic-gate 	}
35970Sstevel@tonic-gate 	if (tran->tran_invalid) {
35980Sstevel@tonic-gate 		error = SCF_ERROR_NOT_SET;
35990Sstevel@tonic-gate 		goto error;
36000Sstevel@tonic-gate 	}
36010Sstevel@tonic-gate 
36020Sstevel@tonic-gate 	if (entry->entry_state != ENTRY_STATE_INVALID)
36030Sstevel@tonic-gate 		entry_invalidate(entry, 0, 0);
36040Sstevel@tonic-gate 
36050Sstevel@tonic-gate 	old = uu_list_find(tran->tran_props, &prop, NULL, &idx);
36060Sstevel@tonic-gate 	if (old != NULL) {
36070Sstevel@tonic-gate 		error = SCF_ERROR_IN_USE;
36080Sstevel@tonic-gate 		goto error;
36090Sstevel@tonic-gate 	}
36100Sstevel@tonic-gate 
36110Sstevel@tonic-gate 	ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop,
36120Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d);
36130Sstevel@tonic-gate 	if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) {
36140Sstevel@tonic-gate 		goto error;
36150Sstevel@tonic-gate 	}
36160Sstevel@tonic-gate 
36170Sstevel@tonic-gate 	switch (action) {
36180Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_DELETE:
36190Sstevel@tonic-gate 		if (ret == -1) {
36200Sstevel@tonic-gate 			error = SCF_ERROR_NOT_FOUND;
36210Sstevel@tonic-gate 			goto error;
36220Sstevel@tonic-gate 		}
36230Sstevel@tonic-gate 		break;
36240Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_NEW:
36250Sstevel@tonic-gate 		if (ret != -1) {
36260Sstevel@tonic-gate 			error = SCF_ERROR_EXISTS;
36270Sstevel@tonic-gate 			goto error;
36280Sstevel@tonic-gate 		}
36290Sstevel@tonic-gate 		break;
36300Sstevel@tonic-gate 
36310Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_CLEAR:
36320Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_REPLACE:
36330Sstevel@tonic-gate 		if (ret == -1) {
36340Sstevel@tonic-gate 			error = SCF_ERROR_NOT_FOUND;
36350Sstevel@tonic-gate 			goto error;
36360Sstevel@tonic-gate 		}
36370Sstevel@tonic-gate 		if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) {
36380Sstevel@tonic-gate 			if (property_type_locked(prop_p, &oldtype) == -1) {
36390Sstevel@tonic-gate 				error = scf_error();
36400Sstevel@tonic-gate 				goto error;
36410Sstevel@tonic-gate 			}
36420Sstevel@tonic-gate 			if (oldtype != type) {
36430Sstevel@tonic-gate 				error = SCF_ERROR_TYPE_MISMATCH;
36440Sstevel@tonic-gate 				goto error;
36450Sstevel@tonic-gate 			}
36460Sstevel@tonic-gate 		}
36470Sstevel@tonic-gate 		break;
36480Sstevel@tonic-gate 	default:
36490Sstevel@tonic-gate 		assert(0);
36500Sstevel@tonic-gate 		abort();
36510Sstevel@tonic-gate 	}
36520Sstevel@tonic-gate 
36530Sstevel@tonic-gate 	(void) strlcpy(entry->entry_namebuf, prop,
36540Sstevel@tonic-gate 	    sizeof (entry->entry_namebuf));
36550Sstevel@tonic-gate 	entry->entry_property = entry->entry_namebuf;
36560Sstevel@tonic-gate 	entry->entry_action = action;
36570Sstevel@tonic-gate 	entry->entry_type = type;
36580Sstevel@tonic-gate 
36590Sstevel@tonic-gate 	entry->entry_state = ENTRY_STATE_IN_TX_ACTION;
36600Sstevel@tonic-gate 	entry->entry_tx = tran;
36610Sstevel@tonic-gate 	uu_list_insert(tran->tran_props, entry, idx);
36620Sstevel@tonic-gate 
36630Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
36640Sstevel@tonic-gate 
36650Sstevel@tonic-gate 	HANDLE_RELE_PROPERTY(h);
36660Sstevel@tonic-gate 
36670Sstevel@tonic-gate 	return (SCF_SUCCESS);
36680Sstevel@tonic-gate 
36690Sstevel@tonic-gate error:
36700Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
36710Sstevel@tonic-gate 
36720Sstevel@tonic-gate 	HANDLE_RELE_PROPERTY(h);
36730Sstevel@tonic-gate 
36740Sstevel@tonic-gate 	return (scf_set_error(error));
36750Sstevel@tonic-gate }
36760Sstevel@tonic-gate 
36770Sstevel@tonic-gate int
36780Sstevel@tonic-gate scf_transaction_property_new(scf_transaction_t *tx,
36790Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
36800Sstevel@tonic-gate {
36810Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW,
36820Sstevel@tonic-gate 	    prop, scf_type_to_protocol_type(type)));
36830Sstevel@tonic-gate }
36840Sstevel@tonic-gate 
36850Sstevel@tonic-gate int
36860Sstevel@tonic-gate scf_transaction_property_change(scf_transaction_t *tx,
36870Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
36880Sstevel@tonic-gate {
36890Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR,
36900Sstevel@tonic-gate 	    prop, scf_type_to_protocol_type(type)));
36910Sstevel@tonic-gate }
36920Sstevel@tonic-gate 
36930Sstevel@tonic-gate int
36940Sstevel@tonic-gate scf_transaction_property_change_type(scf_transaction_t *tx,
36950Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
36960Sstevel@tonic-gate {
36970Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE,
36980Sstevel@tonic-gate 	    prop, scf_type_to_protocol_type(type)));
36990Sstevel@tonic-gate }
37000Sstevel@tonic-gate 
37010Sstevel@tonic-gate int
37020Sstevel@tonic-gate scf_transaction_property_delete(scf_transaction_t *tx,
37030Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop)
37040Sstevel@tonic-gate {
37050Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE,
37060Sstevel@tonic-gate 	    prop, REP_PROTOCOL_TYPE_INVALID));
37070Sstevel@tonic-gate }
37080Sstevel@tonic-gate 
37090Sstevel@tonic-gate #define	BAD_SIZE (-1UL)
37100Sstevel@tonic-gate 
37110Sstevel@tonic-gate static size_t
37120Sstevel@tonic-gate commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t)
37130Sstevel@tonic-gate {
37140Sstevel@tonic-gate 	size_t len;
37150Sstevel@tonic-gate 
37160Sstevel@tonic-gate 	assert(val->value_type == t);
37170Sstevel@tonic-gate 
37180Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_OPAQUE) {
37190Sstevel@tonic-gate 		len = scf_opaque_encode(data, val->value_value,
37200Sstevel@tonic-gate 		    val->value_size);
37210Sstevel@tonic-gate 	} else {
37220Sstevel@tonic-gate 		if (data != NULL)
37230Sstevel@tonic-gate 			len = strlcpy(data, val->value_value,
37240Sstevel@tonic-gate 			    REP_PROTOCOL_VALUE_LEN);
37250Sstevel@tonic-gate 		else
37260Sstevel@tonic-gate 			len = strlen(val->value_value);
37270Sstevel@tonic-gate 		if (len >= REP_PROTOCOL_VALUE_LEN)
37280Sstevel@tonic-gate 			return (BAD_SIZE);
37290Sstevel@tonic-gate 	}
37300Sstevel@tonic-gate 	return (len + 1);	/* count the '\0' */
37310Sstevel@tonic-gate }
37320Sstevel@tonic-gate 
37330Sstevel@tonic-gate static size_t
37340Sstevel@tonic-gate commit_process(scf_transaction_entry_t *cur,
37350Sstevel@tonic-gate     struct rep_protocol_transaction_cmd *out)
37360Sstevel@tonic-gate {
37370Sstevel@tonic-gate 	scf_value_t *child;
37380Sstevel@tonic-gate 	size_t sz = 0;
37390Sstevel@tonic-gate 	size_t len;
37400Sstevel@tonic-gate 	caddr_t data = (caddr_t)out->rptc_data;
37410Sstevel@tonic-gate 	caddr_t val_data;
37420Sstevel@tonic-gate 
37430Sstevel@tonic-gate 	if (out != NULL) {
37440Sstevel@tonic-gate 		len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN);
37450Sstevel@tonic-gate 
37460Sstevel@tonic-gate 		out->rptc_action = cur->entry_action;
37470Sstevel@tonic-gate 		out->rptc_type = cur->entry_type;
37480Sstevel@tonic-gate 		out->rptc_name_len = len + 1;
37490Sstevel@tonic-gate 	} else {
37500Sstevel@tonic-gate 		len = strlen(cur->entry_property);
37510Sstevel@tonic-gate 	}
37520Sstevel@tonic-gate 
37530Sstevel@tonic-gate 	if (len >= REP_PROTOCOL_NAME_LEN)
37540Sstevel@tonic-gate 		return (BAD_SIZE);
37550Sstevel@tonic-gate 
37560Sstevel@tonic-gate 	len = TX_SIZE(len + 1);
37570Sstevel@tonic-gate 
37580Sstevel@tonic-gate 	sz += len;
37590Sstevel@tonic-gate 	val_data = data + len;
37600Sstevel@tonic-gate 
37610Sstevel@tonic-gate 	for (child = cur->entry_head; child != NULL;
37620Sstevel@tonic-gate 	    child = child->value_next) {
37630Sstevel@tonic-gate 		assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE);
37640Sstevel@tonic-gate 		if (out != NULL) {
37650Sstevel@tonic-gate 			len = commit_value(val_data + sizeof (uint32_t), child,
37660Sstevel@tonic-gate 			    cur->entry_type);
37670Sstevel@tonic-gate 			/* LINTED alignment */
37680Sstevel@tonic-gate 			*(uint32_t *)val_data = len;
37690Sstevel@tonic-gate 		} else
37700Sstevel@tonic-gate 			len = commit_value(NULL, child, cur->entry_type);
37710Sstevel@tonic-gate 
37720Sstevel@tonic-gate 		if (len == BAD_SIZE)
37730Sstevel@tonic-gate 			return (BAD_SIZE);
37740Sstevel@tonic-gate 
37750Sstevel@tonic-gate 		len += sizeof (uint32_t);
37760Sstevel@tonic-gate 		len = TX_SIZE(len);
37770Sstevel@tonic-gate 
37780Sstevel@tonic-gate 		sz += len;
37790Sstevel@tonic-gate 		val_data += len;
37800Sstevel@tonic-gate 	}
37810Sstevel@tonic-gate 
37820Sstevel@tonic-gate 	assert(val_data - data == sz);
37830Sstevel@tonic-gate 
37840Sstevel@tonic-gate 	if (out != NULL)
37850Sstevel@tonic-gate 		out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz);
37860Sstevel@tonic-gate 
37870Sstevel@tonic-gate 	return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz));
37880Sstevel@tonic-gate }
37890Sstevel@tonic-gate 
37900Sstevel@tonic-gate int
37910Sstevel@tonic-gate scf_transaction_commit(scf_transaction_t *tran)
37920Sstevel@tonic-gate {
37930Sstevel@tonic-gate 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
37940Sstevel@tonic-gate 
37950Sstevel@tonic-gate 	struct rep_protocol_transaction_commit *request;
37960Sstevel@tonic-gate 	struct rep_protocol_response response;
37970Sstevel@tonic-gate 	uintptr_t cmd;
37980Sstevel@tonic-gate 	scf_transaction_entry_t *cur;
37990Sstevel@tonic-gate 	size_t total, size;
38000Sstevel@tonic-gate 	size_t request_size;
38010Sstevel@tonic-gate 	size_t new_total;
38020Sstevel@tonic-gate 	int r;
38030Sstevel@tonic-gate 
38040Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
38050Sstevel@tonic-gate 	if (tran->tran_state != TRAN_STATE_SETUP ||
38060Sstevel@tonic-gate 	    tran->tran_invalid) {
38070Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
38080Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
38090Sstevel@tonic-gate 	}
38100Sstevel@tonic-gate 
38110Sstevel@tonic-gate 	total = 0;
38120Sstevel@tonic-gate 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
38130Sstevel@tonic-gate 	    cur = uu_list_next(tran->tran_props, cur)) {
38140Sstevel@tonic-gate 		size = commit_process(cur, NULL);
38150Sstevel@tonic-gate 		if (size == BAD_SIZE) {
38160Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&h->rh_lock);
38170Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INTERNAL));
38180Sstevel@tonic-gate 		}
38190Sstevel@tonic-gate 		assert(TX_SIZE(size) == size);
38200Sstevel@tonic-gate 		total += size;
38210Sstevel@tonic-gate 	}
38220Sstevel@tonic-gate 
38230Sstevel@tonic-gate 	request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total);
38240Sstevel@tonic-gate 	request = alloca(request_size);
38250Sstevel@tonic-gate 	(void) memset(request, '\0', request_size);
38260Sstevel@tonic-gate 	request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT;
38270Sstevel@tonic-gate 	request->rpr_entityid = tran->tran_pg.rd_d.rd_entity;
38280Sstevel@tonic-gate 	request->rpr_size = request_size;
38290Sstevel@tonic-gate 	cmd = (uintptr_t)request->rpr_cmd;
38300Sstevel@tonic-gate 
38310Sstevel@tonic-gate 	datael_finish_reset(&tran->tran_pg.rd_d);
38320Sstevel@tonic-gate 
38330Sstevel@tonic-gate 	new_total = 0;
38340Sstevel@tonic-gate 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
38350Sstevel@tonic-gate 	    cur = uu_list_next(tran->tran_props, cur)) {
38360Sstevel@tonic-gate 		size = commit_process(cur, (void *)cmd);
38370Sstevel@tonic-gate 		if (size == BAD_SIZE) {
38380Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&h->rh_lock);
38390Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INTERNAL));
38400Sstevel@tonic-gate 		}
38410Sstevel@tonic-gate 		cmd += size;
38420Sstevel@tonic-gate 		new_total += size;
38430Sstevel@tonic-gate 	}
38440Sstevel@tonic-gate 	assert(new_total == total);
38450Sstevel@tonic-gate 
38460Sstevel@tonic-gate 	r = make_door_call(h, request, request_size,
38470Sstevel@tonic-gate 	    &response, sizeof (response));
38480Sstevel@tonic-gate 
38490Sstevel@tonic-gate 	if (r < 0) {
38500Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
38510Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
38520Sstevel@tonic-gate 	}
38530Sstevel@tonic-gate 
38540Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
38550Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) {
38560Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
38570Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
38580Sstevel@tonic-gate 	}
38590Sstevel@tonic-gate 
38600Sstevel@tonic-gate 	tran->tran_state = TRAN_STATE_COMMITTED;
38610Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
38620Sstevel@tonic-gate 	return (response.rpr_response == REP_PROTOCOL_SUCCESS);
38630Sstevel@tonic-gate }
38640Sstevel@tonic-gate 
38650Sstevel@tonic-gate static void
38660Sstevel@tonic-gate transaction_reset(scf_transaction_t *tran)
38670Sstevel@tonic-gate {
38680Sstevel@tonic-gate 	assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock));
38690Sstevel@tonic-gate 
38700Sstevel@tonic-gate 	tran->tran_state = TRAN_STATE_NEW;
38710Sstevel@tonic-gate 	datael_reset_locked(&tran->tran_pg.rd_d);
38720Sstevel@tonic-gate }
38730Sstevel@tonic-gate 
38740Sstevel@tonic-gate static void
38750Sstevel@tonic-gate scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy,
38760Sstevel@tonic-gate     int and_reset_value)
38770Sstevel@tonic-gate {
38780Sstevel@tonic-gate 	scf_transaction_entry_t *cur;
38790Sstevel@tonic-gate 	void *cookie;
38800Sstevel@tonic-gate 
38810Sstevel@tonic-gate 	(void) pthread_mutex_lock(&tran->tran_pg.rd_d.rd_handle->rh_lock);
38820Sstevel@tonic-gate 	cookie = NULL;
38830Sstevel@tonic-gate 	while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) {
38840Sstevel@tonic-gate 		cur->entry_tx = NULL;
38850Sstevel@tonic-gate 
38860Sstevel@tonic-gate 		assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION);
38870Sstevel@tonic-gate 		cur->entry_state = ENTRY_STATE_INVALID;
38880Sstevel@tonic-gate 
38890Sstevel@tonic-gate 		entry_invalidate(cur, and_destroy, and_reset_value);
38900Sstevel@tonic-gate 		if (and_destroy)
38910Sstevel@tonic-gate 			entry_destroy_locked(cur);
38920Sstevel@tonic-gate 	}
38930Sstevel@tonic-gate 	transaction_reset(tran);
38940Sstevel@tonic-gate 	handle_unrefed(tran->tran_pg.rd_d.rd_handle);
38950Sstevel@tonic-gate }
38960Sstevel@tonic-gate 
38970Sstevel@tonic-gate void
38980Sstevel@tonic-gate scf_transaction_reset(scf_transaction_t *tran)
38990Sstevel@tonic-gate {
39000Sstevel@tonic-gate 	scf_transaction_reset_impl(tran, 0, 0);
39010Sstevel@tonic-gate }
39020Sstevel@tonic-gate 
39030Sstevel@tonic-gate void
39040Sstevel@tonic-gate scf_transaction_reset_all(scf_transaction_t *tran)
39050Sstevel@tonic-gate {
39060Sstevel@tonic-gate 	scf_transaction_reset_impl(tran, 0, 1);
39070Sstevel@tonic-gate }
39080Sstevel@tonic-gate 
39090Sstevel@tonic-gate void
39100Sstevel@tonic-gate scf_transaction_destroy(scf_transaction_t *val)
39110Sstevel@tonic-gate {
39120Sstevel@tonic-gate 	if (val == NULL)
39130Sstevel@tonic-gate 		return;
39140Sstevel@tonic-gate 
39150Sstevel@tonic-gate 	scf_transaction_reset(val);
39160Sstevel@tonic-gate 
39170Sstevel@tonic-gate 	datael_destroy(&val->tran_pg.rd_d);
39180Sstevel@tonic-gate 
39190Sstevel@tonic-gate 	uu_list_destroy(val->tran_props);
39200Sstevel@tonic-gate 	uu_free(val);
39210Sstevel@tonic-gate }
39220Sstevel@tonic-gate 
39230Sstevel@tonic-gate void
39240Sstevel@tonic-gate scf_transaction_destroy_children(scf_transaction_t *tran)
39250Sstevel@tonic-gate {
39260Sstevel@tonic-gate 	scf_transaction_reset_impl(tran, 1, 0);
39270Sstevel@tonic-gate }
39280Sstevel@tonic-gate 
39290Sstevel@tonic-gate scf_transaction_entry_t *
39300Sstevel@tonic-gate scf_entry_create(scf_handle_t *h)
39310Sstevel@tonic-gate {
39320Sstevel@tonic-gate 	scf_transaction_entry_t *ret;
39330Sstevel@tonic-gate 
39340Sstevel@tonic-gate 	if (h == NULL) {
39350Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
39360Sstevel@tonic-gate 		return (NULL);
39370Sstevel@tonic-gate 	}
39380Sstevel@tonic-gate 
39390Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (scf_transaction_entry_t));
39400Sstevel@tonic-gate 	if (ret == NULL) {
39410Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
39420Sstevel@tonic-gate 		return (NULL);
39430Sstevel@tonic-gate 	}
39440Sstevel@tonic-gate 	ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
39450Sstevel@tonic-gate 	ret->entry_handle = h;
39460Sstevel@tonic-gate 
39470Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
39480Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD) {
39490Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
39500Sstevel@tonic-gate 		uu_free(ret);
39510Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
39520Sstevel@tonic-gate 		return (NULL);
39530Sstevel@tonic-gate 	}
39540Sstevel@tonic-gate 	h->rh_entries++;
39550Sstevel@tonic-gate 	h->rh_extrefs++;
39560Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
39570Sstevel@tonic-gate 
39580Sstevel@tonic-gate 	uu_list_node_init(ret, &ret->entry_link, tran_entry_pool);
39590Sstevel@tonic-gate 
39600Sstevel@tonic-gate 	return (ret);
39610Sstevel@tonic-gate }
39620Sstevel@tonic-gate 
39630Sstevel@tonic-gate scf_handle_t *
39640Sstevel@tonic-gate scf_entry_handle(const scf_transaction_entry_t *val)
39650Sstevel@tonic-gate {
39660Sstevel@tonic-gate 	return (handle_get(val->entry_handle));
39670Sstevel@tonic-gate }
39680Sstevel@tonic-gate 
39690Sstevel@tonic-gate void
39700Sstevel@tonic-gate scf_entry_reset(scf_transaction_entry_t *entry)
39710Sstevel@tonic-gate {
39720Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
39730Sstevel@tonic-gate 
39740Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
39750Sstevel@tonic-gate 	entry_invalidate(entry, 0, 0);
39760Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
39770Sstevel@tonic-gate }
39780Sstevel@tonic-gate 
39790Sstevel@tonic-gate void
39800Sstevel@tonic-gate scf_entry_destroy_children(scf_transaction_entry_t *entry)
39810Sstevel@tonic-gate {
39820Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
39830Sstevel@tonic-gate 
39840Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
39850Sstevel@tonic-gate 	entry_invalidate(entry, 1, 0);
39860Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
39870Sstevel@tonic-gate }
39880Sstevel@tonic-gate 
39890Sstevel@tonic-gate void
39900Sstevel@tonic-gate scf_entry_destroy(scf_transaction_entry_t *entry)
39910Sstevel@tonic-gate {
39920Sstevel@tonic-gate 	scf_handle_t *h;
39930Sstevel@tonic-gate 
39940Sstevel@tonic-gate 	if (entry == NULL)
39950Sstevel@tonic-gate 		return;
39960Sstevel@tonic-gate 
39970Sstevel@tonic-gate 	h = entry->entry_handle;
39980Sstevel@tonic-gate 
39990Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
40000Sstevel@tonic-gate 	entry_destroy_locked(entry);
40010Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
40020Sstevel@tonic-gate }
40030Sstevel@tonic-gate 
40040Sstevel@tonic-gate /*
40050Sstevel@tonic-gate  * Fails with
40060Sstevel@tonic-gate  *   _HANDLE_MISMATCH
40070Sstevel@tonic-gate  *   _NOT_SET - has not been added to a transaction
40080Sstevel@tonic-gate  *   _INTERNAL - entry is corrupt
40090Sstevel@tonic-gate  *   _INVALID_ARGUMENT - entry's transaction is not started or corrupt
40100Sstevel@tonic-gate  *			 entry is set to delete a property
40110Sstevel@tonic-gate  *			 v is reset or corrupt
40120Sstevel@tonic-gate  *   _TYPE_MISMATCH - entry & v's types aren't compatible
40130Sstevel@tonic-gate  *   _IN_USE - v has been added to another entry
40140Sstevel@tonic-gate  */
40150Sstevel@tonic-gate int
40160Sstevel@tonic-gate scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v)
40170Sstevel@tonic-gate {
40180Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
40190Sstevel@tonic-gate 
40200Sstevel@tonic-gate 	if (h != v->value_handle)
40210Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
40220Sstevel@tonic-gate 
40230Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
40240Sstevel@tonic-gate 
40250Sstevel@tonic-gate 	if (entry->entry_state == ENTRY_STATE_INVALID) {
40260Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
40270Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
40280Sstevel@tonic-gate 	}
40290Sstevel@tonic-gate 	assert(entry->entry_state == ENTRY_STATE_IN_TX_ACTION);
40300Sstevel@tonic-gate 
40310Sstevel@tonic-gate 	if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) {
40320Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
40330Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
40340Sstevel@tonic-gate 	}
40350Sstevel@tonic-gate 
40360Sstevel@tonic-gate 	if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) {
40370Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
40380Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
40390Sstevel@tonic-gate 	}
40400Sstevel@tonic-gate 
40410Sstevel@tonic-gate 	if (v->value_type == REP_PROTOCOL_TYPE_INVALID) {
40420Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
40430Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
40440Sstevel@tonic-gate 	}
40450Sstevel@tonic-gate 
40460Sstevel@tonic-gate 	if (!scf_is_compatible_type(entry->entry_type, v->value_type)) {
40470Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
40480Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
40490Sstevel@tonic-gate 	}
40500Sstevel@tonic-gate 
40510Sstevel@tonic-gate 	if (v->value_tx != NULL) {
40520Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
40530Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
40540Sstevel@tonic-gate 	}
40550Sstevel@tonic-gate 
40560Sstevel@tonic-gate 	v->value_tx = entry;
40570Sstevel@tonic-gate 	v->value_next = entry->entry_head;
40580Sstevel@tonic-gate 	entry->entry_head = v;
40590Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
40600Sstevel@tonic-gate 
40610Sstevel@tonic-gate 	return (SCF_SUCCESS);
40620Sstevel@tonic-gate }
40630Sstevel@tonic-gate 
40640Sstevel@tonic-gate /*
40650Sstevel@tonic-gate  * value functions
40660Sstevel@tonic-gate  */
40670Sstevel@tonic-gate scf_value_t *
40680Sstevel@tonic-gate scf_value_create(scf_handle_t *h)
40690Sstevel@tonic-gate {
40700Sstevel@tonic-gate 	scf_value_t *ret;
40710Sstevel@tonic-gate 
40720Sstevel@tonic-gate 	if (h == NULL) {
40730Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
40740Sstevel@tonic-gate 		return (NULL);
40750Sstevel@tonic-gate 	}
40760Sstevel@tonic-gate 
40770Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
40780Sstevel@tonic-gate 	if (ret != NULL) {
40790Sstevel@tonic-gate 		ret->value_type = REP_PROTOCOL_TYPE_INVALID;
40800Sstevel@tonic-gate 		ret->value_handle = h;
40810Sstevel@tonic-gate 		(void) pthread_mutex_lock(&h->rh_lock);
40820Sstevel@tonic-gate 		if (h->rh_flags & HANDLE_DEAD) {
40830Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&h->rh_lock);
40840Sstevel@tonic-gate 			uu_free(ret);
40850Sstevel@tonic-gate 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
40860Sstevel@tonic-gate 			return (NULL);
40870Sstevel@tonic-gate 		}
40880Sstevel@tonic-gate 		h->rh_values++;
40890Sstevel@tonic-gate 		h->rh_extrefs++;
40900Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
40910Sstevel@tonic-gate 	} else {
40920Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
40930Sstevel@tonic-gate 	}
40940Sstevel@tonic-gate 
40950Sstevel@tonic-gate 	return (ret);
40960Sstevel@tonic-gate }
40970Sstevel@tonic-gate 
40980Sstevel@tonic-gate static void
40990Sstevel@tonic-gate scf_value_reset_locked(scf_value_t *val, int and_destroy)
41000Sstevel@tonic-gate {
41010Sstevel@tonic-gate 	scf_value_t **curp;
41020Sstevel@tonic-gate 	scf_transaction_entry_t *te;
41030Sstevel@tonic-gate 
41040Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
41050Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
41060Sstevel@tonic-gate 	if (val->value_tx != NULL) {
41070Sstevel@tonic-gate 		te = val->value_tx;
41080Sstevel@tonic-gate 		te->entry_tx->tran_invalid = 1;
41090Sstevel@tonic-gate 
41100Sstevel@tonic-gate 		val->value_tx = NULL;
41110Sstevel@tonic-gate 
41120Sstevel@tonic-gate 		for (curp = &te->entry_head; *curp != NULL;
41130Sstevel@tonic-gate 		    curp = &(*curp)->value_next) {
41140Sstevel@tonic-gate 			if (*curp == val) {
41150Sstevel@tonic-gate 				*curp = val->value_next;
41160Sstevel@tonic-gate 				curp = NULL;
41170Sstevel@tonic-gate 				break;
41180Sstevel@tonic-gate 			}
41190Sstevel@tonic-gate 		}
41200Sstevel@tonic-gate 		assert(curp == NULL);
41210Sstevel@tonic-gate 	}
41220Sstevel@tonic-gate 	val->value_type = REP_PROTOCOL_TYPE_INVALID;
41230Sstevel@tonic-gate 
41240Sstevel@tonic-gate 	if (and_destroy) {
41250Sstevel@tonic-gate 		val->value_handle = NULL;
41260Sstevel@tonic-gate 		assert(h->rh_values > 0);
41270Sstevel@tonic-gate 		--h->rh_values;
41280Sstevel@tonic-gate 		--h->rh_extrefs;
41290Sstevel@tonic-gate 		uu_free(val);
41300Sstevel@tonic-gate 	}
41310Sstevel@tonic-gate }
41320Sstevel@tonic-gate 
41330Sstevel@tonic-gate void
41340Sstevel@tonic-gate scf_value_reset(scf_value_t *val)
41350Sstevel@tonic-gate {
41360Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
41370Sstevel@tonic-gate 
41380Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
41390Sstevel@tonic-gate 	scf_value_reset_locked(val, 0);
41400Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
41410Sstevel@tonic-gate }
41420Sstevel@tonic-gate 
41430Sstevel@tonic-gate scf_handle_t *
41440Sstevel@tonic-gate scf_value_handle(const scf_value_t *val)
41450Sstevel@tonic-gate {
41460Sstevel@tonic-gate 	return (handle_get(val->value_handle));
41470Sstevel@tonic-gate }
41480Sstevel@tonic-gate 
41490Sstevel@tonic-gate void
41500Sstevel@tonic-gate scf_value_destroy(scf_value_t *val)
41510Sstevel@tonic-gate {
41520Sstevel@tonic-gate 	scf_handle_t *h;
41530Sstevel@tonic-gate 
41540Sstevel@tonic-gate 	if (val == NULL)
41550Sstevel@tonic-gate 		return;
41560Sstevel@tonic-gate 
41570Sstevel@tonic-gate 	h = val->value_handle;
41580Sstevel@tonic-gate 
41590Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
41600Sstevel@tonic-gate 	scf_value_reset_locked(val, 1);
41610Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
41620Sstevel@tonic-gate }
41630Sstevel@tonic-gate 
41640Sstevel@tonic-gate scf_type_t
41650Sstevel@tonic-gate scf_value_base_type(const scf_value_t *val)
41660Sstevel@tonic-gate {
41670Sstevel@tonic-gate 	rep_protocol_value_type_t t, cur;
41680Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
41690Sstevel@tonic-gate 
41700Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
41710Sstevel@tonic-gate 	t = val->value_type;
41720Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
41730Sstevel@tonic-gate 
41740Sstevel@tonic-gate 	for (;;) {
41750Sstevel@tonic-gate 		cur = scf_proto_underlying_type(t);
41760Sstevel@tonic-gate 		if (cur == t)
41770Sstevel@tonic-gate 			break;
41780Sstevel@tonic-gate 		t = cur;
41790Sstevel@tonic-gate 	}
41800Sstevel@tonic-gate 
41810Sstevel@tonic-gate 	return (scf_protocol_type_to_type(t));
41820Sstevel@tonic-gate }
41830Sstevel@tonic-gate 
41840Sstevel@tonic-gate scf_type_t
41850Sstevel@tonic-gate scf_value_type(const scf_value_t *val)
41860Sstevel@tonic-gate {
41870Sstevel@tonic-gate 	rep_protocol_value_type_t t;
41880Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
41890Sstevel@tonic-gate 
41900Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
41910Sstevel@tonic-gate 	t = val->value_type;
41920Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
41930Sstevel@tonic-gate 
41940Sstevel@tonic-gate 	return (scf_protocol_type_to_type(t));
41950Sstevel@tonic-gate }
41960Sstevel@tonic-gate 
41970Sstevel@tonic-gate int
41980Sstevel@tonic-gate scf_value_is_type(const scf_value_t *val, scf_type_t base_arg)
41990Sstevel@tonic-gate {
42000Sstevel@tonic-gate 	rep_protocol_value_type_t t;
42010Sstevel@tonic-gate 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
42020Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
42030Sstevel@tonic-gate 
42040Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
42050Sstevel@tonic-gate 	t = val->value_type;
42060Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
42070Sstevel@tonic-gate 
42080Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_INVALID)
42090Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
42100Sstevel@tonic-gate 	if (base == REP_PROTOCOL_TYPE_INVALID)
42110Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
42120Sstevel@tonic-gate 	if (!scf_is_compatible_type(base, t))
42130Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
42140Sstevel@tonic-gate 
42150Sstevel@tonic-gate 	return (SCF_SUCCESS);
42160Sstevel@tonic-gate }
42170Sstevel@tonic-gate 
42180Sstevel@tonic-gate /*
42190Sstevel@tonic-gate  * Fails with
42200Sstevel@tonic-gate  *   _NOT_SET - val is reset
42210Sstevel@tonic-gate  *   _TYPE_MISMATCH - val's type is not compatible with t
42220Sstevel@tonic-gate  */
42230Sstevel@tonic-gate static int
42240Sstevel@tonic-gate scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t)
42250Sstevel@tonic-gate {
42260Sstevel@tonic-gate 	if (val->value_type == REP_PROTOCOL_TYPE_INVALID) {
42270Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NOT_SET);
42280Sstevel@tonic-gate 		return (0);
42290Sstevel@tonic-gate 	}
42300Sstevel@tonic-gate 	if (!scf_is_compatible_type(t, val->value_type)) {
42310Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
42320Sstevel@tonic-gate 		return (0);
42330Sstevel@tonic-gate 	}
42340Sstevel@tonic-gate 	return (1);
42350Sstevel@tonic-gate }
42360Sstevel@tonic-gate 
42370Sstevel@tonic-gate /*
42380Sstevel@tonic-gate  * Fails with
42390Sstevel@tonic-gate  *   _NOT_SET - val is reset
42400Sstevel@tonic-gate  *   _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
42410Sstevel@tonic-gate  */
42420Sstevel@tonic-gate int
42430Sstevel@tonic-gate scf_value_get_boolean(const scf_value_t *val, uint8_t *out)
42440Sstevel@tonic-gate {
42450Sstevel@tonic-gate 	char c;
42460Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
42470Sstevel@tonic-gate 	uint8_t o;
42480Sstevel@tonic-gate 
42490Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
42500Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) {
42510Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
42520Sstevel@tonic-gate 		return (-1);
42530Sstevel@tonic-gate 	}
42540Sstevel@tonic-gate 
42550Sstevel@tonic-gate 	c = val->value_value[0];
42560Sstevel@tonic-gate 	assert((c == '0' || c == '1') && val->value_value[1] == 0);
42570Sstevel@tonic-gate 
42580Sstevel@tonic-gate 	o = (c != '0');
42590Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
42600Sstevel@tonic-gate 	if (out != NULL)
42610Sstevel@tonic-gate 		*out = o;
42620Sstevel@tonic-gate 	return (SCF_SUCCESS);
42630Sstevel@tonic-gate }
42640Sstevel@tonic-gate 
42650Sstevel@tonic-gate int
42660Sstevel@tonic-gate scf_value_get_count(const scf_value_t *val, uint64_t *out)
42670Sstevel@tonic-gate {
42680Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
42690Sstevel@tonic-gate 	uint64_t o;
42700Sstevel@tonic-gate 
42710Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
42720Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) {
42730Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
42740Sstevel@tonic-gate 		return (-1);
42750Sstevel@tonic-gate 	}
42760Sstevel@tonic-gate 
42770Sstevel@tonic-gate 	o = strtoull(val->value_value, NULL, 10);
42780Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
42790Sstevel@tonic-gate 	if (out != NULL)
42800Sstevel@tonic-gate 		*out = o;
42810Sstevel@tonic-gate 	return (SCF_SUCCESS);
42820Sstevel@tonic-gate }
42830Sstevel@tonic-gate 
42840Sstevel@tonic-gate int
42850Sstevel@tonic-gate scf_value_get_integer(const scf_value_t *val, int64_t *out)
42860Sstevel@tonic-gate {
42870Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
42880Sstevel@tonic-gate 	int64_t o;
42890Sstevel@tonic-gate 
42900Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
42910Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) {
42920Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
42930Sstevel@tonic-gate 		return (-1);
42940Sstevel@tonic-gate 	}
42950Sstevel@tonic-gate 
42960Sstevel@tonic-gate 	o = strtoll(val->value_value, NULL, 10);
42970Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
42980Sstevel@tonic-gate 	if (out != NULL)
42990Sstevel@tonic-gate 		*out = o;
43000Sstevel@tonic-gate 	return (SCF_SUCCESS);
43010Sstevel@tonic-gate }
43020Sstevel@tonic-gate 
43030Sstevel@tonic-gate int
43040Sstevel@tonic-gate scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out)
43050Sstevel@tonic-gate {
43060Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
43070Sstevel@tonic-gate 	char *p;
43080Sstevel@tonic-gate 	int64_t os;
43090Sstevel@tonic-gate 	int32_t ons;
43100Sstevel@tonic-gate 
43110Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
43120Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) {
43130Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43140Sstevel@tonic-gate 		return (-1);
43150Sstevel@tonic-gate 	}
43160Sstevel@tonic-gate 
43170Sstevel@tonic-gate 	os = strtoll(val->value_value, &p, 10);
43180Sstevel@tonic-gate 	if (*p == '.')
43190Sstevel@tonic-gate 		ons = strtoul(p + 1, NULL, 10);
43200Sstevel@tonic-gate 	else
43210Sstevel@tonic-gate 		ons = 0;
43220Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
43230Sstevel@tonic-gate 	if (sec_out != NULL)
43240Sstevel@tonic-gate 		*sec_out = os;
43250Sstevel@tonic-gate 	if (nsec_out != NULL)
43260Sstevel@tonic-gate 		*nsec_out = ons;
43270Sstevel@tonic-gate 
43280Sstevel@tonic-gate 	return (SCF_SUCCESS);
43290Sstevel@tonic-gate }
43300Sstevel@tonic-gate 
43310Sstevel@tonic-gate /*
43320Sstevel@tonic-gate  * Fails with
43330Sstevel@tonic-gate  *   _NOT_SET - val is reset
43340Sstevel@tonic-gate  *   _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
43350Sstevel@tonic-gate  */
43360Sstevel@tonic-gate ssize_t
43370Sstevel@tonic-gate scf_value_get_astring(const scf_value_t *val, char *out, size_t len)
43380Sstevel@tonic-gate {
43390Sstevel@tonic-gate 	ssize_t ret;
43400Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
43410Sstevel@tonic-gate 
43420Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
43430Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) {
43440Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43450Sstevel@tonic-gate 		return ((ssize_t)-1);
43460Sstevel@tonic-gate 	}
43470Sstevel@tonic-gate 	ret = (ssize_t)strlcpy(out, val->value_value, len);
43480Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
43490Sstevel@tonic-gate 	return (ret);
43500Sstevel@tonic-gate }
43510Sstevel@tonic-gate 
43520Sstevel@tonic-gate ssize_t
43530Sstevel@tonic-gate scf_value_get_ustring(const scf_value_t *val, char *out, size_t len)
43540Sstevel@tonic-gate {
43550Sstevel@tonic-gate 	ssize_t ret;
43560Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
43570Sstevel@tonic-gate 
43580Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
43590Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) {
43600Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43610Sstevel@tonic-gate 		return ((ssize_t)-1);
43620Sstevel@tonic-gate 	}
43630Sstevel@tonic-gate 	ret = (ssize_t)strlcpy(out, val->value_value, len);
43640Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
43650Sstevel@tonic-gate 	return (ret);
43660Sstevel@tonic-gate }
43670Sstevel@tonic-gate 
43680Sstevel@tonic-gate ssize_t
43690Sstevel@tonic-gate scf_value_get_opaque(const scf_value_t *v, void *out, size_t len)
43700Sstevel@tonic-gate {
43710Sstevel@tonic-gate 	ssize_t ret;
43720Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
43730Sstevel@tonic-gate 
43740Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
43750Sstevel@tonic-gate 	if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) {
43760Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43770Sstevel@tonic-gate 		return ((ssize_t)-1);
43780Sstevel@tonic-gate 	}
43790Sstevel@tonic-gate 	if (len > v->value_size)
43800Sstevel@tonic-gate 		len = v->value_size;
43810Sstevel@tonic-gate 	ret = len;
43820Sstevel@tonic-gate 
43830Sstevel@tonic-gate 	(void) memcpy(out, v->value_value, len);
43840Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
43850Sstevel@tonic-gate 	return (ret);
43860Sstevel@tonic-gate }
43870Sstevel@tonic-gate 
43880Sstevel@tonic-gate void
43890Sstevel@tonic-gate scf_value_set_boolean(scf_value_t *v, uint8_t new)
43900Sstevel@tonic-gate {
43910Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
43920Sstevel@tonic-gate 
43930Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
43940Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
43950Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_BOOLEAN;
43960Sstevel@tonic-gate 	(void) sprintf(v->value_value, "%d", (new != 0));
43970Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
43980Sstevel@tonic-gate }
43990Sstevel@tonic-gate 
44000Sstevel@tonic-gate void
44010Sstevel@tonic-gate scf_value_set_count(scf_value_t *v, uint64_t new)
44020Sstevel@tonic-gate {
44030Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
44040Sstevel@tonic-gate 
44050Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
44060Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
44070Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_COUNT;
44080Sstevel@tonic-gate 	(void) sprintf(v->value_value, "%llu", (unsigned long long)new);
44090Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
44100Sstevel@tonic-gate }
44110Sstevel@tonic-gate 
44120Sstevel@tonic-gate void
44130Sstevel@tonic-gate scf_value_set_integer(scf_value_t *v, int64_t new)
44140Sstevel@tonic-gate {
44150Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
44160Sstevel@tonic-gate 
44170Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
44180Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
44190Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_INTEGER;
44200Sstevel@tonic-gate 	(void) sprintf(v->value_value, "%lld", (long long)new);
44210Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
44220Sstevel@tonic-gate }
44230Sstevel@tonic-gate 
44240Sstevel@tonic-gate int
44250Sstevel@tonic-gate scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec)
44260Sstevel@tonic-gate {
44270Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
44280Sstevel@tonic-gate 
44290Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
44300Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
44310Sstevel@tonic-gate 	if (new_nsec < 0 || new_nsec >= NANOSEC) {
44320Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
44330Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
44340Sstevel@tonic-gate 	}
44350Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_TIME;
44360Sstevel@tonic-gate 	if (new_nsec == 0)
44370Sstevel@tonic-gate 		(void) sprintf(v->value_value, "%lld", (long long)new_sec);
44380Sstevel@tonic-gate 	else
44390Sstevel@tonic-gate 		(void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec,
44400Sstevel@tonic-gate 		    (unsigned)new_nsec);
44410Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
44420Sstevel@tonic-gate 	return (0);
44430Sstevel@tonic-gate }
44440Sstevel@tonic-gate 
44450Sstevel@tonic-gate int
44460Sstevel@tonic-gate scf_value_set_astring(scf_value_t *v, const char *new)
44470Sstevel@tonic-gate {
44480Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
44490Sstevel@tonic-gate 
44500Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
44510Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
44520Sstevel@tonic-gate 	if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) {
44530Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
44540Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
44550Sstevel@tonic-gate 	}
44560Sstevel@tonic-gate 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
44570Sstevel@tonic-gate 	    sizeof (v->value_value)) {
44580Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
44590Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
44600Sstevel@tonic-gate 	}
44610Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_STRING;
44620Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
44630Sstevel@tonic-gate 	return (0);
44640Sstevel@tonic-gate }
44650Sstevel@tonic-gate 
44660Sstevel@tonic-gate int
44670Sstevel@tonic-gate scf_value_set_ustring(scf_value_t *v, const char *new)
44680Sstevel@tonic-gate {
44690Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
44700Sstevel@tonic-gate 
44710Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
44720Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
44730Sstevel@tonic-gate 	if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) {
44740Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
44750Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
44760Sstevel@tonic-gate 	}
44770Sstevel@tonic-gate 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
44780Sstevel@tonic-gate 	    sizeof (v->value_value)) {
44790Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
44800Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
44810Sstevel@tonic-gate 	}
44820Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_SUBTYPE_USTRING;
44830Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
44840Sstevel@tonic-gate 	return (0);
44850Sstevel@tonic-gate }
44860Sstevel@tonic-gate 
44870Sstevel@tonic-gate int
44880Sstevel@tonic-gate scf_value_set_opaque(scf_value_t *v, const void *new, size_t len)
44890Sstevel@tonic-gate {
44900Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
44910Sstevel@tonic-gate 
44920Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
44930Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
44940Sstevel@tonic-gate 	if (len > sizeof (v->value_value)) {
44950Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
44960Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
44970Sstevel@tonic-gate 	}
44980Sstevel@tonic-gate 	(void) memcpy(v->value_value, new, len);
44990Sstevel@tonic-gate 	v->value_size = len;
45000Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_OPAQUE;
45010Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
45020Sstevel@tonic-gate 	return (0);
45030Sstevel@tonic-gate }
45040Sstevel@tonic-gate 
45050Sstevel@tonic-gate /*
45060Sstevel@tonic-gate  * Fails with
45070Sstevel@tonic-gate  *   _NOT_SET - v_arg is reset
45080Sstevel@tonic-gate  *   _INTERNAL - v_arg is corrupt
45090Sstevel@tonic-gate  *
45100Sstevel@tonic-gate  * If t is not _TYPE_INVALID, fails with
45110Sstevel@tonic-gate  *   _TYPE_MISMATCH - v_arg's type is not compatible with t
45120Sstevel@tonic-gate  */
45130Sstevel@tonic-gate static ssize_t
45140Sstevel@tonic-gate scf_value_get_as_string_common(const scf_value_t *v_arg,
45150Sstevel@tonic-gate     rep_protocol_value_type_t t, char *buf, size_t bufsz)
45160Sstevel@tonic-gate {
45170Sstevel@tonic-gate 	scf_handle_t *h = v_arg->value_handle;
45180Sstevel@tonic-gate 	scf_value_t v_s;
45190Sstevel@tonic-gate 	scf_value_t *v = &v_s;
45200Sstevel@tonic-gate 	ssize_t r;
45210Sstevel@tonic-gate 	uint8_t b;
45220Sstevel@tonic-gate 
45230Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
45240Sstevel@tonic-gate 	if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) {
45250Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
45260Sstevel@tonic-gate 		return (-1);
45270Sstevel@tonic-gate 	}
45280Sstevel@tonic-gate 
45290Sstevel@tonic-gate 	v_s = *v_arg;			/* copy locally so we can unlock */
45300Sstevel@tonic-gate 	h->rh_values++;			/* keep the handle from going away */
45310Sstevel@tonic-gate 	h->rh_extrefs++;
45320Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
45330Sstevel@tonic-gate 
45340Sstevel@tonic-gate 
45350Sstevel@tonic-gate 	switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) {
45360Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_BOOLEAN:
45370Sstevel@tonic-gate 		r = scf_value_get_boolean(v, &b);
45380Sstevel@tonic-gate 		assert(r == SCF_SUCCESS);
45390Sstevel@tonic-gate 
45400Sstevel@tonic-gate 		r = strlcpy(buf, b ? "true" : "false", bufsz);
45410Sstevel@tonic-gate 		break;
45420Sstevel@tonic-gate 
45430Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_COUNT:
45440Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_INTEGER:
45450Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_TIME:
45460Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_STRING:
45470Sstevel@tonic-gate 		r = strlcpy(buf, v->value_value, bufsz);
45480Sstevel@tonic-gate 		break;
45490Sstevel@tonic-gate 
45500Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_OPAQUE:
45510Sstevel@tonic-gate 		/*
45520Sstevel@tonic-gate 		 * Note that we only write out full hex bytes -- if they're
45530Sstevel@tonic-gate 		 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
45540Sstevel@tonic-gate 		 * with data.
45550Sstevel@tonic-gate 		 */
45560Sstevel@tonic-gate 		if (bufsz > 0)
45570Sstevel@tonic-gate 			(void) scf_opaque_encode(buf, v->value_value,
45580Sstevel@tonic-gate 			    MIN(v->value_size, (bufsz - 1)/2));
45590Sstevel@tonic-gate 		r = (v->value_size * 2);
45600Sstevel@tonic-gate 		break;
45610Sstevel@tonic-gate 
45620Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_INVALID:
45630Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_NOT_SET);
45640Sstevel@tonic-gate 		break;
45650Sstevel@tonic-gate 
45660Sstevel@tonic-gate 	default:
45670Sstevel@tonic-gate 		r = (scf_set_error(SCF_ERROR_INTERNAL));
45680Sstevel@tonic-gate 		break;
45690Sstevel@tonic-gate 	}
45700Sstevel@tonic-gate 
45710Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
45720Sstevel@tonic-gate 	h->rh_values--;
45730Sstevel@tonic-gate 	h->rh_extrefs--;
45740Sstevel@tonic-gate 	handle_unrefed(h);
45750Sstevel@tonic-gate 
45760Sstevel@tonic-gate 	return (r);
45770Sstevel@tonic-gate }
45780Sstevel@tonic-gate 
45790Sstevel@tonic-gate ssize_t
45800Sstevel@tonic-gate scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz)
45810Sstevel@tonic-gate {
45820Sstevel@tonic-gate 	return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID,
45830Sstevel@tonic-gate 	    buf, bufsz));
45840Sstevel@tonic-gate }
45850Sstevel@tonic-gate 
45860Sstevel@tonic-gate ssize_t
45870Sstevel@tonic-gate scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type,
45880Sstevel@tonic-gate     char *buf, size_t bufsz)
45890Sstevel@tonic-gate {
45900Sstevel@tonic-gate 	rep_protocol_value_type_t ty = scf_type_to_protocol_type(type);
45910Sstevel@tonic-gate 	if (ty == REP_PROTOCOL_TYPE_INVALID)
45920Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
45930Sstevel@tonic-gate 
45940Sstevel@tonic-gate 	return (scf_value_get_as_string_common(v, ty, buf, bufsz));
45950Sstevel@tonic-gate }
45960Sstevel@tonic-gate 
45970Sstevel@tonic-gate int
45980Sstevel@tonic-gate scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str)
45990Sstevel@tonic-gate {
46000Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
46010Sstevel@tonic-gate 	rep_protocol_value_type_t ty;
46020Sstevel@tonic-gate 
46030Sstevel@tonic-gate 	switch (type) {
46040Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN: {
46050Sstevel@tonic-gate 		uint8_t b;
46060Sstevel@tonic-gate 
46070Sstevel@tonic-gate 		if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 ||
46080Sstevel@tonic-gate 		    strcmp(str, "1") == 0)
46090Sstevel@tonic-gate 			b = 1;
46100Sstevel@tonic-gate 		else if (strcmp(str, "false") == 0 ||
46110Sstevel@tonic-gate 		    strcmp(str, "f") == 0 || strcmp(str, "0") == 0)
46120Sstevel@tonic-gate 			b = 0;
46130Sstevel@tonic-gate 		else {
46140Sstevel@tonic-gate 			goto bad;
46150Sstevel@tonic-gate 		}
46160Sstevel@tonic-gate 
46170Sstevel@tonic-gate 		scf_value_set_boolean(v, b);
46180Sstevel@tonic-gate 		return (0);
46190Sstevel@tonic-gate 	}
46200Sstevel@tonic-gate 
46210Sstevel@tonic-gate 	case SCF_TYPE_COUNT: {
46220Sstevel@tonic-gate 		uint64_t c;
46230Sstevel@tonic-gate 		char *endp;
46240Sstevel@tonic-gate 
46250Sstevel@tonic-gate 		errno = 0;
46260Sstevel@tonic-gate 		c = strtoul(str, &endp, 0);
46270Sstevel@tonic-gate 
46280Sstevel@tonic-gate 		if (errno != 0 || endp == str || *endp != '\0')
46290Sstevel@tonic-gate 			goto bad;
46300Sstevel@tonic-gate 
46310Sstevel@tonic-gate 		scf_value_set_count(v, c);
46320Sstevel@tonic-gate 		return (0);
46330Sstevel@tonic-gate 	}
46340Sstevel@tonic-gate 
46350Sstevel@tonic-gate 	case SCF_TYPE_INTEGER: {
46360Sstevel@tonic-gate 		int64_t i;
46370Sstevel@tonic-gate 		char *endp;
46380Sstevel@tonic-gate 
46390Sstevel@tonic-gate 		errno = 0;
46400Sstevel@tonic-gate 		i = strtol(str, &endp, 0);
46410Sstevel@tonic-gate 
46420Sstevel@tonic-gate 		if (errno != 0 || endp == str || *endp != '\0')
46430Sstevel@tonic-gate 			goto bad;
46440Sstevel@tonic-gate 
46450Sstevel@tonic-gate 		scf_value_set_integer(v, i);
46460Sstevel@tonic-gate 		return (0);
46470Sstevel@tonic-gate 	}
46480Sstevel@tonic-gate 
46490Sstevel@tonic-gate 	case SCF_TYPE_TIME: {
46500Sstevel@tonic-gate 		int64_t s;
46510Sstevel@tonic-gate 		uint32_t ns = 0;
46520Sstevel@tonic-gate 		char *endp, *ns_str;
46530Sstevel@tonic-gate 		size_t len;
46540Sstevel@tonic-gate 
46550Sstevel@tonic-gate 		errno = 0;
46560Sstevel@tonic-gate 		s = strtoll(str, &endp, 10);
46570Sstevel@tonic-gate 		if (errno != 0 || endp == str ||
46580Sstevel@tonic-gate 		    (*endp != '\0' && *endp != '.'))
46590Sstevel@tonic-gate 			goto bad;
46600Sstevel@tonic-gate 
46610Sstevel@tonic-gate 		if (*endp == '.') {
46620Sstevel@tonic-gate 			ns_str = endp + 1;
46630Sstevel@tonic-gate 			len = strlen(ns_str);
46640Sstevel@tonic-gate 			if (len == 0 || len > 9)
46650Sstevel@tonic-gate 				goto bad;
46660Sstevel@tonic-gate 
46670Sstevel@tonic-gate 			ns = strtoul(ns_str, &endp, 10);
46680Sstevel@tonic-gate 			if (errno != 0 || endp == ns_str || *endp != '\0')
46690Sstevel@tonic-gate 				goto bad;
46700Sstevel@tonic-gate 
46710Sstevel@tonic-gate 			while (len++ < 9)
46720Sstevel@tonic-gate 				ns *= 10;
46730Sstevel@tonic-gate 			assert(ns < NANOSEC);
46740Sstevel@tonic-gate 		}
46750Sstevel@tonic-gate 
46760Sstevel@tonic-gate 		return (scf_value_set_time(v, s, ns));
46770Sstevel@tonic-gate 	}
46780Sstevel@tonic-gate 
46790Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
46800Sstevel@tonic-gate 	case SCF_TYPE_USTRING:
46810Sstevel@tonic-gate 	case SCF_TYPE_OPAQUE:
46820Sstevel@tonic-gate 	case SCF_TYPE_URI:
46830Sstevel@tonic-gate 	case SCF_TYPE_FMRI:
46840Sstevel@tonic-gate 	case SCF_TYPE_HOST:
46850Sstevel@tonic-gate 	case SCF_TYPE_HOSTNAME:
46860Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V4:
46870Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V6:
46880Sstevel@tonic-gate 		ty = scf_type_to_protocol_type(type);
46890Sstevel@tonic-gate 
46900Sstevel@tonic-gate 		(void) pthread_mutex_lock(&h->rh_lock);
46910Sstevel@tonic-gate 		scf_value_reset_locked(v, 0);
46920Sstevel@tonic-gate 		if (type == SCF_TYPE_OPAQUE) {
46930Sstevel@tonic-gate 			v->value_size = scf_opaque_decode(v->value_value,
46940Sstevel@tonic-gate 			    str, sizeof (v->value_value));
46950Sstevel@tonic-gate 			if (!scf_validate_encoded_value(ty, str)) {
46960Sstevel@tonic-gate 				(void) pthread_mutex_lock(&h->rh_lock);
46970Sstevel@tonic-gate 				goto bad;
46980Sstevel@tonic-gate 			}
46990Sstevel@tonic-gate 		} else {
47000Sstevel@tonic-gate 			(void) strlcpy(v->value_value, str,
47010Sstevel@tonic-gate 			    sizeof (v->value_value));
47020Sstevel@tonic-gate 			if (!scf_validate_encoded_value(ty, v->value_value)) {
47030Sstevel@tonic-gate 				(void) pthread_mutex_lock(&h->rh_lock);
47040Sstevel@tonic-gate 				goto bad;
47050Sstevel@tonic-gate 			}
47060Sstevel@tonic-gate 		}
47070Sstevel@tonic-gate 		v->value_type = ty;
47080Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47090Sstevel@tonic-gate 		return (SCF_SUCCESS);
47100Sstevel@tonic-gate 
47110Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_INVALID:
47120Sstevel@tonic-gate 	default:
47130Sstevel@tonic-gate 		scf_value_reset(v);
47140Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
47150Sstevel@tonic-gate 	}
47160Sstevel@tonic-gate bad:
47170Sstevel@tonic-gate 	scf_value_reset(v);
47180Sstevel@tonic-gate 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
47190Sstevel@tonic-gate }
47200Sstevel@tonic-gate 
47210Sstevel@tonic-gate int
47220Sstevel@tonic-gate scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop)
47230Sstevel@tonic-gate {
47240Sstevel@tonic-gate 	return (datael_setup_iter(iter, &prop->rd_d,
47250Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_VALUE, 0));
47260Sstevel@tonic-gate }
47270Sstevel@tonic-gate 
47280Sstevel@tonic-gate int
47290Sstevel@tonic-gate scf_iter_next_value(scf_iter_t *iter, scf_value_t *v)
47300Sstevel@tonic-gate {
47310Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
47320Sstevel@tonic-gate 
47330Sstevel@tonic-gate 	struct rep_protocol_iter_read_value request;
47340Sstevel@tonic-gate 	struct rep_protocol_value_response response;
47350Sstevel@tonic-gate 
47360Sstevel@tonic-gate 	int r;
47370Sstevel@tonic-gate 
47380Sstevel@tonic-gate 	if (h != v->value_handle)
47390Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
47400Sstevel@tonic-gate 
47410Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
47420Sstevel@tonic-gate 
47430Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
47440Sstevel@tonic-gate 
47450Sstevel@tonic-gate 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
47460Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47470Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
47480Sstevel@tonic-gate 	}
47490Sstevel@tonic-gate 
47500Sstevel@tonic-gate 	if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) {
47510Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47520Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
47530Sstevel@tonic-gate 	}
47540Sstevel@tonic-gate 
47550Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE;
47560Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
47570Sstevel@tonic-gate 	request.rpr_sequence = iter->iter_sequence;
47580Sstevel@tonic-gate 
47590Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
47600Sstevel@tonic-gate 	    &response, sizeof (response));
47610Sstevel@tonic-gate 
47620Sstevel@tonic-gate 	if (r < 0) {
47630Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47640Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
47650Sstevel@tonic-gate 	}
47660Sstevel@tonic-gate 
47670Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE) {
47680Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47690Sstevel@tonic-gate 		return (0);
47700Sstevel@tonic-gate 	}
47710Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
47720Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47730Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
47740Sstevel@tonic-gate 	}
47750Sstevel@tonic-gate 	iter->iter_sequence++;
47760Sstevel@tonic-gate 
47770Sstevel@tonic-gate 	v->value_type = response.rpr_type;
47780Sstevel@tonic-gate 
47790Sstevel@tonic-gate 	assert(scf_validate_encoded_value(response.rpr_type,
47800Sstevel@tonic-gate 	    response.rpr_value));
47810Sstevel@tonic-gate 
47820Sstevel@tonic-gate 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
47830Sstevel@tonic-gate 		(void) strlcpy(v->value_value, response.rpr_value,
47840Sstevel@tonic-gate 		    sizeof (v->value_value));
47850Sstevel@tonic-gate 	} else {
47860Sstevel@tonic-gate 		v->value_size = scf_opaque_decode(v->value_value,
47870Sstevel@tonic-gate 		    response.rpr_value, sizeof (v->value_value));
47880Sstevel@tonic-gate 	}
47890Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
47900Sstevel@tonic-gate 
47910Sstevel@tonic-gate 	return (1);
47920Sstevel@tonic-gate }
47930Sstevel@tonic-gate 
47940Sstevel@tonic-gate int
47950Sstevel@tonic-gate scf_property_get_value(const scf_property_t *prop, scf_value_t *v)
47960Sstevel@tonic-gate {
47970Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
47980Sstevel@tonic-gate 	struct rep_protocol_property_request request;
47990Sstevel@tonic-gate 	struct rep_protocol_value_response response;
48000Sstevel@tonic-gate 	int r;
48010Sstevel@tonic-gate 
48020Sstevel@tonic-gate 	if (h != v->value_handle)
48030Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
48040Sstevel@tonic-gate 
48050Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
48060Sstevel@tonic-gate 
48070Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE;
48080Sstevel@tonic-gate 	request.rpr_entityid = prop->rd_d.rd_entity;
48090Sstevel@tonic-gate 
48100Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
48110Sstevel@tonic-gate 	datael_finish_reset(&prop->rd_d);
48120Sstevel@tonic-gate 
48130Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
48140Sstevel@tonic-gate 	    &response, sizeof (response));
48150Sstevel@tonic-gate 
48160Sstevel@tonic-gate 	if (r < 0) {
48170Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
48180Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
48190Sstevel@tonic-gate 	}
48200Sstevel@tonic-gate 
48210Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
48220Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) {
48230Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
48240Sstevel@tonic-gate 		assert(response.rpr_response !=
48250Sstevel@tonic-gate 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
48260Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
48270Sstevel@tonic-gate 	}
48280Sstevel@tonic-gate 
48290Sstevel@tonic-gate 	v->value_type = response.rpr_type;
48300Sstevel@tonic-gate 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
48310Sstevel@tonic-gate 		(void) strlcpy(v->value_value, response.rpr_value,
48320Sstevel@tonic-gate 		    sizeof (v->value_value));
48330Sstevel@tonic-gate 	} else {
48340Sstevel@tonic-gate 		v->value_size = scf_opaque_decode(v->value_value,
48350Sstevel@tonic-gate 		    response.rpr_value, sizeof (v->value_value));
48360Sstevel@tonic-gate 	}
48370Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
48380Sstevel@tonic-gate 	return ((response.rpr_response == REP_PROTOCOL_SUCCESS)?
48390Sstevel@tonic-gate 	    SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
48400Sstevel@tonic-gate }
48410Sstevel@tonic-gate 
48420Sstevel@tonic-gate int
48430Sstevel@tonic-gate scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc)
48440Sstevel@tonic-gate {
48450Sstevel@tonic-gate 	return (datael_get_parent(&pg->rd_d, &svc->rd_d));
48460Sstevel@tonic-gate }
48470Sstevel@tonic-gate 
48480Sstevel@tonic-gate int
48490Sstevel@tonic-gate scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst)
48500Sstevel@tonic-gate {
48510Sstevel@tonic-gate 	return (datael_get_parent(&pg->rd_d, &inst->rd_d));
48520Sstevel@tonic-gate }
48530Sstevel@tonic-gate 
48540Sstevel@tonic-gate int
48550Sstevel@tonic-gate scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg,
48560Sstevel@tonic-gate     scf_snaplevel_t *level)
48570Sstevel@tonic-gate {
48580Sstevel@tonic-gate 	return (datael_get_parent(&pg->rd_d, &level->rd_d));
48590Sstevel@tonic-gate }
48600Sstevel@tonic-gate 
48610Sstevel@tonic-gate int
48620Sstevel@tonic-gate scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s)
48630Sstevel@tonic-gate {
48640Sstevel@tonic-gate 	return (datael_get_parent(&svc->rd_d, &s->rd_d));
48650Sstevel@tonic-gate }
48660Sstevel@tonic-gate 
48670Sstevel@tonic-gate int
48680Sstevel@tonic-gate scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc)
48690Sstevel@tonic-gate {
48700Sstevel@tonic-gate 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
48710Sstevel@tonic-gate }
48720Sstevel@tonic-gate 
48730Sstevel@tonic-gate int
48740Sstevel@tonic-gate scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc)
48750Sstevel@tonic-gate {
48760Sstevel@tonic-gate 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
48770Sstevel@tonic-gate }
48780Sstevel@tonic-gate 
48790Sstevel@tonic-gate int
48800Sstevel@tonic-gate scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc)
48810Sstevel@tonic-gate {
48820Sstevel@tonic-gate 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
48830Sstevel@tonic-gate }
48840Sstevel@tonic-gate 
48850Sstevel@tonic-gate /*
48860Sstevel@tonic-gate  * FMRI functions
48870Sstevel@tonic-gate  *
48880Sstevel@tonic-gate  * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
48890Sstevel@tonic-gate  * scf_parse_fmri(), fmri isn't const because that would require
48900Sstevel@tonic-gate  * allocating memory. Also, note that scope, at least, is not necessarily
48910Sstevel@tonic-gate  * in the passed in fmri.
48920Sstevel@tonic-gate  */
48930Sstevel@tonic-gate 
48940Sstevel@tonic-gate int
48950Sstevel@tonic-gate scf_parse_svc_fmri(char *fmri, const char **scope, const char **service,
48960Sstevel@tonic-gate     const char **instance, const char **propertygroup, const char **property)
48970Sstevel@tonic-gate {
48980Sstevel@tonic-gate 	char *s, *e, *te, *tpg;
48990Sstevel@tonic-gate 	char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL;
49000Sstevel@tonic-gate 
49010Sstevel@tonic-gate 	if (scope != NULL)
49020Sstevel@tonic-gate 		*scope = NULL;
49030Sstevel@tonic-gate 	if (service != NULL)
49040Sstevel@tonic-gate 		*service = NULL;
49050Sstevel@tonic-gate 	if (instance != NULL)
49060Sstevel@tonic-gate 		*instance = NULL;
49070Sstevel@tonic-gate 	if (propertygroup != NULL)
49080Sstevel@tonic-gate 		*propertygroup = NULL;
49090Sstevel@tonic-gate 	if (property != NULL)
49100Sstevel@tonic-gate 		*property = NULL;
49110Sstevel@tonic-gate 
49120Sstevel@tonic-gate 	s = fmri;
49130Sstevel@tonic-gate 	e = strchr(s, '\0');
49140Sstevel@tonic-gate 
49150Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_SVC_PREFIX,
49160Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0)
49170Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_SVC_PREFIX) - 1;
49180Sstevel@tonic-gate 
49190Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
49200Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
49210Sstevel@tonic-gate 		char *my_scope;
49220Sstevel@tonic-gate 
49230Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
49240Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
49250Sstevel@tonic-gate 		if (te == NULL)
49260Sstevel@tonic-gate 			te = e;
49270Sstevel@tonic-gate 
49280Sstevel@tonic-gate 		*te = 0;
49290Sstevel@tonic-gate 		my_scope = s;
49300Sstevel@tonic-gate 
49310Sstevel@tonic-gate 		s = te;
49320Sstevel@tonic-gate 		if (s < e)
49330Sstevel@tonic-gate 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
49340Sstevel@tonic-gate 
49350Sstevel@tonic-gate 		/* If the scope ends with the suffix, remove it. */
49360Sstevel@tonic-gate 		te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX);
49370Sstevel@tonic-gate 		if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0)
49380Sstevel@tonic-gate 			*te = 0;
49390Sstevel@tonic-gate 
49400Sstevel@tonic-gate 		/* Validate the scope. */
49410Sstevel@tonic-gate 		if (my_scope[0] == '\0')
49420Sstevel@tonic-gate 			my_scope = SCF_FMRI_LOCAL_SCOPE;
49430Sstevel@tonic-gate 		else if (uu_check_name(my_scope, 0) == -1) {
49440Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
49450Sstevel@tonic-gate 		}
49460Sstevel@tonic-gate 
49470Sstevel@tonic-gate 		if (scope != NULL)
49480Sstevel@tonic-gate 			*scope = my_scope;
49490Sstevel@tonic-gate 	} else {
49500Sstevel@tonic-gate 		if (scope != NULL)
49510Sstevel@tonic-gate 			*scope = SCF_FMRI_LOCAL_SCOPE;
49520Sstevel@tonic-gate 	}
49530Sstevel@tonic-gate 
49540Sstevel@tonic-gate 	if (s[0] != 0) {
49550Sstevel@tonic-gate 		if (strncmp(s, SCF_FMRI_SERVICE_PREFIX,
49560Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0)
49570Sstevel@tonic-gate 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
49580Sstevel@tonic-gate 
49590Sstevel@tonic-gate 		/*
49600Sstevel@tonic-gate 		 * Can't validate service here because it might not be null
49610Sstevel@tonic-gate 		 * terminated.
49620Sstevel@tonic-gate 		 */
49630Sstevel@tonic-gate 		my_s = s;
49640Sstevel@tonic-gate 	}
49650Sstevel@tonic-gate 
49660Sstevel@tonic-gate 	tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
49670Sstevel@tonic-gate 	te = strstr(s, SCF_FMRI_INSTANCE_PREFIX);
49680Sstevel@tonic-gate 	if (te != NULL && (tpg == NULL || te < tpg)) {
49690Sstevel@tonic-gate 		*te = 0;
49700Sstevel@tonic-gate 		te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
49710Sstevel@tonic-gate 
49720Sstevel@tonic-gate 		/* Can't validate instance here either. */
49730Sstevel@tonic-gate 		my_i = s = te;
49740Sstevel@tonic-gate 
49750Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
49760Sstevel@tonic-gate 	} else {
49770Sstevel@tonic-gate 		te = tpg;
49780Sstevel@tonic-gate 	}
49790Sstevel@tonic-gate 
49800Sstevel@tonic-gate 	if (te != NULL) {
49810Sstevel@tonic-gate 		*te = 0;
49820Sstevel@tonic-gate 		te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
49830Sstevel@tonic-gate 
49840Sstevel@tonic-gate 		my_pg = s = te;
49850Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_PROPERTY_PREFIX);
49860Sstevel@tonic-gate 		if (te != NULL) {
49870Sstevel@tonic-gate 			*te = 0;
49880Sstevel@tonic-gate 			te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
49890Sstevel@tonic-gate 
49900Sstevel@tonic-gate 			my_p = te;
49910Sstevel@tonic-gate 			s = te;
49920Sstevel@tonic-gate 		}
49930Sstevel@tonic-gate 	}
49940Sstevel@tonic-gate 
49950Sstevel@tonic-gate 	if (my_s != NULL) {
49960Sstevel@tonic-gate 		if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1)
49970Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
49980Sstevel@tonic-gate 
49990Sstevel@tonic-gate 		if (service != NULL)
50000Sstevel@tonic-gate 			*service = my_s;
50010Sstevel@tonic-gate 	}
50020Sstevel@tonic-gate 
50030Sstevel@tonic-gate 	if (my_i != NULL) {
50040Sstevel@tonic-gate 		if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1)
50050Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
50060Sstevel@tonic-gate 
50070Sstevel@tonic-gate 		if (instance != NULL)
50080Sstevel@tonic-gate 			*instance = my_i;
50090Sstevel@tonic-gate 	}
50100Sstevel@tonic-gate 
50110Sstevel@tonic-gate 	if (my_pg != NULL) {
50120Sstevel@tonic-gate 		if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1)
50130Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
50140Sstevel@tonic-gate 
50150Sstevel@tonic-gate 		if (propertygroup != NULL)
50160Sstevel@tonic-gate 			*propertygroup = my_pg;
50170Sstevel@tonic-gate 	}
50180Sstevel@tonic-gate 
50190Sstevel@tonic-gate 	if (my_p != NULL) {
50200Sstevel@tonic-gate 		if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1)
50210Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
50220Sstevel@tonic-gate 
50230Sstevel@tonic-gate 		if (property != NULL)
50240Sstevel@tonic-gate 			*property = my_p;
50250Sstevel@tonic-gate 	}
50260Sstevel@tonic-gate 
50270Sstevel@tonic-gate 	return (0);
50280Sstevel@tonic-gate }
50290Sstevel@tonic-gate 
50300Sstevel@tonic-gate int
50310Sstevel@tonic-gate scf_parse_file_fmri(char *fmri, const char **scope, const char **path)
50320Sstevel@tonic-gate {
50330Sstevel@tonic-gate 	char *s, *e, *te;
50340Sstevel@tonic-gate 
50350Sstevel@tonic-gate 	if (scope != NULL)
50360Sstevel@tonic-gate 		*scope = NULL;
50370Sstevel@tonic-gate 
50380Sstevel@tonic-gate 	s = fmri;
50390Sstevel@tonic-gate 	e = strchr(s, '\0');
50400Sstevel@tonic-gate 
50410Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_FILE_PREFIX,
50420Sstevel@tonic-gate 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0)
50430Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_FILE_PREFIX) - 1;
50440Sstevel@tonic-gate 
50450Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
50460Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
50470Sstevel@tonic-gate 		char *my_scope;
50480Sstevel@tonic-gate 
50490Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
50500Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
50510Sstevel@tonic-gate 		if (te == NULL)
50520Sstevel@tonic-gate 			te = e;
50530Sstevel@tonic-gate 
50540Sstevel@tonic-gate 		*te = 0;
50550Sstevel@tonic-gate 		my_scope = s;
50560Sstevel@tonic-gate 
50570Sstevel@tonic-gate 		s = te;
50580Sstevel@tonic-gate 
50590Sstevel@tonic-gate 		/* Validate the scope. */
50600Sstevel@tonic-gate 		if (my_scope[0] != '\0' &&
50610Sstevel@tonic-gate 		    strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
50620Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
50630Sstevel@tonic-gate 		}
50640Sstevel@tonic-gate 
50650Sstevel@tonic-gate 		if (scope != NULL)
50660Sstevel@tonic-gate 			*scope = my_scope;
50670Sstevel@tonic-gate 	} else {
50680Sstevel@tonic-gate 		/*
50690Sstevel@tonic-gate 		 * FMRI paths must be absolute
50700Sstevel@tonic-gate 		 */
50710Sstevel@tonic-gate 		if (s[0] != '/')
50720Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
50730Sstevel@tonic-gate 	}
50740Sstevel@tonic-gate 
50750Sstevel@tonic-gate 	s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
50760Sstevel@tonic-gate 
50770Sstevel@tonic-gate 	if (s >= e)
50780Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
50790Sstevel@tonic-gate 
50800Sstevel@tonic-gate 	/*
50810Sstevel@tonic-gate 	 * If the user requests it, return the full path of the file.
50820Sstevel@tonic-gate 	 */
50830Sstevel@tonic-gate 	if (path != NULL) {
50840Sstevel@tonic-gate 		assert(s > fmri);
50850Sstevel@tonic-gate 		s[-1] = '/';
50860Sstevel@tonic-gate 		*path = s - 1;
50870Sstevel@tonic-gate 	}
50880Sstevel@tonic-gate 
50890Sstevel@tonic-gate 	return (0);
50900Sstevel@tonic-gate }
50910Sstevel@tonic-gate 
50920Sstevel@tonic-gate int
50930Sstevel@tonic-gate scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service,
50940Sstevel@tonic-gate     const char **instance, const char **propertygroup, const char **property)
50950Sstevel@tonic-gate {
50960Sstevel@tonic-gate 	if (strncmp(fmri, SCF_FMRI_SVC_PREFIX,
50970Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
50980Sstevel@tonic-gate 		if (type)
50990Sstevel@tonic-gate 			*type = SCF_FMRI_TYPE_SVC;
51000Sstevel@tonic-gate 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
51010Sstevel@tonic-gate 			    propertygroup, property));
51020Sstevel@tonic-gate 	} else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX,
51030Sstevel@tonic-gate 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
51040Sstevel@tonic-gate 		if (type)
51050Sstevel@tonic-gate 			*type = SCF_FMRI_TYPE_FILE;
51060Sstevel@tonic-gate 		return (scf_parse_file_fmri(fmri, scope, NULL));
51070Sstevel@tonic-gate 	} else {
51080Sstevel@tonic-gate 		/*
51090Sstevel@tonic-gate 		 * Parse as a svc if the fmri type is not explicitly
51100Sstevel@tonic-gate 		 * specified.
51110Sstevel@tonic-gate 		 */
51120Sstevel@tonic-gate 		if (type)
51130Sstevel@tonic-gate 			*type = SCF_FMRI_TYPE_SVC;
51140Sstevel@tonic-gate 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
51150Sstevel@tonic-gate 		    propertygroup, property));
51160Sstevel@tonic-gate 	}
51170Sstevel@tonic-gate }
51180Sstevel@tonic-gate 
51190Sstevel@tonic-gate /*
51200Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT.  fmri and buf may be equal.
51210Sstevel@tonic-gate  */
51220Sstevel@tonic-gate ssize_t
51230Sstevel@tonic-gate scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz)
51240Sstevel@tonic-gate {
51250Sstevel@tonic-gate 	const char *scope, *service, *instance, *pg, *property;
51260Sstevel@tonic-gate 	char local[6 * REP_PROTOCOL_NAME_LEN];
51270Sstevel@tonic-gate 	int r;
51280Sstevel@tonic-gate 	size_t len;
51290Sstevel@tonic-gate 
51300Sstevel@tonic-gate 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
51310Sstevel@tonic-gate 		/* Should this be CONSTRAINT_VIOLATED? */
51320Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
51330Sstevel@tonic-gate 		return (-1);
51340Sstevel@tonic-gate 	}
51350Sstevel@tonic-gate 
51360Sstevel@tonic-gate 
51370Sstevel@tonic-gate 	r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg,
51380Sstevel@tonic-gate 	    &property);
51390Sstevel@tonic-gate 	if (r != 0)
51400Sstevel@tonic-gate 		return (-1);
51410Sstevel@tonic-gate 
51420Sstevel@tonic-gate 	len = strlcpy(buf, "svc:/", bufsz);
51430Sstevel@tonic-gate 
51440Sstevel@tonic-gate 	if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) {
51450Sstevel@tonic-gate 		len += strlcat(buf, "/", bufsz);
51460Sstevel@tonic-gate 		len += strlcat(buf, scope, bufsz);
51470Sstevel@tonic-gate 	}
51480Sstevel@tonic-gate 
51490Sstevel@tonic-gate 	if (service)
51500Sstevel@tonic-gate 		len += strlcat(buf, service, bufsz);
51510Sstevel@tonic-gate 
51520Sstevel@tonic-gate 	if (instance) {
51530Sstevel@tonic-gate 		len += strlcat(buf, ":", bufsz);
51540Sstevel@tonic-gate 		len += strlcat(buf, instance, bufsz);
51550Sstevel@tonic-gate 	}
51560Sstevel@tonic-gate 
51570Sstevel@tonic-gate 	if (pg) {
51580Sstevel@tonic-gate 		len += strlcat(buf, "/:properties/", bufsz);
51590Sstevel@tonic-gate 		len += strlcat(buf, pg, bufsz);
51600Sstevel@tonic-gate 	}
51610Sstevel@tonic-gate 
51620Sstevel@tonic-gate 	if (property) {
51630Sstevel@tonic-gate 		len += strlcat(buf, "/", bufsz);
51640Sstevel@tonic-gate 		len += strlcat(buf, property, bufsz);
51650Sstevel@tonic-gate 	}
51660Sstevel@tonic-gate 
51670Sstevel@tonic-gate 	return (len);
51680Sstevel@tonic-gate }
51690Sstevel@tonic-gate 
51700Sstevel@tonic-gate int
51710Sstevel@tonic-gate scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc,
51720Sstevel@tonic-gate     scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg,
51730Sstevel@tonic-gate     scf_property_t *prop, int flags)
51740Sstevel@tonic-gate {
51750Sstevel@tonic-gate 	const char *scope, *service, *instance, *propertygroup, *property;
51760Sstevel@tonic-gate 	int last;
51770Sstevel@tonic-gate 	char local[6 * REP_PROTOCOL_NAME_LEN];
51780Sstevel@tonic-gate 	int ret;
51790Sstevel@tonic-gate 	const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE |
51800Sstevel@tonic-gate 	    RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY;
51810Sstevel@tonic-gate 
51820Sstevel@tonic-gate 	/*
51830Sstevel@tonic-gate 	 * verify that all handles match
51840Sstevel@tonic-gate 	 */
51850Sstevel@tonic-gate 	if ((sc != NULL && h != sc->rd_d.rd_handle) ||
51860Sstevel@tonic-gate 	    (svc != NULL && h != svc->rd_d.rd_handle) ||
51870Sstevel@tonic-gate 	    (inst != NULL && h != inst->rd_d.rd_handle) ||
51880Sstevel@tonic-gate 	    (pg != NULL && h != pg->rd_d.rd_handle) ||
51890Sstevel@tonic-gate 	    (prop != NULL && h != prop->rd_d.rd_handle))
51900Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
51910Sstevel@tonic-gate 
51920Sstevel@tonic-gate 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
51930Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
51940Sstevel@tonic-gate 		goto reset_args;
51950Sstevel@tonic-gate 	}
51960Sstevel@tonic-gate 
51970Sstevel@tonic-gate 	/*
51980Sstevel@tonic-gate 	 * We can simply return from an error in parsing, because
51990Sstevel@tonic-gate 	 * scf_parse_fmri sets the error code correctly.
52000Sstevel@tonic-gate 	 */
52010Sstevel@tonic-gate 	if (scf_parse_svc_fmri(local, &scope, &service, &instance,
52020Sstevel@tonic-gate 	    &propertygroup, &property) == -1) {
52030Sstevel@tonic-gate 		ret = -1;
52040Sstevel@tonic-gate 		goto reset_args;
52050Sstevel@tonic-gate 	}
52060Sstevel@tonic-gate 
52070Sstevel@tonic-gate 	/*
52080Sstevel@tonic-gate 	 * the FMRI looks valid at this point -- do constraint checks.
52090Sstevel@tonic-gate 	 */
52100Sstevel@tonic-gate 
52110Sstevel@tonic-gate 	if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) {
52120Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
52130Sstevel@tonic-gate 		goto reset_args;
52140Sstevel@tonic-gate 	}
52150Sstevel@tonic-gate 	if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) {
52160Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
52170Sstevel@tonic-gate 		goto reset_args;
52180Sstevel@tonic-gate 	}
52190Sstevel@tonic-gate 
52200Sstevel@tonic-gate 	if (prop != NULL)
52210Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_PROPERTY;
52220Sstevel@tonic-gate 	else if (pg != NULL)
52230Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_PROPERTYGRP;
52240Sstevel@tonic-gate 	else if (inst != NULL)
52250Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_INSTANCE;
52260Sstevel@tonic-gate 	else if (svc != NULL)
52270Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_SERVICE;
52280Sstevel@tonic-gate 	else if (sc != NULL)
52290Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_SCOPE;
52300Sstevel@tonic-gate 	else
52310Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_NONE;
52320Sstevel@tonic-gate 
52330Sstevel@tonic-gate 	if (flags & SCF_DECODE_FMRI_EXACT) {
52340Sstevel@tonic-gate 		int last_fmri;
52350Sstevel@tonic-gate 
52360Sstevel@tonic-gate 		if (property != NULL)
52370Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTY;
52380Sstevel@tonic-gate 		else if (propertygroup != NULL)
52390Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP;
52400Sstevel@tonic-gate 		else if (instance != NULL)
52410Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_INSTANCE;
52420Sstevel@tonic-gate 		else if (service != NULL)
52430Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_SERVICE;
52440Sstevel@tonic-gate 		else if (scope != NULL)
52450Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_SCOPE;
52460Sstevel@tonic-gate 		else
52470Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_NONE;
52480Sstevel@tonic-gate 
52490Sstevel@tonic-gate 		if (last != last_fmri) {
52500Sstevel@tonic-gate 			ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
52510Sstevel@tonic-gate 			goto reset_args;
52520Sstevel@tonic-gate 		}
52530Sstevel@tonic-gate 	}
52540Sstevel@tonic-gate 
52550Sstevel@tonic-gate 	if ((flags & SCF_DECODE_FMRI_TRUNCATE) &&
52560Sstevel@tonic-gate 	    last == REP_PROTOCOL_ENTITY_NONE) {
52570Sstevel@tonic-gate 		ret = 0;				/* nothing to do */
52580Sstevel@tonic-gate 		goto reset_args;
52590Sstevel@tonic-gate 	}
52600Sstevel@tonic-gate 
52610Sstevel@tonic-gate 	if (!(flags & SCF_DECODE_FMRI_TRUNCATE))
52620Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_NONE;	/* never stop */
52630Sstevel@tonic-gate 
52640Sstevel@tonic-gate 	/*
52650Sstevel@tonic-gate 	 * passed the constraint checks -- try to grab the thing itself.
52660Sstevel@tonic-gate 	 */
52670Sstevel@tonic-gate 
52680Sstevel@tonic-gate 	handle_hold_subhandles(h, holds);
52690Sstevel@tonic-gate 	if (sc == NULL)
52700Sstevel@tonic-gate 		sc = h->rh_scope;
52710Sstevel@tonic-gate 	else
52720Sstevel@tonic-gate 		datael_reset(&sc->rd_d);
52730Sstevel@tonic-gate 
52740Sstevel@tonic-gate 	if (svc == NULL)
52750Sstevel@tonic-gate 		svc = h->rh_service;
52760Sstevel@tonic-gate 	else
52770Sstevel@tonic-gate 		datael_reset(&svc->rd_d);
52780Sstevel@tonic-gate 
52790Sstevel@tonic-gate 	if (inst == NULL)
52800Sstevel@tonic-gate 		inst = h->rh_instance;
52810Sstevel@tonic-gate 	else
52820Sstevel@tonic-gate 		datael_reset(&inst->rd_d);
52830Sstevel@tonic-gate 
52840Sstevel@tonic-gate 	if (pg == NULL)
52850Sstevel@tonic-gate 		pg = h->rh_pg;
52860Sstevel@tonic-gate 	else
52870Sstevel@tonic-gate 		datael_reset(&pg->rd_d);
52880Sstevel@tonic-gate 
52890Sstevel@tonic-gate 	if (prop == NULL)
52900Sstevel@tonic-gate 		prop = h->rh_property;
52910Sstevel@tonic-gate 	else
52920Sstevel@tonic-gate 		datael_reset(&prop->rd_d);
52930Sstevel@tonic-gate 
52940Sstevel@tonic-gate 	/*
52950Sstevel@tonic-gate 	 * We only support local scopes, but we check *after* getting
52960Sstevel@tonic-gate 	 * the local scope, so that any repository-related errors take
52970Sstevel@tonic-gate 	 * precedence.
52980Sstevel@tonic-gate 	 */
52990Sstevel@tonic-gate 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) {
53000Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
53010Sstevel@tonic-gate 		ret = -1;
53020Sstevel@tonic-gate 		goto reset_args;
53030Sstevel@tonic-gate 	}
53040Sstevel@tonic-gate 
53050Sstevel@tonic-gate 	if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
53060Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
53070Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_NOT_FOUND);
53080Sstevel@tonic-gate 		goto reset_args;
53090Sstevel@tonic-gate 	}
53100Sstevel@tonic-gate 
53110Sstevel@tonic-gate 
53120Sstevel@tonic-gate 	if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) {
53130Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
53140Sstevel@tonic-gate 		return (0);
53150Sstevel@tonic-gate 	}
53160Sstevel@tonic-gate 
53170Sstevel@tonic-gate 	if (scf_scope_get_service(sc, service, svc) == -1) {
53180Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
53190Sstevel@tonic-gate 		ret = -1;
53200Sstevel@tonic-gate 		assert(scf_error() != SCF_ERROR_NOT_SET);
53210Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_DELETED)
53220Sstevel@tonic-gate 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
53230Sstevel@tonic-gate 		goto reset_args;
53240Sstevel@tonic-gate 	}
53250Sstevel@tonic-gate 
53260Sstevel@tonic-gate 	if (last == REP_PROTOCOL_ENTITY_SERVICE) {
53270Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
53280Sstevel@tonic-gate 		return (0);
53290Sstevel@tonic-gate 	}
53300Sstevel@tonic-gate 
53310Sstevel@tonic-gate 	if (instance == NULL) {
53320Sstevel@tonic-gate 		if (propertygroup == NULL ||
53330Sstevel@tonic-gate 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
53340Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
53350Sstevel@tonic-gate 			return (0);
53360Sstevel@tonic-gate 		}
53370Sstevel@tonic-gate 
53380Sstevel@tonic-gate 		if (scf_service_get_pg(svc, propertygroup, pg) == -1) {
53390Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
53400Sstevel@tonic-gate 			ret = -1;
53410Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_NOT_SET);
53420Sstevel@tonic-gate 			if (scf_error() == SCF_ERROR_DELETED)
53430Sstevel@tonic-gate 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
53440Sstevel@tonic-gate 			goto reset_args;
53450Sstevel@tonic-gate 		}
53460Sstevel@tonic-gate 	} else {
53470Sstevel@tonic-gate 		if (scf_service_get_instance(svc, instance, inst) == -1) {
53480Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
53490Sstevel@tonic-gate 			ret = -1;
53500Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_NOT_SET);
53510Sstevel@tonic-gate 			if (scf_error() == SCF_ERROR_DELETED)
53520Sstevel@tonic-gate 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
53530Sstevel@tonic-gate 			goto reset_args;
53540Sstevel@tonic-gate 		}
53550Sstevel@tonic-gate 
53560Sstevel@tonic-gate 		if (propertygroup == NULL ||
53570Sstevel@tonic-gate 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
53580Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
53590Sstevel@tonic-gate 			return (0);
53600Sstevel@tonic-gate 		}
53610Sstevel@tonic-gate 
53620Sstevel@tonic-gate 		if (scf_instance_get_pg(inst, propertygroup, pg) == -1) {
53630Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
53640Sstevel@tonic-gate 			ret = -1;
53650Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_NOT_SET);
53660Sstevel@tonic-gate 			if (scf_error() == SCF_ERROR_DELETED)
53670Sstevel@tonic-gate 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
53680Sstevel@tonic-gate 			goto reset_args;
53690Sstevel@tonic-gate 		}
53700Sstevel@tonic-gate 	}
53710Sstevel@tonic-gate 
53720Sstevel@tonic-gate 	if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
53730Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
53740Sstevel@tonic-gate 		return (0);
53750Sstevel@tonic-gate 	}
53760Sstevel@tonic-gate 
53770Sstevel@tonic-gate 	if (scf_pg_get_property(pg, property, prop) == -1) {
53780Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
53790Sstevel@tonic-gate 		ret = -1;
53800Sstevel@tonic-gate 		assert(scf_error() != SCF_ERROR_NOT_SET);
53810Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_DELETED)
53820Sstevel@tonic-gate 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
53830Sstevel@tonic-gate 		goto reset_args;
53840Sstevel@tonic-gate 	}
53850Sstevel@tonic-gate 
53860Sstevel@tonic-gate 	handle_rele_subhandles(h, holds);
53870Sstevel@tonic-gate 	return (0);
53880Sstevel@tonic-gate 
53890Sstevel@tonic-gate reset_args:
53900Sstevel@tonic-gate 	if (sc != NULL)
53910Sstevel@tonic-gate 		datael_reset(&sc->rd_d);
53920Sstevel@tonic-gate 	if (svc != NULL)
53930Sstevel@tonic-gate 		datael_reset(&svc->rd_d);
53940Sstevel@tonic-gate 	if (inst != NULL)
53950Sstevel@tonic-gate 		datael_reset(&inst->rd_d);
53960Sstevel@tonic-gate 	if (pg != NULL)
53970Sstevel@tonic-gate 		datael_reset(&pg->rd_d);
53980Sstevel@tonic-gate 	if (prop != NULL)
53990Sstevel@tonic-gate 		datael_reset(&prop->rd_d);
54000Sstevel@tonic-gate 
54010Sstevel@tonic-gate 	return (ret);
54020Sstevel@tonic-gate }
54030Sstevel@tonic-gate 
54040Sstevel@tonic-gate /*
54050Sstevel@tonic-gate  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
54060Sstevel@tonic-gate  * big, bad entity id, request not applicable to entity, name too long for
54070Sstevel@tonic-gate  * buffer), _NOT_SET, or _DELETED.
54080Sstevel@tonic-gate  */
54090Sstevel@tonic-gate ssize_t
54100Sstevel@tonic-gate scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz)
54110Sstevel@tonic-gate {
54120Sstevel@tonic-gate 	ssize_t r, len;
54130Sstevel@tonic-gate 
54140Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
54150Sstevel@tonic-gate 
54160Sstevel@tonic-gate 	r = scf_scope_get_name(scope, tmp, sizeof (tmp));
54170Sstevel@tonic-gate 
54180Sstevel@tonic-gate 	if (r <= 0)
54190Sstevel@tonic-gate 		return (r);
54200Sstevel@tonic-gate 
54210Sstevel@tonic-gate 	len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz);
54220Sstevel@tonic-gate 	if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) {
54230Sstevel@tonic-gate 		if (len >= sz)
54240Sstevel@tonic-gate 			return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
54250Sstevel@tonic-gate 
54260Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
54270Sstevel@tonic-gate 		if (len >= sz)
54280Sstevel@tonic-gate 			return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
54290Sstevel@tonic-gate 		len = strlcat(out,
54300Sstevel@tonic-gate 		    SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz);
54310Sstevel@tonic-gate 	}
54320Sstevel@tonic-gate 
54330Sstevel@tonic-gate 	return (len);
54340Sstevel@tonic-gate }
54350Sstevel@tonic-gate 
54360Sstevel@tonic-gate /*
54370Sstevel@tonic-gate  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
54380Sstevel@tonic-gate  * big, bad element id, bad ids, bad types, scope has no parent, request not
54390Sstevel@tonic-gate  * applicable to entity, name too long), _NOT_SET, _DELETED,
54400Sstevel@tonic-gate  */
54410Sstevel@tonic-gate ssize_t
54420Sstevel@tonic-gate scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz)
54430Sstevel@tonic-gate {
54440Sstevel@tonic-gate 	scf_handle_t *h = svc->rd_d.rd_handle;
54450Sstevel@tonic-gate 	scf_scope_t *scope = HANDLE_HOLD_SCOPE(h);
54460Sstevel@tonic-gate 	ssize_t r, len;
54470Sstevel@tonic-gate 
54480Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
54490Sstevel@tonic-gate 
54500Sstevel@tonic-gate 	r = datael_get_parent(&svc->rd_d, &scope->rd_d);
54510Sstevel@tonic-gate 	if (r != SCF_SUCCESS) {
54520Sstevel@tonic-gate 		HANDLE_RELE_SCOPE(h);
54530Sstevel@tonic-gate 
54540Sstevel@tonic-gate 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
54550Sstevel@tonic-gate 		return (-1);
54560Sstevel@tonic-gate 	}
54570Sstevel@tonic-gate 	if (out != NULL && sz > 0)
54580Sstevel@tonic-gate 		len = scf_scope_to_fmri(scope, out, sz);
54590Sstevel@tonic-gate 	else
54600Sstevel@tonic-gate 		len = scf_scope_to_fmri(scope, tmp, 2);
54610Sstevel@tonic-gate 
54620Sstevel@tonic-gate 	HANDLE_RELE_SCOPE(h);
54630Sstevel@tonic-gate 
54640Sstevel@tonic-gate 	if (len < 0)
54650Sstevel@tonic-gate 		return (-1);
54660Sstevel@tonic-gate 
54670Sstevel@tonic-gate 	if (out == NULL || len >= sz)
54680Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
54690Sstevel@tonic-gate 	else
54700Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz);
54710Sstevel@tonic-gate 
54720Sstevel@tonic-gate 	r = scf_service_get_name(svc, tmp, sizeof (tmp));
54730Sstevel@tonic-gate 	if (r < 0)
54740Sstevel@tonic-gate 		return (r);
54750Sstevel@tonic-gate 
54760Sstevel@tonic-gate 	if (out == NULL || len >= sz)
54770Sstevel@tonic-gate 		len += r;
54780Sstevel@tonic-gate 	else
54790Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
54800Sstevel@tonic-gate 
54810Sstevel@tonic-gate 	return (len);
54820Sstevel@tonic-gate }
54830Sstevel@tonic-gate 
54840Sstevel@tonic-gate ssize_t
54850Sstevel@tonic-gate scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz)
54860Sstevel@tonic-gate {
54870Sstevel@tonic-gate 	scf_handle_t *h = inst->rd_d.rd_handle;
54880Sstevel@tonic-gate 	scf_service_t *svc = HANDLE_HOLD_SERVICE(h);
54890Sstevel@tonic-gate 	ssize_t r, len;
54900Sstevel@tonic-gate 
54910Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
54920Sstevel@tonic-gate 
54930Sstevel@tonic-gate 	r = datael_get_parent(&inst->rd_d, &svc->rd_d);
54940Sstevel@tonic-gate 	if (r != SCF_SUCCESS) {
54950Sstevel@tonic-gate 		HANDLE_RELE_SERVICE(h);
54960Sstevel@tonic-gate 		return (-1);
54970Sstevel@tonic-gate 	}
54980Sstevel@tonic-gate 
54990Sstevel@tonic-gate 	len = scf_service_to_fmri(svc, out, sz);
55000Sstevel@tonic-gate 
55010Sstevel@tonic-gate 	HANDLE_RELE_SERVICE(h);
55020Sstevel@tonic-gate 
55030Sstevel@tonic-gate 	if (len < 0)
55040Sstevel@tonic-gate 		return (len);
55050Sstevel@tonic-gate 
55060Sstevel@tonic-gate 	if (len >= sz)
55070Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
55080Sstevel@tonic-gate 	else
55090Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz);
55100Sstevel@tonic-gate 
55110Sstevel@tonic-gate 	r = scf_instance_get_name(inst, tmp, sizeof (tmp));
55120Sstevel@tonic-gate 	if (r < 0)
55130Sstevel@tonic-gate 		return (r);
55140Sstevel@tonic-gate 
55150Sstevel@tonic-gate 	if (len >= sz)
55160Sstevel@tonic-gate 		len += r;
55170Sstevel@tonic-gate 	else
55180Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
55190Sstevel@tonic-gate 
55200Sstevel@tonic-gate 	return (len);
55210Sstevel@tonic-gate }
55220Sstevel@tonic-gate 
55230Sstevel@tonic-gate ssize_t
55240Sstevel@tonic-gate scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz)
55250Sstevel@tonic-gate {
55260Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
55270Sstevel@tonic-gate 
55280Sstevel@tonic-gate 	struct rep_protocol_entity_parent_type request;
55290Sstevel@tonic-gate 	struct rep_protocol_integer_response response;
55300Sstevel@tonic-gate 
55310Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
55320Sstevel@tonic-gate 	ssize_t len, r;
55330Sstevel@tonic-gate 
55340Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
55350Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE;
55360Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
55370Sstevel@tonic-gate 
55380Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
55390Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
55400Sstevel@tonic-gate 	    &response, sizeof (response));
55410Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
55420Sstevel@tonic-gate 
55430Sstevel@tonic-gate 	if (r < 0)
55440Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
55450Sstevel@tonic-gate 
55460Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
55470Sstevel@tonic-gate 	    r < sizeof (response)) {
55480Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
55490Sstevel@tonic-gate 	}
55500Sstevel@tonic-gate 
55510Sstevel@tonic-gate 	switch (response.rpr_value) {
55520Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SERVICE: {
55530Sstevel@tonic-gate 		scf_service_t *svc;
55540Sstevel@tonic-gate 
55550Sstevel@tonic-gate 		svc = HANDLE_HOLD_SERVICE(h);
55560Sstevel@tonic-gate 
55570Sstevel@tonic-gate 		r = datael_get_parent(&pg->rd_d, &svc->rd_d);
55580Sstevel@tonic-gate 
55590Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
55600Sstevel@tonic-gate 			len = scf_service_to_fmri(svc, out, sz);
55610Sstevel@tonic-gate 
55620Sstevel@tonic-gate 		HANDLE_RELE_SERVICE(h);
55630Sstevel@tonic-gate 		break;
55640Sstevel@tonic-gate 	}
55650Sstevel@tonic-gate 
55660Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE: {
55670Sstevel@tonic-gate 		scf_instance_t *inst;
55680Sstevel@tonic-gate 
55690Sstevel@tonic-gate 		inst = HANDLE_HOLD_INSTANCE(h);
55700Sstevel@tonic-gate 
55710Sstevel@tonic-gate 		r = datael_get_parent(&pg->rd_d, &inst->rd_d);
55720Sstevel@tonic-gate 
55730Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
55740Sstevel@tonic-gate 			len = scf_instance_to_fmri(inst, out, sz);
55750Sstevel@tonic-gate 
55760Sstevel@tonic-gate 		HANDLE_RELE_INSTANCE(h);
55770Sstevel@tonic-gate 		break;
55780Sstevel@tonic-gate 	}
55790Sstevel@tonic-gate 
55800Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPLEVEL: {
55810Sstevel@tonic-gate 		scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h);
55820Sstevel@tonic-gate 		scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h);
55830Sstevel@tonic-gate 		scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h);
55840Sstevel@tonic-gate 
55850Sstevel@tonic-gate 		r = datael_get_parent(&pg->rd_d, &level->rd_d);
55860Sstevel@tonic-gate 
55870Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
55880Sstevel@tonic-gate 			r = datael_get_parent(&level->rd_d, &snap->rd_d);
55890Sstevel@tonic-gate 
55900Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
55910Sstevel@tonic-gate 			r = datael_get_parent(&snap->rd_d, &inst->rd_d);
55920Sstevel@tonic-gate 
55930Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
55940Sstevel@tonic-gate 			len = scf_instance_to_fmri(inst, out, sz);
55950Sstevel@tonic-gate 
55960Sstevel@tonic-gate 		HANDLE_RELE_INSTANCE(h);
55970Sstevel@tonic-gate 		HANDLE_RELE_SNAPSHOT(h);
55980Sstevel@tonic-gate 		HANDLE_RELE_SNAPLVL(h);
55990Sstevel@tonic-gate 		break;
56000Sstevel@tonic-gate 	}
56010Sstevel@tonic-gate 
56020Sstevel@tonic-gate 	default:
56030Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
56040Sstevel@tonic-gate 	}
56050Sstevel@tonic-gate 
56060Sstevel@tonic-gate 	if (r != SCF_SUCCESS)
56070Sstevel@tonic-gate 		return (r);
56080Sstevel@tonic-gate 
56090Sstevel@tonic-gate 	if (len >= sz)
56100Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
56110Sstevel@tonic-gate 	else
56120Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz);
56130Sstevel@tonic-gate 
56140Sstevel@tonic-gate 	r = scf_pg_get_name(pg, tmp, sizeof (tmp));
56150Sstevel@tonic-gate 
56160Sstevel@tonic-gate 	if (r < 0)
56170Sstevel@tonic-gate 		return (r);
56180Sstevel@tonic-gate 
56190Sstevel@tonic-gate 	if (len >= sz)
56200Sstevel@tonic-gate 		len += r;
56210Sstevel@tonic-gate 	else
56220Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
56230Sstevel@tonic-gate 
56240Sstevel@tonic-gate 	return (len);
56250Sstevel@tonic-gate }
56260Sstevel@tonic-gate 
56270Sstevel@tonic-gate ssize_t
56280Sstevel@tonic-gate scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz)
56290Sstevel@tonic-gate {
56300Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
56310Sstevel@tonic-gate 	scf_propertygroup_t *pg = HANDLE_HOLD_PG(h);
56320Sstevel@tonic-gate 
56330Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
56340Sstevel@tonic-gate 	ssize_t len;
56350Sstevel@tonic-gate 	int r;
56360Sstevel@tonic-gate 
56370Sstevel@tonic-gate 	r = datael_get_parent(&prop->rd_d, &pg->rd_d);
56380Sstevel@tonic-gate 	if (r != SCF_SUCCESS) {
56390Sstevel@tonic-gate 		HANDLE_RELE_PG(h);
56400Sstevel@tonic-gate 		return (-1);
56410Sstevel@tonic-gate 	}
56420Sstevel@tonic-gate 
56430Sstevel@tonic-gate 	len = scf_pg_to_fmri(pg, out, sz);
56440Sstevel@tonic-gate 
56450Sstevel@tonic-gate 	HANDLE_RELE_PG(h);
56460Sstevel@tonic-gate 
56470Sstevel@tonic-gate 	if (len >= sz)
56480Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
56490Sstevel@tonic-gate 	else
56500Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz);
56510Sstevel@tonic-gate 
56520Sstevel@tonic-gate 	r = scf_property_get_name(prop, tmp, sizeof (tmp));
56530Sstevel@tonic-gate 
56540Sstevel@tonic-gate 	if (r < 0)
56550Sstevel@tonic-gate 		return (r);
56560Sstevel@tonic-gate 
56570Sstevel@tonic-gate 	if (len >= sz)
56580Sstevel@tonic-gate 		len += r;
56590Sstevel@tonic-gate 	else
56600Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
56610Sstevel@tonic-gate 
56620Sstevel@tonic-gate 	return (len);
56630Sstevel@tonic-gate }
56640Sstevel@tonic-gate 
56650Sstevel@tonic-gate int
56660Sstevel@tonic-gate scf_pg_get_underlying_pg(const scf_propertygroup_t *pg,
56670Sstevel@tonic-gate     scf_propertygroup_t *out)
56680Sstevel@tonic-gate {
56690Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
56700Sstevel@tonic-gate 	scf_service_t *svc;
56710Sstevel@tonic-gate 	scf_instance_t *inst;
56720Sstevel@tonic-gate 
56730Sstevel@tonic-gate 	char me[REP_PROTOCOL_NAME_LEN];
56740Sstevel@tonic-gate 	int r;
56750Sstevel@tonic-gate 
56760Sstevel@tonic-gate 	if (h != out->rd_d.rd_handle)
56770Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
56780Sstevel@tonic-gate 
56790Sstevel@tonic-gate 	r = scf_pg_get_name(pg, me, sizeof (me));
56800Sstevel@tonic-gate 
56810Sstevel@tonic-gate 	if (r < 0)
56820Sstevel@tonic-gate 		return (r);
56830Sstevel@tonic-gate 
56840Sstevel@tonic-gate 	svc = HANDLE_HOLD_SERVICE(h);
56850Sstevel@tonic-gate 	inst = HANDLE_HOLD_INSTANCE(h);
56860Sstevel@tonic-gate 
56870Sstevel@tonic-gate 	r = datael_get_parent(&pg->rd_d, &inst->rd_d);
56880Sstevel@tonic-gate 
56890Sstevel@tonic-gate 	if (r == SCF_SUCCESS) {
56900Sstevel@tonic-gate 		r = datael_get_parent(&inst->rd_d, &svc->rd_d);
56910Sstevel@tonic-gate 		if (r != SCF_SUCCESS) {
56920Sstevel@tonic-gate 			goto out;
56930Sstevel@tonic-gate 		}
56940Sstevel@tonic-gate 		r = scf_service_get_pg(svc, me, out);
56950Sstevel@tonic-gate 	} else {
56960Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_NOT_FOUND);
56970Sstevel@tonic-gate 	}
56980Sstevel@tonic-gate 
56990Sstevel@tonic-gate out:
57000Sstevel@tonic-gate 	HANDLE_RELE_SERVICE(h);
57010Sstevel@tonic-gate 	HANDLE_RELE_INSTANCE(h);
57020Sstevel@tonic-gate 	return (r);
57030Sstevel@tonic-gate }
57040Sstevel@tonic-gate 
57050Sstevel@tonic-gate #define	LEGACY_SCHEME	"lrc:"
57060Sstevel@tonic-gate #define	LEGACY_UNKNOWN	"unknown"
57070Sstevel@tonic-gate 
57080Sstevel@tonic-gate /*
57090Sstevel@tonic-gate  * Implementation of scf_walk_fmri()
57100Sstevel@tonic-gate  *
57110Sstevel@tonic-gate  * This is a little tricky due to the many-to-many relationship between patterns
57120Sstevel@tonic-gate  * and matches.  We need to be able to satisfy the following requirements:
57130Sstevel@tonic-gate  *
57140Sstevel@tonic-gate  * 	1) Detect patterns which match more than one FMRI, and be able to
57150Sstevel@tonic-gate  *         report which FMRIs have been matched.
57160Sstevel@tonic-gate  * 	2) Detect patterns which have not matched any FMRIs
57170Sstevel@tonic-gate  * 	3) Visit each matching FMRI exactly once across all patterns
57180Sstevel@tonic-gate  * 	4) Ignore FMRIs which have only been matched due to multiply-matching
57190Sstevel@tonic-gate  *         patterns.
57200Sstevel@tonic-gate  *
57210Sstevel@tonic-gate  * We maintain an array of scf_pattern_t structures, one for each argument, and
57220Sstevel@tonic-gate  * maintain a linked list of scf_match_t structures for each one.  We first
57230Sstevel@tonic-gate  * qualify each pattern's type:
57240Sstevel@tonic-gate  *
57250Sstevel@tonic-gate  *	PATTERN_INVALID		The argument is invalid (too long).
57260Sstevel@tonic-gate  *
57270Sstevel@tonic-gate  *	PATTERN_EXACT		The pattern is a complete FMRI.  The list of
57280Sstevel@tonic-gate  *				matches contains only a single entry.
57290Sstevel@tonic-gate  *
57300Sstevel@tonic-gate  * 	PATTERN_GLOB		The pattern will be matched against all
57310Sstevel@tonic-gate  * 				FMRIs via fnmatch() in the second phase.
57320Sstevel@tonic-gate  * 				Matches will be added to the pattern's list
57330Sstevel@tonic-gate  * 				as they are found.
57340Sstevel@tonic-gate  *
57350Sstevel@tonic-gate  * 	PATTERN_PARTIAL		Everything else.  We will assume that this is
57360Sstevel@tonic-gate  * 				an abbreviated FMRI, and match according to
57370Sstevel@tonic-gate  * 				our abbreviated FMRI rules.  Matches will be
57380Sstevel@tonic-gate  * 				added to the pattern's list as they are found.
57390Sstevel@tonic-gate  *
57400Sstevel@tonic-gate  * The first pass searches for arguments that are complete FMRIs.  These are
57410Sstevel@tonic-gate  * classified as EXACT patterns and do not necessitate searching the entire
57420Sstevel@tonic-gate  * tree.
57430Sstevel@tonic-gate  *
57440Sstevel@tonic-gate  * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
57450Sstevel@tonic-gate  * arguments were given), we iterate over all services and instances in the
57460Sstevel@tonic-gate  * repository, looking for matches.
57470Sstevel@tonic-gate  *
57480Sstevel@tonic-gate  * When a match is found, we add the match to the pattern's list.  We also enter
57490Sstevel@tonic-gate  * the match into a hash table, resulting in something like this:
57500Sstevel@tonic-gate  *
57510Sstevel@tonic-gate  *       scf_pattern_t       scf_match_t
57520Sstevel@tonic-gate  *     +---------------+      +-------+     +-------+
57530Sstevel@tonic-gate  *     | pattern 'foo' |----->| match |---->| match |
57540Sstevel@tonic-gate  *     +---------------+      +-------+     +-------+
57550Sstevel@tonic-gate  *                                |             |
57560Sstevel@tonic-gate  *           scf_match_key_t      |             |
57570Sstevel@tonic-gate  *           +--------------+     |             |
57580Sstevel@tonic-gate  *           | FMRI bar/foo |<----+             |
57590Sstevel@tonic-gate  *           +--------------+                   |
57600Sstevel@tonic-gate  *           | FMRI baz/foo |<------------------+
57610Sstevel@tonic-gate  *           +--------------+
57620Sstevel@tonic-gate  *
57630Sstevel@tonic-gate  * Once we have all of this set up, we do one pass to report patterns matching
57640Sstevel@tonic-gate  * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
57650Sstevel@tonic-gate  * match was found.
57660Sstevel@tonic-gate  *
57670Sstevel@tonic-gate  * Finally, we walk through all valid patterns, and for each match, if we
57680Sstevel@tonic-gate  * haven't already seen the match (as recorded in the hash table), then we
57690Sstevel@tonic-gate  * execute the callback.
57700Sstevel@tonic-gate  */
57710Sstevel@tonic-gate 
57720Sstevel@tonic-gate struct scf_matchkey;
57730Sstevel@tonic-gate struct scf_match;
57740Sstevel@tonic-gate 
57750Sstevel@tonic-gate /*
57760Sstevel@tonic-gate  * scf_pattern_t
57770Sstevel@tonic-gate  */
57780Sstevel@tonic-gate typedef struct scf_pattern {
57790Sstevel@tonic-gate 	enum	{
57800Sstevel@tonic-gate 		PATTERN_INVALID,	/* Uninitialized state */
57810Sstevel@tonic-gate 		PATTERN_EXACT,
57820Sstevel@tonic-gate 		PATTERN_GLOB,
57830Sstevel@tonic-gate 		PATTERN_PARTIAL
57840Sstevel@tonic-gate 	} sp_type;
57850Sstevel@tonic-gate 	char			*sp_arg;	/* Original argument */
57860Sstevel@tonic-gate 	struct scf_match	*sp_matches;	/* List of matches */
57870Sstevel@tonic-gate 	int			sp_matchcount;	/* # of matches */
57880Sstevel@tonic-gate } scf_pattern_t;
57890Sstevel@tonic-gate 
57900Sstevel@tonic-gate /*
57910Sstevel@tonic-gate  * scf_matchkey_t
57920Sstevel@tonic-gate  */
57930Sstevel@tonic-gate typedef struct scf_matchkey {
57940Sstevel@tonic-gate 	char			*sk_fmri;	/* Matching FMRI */
57950Sstevel@tonic-gate 	char			*sk_legacy;	/* Legacy name */
57960Sstevel@tonic-gate 	int			sk_seen;	/* If we've been seen */
57970Sstevel@tonic-gate 	struct scf_matchkey	*sk_next;	/* Next in hash chain */
57980Sstevel@tonic-gate } scf_matchkey_t;
57990Sstevel@tonic-gate 
58000Sstevel@tonic-gate /*
58010Sstevel@tonic-gate  * scf_match_t
58020Sstevel@tonic-gate  */
58030Sstevel@tonic-gate typedef struct scf_match {
58040Sstevel@tonic-gate 	scf_matchkey_t		*sm_key;
58050Sstevel@tonic-gate 	struct scf_match	*sm_next;
58060Sstevel@tonic-gate } scf_match_t;
58070Sstevel@tonic-gate 
58080Sstevel@tonic-gate #define	WALK_HTABLE_SIZE	123
58090Sstevel@tonic-gate 
58100Sstevel@tonic-gate /*
58110Sstevel@tonic-gate  * scf_get_key()
58120Sstevel@tonic-gate  *
58130Sstevel@tonic-gate  * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
58140Sstevel@tonic-gate  * this FMRI.  If the FMRI does not exist, it is added to the hash table.  If a
58150Sstevel@tonic-gate  * new entry cannot be allocated due to lack of memory, NULL is returned.
58160Sstevel@tonic-gate  */
58170Sstevel@tonic-gate static scf_matchkey_t *
58180Sstevel@tonic-gate scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy)
58190Sstevel@tonic-gate {
58200Sstevel@tonic-gate 	uint_t h = 0, g;
58210Sstevel@tonic-gate 	const char *p, *k;
58220Sstevel@tonic-gate 	scf_matchkey_t *key;
58230Sstevel@tonic-gate 
58240Sstevel@tonic-gate 	k = strstr(fmri, ":/");
58250Sstevel@tonic-gate 	assert(k != NULL);
58260Sstevel@tonic-gate 	k += 2;
58270Sstevel@tonic-gate 
58280Sstevel@tonic-gate 	/*
58290Sstevel@tonic-gate 	 * Generic hash function from uts/common/os/modhash.c.
58300Sstevel@tonic-gate 	 */
58310Sstevel@tonic-gate 	for (p = k; *p != '\0'; ++p) {
58320Sstevel@tonic-gate 		h = (h << 4) + *p;
58330Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
58340Sstevel@tonic-gate 			h ^= (g >> 24);
58350Sstevel@tonic-gate 			h ^= g;
58360Sstevel@tonic-gate 		}
58370Sstevel@tonic-gate 	}
58380Sstevel@tonic-gate 
58390Sstevel@tonic-gate 	h %= WALK_HTABLE_SIZE;
58400Sstevel@tonic-gate 
58410Sstevel@tonic-gate 	/*
58420Sstevel@tonic-gate 	 * Search for an existing key
58430Sstevel@tonic-gate 	 */
58440Sstevel@tonic-gate 	for (key = htable[h]; key != NULL; key = key->sk_next) {
58450Sstevel@tonic-gate 		if (strcmp(key->sk_fmri, fmri) == 0)
58460Sstevel@tonic-gate 			return (key);
58470Sstevel@tonic-gate 	}
58480Sstevel@tonic-gate 
58490Sstevel@tonic-gate 	if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL)
58500Sstevel@tonic-gate 		return (NULL);
58510Sstevel@tonic-gate 
58520Sstevel@tonic-gate 	/*
58530Sstevel@tonic-gate 	 * Add new key to hash table.
58540Sstevel@tonic-gate 	 */
58550Sstevel@tonic-gate 	if ((key->sk_fmri = strdup(fmri)) == NULL) {
58560Sstevel@tonic-gate 		free(key);
58570Sstevel@tonic-gate 		return (NULL);
58580Sstevel@tonic-gate 	}
58590Sstevel@tonic-gate 
58600Sstevel@tonic-gate 	if (legacy == NULL) {
58610Sstevel@tonic-gate 		key->sk_legacy = NULL;
58620Sstevel@tonic-gate 	} else if ((key->sk_legacy = strdup(legacy)) == NULL) {
58630Sstevel@tonic-gate 		free(key->sk_fmri);
58640Sstevel@tonic-gate 		free(key);
58650Sstevel@tonic-gate 		return (NULL);
58660Sstevel@tonic-gate 	}
58670Sstevel@tonic-gate 
58680Sstevel@tonic-gate 	key->sk_next = htable[h];
58690Sstevel@tonic-gate 	htable[h] = key;
58700Sstevel@tonic-gate 
58710Sstevel@tonic-gate 	return (key);
58720Sstevel@tonic-gate }
58730Sstevel@tonic-gate 
58740Sstevel@tonic-gate /*
58750Sstevel@tonic-gate  * Given an FMRI, insert it into the pattern's list appropriately.
58760Sstevel@tonic-gate  * svc_explicit indicates whether matching services should take
58770Sstevel@tonic-gate  * precedence over matching instances.
58780Sstevel@tonic-gate  */
58790Sstevel@tonic-gate static scf_error_t
58800Sstevel@tonic-gate scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy,
58810Sstevel@tonic-gate     scf_pattern_t *pattern, int svc_explicit)
58820Sstevel@tonic-gate {
58830Sstevel@tonic-gate 	scf_match_t *match;
58840Sstevel@tonic-gate 
58850Sstevel@tonic-gate 	/*
58860Sstevel@tonic-gate 	 * If svc_explicit is set, enforce the constaint that matching
58870Sstevel@tonic-gate 	 * instances take precedence over matching services. Otherwise,
58880Sstevel@tonic-gate 	 * matching services take precedence over matching instances.
58890Sstevel@tonic-gate 	 */
58900Sstevel@tonic-gate 	if (svc_explicit) {
58910Sstevel@tonic-gate 		scf_match_t *next, *prev;
58920Sstevel@tonic-gate 		/*
58930Sstevel@tonic-gate 		 * If we match an instance, check to see if we must remove
58940Sstevel@tonic-gate 		 * any matching services (for SCF_WALK_EXPLICIT).
58950Sstevel@tonic-gate 		 */
58960Sstevel@tonic-gate 		for (prev = match = pattern->sp_matches; match != NULL;
58970Sstevel@tonic-gate 		    match = next) {
58980Sstevel@tonic-gate 			size_t len = strlen(match->sm_key->sk_fmri);
58990Sstevel@tonic-gate 			next = match->sm_next;
59000Sstevel@tonic-gate 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
59010Sstevel@tonic-gate 			    fmri[len] == ':') {
59020Sstevel@tonic-gate 				if (prev == match)
59030Sstevel@tonic-gate 					pattern->sp_matches = match->sm_next;
59040Sstevel@tonic-gate 				else
59050Sstevel@tonic-gate 					prev->sm_next = match->sm_next;
59060Sstevel@tonic-gate 				pattern->sp_matchcount--;
59070Sstevel@tonic-gate 				free(match);
59080Sstevel@tonic-gate 			} else
59090Sstevel@tonic-gate 				prev = match;
59100Sstevel@tonic-gate 		}
59110Sstevel@tonic-gate 	} else {
59120Sstevel@tonic-gate 		/*
59130Sstevel@tonic-gate 		 * If we've matched a service don't add any instances (for
59140Sstevel@tonic-gate 		 * SCF_WALK_SERVICE).
59150Sstevel@tonic-gate 		 */
59160Sstevel@tonic-gate 		for (match = pattern->sp_matches; match != NULL;
59170Sstevel@tonic-gate 		    match = match->sm_next) {
59180Sstevel@tonic-gate 			size_t len = strlen(match->sm_key->sk_fmri);
59190Sstevel@tonic-gate 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
59200Sstevel@tonic-gate 			    fmri[len] == ':')
59210Sstevel@tonic-gate 				return (0);
59220Sstevel@tonic-gate 		}
59230Sstevel@tonic-gate 	}
59240Sstevel@tonic-gate 
59250Sstevel@tonic-gate 	if ((match = malloc(sizeof (scf_match_t))) == NULL)
59260Sstevel@tonic-gate 		return (SCF_ERROR_NO_MEMORY);
59270Sstevel@tonic-gate 
59280Sstevel@tonic-gate 	if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) {
59290Sstevel@tonic-gate 		free(match);
59300Sstevel@tonic-gate 		return (SCF_ERROR_NO_MEMORY);
59310Sstevel@tonic-gate 	}
59320Sstevel@tonic-gate 
59330Sstevel@tonic-gate 	match->sm_next = pattern->sp_matches;
59340Sstevel@tonic-gate 	pattern->sp_matches = match;
59350Sstevel@tonic-gate 	pattern->sp_matchcount++;
59360Sstevel@tonic-gate 
59370Sstevel@tonic-gate 	return (0);
59380Sstevel@tonic-gate }
59390Sstevel@tonic-gate 
59400Sstevel@tonic-gate /*
59410Sstevel@tonic-gate  * Returns 1 if the fmri matches the given pattern, 0 otherwise.
59420Sstevel@tonic-gate  */
59430Sstevel@tonic-gate static int
59440Sstevel@tonic-gate scf_cmp_pattern(char *fmri, scf_pattern_t *pattern)
59450Sstevel@tonic-gate {
59460Sstevel@tonic-gate 	char *tmp;
59470Sstevel@tonic-gate 
59480Sstevel@tonic-gate 	if (pattern->sp_type == PATTERN_GLOB) {
59490Sstevel@tonic-gate 		if (fnmatch(pattern->sp_arg, fmri, 0) == 0)
59500Sstevel@tonic-gate 			return (1);
59510Sstevel@tonic-gate 	} else if (pattern->sp_type == PATTERN_PARTIAL &&
59520Sstevel@tonic-gate 	    (tmp = strstr(fmri, pattern->sp_arg)) != NULL) {
59530Sstevel@tonic-gate 		/*
59540Sstevel@tonic-gate 		 * We only allow partial matches anchored on the end of
59550Sstevel@tonic-gate 		 * a service or instance, and beginning on an element
59560Sstevel@tonic-gate 		 * boundary.
59570Sstevel@tonic-gate 		 */
59580Sstevel@tonic-gate 		if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' &&
59590Sstevel@tonic-gate 		    tmp[0] != ':')
59600Sstevel@tonic-gate 			return (0);
59610Sstevel@tonic-gate 		tmp += strlen(pattern->sp_arg);
59620Sstevel@tonic-gate 		if (tmp != fmri + strlen(fmri) && tmp[0] != ':' &&
59630Sstevel@tonic-gate 		    tmp[-1] != ':')
59640Sstevel@tonic-gate 			return (0);
59650Sstevel@tonic-gate 
59660Sstevel@tonic-gate 		/*
59670Sstevel@tonic-gate 		 * If the user has supplied a short pattern that matches
59680Sstevel@tonic-gate 		 * 'svc:/' or 'lrc:/', ignore it.
59690Sstevel@tonic-gate 		 */
59700Sstevel@tonic-gate 		if (tmp <= fmri + 4)
59710Sstevel@tonic-gate 			return (0);
59720Sstevel@tonic-gate 
59730Sstevel@tonic-gate 		return (1);
59740Sstevel@tonic-gate 	}
59750Sstevel@tonic-gate 
59760Sstevel@tonic-gate 	return (0);
59770Sstevel@tonic-gate }
59780Sstevel@tonic-gate 
59790Sstevel@tonic-gate /*
59800Sstevel@tonic-gate  * Attempts to match the given FMRI against a set of patterns, keeping track of
59810Sstevel@tonic-gate  * the results.
59820Sstevel@tonic-gate  */
59830Sstevel@tonic-gate static scf_error_t
59840Sstevel@tonic-gate scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy,
59850Sstevel@tonic-gate     int npattern, scf_pattern_t *pattern, int svc_explicit)
59860Sstevel@tonic-gate {
59870Sstevel@tonic-gate 	int i;
59880Sstevel@tonic-gate 	int ret = 0;
59890Sstevel@tonic-gate 
59900Sstevel@tonic-gate 	for (i = 0; i < npattern; i++) {
59910Sstevel@tonic-gate 		if (scf_cmp_pattern(fmri, &pattern[i]) &&
59920Sstevel@tonic-gate 		    (ret = scf_add_match(htable, fmri,
59930Sstevel@tonic-gate 		    legacy, &pattern[i], svc_explicit)) != 0)
59940Sstevel@tonic-gate 			return (ret);
59950Sstevel@tonic-gate 	}
59960Sstevel@tonic-gate 
59970Sstevel@tonic-gate 	return (0);
59980Sstevel@tonic-gate }
59990Sstevel@tonic-gate 
60000Sstevel@tonic-gate scf_error_t
60010Sstevel@tonic-gate scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags,
60020Sstevel@tonic-gate     scf_walk_callback callback, void *data, int *err,
60030Sstevel@tonic-gate     void (*errfunc)(const char *, ...))
60040Sstevel@tonic-gate {
60050Sstevel@tonic-gate 	scf_pattern_t *pattern = NULL;
60060Sstevel@tonic-gate 	int i;
60070Sstevel@tonic-gate 	char *fmri = NULL;
60080Sstevel@tonic-gate 	ssize_t max_fmri_length;
60090Sstevel@tonic-gate 	scf_service_t *svc = NULL;
60100Sstevel@tonic-gate 	scf_instance_t *inst = NULL;
60110Sstevel@tonic-gate 	scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL;
60120Sstevel@tonic-gate 	scf_scope_t *scope = NULL;
60130Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
60140Sstevel@tonic-gate 	scf_property_t *prop = NULL;
60150Sstevel@tonic-gate 	scf_value_t *value = NULL;
60160Sstevel@tonic-gate 	int ret = 0;
60170Sstevel@tonic-gate 	scf_matchkey_t **htable = NULL;
60180Sstevel@tonic-gate 	int pattern_search = 0;
60190Sstevel@tonic-gate 	ssize_t max_name_length;
60200Sstevel@tonic-gate 	char *pgname = NULL;
60210Sstevel@tonic-gate 	scf_walkinfo_t info;
60220Sstevel@tonic-gate 
60230Sstevel@tonic-gate #ifndef NDEBUG
60240Sstevel@tonic-gate 	if (flags & SCF_WALK_EXPLICIT)
60250Sstevel@tonic-gate 		assert(flags & SCF_WALK_SERVICE);
60260Sstevel@tonic-gate 	if (flags & SCF_WALK_NOINSTANCE)
60270Sstevel@tonic-gate 		assert(flags & SCF_WALK_SERVICE);
60280Sstevel@tonic-gate 	if (flags & SCF_WALK_PROPERTY)
60290Sstevel@tonic-gate 		assert(!(flags & SCF_WALK_LEGACY));
60300Sstevel@tonic-gate #endif
60310Sstevel@tonic-gate 
60320Sstevel@tonic-gate 	/*
60330Sstevel@tonic-gate 	 * Setup initial variables
60340Sstevel@tonic-gate 	 */
60350Sstevel@tonic-gate 	if ((max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1 ||
60360Sstevel@tonic-gate 	    (max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1)
60370Sstevel@tonic-gate 		return (SCF_ERROR_INTERNAL);
60380Sstevel@tonic-gate 
60390Sstevel@tonic-gate 	if ((fmri = malloc(max_fmri_length + 1)) == NULL ||
60400Sstevel@tonic-gate 	    (pgname = malloc(max_name_length + 1)) == NULL) {
60410Sstevel@tonic-gate 		ret = SCF_ERROR_NO_MEMORY;
60420Sstevel@tonic-gate 		goto error;
60430Sstevel@tonic-gate 	}
60440Sstevel@tonic-gate 
60450Sstevel@tonic-gate 	if (argc == 0) {
60460Sstevel@tonic-gate 		pattern = NULL;
60470Sstevel@tonic-gate 	} else if ((pattern = calloc(argc, sizeof (scf_pattern_t)))
60480Sstevel@tonic-gate 	    == NULL) {
60490Sstevel@tonic-gate 		ret = SCF_ERROR_NO_MEMORY;
60500Sstevel@tonic-gate 		goto error;
60510Sstevel@tonic-gate 	}
60520Sstevel@tonic-gate 
60530Sstevel@tonic-gate 	if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) {
60540Sstevel@tonic-gate 		ret = SCF_ERROR_NO_MEMORY;
60550Sstevel@tonic-gate 		goto error;
60560Sstevel@tonic-gate 	}
60570Sstevel@tonic-gate 
60580Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
60590Sstevel@tonic-gate 	    (svc = scf_service_create(h)) == NULL ||
60600Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL ||
60610Sstevel@tonic-gate 	    (sciter = scf_iter_create(h)) == NULL ||
60620Sstevel@tonic-gate 	    (siter = scf_iter_create(h)) == NULL ||
60630Sstevel@tonic-gate 	    (scope = scf_scope_create(h)) == NULL ||
60640Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
60650Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
60660Sstevel@tonic-gate 	    (value = scf_value_create(h)) == NULL) {
60670Sstevel@tonic-gate 		ret = scf_error();
60680Sstevel@tonic-gate 		goto error;
60690Sstevel@tonic-gate 	}
60700Sstevel@tonic-gate 
60710Sstevel@tonic-gate 	/*
60720Sstevel@tonic-gate 	 * For each fmri given, we first check to see if it's a full service,
60730Sstevel@tonic-gate 	 * instance, property group, or property FMRI.  This avoids having to do
60740Sstevel@tonic-gate 	 * the (rather expensive) walk of all instances.  Any element which does
60750Sstevel@tonic-gate 	 * not match a full fmri is identified as a globbed pattern or a partial
60760Sstevel@tonic-gate 	 * fmri and stored in a private array when walking instances.
60770Sstevel@tonic-gate 	 */
60780Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
60790Sstevel@tonic-gate 		const char *scope_name, *svc_name, *inst_name, *pg_name;
60800Sstevel@tonic-gate 		const char *prop_name;
60810Sstevel@tonic-gate 
60820Sstevel@tonic-gate 		if (strlen(argv[i]) > max_fmri_length) {
60830Sstevel@tonic-gate 			errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]);
60840Sstevel@tonic-gate 			if (err != NULL)
60850Sstevel@tonic-gate 				*err = UU_EXIT_FATAL;
60860Sstevel@tonic-gate 			continue;
60870Sstevel@tonic-gate 		}
60880Sstevel@tonic-gate 
60890Sstevel@tonic-gate 		(void) strcpy(fmri, argv[i]);
60900Sstevel@tonic-gate 		if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name,
60910Sstevel@tonic-gate 		    &pg_name, &prop_name) != SCF_SUCCESS)
60920Sstevel@tonic-gate 			goto badfmri;
60930Sstevel@tonic-gate 
60940Sstevel@tonic-gate 		/*
60950Sstevel@tonic-gate 		 * If the user has specified SCF_WALK_PROPERTY, allow property
60960Sstevel@tonic-gate 		 * groups and properties.
60970Sstevel@tonic-gate 		 */
60980Sstevel@tonic-gate 		if (pg_name != NULL || prop_name != NULL) {
60990Sstevel@tonic-gate 			if (!(flags & SCF_WALK_PROPERTY))
61000Sstevel@tonic-gate 				goto badfmri;
61010Sstevel@tonic-gate 
61020Sstevel@tonic-gate 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
61030Sstevel@tonic-gate 			    NULL, pg, prop, 0) != 0)
61040Sstevel@tonic-gate 				goto badfmri;
61050Sstevel@tonic-gate 
61060Sstevel@tonic-gate 			if (scf_pg_get_name(pg, NULL, 0) < 0 &&
61070Sstevel@tonic-gate 			    scf_property_get_name(prop, NULL, 0) < 0)
61080Sstevel@tonic-gate 				goto badfmri;
61090Sstevel@tonic-gate 
61100Sstevel@tonic-gate 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
61110Sstevel@tonic-gate 			    <= 0) {
61120Sstevel@tonic-gate 				/*
61130Sstevel@tonic-gate 				 * scf_parse_fmri() should have caught this.
61140Sstevel@tonic-gate 				 */
61150Sstevel@tonic-gate 				abort();
61160Sstevel@tonic-gate 			}
61170Sstevel@tonic-gate 
61180Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
61190Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
61200Sstevel@tonic-gate 				goto error;
61210Sstevel@tonic-gate 
61220Sstevel@tonic-gate 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
61230Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
61240Sstevel@tonic-gate 				goto error;
61250Sstevel@tonic-gate 			}
61260Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_EXACT;
61270Sstevel@tonic-gate 		}
61280Sstevel@tonic-gate 
61290Sstevel@tonic-gate 		/*
61300Sstevel@tonic-gate 		 * We need at least a service name
61310Sstevel@tonic-gate 		 */
61320Sstevel@tonic-gate 		if (scope_name == NULL || svc_name == NULL)
61330Sstevel@tonic-gate 			goto badfmri;
61340Sstevel@tonic-gate 
61350Sstevel@tonic-gate 		/*
61360Sstevel@tonic-gate 		 * If we have a fully qualified instance, add it to our list of
61370Sstevel@tonic-gate 		 * fmris to watch.
61380Sstevel@tonic-gate 		 */
61390Sstevel@tonic-gate 		if (inst_name != NULL) {
61400Sstevel@tonic-gate 			if (flags & SCF_WALK_NOINSTANCE)
61410Sstevel@tonic-gate 				goto badfmri;
61420Sstevel@tonic-gate 
61430Sstevel@tonic-gate 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
61440Sstevel@tonic-gate 			    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
61450Sstevel@tonic-gate 				goto badfmri;
61460Sstevel@tonic-gate 
61470Sstevel@tonic-gate 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
61480Sstevel@tonic-gate 			    <= 0)
61490Sstevel@tonic-gate 				goto badfmri;
61500Sstevel@tonic-gate 
61510Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
61520Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
61530Sstevel@tonic-gate 				goto error;
61540Sstevel@tonic-gate 
61550Sstevel@tonic-gate 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
61560Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
61570Sstevel@tonic-gate 				goto error;
61580Sstevel@tonic-gate 			}
61590Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_EXACT;
61600Sstevel@tonic-gate 
61610Sstevel@tonic-gate 			continue;
61620Sstevel@tonic-gate 		}
61630Sstevel@tonic-gate 
61640Sstevel@tonic-gate 		if (scf_handle_decode_fmri(h, argv[i], NULL, svc,
61650Sstevel@tonic-gate 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) !=
61660Sstevel@tonic-gate 		    SCF_SUCCESS)
61670Sstevel@tonic-gate 			goto badfmri;
61680Sstevel@tonic-gate 
61690Sstevel@tonic-gate 		/*
61700Sstevel@tonic-gate 		 * If the user allows for bare services, then simply
61710Sstevel@tonic-gate 		 * pass this service on.
61720Sstevel@tonic-gate 		 */
61730Sstevel@tonic-gate 		if (flags & SCF_WALK_SERVICE) {
61740Sstevel@tonic-gate 			if (scf_service_to_fmri(svc, fmri,
61750Sstevel@tonic-gate 			    max_fmri_length + 1) <= 0) {
61760Sstevel@tonic-gate 				ret = scf_error();
61770Sstevel@tonic-gate 				goto error;
61780Sstevel@tonic-gate 			}
61790Sstevel@tonic-gate 
61800Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
61810Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
61820Sstevel@tonic-gate 				goto error;
61830Sstevel@tonic-gate 
61840Sstevel@tonic-gate 			if ((pattern[i].sp_arg = strdup(argv[i]))
61850Sstevel@tonic-gate 			    == NULL) {
61860Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
61870Sstevel@tonic-gate 				goto error;
61880Sstevel@tonic-gate 			}
61890Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_EXACT;
61900Sstevel@tonic-gate 			continue;
61910Sstevel@tonic-gate 		}
61920Sstevel@tonic-gate 
61930Sstevel@tonic-gate 		if (flags & SCF_WALK_NOINSTANCE)
61940Sstevel@tonic-gate 			goto badfmri;
61950Sstevel@tonic-gate 
61960Sstevel@tonic-gate 		/*
61970Sstevel@tonic-gate 		 * Otherwise, iterate over all instances in the service.
61980Sstevel@tonic-gate 		 */
61990Sstevel@tonic-gate 		if (scf_iter_service_instances(iter, svc) !=
62000Sstevel@tonic-gate 		    SCF_SUCCESS) {
62010Sstevel@tonic-gate 			ret = scf_error();
62020Sstevel@tonic-gate 			goto error;
62030Sstevel@tonic-gate 		}
62040Sstevel@tonic-gate 
62050Sstevel@tonic-gate 		for (;;) {
62060Sstevel@tonic-gate 			ret = scf_iter_next_instance(iter, inst);
62070Sstevel@tonic-gate 			if (ret == 0)
62080Sstevel@tonic-gate 				break;
62090Sstevel@tonic-gate 			if (ret != 1) {
62100Sstevel@tonic-gate 				ret = scf_error();
62110Sstevel@tonic-gate 				goto error;
62120Sstevel@tonic-gate 			}
62130Sstevel@tonic-gate 
62140Sstevel@tonic-gate 			if (scf_instance_to_fmri(inst, fmri,
62150Sstevel@tonic-gate 			    max_fmri_length + 1) == -1)
62160Sstevel@tonic-gate 				goto badfmri;
62170Sstevel@tonic-gate 
62180Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
62190Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
62200Sstevel@tonic-gate 				goto error;
62210Sstevel@tonic-gate 		}
62220Sstevel@tonic-gate 
62230Sstevel@tonic-gate 		if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
62240Sstevel@tonic-gate 			ret = SCF_ERROR_NO_MEMORY;
62250Sstevel@tonic-gate 			goto error;
62260Sstevel@tonic-gate 		}
62270Sstevel@tonic-gate 		pattern[i].sp_type = PATTERN_EXACT;
62280Sstevel@tonic-gate 
62290Sstevel@tonic-gate 		continue;
62300Sstevel@tonic-gate 
62310Sstevel@tonic-gate badfmri:
62320Sstevel@tonic-gate 
62330Sstevel@tonic-gate 		/*
62340Sstevel@tonic-gate 		 * If we got here because of a fatal error, bail out
62350Sstevel@tonic-gate 		 * immediately.
62360Sstevel@tonic-gate 		 */
62370Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
62380Sstevel@tonic-gate 			ret = scf_error();
62390Sstevel@tonic-gate 			goto error;
62400Sstevel@tonic-gate 		}
62410Sstevel@tonic-gate 
62420Sstevel@tonic-gate 		/*
62430Sstevel@tonic-gate 		 * At this point we failed to interpret the argument as a
62440Sstevel@tonic-gate 		 * complete fmri, so mark it as a partial or globbed FMRI for
62450Sstevel@tonic-gate 		 * later processing.
62460Sstevel@tonic-gate 		 */
62470Sstevel@tonic-gate 		if (strpbrk(argv[i], "*?[") != NULL) {
62480Sstevel@tonic-gate 			/*
62490Sstevel@tonic-gate 			 * Prepend svc:/ to patterns which don't begin with * or
62500Sstevel@tonic-gate 			 * svc: or lrc:.
62510Sstevel@tonic-gate 			 */
62520Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_GLOB;
62530Sstevel@tonic-gate 			if (argv[i][0] == '*' ||
62540Sstevel@tonic-gate 			    (strlen(argv[i]) >= 4 && argv[i][3] == ':'))
62550Sstevel@tonic-gate 				pattern[i].sp_arg = strdup(argv[i]);
62560Sstevel@tonic-gate 			else {
62570Sstevel@tonic-gate 				pattern[i].sp_arg = malloc(strlen(argv[i]) + 6);
62580Sstevel@tonic-gate 				if (pattern[i].sp_arg != NULL)
62590Sstevel@tonic-gate 					(void) snprintf(pattern[i].sp_arg,
62600Sstevel@tonic-gate 					    strlen(argv[i]) + 6, "svc:/%s",
62610Sstevel@tonic-gate 					    argv[i]);
62620Sstevel@tonic-gate 			}
62630Sstevel@tonic-gate 		} else {
62640Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_PARTIAL;
62650Sstevel@tonic-gate 			pattern[i].sp_arg = strdup(argv[i]);
62660Sstevel@tonic-gate 		}
62670Sstevel@tonic-gate 		pattern_search = 1;
62680Sstevel@tonic-gate 		if (pattern[i].sp_arg == NULL) {
62690Sstevel@tonic-gate 			ret = SCF_ERROR_NO_MEMORY;
62700Sstevel@tonic-gate 			goto error;
62710Sstevel@tonic-gate 		}
62720Sstevel@tonic-gate 	}
62730Sstevel@tonic-gate 
62740Sstevel@tonic-gate 	if (pattern_search || argc == 0) {
62750Sstevel@tonic-gate 		/*
62760Sstevel@tonic-gate 		 * We have a set of patterns to search for.  Iterate over all
62770Sstevel@tonic-gate 		 * instances and legacy services searching for matches.
62780Sstevel@tonic-gate 		 */
62790Sstevel@tonic-gate 		if (scf_handle_get_local_scope(h, scope) != 0) {
62800Sstevel@tonic-gate 			ret = scf_error();
62810Sstevel@tonic-gate 			goto error;
62820Sstevel@tonic-gate 		}
62830Sstevel@tonic-gate 
62840Sstevel@tonic-gate 		if (scf_iter_scope_services(sciter, scope) != 0) {
62850Sstevel@tonic-gate 			ret = scf_error();
62860Sstevel@tonic-gate 			goto error;
62870Sstevel@tonic-gate 		}
62880Sstevel@tonic-gate 
62890Sstevel@tonic-gate 		for (;;) {
62900Sstevel@tonic-gate 			ret = scf_iter_next_service(sciter, svc);
62910Sstevel@tonic-gate 			if (ret == 0)
62920Sstevel@tonic-gate 				break;
62930Sstevel@tonic-gate 			if (ret != 1) {
62940Sstevel@tonic-gate 				ret = scf_error();
62950Sstevel@tonic-gate 				goto error;
62960Sstevel@tonic-gate 			}
62970Sstevel@tonic-gate 
62980Sstevel@tonic-gate 			if (flags & SCF_WALK_SERVICE) {
62990Sstevel@tonic-gate 				/*
63000Sstevel@tonic-gate 				 * If the user is requesting bare services, try
63010Sstevel@tonic-gate 				 * to match the service first.
63020Sstevel@tonic-gate 				 */
63030Sstevel@tonic-gate 				if (scf_service_to_fmri(svc, fmri,
63040Sstevel@tonic-gate 				    max_fmri_length + 1) < 0) {
63050Sstevel@tonic-gate 					ret = scf_error();
63060Sstevel@tonic-gate 					goto error;
63070Sstevel@tonic-gate 				}
63080Sstevel@tonic-gate 
63090Sstevel@tonic-gate 				if (argc == 0) {
63100Sstevel@tonic-gate 					info.fmri = fmri;
63110Sstevel@tonic-gate 					info.scope = scope;
63120Sstevel@tonic-gate 					info.svc = svc;
63130Sstevel@tonic-gate 					info.inst = NULL;
63140Sstevel@tonic-gate 					info.pg = NULL;
63150Sstevel@tonic-gate 					info.prop = NULL;
63160Sstevel@tonic-gate 					if ((ret = callback(data, &info)) != 0)
63170Sstevel@tonic-gate 						goto error;
63180Sstevel@tonic-gate 					continue;
63190Sstevel@tonic-gate 				} else if ((ret = scf_pattern_match(htable,
63200Sstevel@tonic-gate 				    fmri, NULL, argc, pattern,
63210Sstevel@tonic-gate 				    flags & SCF_WALK_EXPLICIT)) != 0) {
63220Sstevel@tonic-gate 					goto error;
63230Sstevel@tonic-gate 				}
63240Sstevel@tonic-gate 			}
63250Sstevel@tonic-gate 
63260Sstevel@tonic-gate 			if (flags & SCF_WALK_NOINSTANCE)
63270Sstevel@tonic-gate 				continue;
63280Sstevel@tonic-gate 
63290Sstevel@tonic-gate 			/*
63300Sstevel@tonic-gate 			 * Iterate over all instances in the service.
63310Sstevel@tonic-gate 			 */
63320Sstevel@tonic-gate 			if (scf_iter_service_instances(siter, svc) != 0) {
63330Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_DELETED) {
63340Sstevel@tonic-gate 					ret = scf_error();
63350Sstevel@tonic-gate 					goto error;
63360Sstevel@tonic-gate 				}
63370Sstevel@tonic-gate 				continue;
63380Sstevel@tonic-gate 			}
63390Sstevel@tonic-gate 
63400Sstevel@tonic-gate 			for (;;) {
63410Sstevel@tonic-gate 				ret = scf_iter_next_instance(siter, inst);
63420Sstevel@tonic-gate 				if (ret == 0)
63430Sstevel@tonic-gate 					break;
63440Sstevel@tonic-gate 				if (ret != 1) {
63450Sstevel@tonic-gate 					if (scf_error() != SCF_ERROR_DELETED) {
63460Sstevel@tonic-gate 						ret = scf_error();
63470Sstevel@tonic-gate 						goto error;
63480Sstevel@tonic-gate 					}
63490Sstevel@tonic-gate 					break;
63500Sstevel@tonic-gate 				}
63510Sstevel@tonic-gate 
63520Sstevel@tonic-gate 				if (scf_instance_to_fmri(inst, fmri,
63530Sstevel@tonic-gate 				    max_fmri_length + 1) < 0) {
63540Sstevel@tonic-gate 					ret = scf_error();
63550Sstevel@tonic-gate 					goto error;
63560Sstevel@tonic-gate 				}
63570Sstevel@tonic-gate 
63580Sstevel@tonic-gate 				/*
63590Sstevel@tonic-gate 				 * Without arguments, execute the callback
63600Sstevel@tonic-gate 				 * immediately.
63610Sstevel@tonic-gate 				 */
63620Sstevel@tonic-gate 				if (argc == 0) {
63630Sstevel@tonic-gate 					info.fmri = fmri;
63640Sstevel@tonic-gate 					info.scope = scope;
63650Sstevel@tonic-gate 					info.svc = svc;
63660Sstevel@tonic-gate 					info.inst = inst;
63670Sstevel@tonic-gate 					info.pg = NULL;
63680Sstevel@tonic-gate 					info.prop = NULL;
63690Sstevel@tonic-gate 					if ((ret = callback(data, &info)) != 0)
63700Sstevel@tonic-gate 						goto error;
63710Sstevel@tonic-gate 				} else if ((ret = scf_pattern_match(htable,
63720Sstevel@tonic-gate 				    fmri, NULL, argc, pattern,
63730Sstevel@tonic-gate 				    flags & SCF_WALK_EXPLICIT)) != 0) {
63740Sstevel@tonic-gate 					goto error;
63750Sstevel@tonic-gate 				}
63760Sstevel@tonic-gate 			}
63770Sstevel@tonic-gate 		}
63780Sstevel@tonic-gate 
63790Sstevel@tonic-gate 		/*
63800Sstevel@tonic-gate 		 * Search legacy services
63810Sstevel@tonic-gate 		 */
63820Sstevel@tonic-gate 		if ((flags & SCF_WALK_LEGACY)) {
63830Sstevel@tonic-gate 			if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE,
63840Sstevel@tonic-gate 			    svc) != 0) {
63850Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_NOT_FOUND) {
63860Sstevel@tonic-gate 					ret = scf_error();
63870Sstevel@tonic-gate 					goto error;
63880Sstevel@tonic-gate 				}
63890Sstevel@tonic-gate 
63900Sstevel@tonic-gate 				goto nolegacy;
63910Sstevel@tonic-gate 			}
63920Sstevel@tonic-gate 
63930Sstevel@tonic-gate 			if (scf_iter_service_pgs_typed(iter, svc,
63940Sstevel@tonic-gate 			    SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
63950Sstevel@tonic-gate 				ret = scf_error();
63960Sstevel@tonic-gate 				goto error;
63970Sstevel@tonic-gate 			}
63980Sstevel@tonic-gate 
63990Sstevel@tonic-gate 			(void) strcpy(fmri, LEGACY_SCHEME);
64000Sstevel@tonic-gate 
64010Sstevel@tonic-gate 			for (;;) {
64020Sstevel@tonic-gate 				ret = scf_iter_next_pg(iter, pg);
64030Sstevel@tonic-gate 				if (ret == -1) {
64040Sstevel@tonic-gate 					ret = scf_error();
64050Sstevel@tonic-gate 					goto error;
64060Sstevel@tonic-gate 				}
64070Sstevel@tonic-gate 				if (ret == 0)
64080Sstevel@tonic-gate 					break;
64090Sstevel@tonic-gate 
64100Sstevel@tonic-gate 				if (scf_pg_get_property(pg,
64110Sstevel@tonic-gate 				    SCF_LEGACY_PROPERTY_NAME, prop) == -1) {
64120Sstevel@tonic-gate 					ret = scf_error();
64130Sstevel@tonic-gate 					if (ret == SCF_ERROR_DELETED ||
64140Sstevel@tonic-gate 					    ret == SCF_ERROR_NOT_FOUND) {
64150Sstevel@tonic-gate 						ret = 0;
64160Sstevel@tonic-gate 						continue;
64170Sstevel@tonic-gate 					}
64180Sstevel@tonic-gate 					goto error;
64190Sstevel@tonic-gate 				}
64200Sstevel@tonic-gate 
64210Sstevel@tonic-gate 				if (scf_property_is_type(prop, SCF_TYPE_ASTRING)
64220Sstevel@tonic-gate 				    != SCF_SUCCESS) {
64230Sstevel@tonic-gate 					if (scf_error() == SCF_ERROR_DELETED)
64240Sstevel@tonic-gate 						continue;
64250Sstevel@tonic-gate 					ret = scf_error();
64260Sstevel@tonic-gate 					goto error;
64270Sstevel@tonic-gate 				}
64280Sstevel@tonic-gate 
64290Sstevel@tonic-gate 				if (scf_property_get_value(prop, value) !=
64300Sstevel@tonic-gate 				    SCF_SUCCESS)
64310Sstevel@tonic-gate 					continue;
64320Sstevel@tonic-gate 
64330Sstevel@tonic-gate 				if (scf_value_get_astring(value,
64340Sstevel@tonic-gate 				    fmri + sizeof (LEGACY_SCHEME) - 1,
64350Sstevel@tonic-gate 				    max_fmri_length + 2 -
64360Sstevel@tonic-gate 				    sizeof (LEGACY_SCHEME)) <= 0)
64370Sstevel@tonic-gate 					continue;
64380Sstevel@tonic-gate 
64390Sstevel@tonic-gate 				if (scf_pg_get_name(pg, pgname,
64400Sstevel@tonic-gate 				    max_name_length + 1) <= 0) {
64410Sstevel@tonic-gate 					if (scf_error() == SCF_ERROR_DELETED)
64420Sstevel@tonic-gate 						continue;
64430Sstevel@tonic-gate 					ret = scf_error();
64440Sstevel@tonic-gate 					goto error;
64450Sstevel@tonic-gate 				}
64460Sstevel@tonic-gate 
64470Sstevel@tonic-gate 				if (argc == 0) {
64480Sstevel@tonic-gate 					info.fmri = fmri;
64490Sstevel@tonic-gate 					info.scope = scope;
64500Sstevel@tonic-gate 					info.svc = NULL;
64510Sstevel@tonic-gate 					info.inst = NULL;
64520Sstevel@tonic-gate 					info.pg = pg;
64530Sstevel@tonic-gate 					info.prop = NULL;
64540Sstevel@tonic-gate 					if ((ret = callback(data, &info)) != 0)
64550Sstevel@tonic-gate 						goto error;
64560Sstevel@tonic-gate 				} else if ((ret = scf_pattern_match(htable,
64570Sstevel@tonic-gate 				    fmri, pgname, argc, pattern,
64580Sstevel@tonic-gate 				    flags & SCF_WALK_EXPLICIT)) != 0)
64590Sstevel@tonic-gate 					goto error;
64600Sstevel@tonic-gate 			}
64610Sstevel@tonic-gate 
64620Sstevel@tonic-gate 		}
64630Sstevel@tonic-gate 	}
64640Sstevel@tonic-gate nolegacy:
64650Sstevel@tonic-gate 	ret = 0;
64660Sstevel@tonic-gate 
64670Sstevel@tonic-gate 	if (argc == 0)
64680Sstevel@tonic-gate 		goto error;
64690Sstevel@tonic-gate 
64700Sstevel@tonic-gate 	/*
64710Sstevel@tonic-gate 	 * Check all patterns, and see if we have that any that didn't match
64720Sstevel@tonic-gate 	 * or any that matched multiple instances.  For svcprop, add up the
64730Sstevel@tonic-gate 	 * total number of matching keys.
64740Sstevel@tonic-gate 	 */
64750Sstevel@tonic-gate 	info.count = 0;
64760Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
64770Sstevel@tonic-gate 		scf_match_t *match;
64780Sstevel@tonic-gate 
64790Sstevel@tonic-gate 		if (pattern[i].sp_type == PATTERN_INVALID)
64800Sstevel@tonic-gate 			continue;
64810Sstevel@tonic-gate 		if (pattern[i].sp_matchcount == 0) {
64820Sstevel@tonic-gate 			scf_msg_t msgid;
64830Sstevel@tonic-gate 			/*
64840Sstevel@tonic-gate 			 * Provide a useful error message based on the argument
64850Sstevel@tonic-gate 			 * and the type of entity requested.
64860Sstevel@tonic-gate 			 */
64870Sstevel@tonic-gate 			if (!(flags & SCF_WALK_LEGACY) &&
64880Sstevel@tonic-gate 			    strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0)
64890Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_LEGACY;
64900Sstevel@tonic-gate 			else if (flags & SCF_WALK_PROPERTY)
64910Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOENTITY;
64920Sstevel@tonic-gate 			else if (flags & SCF_WALK_NOINSTANCE)
64930Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOSERVICE;
64940Sstevel@tonic-gate 			else if (flags & SCF_WALK_SERVICE)
64950Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOINSTSVC;
64960Sstevel@tonic-gate 			else
64970Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOINSTANCE;
64980Sstevel@tonic-gate 
64990Sstevel@tonic-gate 			errfunc(scf_get_msg(msgid), pattern[i].sp_arg);
65000Sstevel@tonic-gate 			if (err)
65010Sstevel@tonic-gate 				*err = UU_EXIT_FATAL;
65020Sstevel@tonic-gate 		} else if (!(flags & SCF_WALK_MULTIPLE) &&
65030Sstevel@tonic-gate 		    pattern[i].sp_matchcount > 1) {
65040Sstevel@tonic-gate 			size_t len, off;
65050Sstevel@tonic-gate 			char *msg;
65060Sstevel@tonic-gate 
65070Sstevel@tonic-gate 			/*
65080Sstevel@tonic-gate 			 * Construct a message with all possible FMRIs before
65090Sstevel@tonic-gate 			 * passing off to error handling function.
65100Sstevel@tonic-gate 			 *
65110Sstevel@tonic-gate 			 * Note that strlen(scf_get_msg(...)) includes the
65120Sstevel@tonic-gate 			 * length of '%s', which accounts for the terminating
65130Sstevel@tonic-gate 			 * null byte.
65140Sstevel@tonic-gate 			 */
65150Sstevel@tonic-gate 			len = strlen(scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH)) +
65160Sstevel@tonic-gate 			    strlen(pattern[i].sp_arg);
65170Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
65180Sstevel@tonic-gate 			    match = match->sm_next) {
65190Sstevel@tonic-gate 				len += strlen(match->sm_key->sk_fmri) + 2;
65200Sstevel@tonic-gate 			}
65210Sstevel@tonic-gate 			if ((msg = malloc(len)) == NULL) {
65220Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
65230Sstevel@tonic-gate 				goto error;
65240Sstevel@tonic-gate 			}
65250Sstevel@tonic-gate 
65260Sstevel@tonic-gate 			/* LINTED - format argument */
65270Sstevel@tonic-gate 			(void) snprintf(msg, len,
65280Sstevel@tonic-gate 			    scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH),
65290Sstevel@tonic-gate 			    pattern[i].sp_arg);
65300Sstevel@tonic-gate 			off = strlen(msg);
65310Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
65320Sstevel@tonic-gate 			    match = match->sm_next) {
65330Sstevel@tonic-gate 				off += snprintf(msg + off, len - off, "\t%s\n",
65340Sstevel@tonic-gate 				    match->sm_key->sk_fmri);
65350Sstevel@tonic-gate 			}
65360Sstevel@tonic-gate 
65370Sstevel@tonic-gate 			errfunc(msg);
65380Sstevel@tonic-gate 			if (err != NULL)
65390Sstevel@tonic-gate 				*err = UU_EXIT_FATAL;
65400Sstevel@tonic-gate 
65410Sstevel@tonic-gate 			free(msg);
65420Sstevel@tonic-gate 		} else {
65430Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
65440Sstevel@tonic-gate 			    match = match->sm_next) {
65450Sstevel@tonic-gate 				if (!match->sm_key->sk_seen)
65460Sstevel@tonic-gate 					info.count++;
65470Sstevel@tonic-gate 				match->sm_key->sk_seen = 1;
65480Sstevel@tonic-gate 			}
65490Sstevel@tonic-gate 		}
65500Sstevel@tonic-gate 	}
65510Sstevel@tonic-gate 
65520Sstevel@tonic-gate 	/*
65530Sstevel@tonic-gate 	 * Clear 'sk_seen' for all keys.
65540Sstevel@tonic-gate 	 */
65550Sstevel@tonic-gate 	for (i = 0; i < WALK_HTABLE_SIZE; i++) {
65560Sstevel@tonic-gate 		scf_matchkey_t *key;
65570Sstevel@tonic-gate 		for (key = htable[i]; key != NULL; key = key->sk_next)
65580Sstevel@tonic-gate 			key->sk_seen = 0;
65590Sstevel@tonic-gate 	}
65600Sstevel@tonic-gate 
65610Sstevel@tonic-gate 	/*
65620Sstevel@tonic-gate 	 * Iterate over all the FMRIs in our hash table and execute the
65630Sstevel@tonic-gate 	 * callback.
65640Sstevel@tonic-gate 	 */
65650Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
65660Sstevel@tonic-gate 		scf_match_t *match;
65670Sstevel@tonic-gate 		scf_matchkey_t *key;
65680Sstevel@tonic-gate 
65690Sstevel@tonic-gate 		/*
65700Sstevel@tonic-gate 		 * Ignore patterns which didn't match anything or matched too
65710Sstevel@tonic-gate 		 * many FMRIs.
65720Sstevel@tonic-gate 		 */
65730Sstevel@tonic-gate 		if (pattern[i].sp_matchcount == 0 ||
65740Sstevel@tonic-gate 		    (!(flags & SCF_WALK_MULTIPLE) &&
65750Sstevel@tonic-gate 		    pattern[i].sp_matchcount > 1))
65760Sstevel@tonic-gate 			continue;
65770Sstevel@tonic-gate 
65780Sstevel@tonic-gate 		for (match = pattern[i].sp_matches; match != NULL;
65790Sstevel@tonic-gate 		    match = match->sm_next) {
65800Sstevel@tonic-gate 
65810Sstevel@tonic-gate 			key = match->sm_key;
65820Sstevel@tonic-gate 			if (key->sk_seen)
65830Sstevel@tonic-gate 				continue;
65840Sstevel@tonic-gate 
65850Sstevel@tonic-gate 			key->sk_seen = 1;
65860Sstevel@tonic-gate 
65870Sstevel@tonic-gate 			if (key->sk_legacy != NULL) {
65880Sstevel@tonic-gate 				if (scf_scope_get_service(scope,
65890Sstevel@tonic-gate 				    "smf/legacy_run", svc) != 0) {
65900Sstevel@tonic-gate 					ret = scf_error();
65910Sstevel@tonic-gate 					goto error;
65920Sstevel@tonic-gate 				}
65930Sstevel@tonic-gate 
65940Sstevel@tonic-gate 				if (scf_service_get_pg(svc, key->sk_legacy,
65950Sstevel@tonic-gate 				    pg) != 0)
65960Sstevel@tonic-gate 					continue;
65970Sstevel@tonic-gate 
65980Sstevel@tonic-gate 				info.fmri = key->sk_fmri;
65990Sstevel@tonic-gate 				info.scope = scope;
66000Sstevel@tonic-gate 				info.svc = NULL;
66010Sstevel@tonic-gate 				info.inst = NULL;
66020Sstevel@tonic-gate 				info.pg = pg;
66030Sstevel@tonic-gate 				info.prop = NULL;
66040Sstevel@tonic-gate 				if ((ret = callback(data, &info)) != 0)
66050Sstevel@tonic-gate 					goto error;
66060Sstevel@tonic-gate 			} else {
66070Sstevel@tonic-gate 				if (scf_handle_decode_fmri(h, key->sk_fmri,
66080Sstevel@tonic-gate 				    scope, svc, inst, pg, prop, 0) !=
66090Sstevel@tonic-gate 				    SCF_SUCCESS)
66100Sstevel@tonic-gate 					continue;
66110Sstevel@tonic-gate 
66120Sstevel@tonic-gate 				info.fmri = key->sk_fmri;
66130Sstevel@tonic-gate 				info.scope = scope;
66140Sstevel@tonic-gate 				info.svc = svc;
66150Sstevel@tonic-gate 				if (scf_instance_get_name(inst, NULL, 0) < 0) {
66160Sstevel@tonic-gate 					if (scf_error() ==
66170Sstevel@tonic-gate 					    SCF_ERROR_CONNECTION_BROKEN) {
66180Sstevel@tonic-gate 						ret = scf_error();
66190Sstevel@tonic-gate 						goto error;
66200Sstevel@tonic-gate 					}
66210Sstevel@tonic-gate 					info.inst = NULL;
66220Sstevel@tonic-gate 				} else {
66230Sstevel@tonic-gate 					info.inst = inst;
66240Sstevel@tonic-gate 				}
66250Sstevel@tonic-gate 				if (scf_pg_get_name(pg, NULL, 0) < 0) {
66260Sstevel@tonic-gate 					if (scf_error() ==
66270Sstevel@tonic-gate 					    SCF_ERROR_CONNECTION_BROKEN) {
66280Sstevel@tonic-gate 						ret = scf_error();
66290Sstevel@tonic-gate 						goto error;
66300Sstevel@tonic-gate 					}
66310Sstevel@tonic-gate 					info.pg = NULL;
66320Sstevel@tonic-gate 				} else {
66330Sstevel@tonic-gate 					info.pg = pg;
66340Sstevel@tonic-gate 				}
66350Sstevel@tonic-gate 				if (scf_property_get_name(prop, NULL, 0) < 0) {
66360Sstevel@tonic-gate 					if (scf_error() ==
66370Sstevel@tonic-gate 					    SCF_ERROR_CONNECTION_BROKEN) {
66380Sstevel@tonic-gate 						ret = scf_error();
66390Sstevel@tonic-gate 						goto error;
66400Sstevel@tonic-gate 					}
66410Sstevel@tonic-gate 					info.prop = NULL;
66420Sstevel@tonic-gate 				} else {
66430Sstevel@tonic-gate 					info.prop = prop;
66440Sstevel@tonic-gate 				}
66450Sstevel@tonic-gate 
66460Sstevel@tonic-gate 				if ((ret = callback(data, &info)) != 0)
66470Sstevel@tonic-gate 					goto error;
66480Sstevel@tonic-gate 			}
66490Sstevel@tonic-gate 		}
66500Sstevel@tonic-gate 	}
66510Sstevel@tonic-gate 
66520Sstevel@tonic-gate error:
66530Sstevel@tonic-gate 	if (htable) {
66540Sstevel@tonic-gate 		scf_matchkey_t *key, *next;
66550Sstevel@tonic-gate 
66560Sstevel@tonic-gate 		for (i = 0; i < WALK_HTABLE_SIZE; i++) {
66570Sstevel@tonic-gate 
66580Sstevel@tonic-gate 			for (key = htable[i]; key != NULL;
66590Sstevel@tonic-gate 			    key = next) {
66600Sstevel@tonic-gate 
66610Sstevel@tonic-gate 				next = key->sk_next;
66620Sstevel@tonic-gate 
66630Sstevel@tonic-gate 				if (key->sk_fmri != NULL)
66640Sstevel@tonic-gate 					free(key->sk_fmri);
66650Sstevel@tonic-gate 				if (key->sk_legacy != NULL)
66660Sstevel@tonic-gate 					free(key->sk_legacy);
66670Sstevel@tonic-gate 				free(key);
66680Sstevel@tonic-gate 			}
66690Sstevel@tonic-gate 		}
66700Sstevel@tonic-gate 		free(htable);
66710Sstevel@tonic-gate 	}
66720Sstevel@tonic-gate 	if (pattern != NULL) {
66730Sstevel@tonic-gate 		for (i = 0; i < argc; i++) {
66740Sstevel@tonic-gate 			scf_match_t *match, *next;
66750Sstevel@tonic-gate 
66760Sstevel@tonic-gate 			if (pattern[i].sp_arg != NULL)
66770Sstevel@tonic-gate 				free(pattern[i].sp_arg);
66780Sstevel@tonic-gate 
66790Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
66800Sstevel@tonic-gate 			    match = next) {
66810Sstevel@tonic-gate 
66820Sstevel@tonic-gate 				next = match->sm_next;
66830Sstevel@tonic-gate 
66840Sstevel@tonic-gate 				free(match);
66850Sstevel@tonic-gate 			}
66860Sstevel@tonic-gate 		}
66870Sstevel@tonic-gate 		free(pattern);
66880Sstevel@tonic-gate 	}
66890Sstevel@tonic-gate 
66900Sstevel@tonic-gate 	free(fmri);
66910Sstevel@tonic-gate 	free(pgname);
66920Sstevel@tonic-gate 
66930Sstevel@tonic-gate 	scf_value_destroy(value);
66940Sstevel@tonic-gate 	scf_property_destroy(prop);
66950Sstevel@tonic-gate 	scf_pg_destroy(pg);
66960Sstevel@tonic-gate 	scf_scope_destroy(scope);
66970Sstevel@tonic-gate 	scf_iter_destroy(siter);
66980Sstevel@tonic-gate 	scf_iter_destroy(sciter);
66990Sstevel@tonic-gate 	scf_iter_destroy(iter);
67000Sstevel@tonic-gate 	scf_instance_destroy(inst);
67010Sstevel@tonic-gate 	scf_service_destroy(svc);
67020Sstevel@tonic-gate 
67030Sstevel@tonic-gate 	return (ret);
67040Sstevel@tonic-gate }
67050Sstevel@tonic-gate 
67060Sstevel@tonic-gate /*
67070Sstevel@tonic-gate  * _scf_request_backup:  a simple wrapper routine
67080Sstevel@tonic-gate  */
67090Sstevel@tonic-gate int
67100Sstevel@tonic-gate _scf_request_backup(scf_handle_t *h, const char *name)
67110Sstevel@tonic-gate {
67120Sstevel@tonic-gate 	struct rep_protocol_backup_request request;
67130Sstevel@tonic-gate 	struct rep_protocol_response response;
67140Sstevel@tonic-gate 
67150Sstevel@tonic-gate 	int r;
67160Sstevel@tonic-gate 
67170Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
67180Sstevel@tonic-gate 	    sizeof (request.rpr_name))
67190Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
67200Sstevel@tonic-gate 
67210Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
67220Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_BACKUP;
6723*407Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
67240Sstevel@tonic-gate 
67250Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
67260Sstevel@tonic-gate 	    &response, sizeof (response));
67270Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
67280Sstevel@tonic-gate 
67290Sstevel@tonic-gate 	if (r < 0) {
67300Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
67310Sstevel@tonic-gate 	}
67320Sstevel@tonic-gate 
67330Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
67340Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
67350Sstevel@tonic-gate 	return (SCF_SUCCESS);
67360Sstevel@tonic-gate }
6737