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