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