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