1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * This is the main implementation file for the low-level repository
31*7c478bd9Sstevel@tonic-gate  * interface.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include "lowlevel_impl.h"
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate #include "repcache_protocol.h"
37*7c478bd9Sstevel@tonic-gate #include "scf_type.h"
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <assert.h>
40*7c478bd9Sstevel@tonic-gate #include <alloca.h>
41*7c478bd9Sstevel@tonic-gate #include <door.h>
42*7c478bd9Sstevel@tonic-gate #include <errno.h>
43*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
44*7c478bd9Sstevel@tonic-gate #include <fnmatch.h>
45*7c478bd9Sstevel@tonic-gate #include <libuutil.h>
46*7c478bd9Sstevel@tonic-gate #include <poll.h>
47*7c478bd9Sstevel@tonic-gate #include <pthread.h>
48*7c478bd9Sstevel@tonic-gate #include <stddef.h>
49*7c478bd9Sstevel@tonic-gate #include <stdio.h>
50*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
51*7c478bd9Sstevel@tonic-gate #include <string.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
54*7c478bd9Sstevel@tonic-gate #include <unistd.h>
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #define	ENV_SCF_DEBUG		"LIBSCF_DEBUG"
57*7c478bd9Sstevel@tonic-gate #define	ENV_SCF_DOORPATH	"LIBSCF_DOORPATH"
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate static uint32_t default_debug = 0;
60*7c478bd9Sstevel@tonic-gate static const char *default_door_path = REPOSITORY_DOOR_NAME;
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate #define	CALL_FAILED		-1
63*7c478bd9Sstevel@tonic-gate #define	RESULT_TOO_BIG		-2
64*7c478bd9Sstevel@tonic-gate #define	NOT_BOUND		-3
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate static pthread_mutex_t	lowlevel_init_lock;
67*7c478bd9Sstevel@tonic-gate static int32_t		lowlevel_inited;
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate static uu_list_pool_t	*tran_entry_pool;
70*7c478bd9Sstevel@tonic-gate static uu_list_pool_t	*datael_pool;
71*7c478bd9Sstevel@tonic-gate static uu_list_pool_t	*iter_pool;
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate /*
74*7c478bd9Sstevel@tonic-gate  * We want MUTEX_HELD, but we also want pthreads.
75*7c478bd9Sstevel@tonic-gate  */
76*7c478bd9Sstevel@tonic-gate struct _lwp_mutex;
77*7c478bd9Sstevel@tonic-gate extern int _mutex_held(struct _lwp_mutex *);
78*7c478bd9Sstevel@tonic-gate #define	MUTEX_HELD(m)		_mutex_held((struct _lwp_mutex *)(m))
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate /*
81*7c478bd9Sstevel@tonic-gate  * no cancellation, please
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate struct _lwp_cond;
84*7c478bd9Sstevel@tonic-gate extern int _cond_wait(struct _lwp_cond *, struct _lwp_mutex *);
85*7c478bd9Sstevel@tonic-gate #define	PTHREAD_COND_WAIT(cv, mx) \
86*7c478bd9Sstevel@tonic-gate 	    _cond_wait((struct _lwp_cond *)(cv), (struct _lwp_mutex *)(mx))
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate #ifdef lint
89*7c478bd9Sstevel@tonic-gate #define	assert_nolint(x) (void)0
90*7c478bd9Sstevel@tonic-gate #else
91*7c478bd9Sstevel@tonic-gate #define	assert_nolint(x) assert(x)
92*7c478bd9Sstevel@tonic-gate #endif
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate static void scf_iter_reset_locked(scf_iter_t *iter);
95*7c478bd9Sstevel@tonic-gate static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate #define	TYPE_VALUE	(-100)
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * Hold and release subhandles.  We only allow one thread access to the
101*7c478bd9Sstevel@tonic-gate  * subhandles at a time, and he can use any subset, grabbing and releasing
102*7c478bd9Sstevel@tonic-gate  * them in any order.  The only restrictions are that you cannot hold an
103*7c478bd9Sstevel@tonic-gate  * already-held subhandle, and all subhandles must be released before
104*7c478bd9Sstevel@tonic-gate  * returning to the original caller.
105*7c478bd9Sstevel@tonic-gate  */
106*7c478bd9Sstevel@tonic-gate static void
107*7c478bd9Sstevel@tonic-gate handle_hold_subhandles(scf_handle_t *h, int mask)
108*7c478bd9Sstevel@tonic-gate {
109*7c478bd9Sstevel@tonic-gate 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
112*7c478bd9Sstevel@tonic-gate 	while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self())
113*7c478bd9Sstevel@tonic-gate 		(void) PTHREAD_COND_WAIT(&h->rh_cv, &h->rh_lock);
114*7c478bd9Sstevel@tonic-gate 	if (h->rh_hold_flags == 0)
115*7c478bd9Sstevel@tonic-gate 		h->rh_holder = pthread_self();
116*7c478bd9Sstevel@tonic-gate 	assert(!(h->rh_hold_flags & mask));
117*7c478bd9Sstevel@tonic-gate 	h->rh_hold_flags |= mask;
118*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
119*7c478bd9Sstevel@tonic-gate }
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate static void
122*7c478bd9Sstevel@tonic-gate handle_rele_subhandles(scf_handle_t *h, int mask)
123*7c478bd9Sstevel@tonic-gate {
124*7c478bd9Sstevel@tonic-gate 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
127*7c478bd9Sstevel@tonic-gate 	assert(h->rh_holder == pthread_self());
128*7c478bd9Sstevel@tonic-gate 	assert((h->rh_hold_flags & mask));
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	h->rh_hold_flags &= ~mask;
131*7c478bd9Sstevel@tonic-gate 	if (h->rh_hold_flags == 0)
132*7c478bd9Sstevel@tonic-gate 		(void) pthread_cond_signal(&h->rh_cv);
133*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
134*7c478bd9Sstevel@tonic-gate }
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate #define	HOLD_HANDLE(h, flag, field) \
137*7c478bd9Sstevel@tonic-gate 	(handle_hold_subhandles((h), (flag)), (h)->field)
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate #define	RELE_HANDLE(h, flag) \
140*7c478bd9Sstevel@tonic-gate 	(handle_rele_subhandles((h), (flag)))
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate /*
143*7c478bd9Sstevel@tonic-gate  * convenience macros, for functions that only need a one or two handles at
144*7c478bd9Sstevel@tonic-gate  * any given time
145*7c478bd9Sstevel@tonic-gate  */
146*7c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_ITER(h)	HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
147*7c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SCOPE(h)	HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
148*7c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SERVICE(h)	HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
149*7c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_INSTANCE(h)	HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
150*7c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SNAPSHOT(h)	HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
151*7c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SNAPLVL(h)	HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
152*7c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_PG(h)	HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
153*7c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_PROPERTY(h)	HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
154*7c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_VALUE(h)	HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_ITER(h)	RELE_HANDLE((h), RH_HOLD_ITER)
157*7c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SCOPE(h)	RELE_HANDLE((h), RH_HOLD_SCOPE)
158*7c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SERVICE(h)	RELE_HANDLE((h), RH_HOLD_SERVICE)
159*7c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_INSTANCE(h)	RELE_HANDLE((h), RH_HOLD_INSTANCE)
160*7c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SNAPSHOT(h)	RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
161*7c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SNAPLVL(h)	RELE_HANDLE((h), RH_HOLD_SNAPLVL)
162*7c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_PG(h)	RELE_HANDLE((h), RH_HOLD_PG)
163*7c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_PROPERTY(h)	RELE_HANDLE((h), RH_HOLD_PROPERTY)
164*7c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_VALUE(h)	RELE_HANDLE((h), RH_HOLD_VALUE)
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
167*7c478bd9Sstevel@tonic-gate static int
168*7c478bd9Sstevel@tonic-gate transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
169*7c478bd9Sstevel@tonic-gate {
170*7c478bd9Sstevel@tonic-gate 	const char *l_prop =
171*7c478bd9Sstevel@tonic-gate 	    ((scf_transaction_entry_t *)l_arg)->entry_property;
172*7c478bd9Sstevel@tonic-gate 	const char *r_prop =
173*7c478bd9Sstevel@tonic-gate 	    ((scf_transaction_entry_t *)r_arg)->entry_property;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	int ret;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	ret = strcmp(l_prop, r_prop);
178*7c478bd9Sstevel@tonic-gate 	if (ret > 0)
179*7c478bd9Sstevel@tonic-gate 		return (1);
180*7c478bd9Sstevel@tonic-gate 	else if (ret < 0)
181*7c478bd9Sstevel@tonic-gate 		return (-1);
182*7c478bd9Sstevel@tonic-gate 	return (0);
183*7c478bd9Sstevel@tonic-gate }
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate static int
186*7c478bd9Sstevel@tonic-gate lowlevel_init(void)
187*7c478bd9Sstevel@tonic-gate {
188*7c478bd9Sstevel@tonic-gate 	const char *debug;
189*7c478bd9Sstevel@tonic-gate 	const char *door_path;
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&lowlevel_init_lock);
192*7c478bd9Sstevel@tonic-gate 	if (lowlevel_inited == 0) {
193*7c478bd9Sstevel@tonic-gate 		if (!issetugid() &&
194*7c478bd9Sstevel@tonic-gate 		    (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
195*7c478bd9Sstevel@tonic-gate 		    uu_strtoint(debug, &default_debug, sizeof (default_debug),
196*7c478bd9Sstevel@tonic-gate 		    0, 0, 0) == -1) {
197*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
198*7c478bd9Sstevel@tonic-gate 			    ENV_SCF_DEBUG, debug,
199*7c478bd9Sstevel@tonic-gate 			    uu_strerror(uu_error()));
200*7c478bd9Sstevel@tonic-gate 		}
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 		if (!issetugid() &&
203*7c478bd9Sstevel@tonic-gate 		    (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
204*7c478bd9Sstevel@tonic-gate 		    door_path[0] != 0) {
205*7c478bd9Sstevel@tonic-gate 			default_door_path = strdup(door_path);
206*7c478bd9Sstevel@tonic-gate 			if (default_door_path == NULL)
207*7c478bd9Sstevel@tonic-gate 				default_door_path = door_path;
208*7c478bd9Sstevel@tonic-gate 		}
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 		datael_pool = uu_list_pool_create("SUNW,libscf_datael",
211*7c478bd9Sstevel@tonic-gate 		    sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
212*7c478bd9Sstevel@tonic-gate 		    NULL, UU_LIST_POOL_DEBUG);
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 		iter_pool = uu_list_pool_create("SUNW,libscf_iter",
215*7c478bd9Sstevel@tonic-gate 		    sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
216*7c478bd9Sstevel@tonic-gate 		    NULL, UU_LIST_POOL_DEBUG);
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 		assert_nolint(offsetof(scf_transaction_entry_t,
219*7c478bd9Sstevel@tonic-gate 		    entry_property) == 0);
220*7c478bd9Sstevel@tonic-gate 		tran_entry_pool = uu_list_pool_create(
221*7c478bd9Sstevel@tonic-gate 		    "SUNW,libscf_transaction_entity",
222*7c478bd9Sstevel@tonic-gate 		    sizeof (scf_transaction_entry_t),
223*7c478bd9Sstevel@tonic-gate 		    offsetof(scf_transaction_entry_t, entry_link),
224*7c478bd9Sstevel@tonic-gate 		    transaction_entry_compare, UU_LIST_POOL_DEBUG);
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 		if (datael_pool == NULL || iter_pool == NULL ||
227*7c478bd9Sstevel@tonic-gate 		    tran_entry_pool == NULL) {
228*7c478bd9Sstevel@tonic-gate 			lowlevel_inited = -1;
229*7c478bd9Sstevel@tonic-gate 			goto end;
230*7c478bd9Sstevel@tonic-gate 		}
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 		if (!scf_setup_error()) {
233*7c478bd9Sstevel@tonic-gate 			lowlevel_inited = -1;
234*7c478bd9Sstevel@tonic-gate 			goto end;
235*7c478bd9Sstevel@tonic-gate 		}
236*7c478bd9Sstevel@tonic-gate 		lowlevel_inited = 1;
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate end:
239*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&lowlevel_init_lock);
240*7c478bd9Sstevel@tonic-gate 	if (lowlevel_inited > 0)
241*7c478bd9Sstevel@tonic-gate 		return (1);
242*7c478bd9Sstevel@tonic-gate 	return (0);
243*7c478bd9Sstevel@tonic-gate }
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate static const struct {
246*7c478bd9Sstevel@tonic-gate 	scf_type_t ti_type;
247*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t ti_proto_type;
248*7c478bd9Sstevel@tonic-gate 	const char *ti_name;
249*7c478bd9Sstevel@tonic-gate } scf_type_info[] = {
250*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_BOOLEAN,	REP_PROTOCOL_TYPE_BOOLEAN,	"boolean"},
251*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_COUNT,	REP_PROTOCOL_TYPE_COUNT,	"count"},
252*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_INTEGER,	REP_PROTOCOL_TYPE_INTEGER,	"integer"},
253*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_TIME,		REP_PROTOCOL_TYPE_TIME,		"time"},
254*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_ASTRING,	REP_PROTOCOL_TYPE_STRING,	"astring"},
255*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_OPAQUE,	REP_PROTOCOL_TYPE_OPAQUE,	"opaque"},
256*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_USTRING,	REP_PROTOCOL_SUBTYPE_USTRING,	"ustring"},
257*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_URI,		REP_PROTOCOL_SUBTYPE_URI,	"uri"},
258*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_FMRI,		REP_PROTOCOL_SUBTYPE_FMRI,	"fmri"},
259*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_HOST,		REP_PROTOCOL_SUBTYPE_HOST,	"host"},
260*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_HOSTNAME,	REP_PROTOCOL_SUBTYPE_HOSTNAME,	"hostname"},
261*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_NET_ADDR_V4,	REP_PROTOCOL_SUBTYPE_NETADDR_V4,
262*7c478bd9Sstevel@tonic-gate 	    "net_address_v4"},
263*7c478bd9Sstevel@tonic-gate 	{SCF_TYPE_NET_ADDR_V6,	REP_PROTOCOL_SUBTYPE_NETADDR_V6,
264*7c478bd9Sstevel@tonic-gate 	    "net_address_v6"}
265*7c478bd9Sstevel@tonic-gate };
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate #define	SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
268*7c478bd9Sstevel@tonic-gate static rep_protocol_value_type_t
269*7c478bd9Sstevel@tonic-gate scf_type_to_protocol_type(scf_type_t t)
270*7c478bd9Sstevel@tonic-gate {
271*7c478bd9Sstevel@tonic-gate 	int i;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
274*7c478bd9Sstevel@tonic-gate 		if (scf_type_info[i].ti_type == t)
275*7c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_proto_type);
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_TYPE_INVALID);
278*7c478bd9Sstevel@tonic-gate }
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate static scf_type_t
281*7c478bd9Sstevel@tonic-gate scf_protocol_type_to_type(rep_protocol_value_type_t t)
282*7c478bd9Sstevel@tonic-gate {
283*7c478bd9Sstevel@tonic-gate 	int i;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
286*7c478bd9Sstevel@tonic-gate 		if (scf_type_info[i].ti_proto_type == t)
287*7c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_type);
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	return (SCF_TYPE_INVALID);
290*7c478bd9Sstevel@tonic-gate }
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate const char *
293*7c478bd9Sstevel@tonic-gate scf_type_to_string(scf_type_t ty)
294*7c478bd9Sstevel@tonic-gate {
295*7c478bd9Sstevel@tonic-gate 	int i;
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
298*7c478bd9Sstevel@tonic-gate 		if (scf_type_info[i].ti_type == ty)
299*7c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_name);
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	return ("unknown");
302*7c478bd9Sstevel@tonic-gate }
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate scf_type_t
305*7c478bd9Sstevel@tonic-gate scf_string_to_type(const char *name)
306*7c478bd9Sstevel@tonic-gate {
307*7c478bd9Sstevel@tonic-gate 	int i;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
310*7c478bd9Sstevel@tonic-gate 		if (strcmp(scf_type_info[i].ti_name, name) == 0)
311*7c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_type);
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	return (SCF_TYPE_INVALID);
314*7c478bd9Sstevel@tonic-gate }
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate int
317*7c478bd9Sstevel@tonic-gate scf_type_base_type(scf_type_t type, scf_type_t *out)
318*7c478bd9Sstevel@tonic-gate {
319*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
320*7c478bd9Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_INVALID)
321*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	*out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
324*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
325*7c478bd9Sstevel@tonic-gate }
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate /*
328*7c478bd9Sstevel@tonic-gate  * Convert a protocol error code into an SCF_ERROR_* code.
329*7c478bd9Sstevel@tonic-gate  */
330*7c478bd9Sstevel@tonic-gate static scf_error_t
331*7c478bd9Sstevel@tonic-gate proto_error(rep_protocol_responseid_t e)
332*7c478bd9Sstevel@tonic-gate {
333*7c478bd9Sstevel@tonic-gate 	switch (e) {
334*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_MISORDERED:
335*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_UNKNOWN_ID:
336*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_INVALID_TYPE:
337*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_TRUNCATED:
338*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
339*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
340*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_UNKNOWN:
341*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INTERNAL);
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BAD_TX:
344*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INVALID_ARGUMENT);
345*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BAD_REQUEST:
346*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INVALID_ARGUMENT);
347*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
348*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NO_RESOURCES);
349*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_FOUND:
350*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NOT_FOUND);
351*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_DELETED:
352*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_DELETED);
353*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_SET:
354*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NOT_SET);
355*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_EXISTS:
356*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_EXISTS);
357*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_DUPLICATE_ID:
358*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_EXISTS);
359*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
360*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_PERMISSION_DENIED);
361*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
362*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_BACKEND_ACCESS);
363*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BACKEND_READONLY:
364*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_BACKEND_READONLY);
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_SUCCESS:
367*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_DONE:
368*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_LATEST:	/* TX code should handle this */
369*7c478bd9Sstevel@tonic-gate 	default:
370*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
371*7c478bd9Sstevel@tonic-gate 		uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
372*7c478bd9Sstevel@tonic-gate 		    __FILE__, __LINE__, e);
373*7c478bd9Sstevel@tonic-gate #endif
374*7c478bd9Sstevel@tonic-gate 		abort();
375*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
376*7c478bd9Sstevel@tonic-gate 	}
377*7c478bd9Sstevel@tonic-gate }
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate ssize_t
380*7c478bd9Sstevel@tonic-gate scf_limit(uint32_t limit)
381*7c478bd9Sstevel@tonic-gate {
382*7c478bd9Sstevel@tonic-gate 	switch (limit) {
383*7c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_NAME_LENGTH:
384*7c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
385*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_NAME_LEN - 1);
386*7c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_VALUE_LENGTH:
387*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_VALUE_LEN - 1);
388*7c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_FMRI_LENGTH:
389*7c478bd9Sstevel@tonic-gate 		return (SCF_FMRI_PREFIX_MAX_LEN +
390*7c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
391*7c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
392*7c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
393*7c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
394*7c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
395*7c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
396*7c478bd9Sstevel@tonic-gate 		    5 * (REP_PROTOCOL_NAME_LEN - 1));
397*7c478bd9Sstevel@tonic-gate 	default:
398*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
399*7c478bd9Sstevel@tonic-gate 	}
400*7c478bd9Sstevel@tonic-gate }
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate static size_t
403*7c478bd9Sstevel@tonic-gate scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
404*7c478bd9Sstevel@tonic-gate {
405*7c478bd9Sstevel@tonic-gate 	char a, b;
406*7c478bd9Sstevel@tonic-gate 	char *out = out_arg;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
409*7c478bd9Sstevel@tonic-gate 		in += 2;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 		if (a >= '0' && a <= '9')
412*7c478bd9Sstevel@tonic-gate 			a -= '0';
413*7c478bd9Sstevel@tonic-gate 		else if (a >= 'a' && a <= 'f')
414*7c478bd9Sstevel@tonic-gate 			a = a - 'a' + 10;
415*7c478bd9Sstevel@tonic-gate 		else if (a >= 'A' && a <= 'F')
416*7c478bd9Sstevel@tonic-gate 			a = a - 'A' + 10;
417*7c478bd9Sstevel@tonic-gate 		else
418*7c478bd9Sstevel@tonic-gate 			break;
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 		if (b >= '0' && b <= '9')
421*7c478bd9Sstevel@tonic-gate 			b -= '0';
422*7c478bd9Sstevel@tonic-gate 		else if (b >= 'a' && b <= 'f')
423*7c478bd9Sstevel@tonic-gate 			b = b - 'a' + 10;
424*7c478bd9Sstevel@tonic-gate 		else if (b >= 'A' && b <= 'F')
425*7c478bd9Sstevel@tonic-gate 			b = b - 'A' + 10;
426*7c478bd9Sstevel@tonic-gate 		else
427*7c478bd9Sstevel@tonic-gate 			break;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 		*out++ = (a << 4) | b;
430*7c478bd9Sstevel@tonic-gate 		max_out--;
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	return (out - out_arg);
434*7c478bd9Sstevel@tonic-gate }
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate static size_t
437*7c478bd9Sstevel@tonic-gate scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
438*7c478bd9Sstevel@tonic-gate {
439*7c478bd9Sstevel@tonic-gate 	uint8_t *in = (uint8_t *)in_arg;
440*7c478bd9Sstevel@tonic-gate 	uint8_t *end = in + in_sz;
441*7c478bd9Sstevel@tonic-gate 	char *out = out_arg;
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	if (out == NULL)
444*7c478bd9Sstevel@tonic-gate 		return (2 * in_sz);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	while (in < end) {
447*7c478bd9Sstevel@tonic-gate 		uint8_t c = *in++;
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 		uint8_t a = (c & 0xf0) >> 4;
450*7c478bd9Sstevel@tonic-gate 		uint8_t b = (c & 0x0f);
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 		if (a <= 9)
453*7c478bd9Sstevel@tonic-gate 			*out++ = a + '0';
454*7c478bd9Sstevel@tonic-gate 		else
455*7c478bd9Sstevel@tonic-gate 			*out++ = a + 'a' - 10;
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 		if (b <= 9)
458*7c478bd9Sstevel@tonic-gate 			*out++ = b + '0';
459*7c478bd9Sstevel@tonic-gate 		else
460*7c478bd9Sstevel@tonic-gate 			*out++ = b + 'a' - 10;
461*7c478bd9Sstevel@tonic-gate 	}
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	*out = 0;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	return (out - out_arg);
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate static void
469*7c478bd9Sstevel@tonic-gate handle_do_close(scf_handle_t *h)
470*7c478bd9Sstevel@tonic-gate {
471*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
472*7c478bd9Sstevel@tonic-gate 	assert(h->rh_doorfd != -1);
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	/*
475*7c478bd9Sstevel@tonic-gate 	 * if there are any active FD users, we just move the FD over
476*7c478bd9Sstevel@tonic-gate 	 * to rh_doorfd_old -- they'll close it when they finish.
477*7c478bd9Sstevel@tonic-gate 	 */
478*7c478bd9Sstevel@tonic-gate 	if (h->rh_fd_users > 0) {
479*7c478bd9Sstevel@tonic-gate 		h->rh_doorfd_old = h->rh_doorfd;
480*7c478bd9Sstevel@tonic-gate 		h->rh_doorfd = -1;
481*7c478bd9Sstevel@tonic-gate 	} else {
482*7c478bd9Sstevel@tonic-gate 		assert(h->rh_doorfd_old == -1);
483*7c478bd9Sstevel@tonic-gate 		(void) close(h->rh_doorfd);
484*7c478bd9Sstevel@tonic-gate 		h->rh_doorfd = -1;
485*7c478bd9Sstevel@tonic-gate 	}
486*7c478bd9Sstevel@tonic-gate }
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate /*
489*7c478bd9Sstevel@tonic-gate  * Check if a handle is currently bound.  fork()ing implicitly unbinds
490*7c478bd9Sstevel@tonic-gate  * the handle in the child.
491*7c478bd9Sstevel@tonic-gate  */
492*7c478bd9Sstevel@tonic-gate static int
493*7c478bd9Sstevel@tonic-gate handle_is_bound(scf_handle_t *h)
494*7c478bd9Sstevel@tonic-gate {
495*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 	if (h->rh_doorfd == -1)
498*7c478bd9Sstevel@tonic-gate 		return (0);
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 	if (getpid() == h->rh_doorpid)
501*7c478bd9Sstevel@tonic-gate 		return (1);
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	/* forked since our last bind -- initiate handle close */
504*7c478bd9Sstevel@tonic-gate 	handle_do_close(h);
505*7c478bd9Sstevel@tonic-gate 	return (0);
506*7c478bd9Sstevel@tonic-gate }
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate static int
509*7c478bd9Sstevel@tonic-gate handle_has_server(scf_handle_t *h)
510*7c478bd9Sstevel@tonic-gate {
511*7c478bd9Sstevel@tonic-gate 	door_info_t i;
512*7c478bd9Sstevel@tonic-gate 	int ret;
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
515*7c478bd9Sstevel@tonic-gate 	ret = (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
516*7c478bd9Sstevel@tonic-gate 	    i.di_target != -1);
517*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	return (ret);
520*7c478bd9Sstevel@tonic-gate }
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate /*
523*7c478bd9Sstevel@tonic-gate  * This makes a door request on the client door associated with handle h.
524*7c478bd9Sstevel@tonic-gate  * It will automatically retry calls which fail on EINTR.  If h is not bound,
525*7c478bd9Sstevel@tonic-gate  * returns NOT_BOUND.  If the door call fails or the server response is too
526*7c478bd9Sstevel@tonic-gate  * small, returns CALL_FAILED.  If the server response is too big, truncates the
527*7c478bd9Sstevel@tonic-gate  * response and returns RESULT_TOO_BIG.  Otherwise, the size of the result is
528*7c478bd9Sstevel@tonic-gate  * returned.
529*7c478bd9Sstevel@tonic-gate  */
530*7c478bd9Sstevel@tonic-gate static ssize_t
531*7c478bd9Sstevel@tonic-gate make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
532*7c478bd9Sstevel@tonic-gate     void *res, size_t res_sz)
533*7c478bd9Sstevel@tonic-gate {
534*7c478bd9Sstevel@tonic-gate 	door_arg_t arg;
535*7c478bd9Sstevel@tonic-gate 	int r;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
540*7c478bd9Sstevel@tonic-gate 		return (NOT_BOUND);
541*7c478bd9Sstevel@tonic-gate 	}
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	arg.data_ptr = (void *)req;
544*7c478bd9Sstevel@tonic-gate 	arg.data_size = req_sz;
545*7c478bd9Sstevel@tonic-gate 	arg.desc_ptr = NULL;
546*7c478bd9Sstevel@tonic-gate 	arg.desc_num = 0;
547*7c478bd9Sstevel@tonic-gate 	arg.rbuf = res;
548*7c478bd9Sstevel@tonic-gate 	arg.rsize = res_sz;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
551*7c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
552*7c478bd9Sstevel@tonic-gate 			break;
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	if (r < 0) {
556*7c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
557*7c478bd9Sstevel@tonic-gate 	}
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 	if (arg.desc_num > 0) {
560*7c478bd9Sstevel@tonic-gate 		while (arg.desc_num > 0) {
561*7c478bd9Sstevel@tonic-gate 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
562*7c478bd9Sstevel@tonic-gate 				int cfd = arg.desc_ptr->d_data.d_desc.d_id;
563*7c478bd9Sstevel@tonic-gate 				(void) close(cfd);
564*7c478bd9Sstevel@tonic-gate 			}
565*7c478bd9Sstevel@tonic-gate 			arg.desc_ptr++;
566*7c478bd9Sstevel@tonic-gate 			arg.desc_num--;
567*7c478bd9Sstevel@tonic-gate 		}
568*7c478bd9Sstevel@tonic-gate 	}
569*7c478bd9Sstevel@tonic-gate 	if (arg.data_ptr != res && arg.data_size > 0)
570*7c478bd9Sstevel@tonic-gate 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	if (arg.rbuf != res)
573*7c478bd9Sstevel@tonic-gate 		(void) munmap(arg.rbuf, arg.rsize);
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	if (arg.data_size > res_sz)
576*7c478bd9Sstevel@tonic-gate 		return (RESULT_TOO_BIG);
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	if (arg.data_size < sizeof (uint32_t))
579*7c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	return (arg.data_size);
582*7c478bd9Sstevel@tonic-gate }
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate /*
585*7c478bd9Sstevel@tonic-gate  * Should only be used when r < 0.
586*7c478bd9Sstevel@tonic-gate  */
587*7c478bd9Sstevel@tonic-gate #define	DOOR_ERRORS_BLOCK(r)	{					\
588*7c478bd9Sstevel@tonic-gate 	switch (r) {							\
589*7c478bd9Sstevel@tonic-gate 	case NOT_BOUND:							\
590*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_BOUND));		\
591*7c478bd9Sstevel@tonic-gate 									\
592*7c478bd9Sstevel@tonic-gate 	case CALL_FAILED:						\
593*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));	\
594*7c478bd9Sstevel@tonic-gate 									\
595*7c478bd9Sstevel@tonic-gate 	case RESULT_TOO_BIG:						\
596*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));		\
597*7c478bd9Sstevel@tonic-gate 									\
598*7c478bd9Sstevel@tonic-gate 	default:							\
599*7c478bd9Sstevel@tonic-gate 		assert(r == NOT_BOUND || r == CALL_FAILED ||		\
600*7c478bd9Sstevel@tonic-gate 		    r == RESULT_TOO_BIG);				\
601*7c478bd9Sstevel@tonic-gate 		abort();						\
602*7c478bd9Sstevel@tonic-gate 	}								\
603*7c478bd9Sstevel@tonic-gate }
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate /*
606*7c478bd9Sstevel@tonic-gate  * Like make_door_call(), but takes an fd instead of a handle, and expects
607*7c478bd9Sstevel@tonic-gate  * a single file descriptor, returned via res_fd.
608*7c478bd9Sstevel@tonic-gate  *
609*7c478bd9Sstevel@tonic-gate  * If no file descriptor is returned, *res_fd == -1.
610*7c478bd9Sstevel@tonic-gate  */
611*7c478bd9Sstevel@tonic-gate static int
612*7c478bd9Sstevel@tonic-gate make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
613*7c478bd9Sstevel@tonic-gate     size_t res_sz, int *res_fd)
614*7c478bd9Sstevel@tonic-gate {
615*7c478bd9Sstevel@tonic-gate 	door_arg_t arg;
616*7c478bd9Sstevel@tonic-gate 	int r;
617*7c478bd9Sstevel@tonic-gate 	char rbuf[256];
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	*res_fd = -1;
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 	if (fd == -1)
622*7c478bd9Sstevel@tonic-gate 		return (NOT_BOUND);
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	arg.data_ptr = (void *)req;
625*7c478bd9Sstevel@tonic-gate 	arg.data_size = req_sz;
626*7c478bd9Sstevel@tonic-gate 	arg.desc_ptr = NULL;
627*7c478bd9Sstevel@tonic-gate 	arg.desc_num = 0;
628*7c478bd9Sstevel@tonic-gate 	arg.rbuf = rbuf;
629*7c478bd9Sstevel@tonic-gate 	arg.rsize = sizeof (rbuf);
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	while ((r = door_call(fd, &arg)) < 0) {
632*7c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
633*7c478bd9Sstevel@tonic-gate 			break;
634*7c478bd9Sstevel@tonic-gate 	}
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	if (r < 0)
637*7c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	if (arg.desc_num > 1) {
640*7c478bd9Sstevel@tonic-gate 		while (arg.desc_num > 0) {
641*7c478bd9Sstevel@tonic-gate 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
642*7c478bd9Sstevel@tonic-gate 				int cfd =
643*7c478bd9Sstevel@tonic-gate 				    arg.desc_ptr->d_data.d_desc.d_descriptor;
644*7c478bd9Sstevel@tonic-gate 				(void) close(cfd);
645*7c478bd9Sstevel@tonic-gate 			}
646*7c478bd9Sstevel@tonic-gate 			arg.desc_ptr++;
647*7c478bd9Sstevel@tonic-gate 			arg.desc_num--;
648*7c478bd9Sstevel@tonic-gate 		}
649*7c478bd9Sstevel@tonic-gate 	}
650*7c478bd9Sstevel@tonic-gate 	if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
651*7c478bd9Sstevel@tonic-gate 		*res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	if (arg.data_size > 0)
654*7c478bd9Sstevel@tonic-gate 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	if (arg.rbuf != rbuf)
657*7c478bd9Sstevel@tonic-gate 		(void) munmap(arg.rbuf, arg.rsize);
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 	if (arg.data_size > res_sz)
660*7c478bd9Sstevel@tonic-gate 		return (RESULT_TOO_BIG);
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	if (arg.data_size < sizeof (uint32_t))
663*7c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	return (arg.data_size);
666*7c478bd9Sstevel@tonic-gate }
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate /*
669*7c478bd9Sstevel@tonic-gate  * Fails with
670*7c478bd9Sstevel@tonic-gate  *   _VERSION_MISMATCH
671*7c478bd9Sstevel@tonic-gate  *   _NO_MEMORY
672*7c478bd9Sstevel@tonic-gate  */
673*7c478bd9Sstevel@tonic-gate scf_handle_t *
674*7c478bd9Sstevel@tonic-gate scf_handle_create(scf_version_t v)
675*7c478bd9Sstevel@tonic-gate {
676*7c478bd9Sstevel@tonic-gate 	scf_handle_t *ret;
677*7c478bd9Sstevel@tonic-gate 	int failed;
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	/*
680*7c478bd9Sstevel@tonic-gate 	 * This will need to be revisited when we bump SCF_VERSION
681*7c478bd9Sstevel@tonic-gate 	 */
682*7c478bd9Sstevel@tonic-gate 	if (v != SCF_VERSION) {
683*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
684*7c478bd9Sstevel@tonic-gate 		return (NULL);
685*7c478bd9Sstevel@tonic-gate 	}
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 	if (!lowlevel_init()) {
688*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
689*7c478bd9Sstevel@tonic-gate 		return (NULL);
690*7c478bd9Sstevel@tonic-gate 	}
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
693*7c478bd9Sstevel@tonic-gate 	if (ret == NULL) {
694*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
695*7c478bd9Sstevel@tonic-gate 		return (NULL);
696*7c478bd9Sstevel@tonic-gate 	}
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
699*7c478bd9Sstevel@tonic-gate 	ret->rh_iters = uu_list_create(iter_pool, ret, 0);
700*7c478bd9Sstevel@tonic-gate 	if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
701*7c478bd9Sstevel@tonic-gate 		if (ret->rh_dataels != NULL)
702*7c478bd9Sstevel@tonic-gate 			uu_list_destroy(ret->rh_dataels);
703*7c478bd9Sstevel@tonic-gate 		if (ret->rh_iters != NULL)
704*7c478bd9Sstevel@tonic-gate 			uu_list_destroy(ret->rh_iters);
705*7c478bd9Sstevel@tonic-gate 		uu_free(ret);
706*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
707*7c478bd9Sstevel@tonic-gate 		return (NULL);
708*7c478bd9Sstevel@tonic-gate 	}
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	ret->rh_doorfd = -1;
711*7c478bd9Sstevel@tonic-gate 	ret->rh_doorfd_old = -1;
712*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&ret->rh_lock, NULL);
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	handle_hold_subhandles(ret, RH_HOLD_ALL);
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
717*7c478bd9Sstevel@tonic-gate 	    (ret->rh_scope = scf_scope_create(ret)) == NULL ||
718*7c478bd9Sstevel@tonic-gate 	    (ret->rh_service = scf_service_create(ret)) == NULL ||
719*7c478bd9Sstevel@tonic-gate 	    (ret->rh_instance = scf_instance_create(ret)) == NULL ||
720*7c478bd9Sstevel@tonic-gate 	    (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
721*7c478bd9Sstevel@tonic-gate 	    (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
722*7c478bd9Sstevel@tonic-gate 	    (ret->rh_pg = scf_pg_create(ret)) == NULL ||
723*7c478bd9Sstevel@tonic-gate 	    (ret->rh_property = scf_property_create(ret)) == NULL ||
724*7c478bd9Sstevel@tonic-gate 	    (ret->rh_value = scf_value_create(ret)) == NULL);
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	/*
727*7c478bd9Sstevel@tonic-gate 	 * these subhandles count as internal references, not external ones.
728*7c478bd9Sstevel@tonic-gate 	 */
729*7c478bd9Sstevel@tonic-gate 	ret->rh_intrefs = ret->rh_extrefs;
730*7c478bd9Sstevel@tonic-gate 	ret->rh_extrefs = 0;
731*7c478bd9Sstevel@tonic-gate 	handle_rele_subhandles(ret, RH_HOLD_ALL);
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	if (failed) {
734*7c478bd9Sstevel@tonic-gate 		scf_handle_destroy(ret);
735*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
736*7c478bd9Sstevel@tonic-gate 		return (NULL);
737*7c478bd9Sstevel@tonic-gate 	}
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	scf_value_set_count(ret->rh_value, default_debug);
740*7c478bd9Sstevel@tonic-gate 	(void) scf_handle_decorate(ret, "debug", ret->rh_value);
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	return (ret);
743*7c478bd9Sstevel@tonic-gate }
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate int
746*7c478bd9Sstevel@tonic-gate scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
747*7c478bd9Sstevel@tonic-gate {
748*7c478bd9Sstevel@tonic-gate 	if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
749*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
752*7c478bd9Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
753*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
754*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
755*7c478bd9Sstevel@tonic-gate 	}
756*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, "debug") == 0) {
759*7c478bd9Sstevel@tonic-gate 		if (v == SCF_DECORATE_CLEAR) {
760*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
761*7c478bd9Sstevel@tonic-gate 			handle->rh_debug = 0;
762*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
763*7c478bd9Sstevel@tonic-gate 		} else {
764*7c478bd9Sstevel@tonic-gate 			uint64_t val;
765*7c478bd9Sstevel@tonic-gate 			if (scf_value_get_count(v, &val) < 0)
766*7c478bd9Sstevel@tonic-gate 				return (-1);		/* error already set */
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
769*7c478bd9Sstevel@tonic-gate 			handle->rh_debug = (uid_t)val;
770*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
771*7c478bd9Sstevel@tonic-gate 		}
772*7c478bd9Sstevel@tonic-gate 		return (0);
773*7c478bd9Sstevel@tonic-gate 	}
774*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, "door_path") == 0) {
775*7c478bd9Sstevel@tonic-gate 		char name[sizeof (handle->rh_doorpath)];
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 		if (v == SCF_DECORATE_CLEAR) {
778*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
779*7c478bd9Sstevel@tonic-gate 			handle->rh_doorpath[0] = 0;
780*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
781*7c478bd9Sstevel@tonic-gate 		} else {
782*7c478bd9Sstevel@tonic-gate 			ssize_t len;
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 			if ((len = scf_value_get_astring(v, name,
785*7c478bd9Sstevel@tonic-gate 			    sizeof (name))) < 0) {
786*7c478bd9Sstevel@tonic-gate 				return (-1);		/* error already set */
787*7c478bd9Sstevel@tonic-gate 			}
788*7c478bd9Sstevel@tonic-gate 			if (len == 0 || len >= sizeof (name)) {
789*7c478bd9Sstevel@tonic-gate 				return (scf_set_error(
790*7c478bd9Sstevel@tonic-gate 				    SCF_ERROR_INVALID_ARGUMENT));
791*7c478bd9Sstevel@tonic-gate 			}
792*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
793*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(handle->rh_doorpath, name,
794*7c478bd9Sstevel@tonic-gate 			    sizeof (handle->rh_doorpath));
795*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
796*7c478bd9Sstevel@tonic-gate 		}
797*7c478bd9Sstevel@tonic-gate 		return (0);
798*7c478bd9Sstevel@tonic-gate 	}
799*7c478bd9Sstevel@tonic-gate 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
800*7c478bd9Sstevel@tonic-gate }
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate /*
803*7c478bd9Sstevel@tonic-gate  * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
804*7c478bd9Sstevel@tonic-gate  */
805*7c478bd9Sstevel@tonic-gate int
806*7c478bd9Sstevel@tonic-gate _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f,
807*7c478bd9Sstevel@tonic-gate     scf_value_t *v, void *data)
808*7c478bd9Sstevel@tonic-gate {
809*7c478bd9Sstevel@tonic-gate 	scf_decoration_info_t i;
810*7c478bd9Sstevel@tonic-gate 	char name[sizeof (handle->rh_doorpath)];
811*7c478bd9Sstevel@tonic-gate 	uint64_t debug;
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate 	if (f == NULL || v == NULL)
814*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	if (v->value_handle != handle)
817*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	i.sdi_name = (const char *)"debug";
820*7c478bd9Sstevel@tonic-gate 	i.sdi_type = SCF_TYPE_COUNT;
821*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
822*7c478bd9Sstevel@tonic-gate 	debug = handle->rh_debug;
823*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
824*7c478bd9Sstevel@tonic-gate 	if (debug != 0) {
825*7c478bd9Sstevel@tonic-gate 		scf_value_set_count(v, debug);
826*7c478bd9Sstevel@tonic-gate 		i.sdi_value = v;
827*7c478bd9Sstevel@tonic-gate 	} else {
828*7c478bd9Sstevel@tonic-gate 		i.sdi_value = SCF_DECORATE_CLEAR;
829*7c478bd9Sstevel@tonic-gate 	}
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 	if ((*f)(&i, data) == 0)
832*7c478bd9Sstevel@tonic-gate 		return (0);
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	i.sdi_name = (const char *)"door_path";
835*7c478bd9Sstevel@tonic-gate 	i.sdi_type = SCF_TYPE_ASTRING;
836*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
837*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(name, handle->rh_doorpath, sizeof (name));
838*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
839*7c478bd9Sstevel@tonic-gate 	if (name[0] != 0) {
840*7c478bd9Sstevel@tonic-gate 		(void) scf_value_set_astring(v, name);
841*7c478bd9Sstevel@tonic-gate 		i.sdi_value = v;
842*7c478bd9Sstevel@tonic-gate 	} else {
843*7c478bd9Sstevel@tonic-gate 		i.sdi_value = SCF_DECORATE_CLEAR;
844*7c478bd9Sstevel@tonic-gate 	}
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 	if ((*f)(&i, data) == 0)
847*7c478bd9Sstevel@tonic-gate 		return (0);
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	return (1);
850*7c478bd9Sstevel@tonic-gate }
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate /*
853*7c478bd9Sstevel@tonic-gate  * Fails if handle is not bound.
854*7c478bd9Sstevel@tonic-gate  */
855*7c478bd9Sstevel@tonic-gate static int
856*7c478bd9Sstevel@tonic-gate handle_unbind_unlocked(scf_handle_t *handle)
857*7c478bd9Sstevel@tonic-gate {
858*7c478bd9Sstevel@tonic-gate 	rep_protocol_request_t request;
859*7c478bd9Sstevel@tonic-gate 	rep_protocol_response_t response;
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(handle))
862*7c478bd9Sstevel@tonic-gate 		return (-1);
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_CLOSE;
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	(void) make_door_call(handle, &request, sizeof (request),
867*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	handle_do_close(handle);
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
872*7c478bd9Sstevel@tonic-gate }
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate /*
875*7c478bd9Sstevel@tonic-gate  * Fails with
876*7c478bd9Sstevel@tonic-gate  *   _HANDLE_DESTROYED - dp's handle has been destroyed
877*7c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
878*7c478bd9Sstevel@tonic-gate  *		 entity already set up with different type
879*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES - server out of memory
880*7c478bd9Sstevel@tonic-gate  */
881*7c478bd9Sstevel@tonic-gate static int
882*7c478bd9Sstevel@tonic-gate datael_attach(scf_datael_t *dp)
883*7c478bd9Sstevel@tonic-gate {
884*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_setup request;
887*7c478bd9Sstevel@tonic-gate 	rep_protocol_response_t response;
888*7c478bd9Sstevel@tonic-gate 	ssize_t r;
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	dp->rd_reset = 0;		/* setup implicitly resets */
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD)
895*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h))
898*7c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);		/* nothing to do */
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_SETUP;
901*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
902*7c478bd9Sstevel@tonic-gate 	request.rpr_entitytype = dp->rd_type;
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
905*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	if (r == NOT_BOUND || r == CALL_FAILED)
908*7c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);
909*7c478bd9Sstevel@tonic-gate 	if (r == RESULT_TOO_BIG)
910*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
913*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
916*7c478bd9Sstevel@tonic-gate }
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate /*
919*7c478bd9Sstevel@tonic-gate  * Fails with
920*7c478bd9Sstevel@tonic-gate  *   _HANDLE_DESTROYED - iter's handle has been destroyed
921*7c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
922*7c478bd9Sstevel@tonic-gate  *		 iter already existed
923*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
924*7c478bd9Sstevel@tonic-gate  */
925*7c478bd9Sstevel@tonic-gate static int
926*7c478bd9Sstevel@tonic-gate iter_attach(scf_iter_t *iter)
927*7c478bd9Sstevel@tonic-gate {
928*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
929*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_request request;
930*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
931*7c478bd9Sstevel@tonic-gate 	int r;
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD)
936*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h))
939*7c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);		/* nothing to do */
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_SETUP;
942*7c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
945*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	if (r == NOT_BOUND || r == CALL_FAILED)
948*7c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);
949*7c478bd9Sstevel@tonic-gate 	if (r == RESULT_TOO_BIG)
950*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
953*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
956*7c478bd9Sstevel@tonic-gate }
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate /*
959*7c478bd9Sstevel@tonic-gate  * Fails with
960*7c478bd9Sstevel@tonic-gate  *   _IN_USE - handle already bound
961*7c478bd9Sstevel@tonic-gate  *   _NO_SERVER - server door could not be open()ed
962*7c478bd9Sstevel@tonic-gate  *		  door call failed
963*7c478bd9Sstevel@tonic-gate  *		  door_info() failed
964*7c478bd9Sstevel@tonic-gate  *   _VERSION_MISMATCH - server returned bad file descriptor
965*7c478bd9Sstevel@tonic-gate  *			 server claimed bad request
966*7c478bd9Sstevel@tonic-gate  *			 server reported version mismatch
967*7c478bd9Sstevel@tonic-gate  *			 server refused with unknown reason
968*7c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT
969*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES - server is out of memory
970*7c478bd9Sstevel@tonic-gate  *   _PERMISSION_DENIED
971*7c478bd9Sstevel@tonic-gate  *   _INTERNAL - could not set up entities or iters
972*7c478bd9Sstevel@tonic-gate  *		 server response too big
973*7c478bd9Sstevel@tonic-gate  *
974*7c478bd9Sstevel@tonic-gate  * perhaps this should try multiple times.
975*7c478bd9Sstevel@tonic-gate  */
976*7c478bd9Sstevel@tonic-gate int
977*7c478bd9Sstevel@tonic-gate scf_handle_bind(scf_handle_t *handle)
978*7c478bd9Sstevel@tonic-gate {
979*7c478bd9Sstevel@tonic-gate 	scf_datael_t *el;
980*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	pid_t pid;
983*7c478bd9Sstevel@tonic-gate 	int fd;
984*7c478bd9Sstevel@tonic-gate 	int res;
985*7c478bd9Sstevel@tonic-gate 	door_info_t info;
986*7c478bd9Sstevel@tonic-gate 	repository_door_request_t request;
987*7c478bd9Sstevel@tonic-gate 	repository_door_response_t response;
988*7c478bd9Sstevel@tonic-gate 	const char *door_name = default_door_path;
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
991*7c478bd9Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
992*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
993*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
994*7c478bd9Sstevel@tonic-gate 	}
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	/* wait until any active fd users have cleared out */
997*7c478bd9Sstevel@tonic-gate 	while (handle->rh_fd_users > 0)
998*7c478bd9Sstevel@tonic-gate 		(void) PTHREAD_COND_WAIT(&handle->rh_cv, &handle->rh_lock);
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	/* check again, since we had to drop the lock */
1001*7c478bd9Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
1002*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
1003*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
1004*7c478bd9Sstevel@tonic-gate 	}
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate 	assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1);
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	if (handle->rh_doorpath[0] != 0)
1009*7c478bd9Sstevel@tonic-gate 		door_name = handle->rh_doorpath;
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 	fd = open(door_name, O_RDONLY, 0);
1012*7c478bd9Sstevel@tonic-gate 	if (fd == -1) {
1013*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
1014*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NO_SERVER));
1015*7c478bd9Sstevel@tonic-gate 	}
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 	request.rdr_version = REPOSITORY_DOOR_VERSION;
1018*7c478bd9Sstevel@tonic-gate 	request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT;
1019*7c478bd9Sstevel@tonic-gate 	request.rdr_flags = handle->rh_flags;
1020*7c478bd9Sstevel@tonic-gate 	request.rdr_debug = handle->rh_debug;
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 	pid = getpid();
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 	res = make_door_call_retfd(fd, &request, sizeof (request),
1025*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response), &handle->rh_doorfd);
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	if (res < 0) {
1030*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 		assert(res != NOT_BOUND);
1033*7c478bd9Sstevel@tonic-gate 		if (res == CALL_FAILED)
1034*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_NO_SERVER));
1035*7c478bd9Sstevel@tonic-gate 		assert(res == RESULT_TOO_BIG);
1036*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
1037*7c478bd9Sstevel@tonic-gate 	}
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate 	if (handle->rh_doorfd < 0) {
1040*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 		switch (response.rdr_status) {
1043*7c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_SUCCESS:
1044*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_BAD_REQUEST:
1047*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH:
1050*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_BAD_FLAG:
1053*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_NO_RESOURCES:
1056*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_NO_RESOURCES));
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED:
1059*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 		default:
1062*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1063*7c478bd9Sstevel@tonic-gate 		}
1064*7c478bd9Sstevel@tonic-gate 	}
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate 	(void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC);
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	if (door_info(handle->rh_doorfd, &info) < 0) {
1069*7c478bd9Sstevel@tonic-gate 		(void) close(handle->rh_doorfd);
1070*7c478bd9Sstevel@tonic-gate 		handle->rh_doorfd = -1;
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
1073*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NO_SERVER));
1074*7c478bd9Sstevel@tonic-gate 	}
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate 	handle->rh_doorpid = pid;
1077*7c478bd9Sstevel@tonic-gate 	handle->rh_doorid = info.di_uniquifier;
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	/*
1080*7c478bd9Sstevel@tonic-gate 	 * Now, re-attach everything
1081*7c478bd9Sstevel@tonic-gate 	 */
1082*7c478bd9Sstevel@tonic-gate 	for (el = uu_list_first(handle->rh_dataels); el != NULL;
1083*7c478bd9Sstevel@tonic-gate 	    el = uu_list_next(handle->rh_dataels, el)) {
1084*7c478bd9Sstevel@tonic-gate 		if (datael_attach(el) == -1) {
1085*7c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1086*7c478bd9Sstevel@tonic-gate 			(void) handle_unbind_unlocked(handle);
1087*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
1088*7c478bd9Sstevel@tonic-gate 			return (-1);
1089*7c478bd9Sstevel@tonic-gate 		}
1090*7c478bd9Sstevel@tonic-gate 	}
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	for (iter = uu_list_first(handle->rh_iters); iter != NULL;
1093*7c478bd9Sstevel@tonic-gate 	    iter = uu_list_next(handle->rh_iters, iter)) {
1094*7c478bd9Sstevel@tonic-gate 		if (iter_attach(iter) == -1) {
1095*7c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1096*7c478bd9Sstevel@tonic-gate 			(void) handle_unbind_unlocked(handle);
1097*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
1098*7c478bd9Sstevel@tonic-gate 			return (-1);
1099*7c478bd9Sstevel@tonic-gate 		}
1100*7c478bd9Sstevel@tonic-gate 	}
1101*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
1102*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
1103*7c478bd9Sstevel@tonic-gate }
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate int
1106*7c478bd9Sstevel@tonic-gate scf_handle_unbind(scf_handle_t *handle)
1107*7c478bd9Sstevel@tonic-gate {
1108*7c478bd9Sstevel@tonic-gate 	int ret;
1109*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
1110*7c478bd9Sstevel@tonic-gate 	ret = handle_unbind_unlocked(handle);
1111*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
1112*7c478bd9Sstevel@tonic-gate 	return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND));
1113*7c478bd9Sstevel@tonic-gate }
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate static scf_handle_t *
1116*7c478bd9Sstevel@tonic-gate handle_get(scf_handle_t *h)
1117*7c478bd9Sstevel@tonic-gate {
1118*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1119*7c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD) {
1120*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
1121*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
1122*7c478bd9Sstevel@tonic-gate 		return (NULL);
1123*7c478bd9Sstevel@tonic-gate 	}
1124*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1125*7c478bd9Sstevel@tonic-gate 	return (h);
1126*7c478bd9Sstevel@tonic-gate }
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate /*
1129*7c478bd9Sstevel@tonic-gate  * Called when an object is removed from the handle.  On the last remove,
1130*7c478bd9Sstevel@tonic-gate  * cleans up and frees the handle.
1131*7c478bd9Sstevel@tonic-gate  */
1132*7c478bd9Sstevel@tonic-gate static void
1133*7c478bd9Sstevel@tonic-gate handle_unrefed(scf_handle_t *handle)
1134*7c478bd9Sstevel@tonic-gate {
1135*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
1136*7c478bd9Sstevel@tonic-gate 	scf_value_t *v;
1137*7c478bd9Sstevel@tonic-gate 	scf_scope_t *sc;
1138*7c478bd9Sstevel@tonic-gate 	scf_service_t *svc;
1139*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
1140*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
1141*7c478bd9Sstevel@tonic-gate 	scf_snaplevel_t *snaplvl;
1142*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
1143*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
1146*7c478bd9Sstevel@tonic-gate 
1147*7c478bd9Sstevel@tonic-gate 	/*
1148*7c478bd9Sstevel@tonic-gate 	 * Don't do anything if the handle has not yet been destroyed, there
1149*7c478bd9Sstevel@tonic-gate 	 * are still external references, or we're already doing unrefed
1150*7c478bd9Sstevel@tonic-gate 	 * handling.
1151*7c478bd9Sstevel@tonic-gate 	 */
1152*7c478bd9Sstevel@tonic-gate 	if (!(handle->rh_flags & HANDLE_DEAD) ||
1153*7c478bd9Sstevel@tonic-gate 	    handle->rh_extrefs > 0 ||
1154*7c478bd9Sstevel@tonic-gate 	    handle->rh_fd_users > 0 ||
1155*7c478bd9Sstevel@tonic-gate 	    (handle->rh_flags & HANDLE_UNREFED)) {
1156*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
1157*7c478bd9Sstevel@tonic-gate 		return;
1158*7c478bd9Sstevel@tonic-gate 	}
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 	handle->rh_flags |= HANDLE_UNREFED;
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 	/*
1163*7c478bd9Sstevel@tonic-gate 	 * Now that we know that there are no external references, and the
1164*7c478bd9Sstevel@tonic-gate 	 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
1165*7c478bd9Sstevel@tonic-gate 	 * our subhandles and destroy the handle completely.
1166*7c478bd9Sstevel@tonic-gate 	 */
1167*7c478bd9Sstevel@tonic-gate 	assert(handle->rh_intrefs >= 0);
1168*7c478bd9Sstevel@tonic-gate 	handle->rh_extrefs = handle->rh_intrefs;
1169*7c478bd9Sstevel@tonic-gate 	handle->rh_intrefs = 0;
1170*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	handle_hold_subhandles(handle, RH_HOLD_ALL);
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	iter = handle->rh_iter;
1175*7c478bd9Sstevel@tonic-gate 	sc = handle->rh_scope;
1176*7c478bd9Sstevel@tonic-gate 	svc = handle->rh_service;
1177*7c478bd9Sstevel@tonic-gate 	inst = handle->rh_instance;
1178*7c478bd9Sstevel@tonic-gate 	snap = handle->rh_snapshot;
1179*7c478bd9Sstevel@tonic-gate 	snaplvl = handle->rh_snaplvl;
1180*7c478bd9Sstevel@tonic-gate 	pg = handle->rh_pg;
1181*7c478bd9Sstevel@tonic-gate 	prop = handle->rh_property;
1182*7c478bd9Sstevel@tonic-gate 	v = handle->rh_value;
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	handle->rh_iter = NULL;
1185*7c478bd9Sstevel@tonic-gate 	handle->rh_scope = NULL;
1186*7c478bd9Sstevel@tonic-gate 	handle->rh_service = NULL;
1187*7c478bd9Sstevel@tonic-gate 	handle->rh_instance = NULL;
1188*7c478bd9Sstevel@tonic-gate 	handle->rh_snapshot = NULL;
1189*7c478bd9Sstevel@tonic-gate 	handle->rh_snaplvl = NULL;
1190*7c478bd9Sstevel@tonic-gate 	handle->rh_pg = NULL;
1191*7c478bd9Sstevel@tonic-gate 	handle->rh_property = NULL;
1192*7c478bd9Sstevel@tonic-gate 	handle->rh_value = NULL;
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 	if (iter != NULL)
1195*7c478bd9Sstevel@tonic-gate 		scf_iter_destroy(iter);
1196*7c478bd9Sstevel@tonic-gate 	if (sc != NULL)
1197*7c478bd9Sstevel@tonic-gate 		scf_scope_destroy(sc);
1198*7c478bd9Sstevel@tonic-gate 	if (svc != NULL)
1199*7c478bd9Sstevel@tonic-gate 		scf_service_destroy(svc);
1200*7c478bd9Sstevel@tonic-gate 	if (inst != NULL)
1201*7c478bd9Sstevel@tonic-gate 		scf_instance_destroy(inst);
1202*7c478bd9Sstevel@tonic-gate 	if (snap != NULL)
1203*7c478bd9Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
1204*7c478bd9Sstevel@tonic-gate 	if (snaplvl != NULL)
1205*7c478bd9Sstevel@tonic-gate 		scf_snaplevel_destroy(snaplvl);
1206*7c478bd9Sstevel@tonic-gate 	if (pg != NULL)
1207*7c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
1208*7c478bd9Sstevel@tonic-gate 	if (prop != NULL)
1209*7c478bd9Sstevel@tonic-gate 		scf_property_destroy(prop);
1210*7c478bd9Sstevel@tonic-gate 	if (v != NULL)
1211*7c478bd9Sstevel@tonic-gate 		scf_value_destroy(v);
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 	/* there should be no outstanding children at this point */
1216*7c478bd9Sstevel@tonic-gate 	assert(handle->rh_extrefs == 0);
1217*7c478bd9Sstevel@tonic-gate 	assert(handle->rh_intrefs == 0);
1218*7c478bd9Sstevel@tonic-gate 	assert(handle->rh_values == 0);
1219*7c478bd9Sstevel@tonic-gate 	assert(handle->rh_entries == 0);
1220*7c478bd9Sstevel@tonic-gate 	assert(uu_list_numnodes(handle->rh_dataels) == 0);
1221*7c478bd9Sstevel@tonic-gate 	assert(uu_list_numnodes(handle->rh_iters) == 0);
1222*7c478bd9Sstevel@tonic-gate 
1223*7c478bd9Sstevel@tonic-gate 	uu_list_destroy(handle->rh_dataels);
1224*7c478bd9Sstevel@tonic-gate 	uu_list_destroy(handle->rh_iters);
1225*7c478bd9Sstevel@tonic-gate 	handle->rh_dataels = NULL;
1226*7c478bd9Sstevel@tonic-gate 	handle->rh_iters = NULL;
1227*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&handle->rh_lock);
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 	uu_free(handle);
1232*7c478bd9Sstevel@tonic-gate }
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate void
1235*7c478bd9Sstevel@tonic-gate scf_handle_destroy(scf_handle_t *handle)
1236*7c478bd9Sstevel@tonic-gate {
1237*7c478bd9Sstevel@tonic-gate 	if (handle == NULL)
1238*7c478bd9Sstevel@tonic-gate 		return;
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
1241*7c478bd9Sstevel@tonic-gate 	if (handle->rh_flags & HANDLE_DEAD) {
1242*7c478bd9Sstevel@tonic-gate 		/*
1243*7c478bd9Sstevel@tonic-gate 		 * This is an error (you are not allowed to reference the
1244*7c478bd9Sstevel@tonic-gate 		 * handle after it is destroyed), but we can't report it.
1245*7c478bd9Sstevel@tonic-gate 		 */
1246*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
1247*7c478bd9Sstevel@tonic-gate 		return;
1248*7c478bd9Sstevel@tonic-gate 	}
1249*7c478bd9Sstevel@tonic-gate 	handle->rh_flags |= HANDLE_DEAD;
1250*7c478bd9Sstevel@tonic-gate 	(void) handle_unbind_unlocked(handle);
1251*7c478bd9Sstevel@tonic-gate 	handle_unrefed(handle);
1252*7c478bd9Sstevel@tonic-gate }
1253*7c478bd9Sstevel@tonic-gate 
1254*7c478bd9Sstevel@tonic-gate ssize_t
1255*7c478bd9Sstevel@tonic-gate scf_myname(scf_handle_t *h, char *out, size_t len)
1256*7c478bd9Sstevel@tonic-gate {
1257*7c478bd9Sstevel@tonic-gate 	char *cp;
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate 	if (!handle_has_server(h))
1260*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
1261*7c478bd9Sstevel@tonic-gate 
1262*7c478bd9Sstevel@tonic-gate 	cp = getenv("SMF_FMRI");
1263*7c478bd9Sstevel@tonic-gate 	if (cp == NULL)
1264*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	return (strlcpy(out, cp, len));
1267*7c478bd9Sstevel@tonic-gate }
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate static uint32_t
1270*7c478bd9Sstevel@tonic-gate handle_alloc_entityid(scf_handle_t *handle)
1271*7c478bd9Sstevel@tonic-gate {
1272*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
1273*7c478bd9Sstevel@tonic-gate 	return (++handle->rh_nextentity);
1274*7c478bd9Sstevel@tonic-gate }
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate static uint32_t
1277*7c478bd9Sstevel@tonic-gate handle_alloc_iterid(scf_handle_t *handle)
1278*7c478bd9Sstevel@tonic-gate {
1279*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
1280*7c478bd9Sstevel@tonic-gate 	return (++handle->rh_nextiter);
1281*7c478bd9Sstevel@tonic-gate }
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate static uint32_t
1284*7c478bd9Sstevel@tonic-gate handle_alloc_changeid(scf_handle_t *handle)
1285*7c478bd9Sstevel@tonic-gate {
1286*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
1287*7c478bd9Sstevel@tonic-gate 	return (++handle->rh_nextchangeid);
1288*7c478bd9Sstevel@tonic-gate }
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate /*
1291*7c478bd9Sstevel@tonic-gate  * Fails with
1292*7c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - h is NULL
1293*7c478bd9Sstevel@tonic-gate  *   _HANDLE_DESTROYED
1294*7c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
1295*7c478bd9Sstevel@tonic-gate  *		 entity already set up with different type
1296*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
1297*7c478bd9Sstevel@tonic-gate  */
1298*7c478bd9Sstevel@tonic-gate static int
1299*7c478bd9Sstevel@tonic-gate datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
1300*7c478bd9Sstevel@tonic-gate {
1301*7c478bd9Sstevel@tonic-gate 	int ret;
1302*7c478bd9Sstevel@tonic-gate 
1303*7c478bd9Sstevel@tonic-gate 	if (h == NULL)
1304*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate 	uu_list_node_init(dp, &dp->rd_node, datael_pool);
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 	dp->rd_handle = h;
1309*7c478bd9Sstevel@tonic-gate 	dp->rd_type = type;
1310*7c478bd9Sstevel@tonic-gate 	dp->rd_reset = 0;
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1313*7c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD) {
1314*7c478bd9Sstevel@tonic-gate 		/*
1315*7c478bd9Sstevel@tonic-gate 		 * we're in undefined territory (the user cannot use a handle
1316*7c478bd9Sstevel@tonic-gate 		 * directly after it has been destroyed), but we don't want
1317*7c478bd9Sstevel@tonic-gate 		 * to allow any new references to happen, so we fail here.
1318*7c478bd9Sstevel@tonic-gate 		 */
1319*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
1320*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1321*7c478bd9Sstevel@tonic-gate 	}
1322*7c478bd9Sstevel@tonic-gate 	dp->rd_entity = handle_alloc_entityid(h);
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	ret = datael_attach(dp);
1325*7c478bd9Sstevel@tonic-gate 	if (ret == 0) {
1326*7c478bd9Sstevel@tonic-gate 		(void) uu_list_insert_before(h->rh_dataels, NULL, dp);
1327*7c478bd9Sstevel@tonic-gate 		h->rh_extrefs++;
1328*7c478bd9Sstevel@tonic-gate 	} else {
1329*7c478bd9Sstevel@tonic-gate 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1330*7c478bd9Sstevel@tonic-gate 	}
1331*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1332*7c478bd9Sstevel@tonic-gate 
1333*7c478bd9Sstevel@tonic-gate 	return (ret);
1334*7c478bd9Sstevel@tonic-gate }
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate static void
1337*7c478bd9Sstevel@tonic-gate datael_destroy(scf_datael_t *dp)
1338*7c478bd9Sstevel@tonic-gate {
1339*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_teardown request;
1342*7c478bd9Sstevel@tonic-gate 	rep_protocol_response_t response;
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1345*7c478bd9Sstevel@tonic-gate 	uu_list_remove(h->rh_dataels, dp);
1346*7c478bd9Sstevel@tonic-gate 	--h->rh_extrefs;
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate 	if (handle_is_bound(h)) {
1349*7c478bd9Sstevel@tonic-gate 		request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN;
1350*7c478bd9Sstevel@tonic-gate 		request.rpr_entityid = dp->rd_entity;
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate 		(void) make_door_call(h, &request, sizeof (request),
1353*7c478bd9Sstevel@tonic-gate 		    &response, sizeof (response));
1354*7c478bd9Sstevel@tonic-gate 	}
1355*7c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 	dp->rd_handle = NULL;
1358*7c478bd9Sstevel@tonic-gate }
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate static scf_handle_t *
1361*7c478bd9Sstevel@tonic-gate datael_handle(const scf_datael_t *dp)
1362*7c478bd9Sstevel@tonic-gate {
1363*7c478bd9Sstevel@tonic-gate 	return (handle_get(dp->rd_handle));
1364*7c478bd9Sstevel@tonic-gate }
1365*7c478bd9Sstevel@tonic-gate 
1366*7c478bd9Sstevel@tonic-gate /*
1367*7c478bd9Sstevel@tonic-gate  * We delay ENTITY_RESETs until right before the entity is used.  By doing
1368*7c478bd9Sstevel@tonic-gate  * them lazily, we remove quite a few unnecessary calls.
1369*7c478bd9Sstevel@tonic-gate  */
1370*7c478bd9Sstevel@tonic-gate static void
1371*7c478bd9Sstevel@tonic-gate datael_do_reset_locked(scf_datael_t *dp)
1372*7c478bd9Sstevel@tonic-gate {
1373*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_reset request;
1376*7c478bd9Sstevel@tonic-gate 	rep_protocol_response_t response;
1377*7c478bd9Sstevel@tonic-gate 
1378*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_RESET;
1381*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate 	(void) make_door_call(h, &request, sizeof (request),
1384*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1385*7c478bd9Sstevel@tonic-gate 
1386*7c478bd9Sstevel@tonic-gate 	dp->rd_reset = 0;
1387*7c478bd9Sstevel@tonic-gate }
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate static void
1390*7c478bd9Sstevel@tonic-gate datael_reset_locked(scf_datael_t *dp)
1391*7c478bd9Sstevel@tonic-gate {
1392*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&dp->rd_handle->rh_lock));
1393*7c478bd9Sstevel@tonic-gate 	dp->rd_reset = 1;
1394*7c478bd9Sstevel@tonic-gate }
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate static void
1397*7c478bd9Sstevel@tonic-gate datael_reset(scf_datael_t *dp)
1398*7c478bd9Sstevel@tonic-gate {
1399*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1400*7c478bd9Sstevel@tonic-gate 
1401*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1402*7c478bd9Sstevel@tonic-gate 	dp->rd_reset = 1;
1403*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1404*7c478bd9Sstevel@tonic-gate }
1405*7c478bd9Sstevel@tonic-gate 
1406*7c478bd9Sstevel@tonic-gate static void
1407*7c478bd9Sstevel@tonic-gate datael_finish_reset(const scf_datael_t *dp_arg)
1408*7c478bd9Sstevel@tonic-gate {
1409*7c478bd9Sstevel@tonic-gate 	scf_datael_t *dp = (scf_datael_t *)dp_arg;
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate 	if (dp->rd_reset)
1412*7c478bd9Sstevel@tonic-gate 		datael_do_reset_locked(dp);
1413*7c478bd9Sstevel@tonic-gate }
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate /*
1416*7c478bd9Sstevel@tonic-gate  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
1417*7c478bd9Sstevel@tonic-gate  * big, bad entity id, request not applicable to entity, name too long for
1418*7c478bd9Sstevel@tonic-gate  * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
1419*7c478bd9Sstevel@tonic-gate  * instance).
1420*7c478bd9Sstevel@tonic-gate  */
1421*7c478bd9Sstevel@tonic-gate static ssize_t
1422*7c478bd9Sstevel@tonic-gate datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type)
1423*7c478bd9Sstevel@tonic-gate {
1424*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_name request;
1427*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_name_response response;
1428*7c478bd9Sstevel@tonic-gate 	ssize_t r;
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1431*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_NAME;
1432*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
1433*7c478bd9Sstevel@tonic-gate 	request.rpr_answertype = type;
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
1436*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
1437*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1438*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1439*7c478bd9Sstevel@tonic-gate 
1440*7c478bd9Sstevel@tonic-gate 	if (r < 0)
1441*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1444*7c478bd9Sstevel@tonic-gate 		assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST);
1445*7c478bd9Sstevel@tonic-gate 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND)
1446*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1447*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
1448*7c478bd9Sstevel@tonic-gate 	}
1449*7c478bd9Sstevel@tonic-gate 	return (strlcpy(buf, response.rpr_name, size));
1450*7c478bd9Sstevel@tonic-gate }
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate /*
1453*7c478bd9Sstevel@tonic-gate  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
1454*7c478bd9Sstevel@tonic-gate  * (server response too big, bad element id), _EXISTS (elements have same id),
1455*7c478bd9Sstevel@tonic-gate  * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
1456*7c478bd9Sstevel@tonic-gate  * or _SUCCESS.
1457*7c478bd9Sstevel@tonic-gate  */
1458*7c478bd9Sstevel@tonic-gate static int
1459*7c478bd9Sstevel@tonic-gate datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp)
1460*7c478bd9Sstevel@tonic-gate {
1461*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1462*7c478bd9Sstevel@tonic-gate 
1463*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_parent request;
1464*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate 	ssize_t r;
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 	if (h != pp->rd_handle)
1469*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1470*7c478bd9Sstevel@tonic-gate 
1471*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1472*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT;
1473*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
1474*7c478bd9Sstevel@tonic-gate 	request.rpr_outid = pp->rd_entity;
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
1477*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(pp);
1478*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
1479*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1480*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 	if (r < 0)
1483*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
1484*7c478bd9Sstevel@tonic-gate 
1485*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1486*7c478bd9Sstevel@tonic-gate 		if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH)
1487*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1488*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
1489*7c478bd9Sstevel@tonic-gate 	}
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
1492*7c478bd9Sstevel@tonic-gate }
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate /*
1495*7c478bd9Sstevel@tonic-gate  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1496*7c478bd9Sstevel@tonic-gate  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1497*7c478bd9Sstevel@tonic-gate  * too big, bad id, iter already exists, element cannot have children of type,
1498*7c478bd9Sstevel@tonic-gate  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1499*7c478bd9Sstevel@tonic-gate  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1500*7c478bd9Sstevel@tonic-gate  * _BACKEND_ACCESS.
1501*7c478bd9Sstevel@tonic-gate  */
1502*7c478bd9Sstevel@tonic-gate static int
1503*7c478bd9Sstevel@tonic-gate datael_get_child_composed_locked(const scf_datael_t *dp, const char *name,
1504*7c478bd9Sstevel@tonic-gate     uint32_t type, scf_datael_t *out, scf_iter_t *iter)
1505*7c478bd9Sstevel@tonic-gate {
1506*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_start request;
1507*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_read read_request;
1508*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
1509*7c478bd9Sstevel@tonic-gate 
1510*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1511*7c478bd9Sstevel@tonic-gate 	ssize_t r;
1512*7c478bd9Sstevel@tonic-gate 
1513*7c478bd9Sstevel@tonic-gate 	if (h != out->rd_handle)
1514*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate 	if (out->rd_type != type)
1517*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1518*7c478bd9Sstevel@tonic-gate 
1519*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
1520*7c478bd9Sstevel@tonic-gate 	assert(iter != NULL);
1521*7c478bd9Sstevel@tonic-gate 
1522*7c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
1523*7c478bd9Sstevel@tonic-gate 	iter->iter_type = type;
1524*7c478bd9Sstevel@tonic-gate 
1525*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_START;
1526*7c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
1527*7c478bd9Sstevel@tonic-gate 	request.rpr_entity = dp->rd_entity;
1528*7c478bd9Sstevel@tonic-gate 	request.rpr_itertype = type;
1529*7c478bd9Sstevel@tonic-gate 	request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED;
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate 	if (name == NULL || strlcpy(request.rpr_pattern, name,
1532*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
1533*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1534*7c478bd9Sstevel@tonic-gate 	}
1535*7c478bd9Sstevel@tonic-gate 
1536*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
1537*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(out);
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate 	/*
1540*7c478bd9Sstevel@tonic-gate 	 * We hold the handle lock across both door calls, so that they
1541*7c478bd9Sstevel@tonic-gate 	 * appear atomic.
1542*7c478bd9Sstevel@tonic-gate 	 */
1543*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
1544*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1545*7c478bd9Sstevel@tonic-gate 
1546*7c478bd9Sstevel@tonic-gate 	if (r < 0)
1547*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1550*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
1551*7c478bd9Sstevel@tonic-gate 
1552*7c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
1553*7c478bd9Sstevel@tonic-gate 
1554*7c478bd9Sstevel@tonic-gate 	read_request.rpr_request = REP_PROTOCOL_ITER_READ;
1555*7c478bd9Sstevel@tonic-gate 	read_request.rpr_iterid = iter->iter_id;
1556*7c478bd9Sstevel@tonic-gate 	read_request.rpr_sequence = iter->iter_sequence;
1557*7c478bd9Sstevel@tonic-gate 	read_request.rpr_entityid = out->rd_entity;
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &read_request, sizeof (read_request),
1560*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
1563*7c478bd9Sstevel@tonic-gate 
1564*7c478bd9Sstevel@tonic-gate 	if (r < 0)
1565*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE) {
1568*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_FOUND));
1569*7c478bd9Sstevel@tonic-gate 	}
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1572*7c478bd9Sstevel@tonic-gate 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET ||
1573*7c478bd9Sstevel@tonic-gate 		    response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
1574*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INTERNAL));
1575*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
1576*7c478bd9Sstevel@tonic-gate 	}
1577*7c478bd9Sstevel@tonic-gate 
1578*7c478bd9Sstevel@tonic-gate 	return (0);
1579*7c478bd9Sstevel@tonic-gate }
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate /*
1582*7c478bd9Sstevel@tonic-gate  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1583*7c478bd9Sstevel@tonic-gate  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1584*7c478bd9Sstevel@tonic-gate  * too big, bad id, element cannot have children of type, type is invalid),
1585*7c478bd9Sstevel@tonic-gate  * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
1586*7c478bd9Sstevel@tonic-gate  */
1587*7c478bd9Sstevel@tonic-gate static int
1588*7c478bd9Sstevel@tonic-gate datael_get_child_locked(const scf_datael_t *dp, const char *name,
1589*7c478bd9Sstevel@tonic-gate     uint32_t type, scf_datael_t *out)
1590*7c478bd9Sstevel@tonic-gate {
1591*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_get_child request;
1592*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1595*7c478bd9Sstevel@tonic-gate 	ssize_t r;
1596*7c478bd9Sstevel@tonic-gate 
1597*7c478bd9Sstevel@tonic-gate 	if (h != out->rd_handle)
1598*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1599*7c478bd9Sstevel@tonic-gate 
1600*7c478bd9Sstevel@tonic-gate 	if (out->rd_type != type)
1601*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1602*7c478bd9Sstevel@tonic-gate 
1603*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
1604*7c478bd9Sstevel@tonic-gate 
1605*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD;
1606*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
1607*7c478bd9Sstevel@tonic-gate 	request.rpr_childid = out->rd_entity;
1608*7c478bd9Sstevel@tonic-gate 
1609*7c478bd9Sstevel@tonic-gate 	if (name == NULL || strlcpy(request.rpr_name, name,
1610*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) {
1611*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1612*7c478bd9Sstevel@tonic-gate 	}
1613*7c478bd9Sstevel@tonic-gate 
1614*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
1615*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(out);
1616*7c478bd9Sstevel@tonic-gate 
1617*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
1618*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1619*7c478bd9Sstevel@tonic-gate 
1620*7c478bd9Sstevel@tonic-gate 	if (r < 0)
1621*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1624*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
1625*7c478bd9Sstevel@tonic-gate 	return (0);
1626*7c478bd9Sstevel@tonic-gate }
1627*7c478bd9Sstevel@tonic-gate 
1628*7c478bd9Sstevel@tonic-gate static int
1629*7c478bd9Sstevel@tonic-gate datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type,
1630*7c478bd9Sstevel@tonic-gate     scf_datael_t *out, boolean_t composed)
1631*7c478bd9Sstevel@tonic-gate {
1632*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1633*7c478bd9Sstevel@tonic-gate 	uint32_t held = 0;
1634*7c478bd9Sstevel@tonic-gate 	int ret;
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
1637*7c478bd9Sstevel@tonic-gate 
1638*7c478bd9Sstevel@tonic-gate 	if (composed)
1639*7c478bd9Sstevel@tonic-gate 		iter = HANDLE_HOLD_ITER(h);
1640*7c478bd9Sstevel@tonic-gate 
1641*7c478bd9Sstevel@tonic-gate 	if (out == NULL) {
1642*7c478bd9Sstevel@tonic-gate 		switch (type) {
1643*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SERVICE:
1644*7c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_SERVICE(h)->rd_d;
1645*7c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SERVICE;
1646*7c478bd9Sstevel@tonic-gate 			break;
1647*7c478bd9Sstevel@tonic-gate 
1648*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_INSTANCE:
1649*7c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_INSTANCE(h)->rd_d;
1650*7c478bd9Sstevel@tonic-gate 			held = RH_HOLD_INSTANCE;
1651*7c478bd9Sstevel@tonic-gate 			break;
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
1654*7c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d;
1655*7c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SNAPSHOT;
1656*7c478bd9Sstevel@tonic-gate 			break;
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SNAPLEVEL:
1659*7c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_SNAPLVL(h)->rd_d;
1660*7c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SNAPLVL;
1661*7c478bd9Sstevel@tonic-gate 			break;
1662*7c478bd9Sstevel@tonic-gate 
1663*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_PROPERTYGRP:
1664*7c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_PG(h)->rd_d;
1665*7c478bd9Sstevel@tonic-gate 			held = RH_HOLD_PG;
1666*7c478bd9Sstevel@tonic-gate 			break;
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_PROPERTY:
1669*7c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_PROPERTY(h)->rd_d;
1670*7c478bd9Sstevel@tonic-gate 			held = RH_HOLD_PROPERTY;
1671*7c478bd9Sstevel@tonic-gate 			break;
1672*7c478bd9Sstevel@tonic-gate 
1673*7c478bd9Sstevel@tonic-gate 		default:
1674*7c478bd9Sstevel@tonic-gate 			assert(0);
1675*7c478bd9Sstevel@tonic-gate 			abort();
1676*7c478bd9Sstevel@tonic-gate 		}
1677*7c478bd9Sstevel@tonic-gate 	}
1678*7c478bd9Sstevel@tonic-gate 
1679*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1680*7c478bd9Sstevel@tonic-gate 	if (composed)
1681*7c478bd9Sstevel@tonic-gate 		ret = datael_get_child_composed_locked(dp, name, type, out,
1682*7c478bd9Sstevel@tonic-gate 		    iter);
1683*7c478bd9Sstevel@tonic-gate 	else
1684*7c478bd9Sstevel@tonic-gate 		ret = datael_get_child_locked(dp, name, type, out);
1685*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1686*7c478bd9Sstevel@tonic-gate 
1687*7c478bd9Sstevel@tonic-gate 	if (composed)
1688*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_ITER(h);
1689*7c478bd9Sstevel@tonic-gate 
1690*7c478bd9Sstevel@tonic-gate 	if (held)
1691*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, held);
1692*7c478bd9Sstevel@tonic-gate 
1693*7c478bd9Sstevel@tonic-gate 	return (ret);
1694*7c478bd9Sstevel@tonic-gate }
1695*7c478bd9Sstevel@tonic-gate 
1696*7c478bd9Sstevel@tonic-gate /*
1697*7c478bd9Sstevel@tonic-gate  * Fails with
1698*7c478bd9Sstevel@tonic-gate  *   _HANDLE_MISMATCH
1699*7c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - name is too long
1700*7c478bd9Sstevel@tonic-gate  *			 invalid changeid
1701*7c478bd9Sstevel@tonic-gate  *			 name is invalid
1702*7c478bd9Sstevel@tonic-gate  *			 cannot create children for dp's type of node
1703*7c478bd9Sstevel@tonic-gate  *   _NOT_BOUND - handle is not bound
1704*7c478bd9Sstevel@tonic-gate  *   _CONNECTION_BROKEN - server is not reachable
1705*7c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
1706*7c478bd9Sstevel@tonic-gate  *		 dp or cp has unknown id
1707*7c478bd9Sstevel@tonic-gate  *		 type is _PROPERTYGRP
1708*7c478bd9Sstevel@tonic-gate  *		 type is invalid
1709*7c478bd9Sstevel@tonic-gate  *		 dp cannot have children of type type
1710*7c478bd9Sstevel@tonic-gate  *		 database is corrupt
1711*7c478bd9Sstevel@tonic-gate  *   _EXISTS - dp & cp have the same id
1712*7c478bd9Sstevel@tonic-gate  *   _EXISTS - child already exists
1713*7c478bd9Sstevel@tonic-gate  *   _DELETED - dp has been deleted
1714*7c478bd9Sstevel@tonic-gate  *   _NOT_SET - dp is reset
1715*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
1716*7c478bd9Sstevel@tonic-gate  *   _PERMISSION_DENIED
1717*7c478bd9Sstevel@tonic-gate  *   _BACKEND_ACCESS
1718*7c478bd9Sstevel@tonic-gate  *   _BACKEND_READONLY
1719*7c478bd9Sstevel@tonic-gate  *   _NOT_FOUND - could not allocate new id
1720*7c478bd9Sstevel@tonic-gate  */
1721*7c478bd9Sstevel@tonic-gate static int
1722*7c478bd9Sstevel@tonic-gate datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
1723*7c478bd9Sstevel@tonic-gate     scf_datael_t *cp)
1724*7c478bd9Sstevel@tonic-gate {
1725*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_create_child request;
1728*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
1729*7c478bd9Sstevel@tonic-gate 	ssize_t r;
1730*7c478bd9Sstevel@tonic-gate 	uint32_t held = 0;
1731*7c478bd9Sstevel@tonic-gate 
1732*7c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
1733*7c478bd9Sstevel@tonic-gate 		switch (type) {
1734*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SCOPE:
1735*7c478bd9Sstevel@tonic-gate 			cp = &HANDLE_HOLD_SCOPE(h)->rd_d;
1736*7c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SCOPE;
1737*7c478bd9Sstevel@tonic-gate 			break;
1738*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SERVICE:
1739*7c478bd9Sstevel@tonic-gate 			cp = &HANDLE_HOLD_SERVICE(h)->rd_d;
1740*7c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SERVICE;
1741*7c478bd9Sstevel@tonic-gate 			break;
1742*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_INSTANCE:
1743*7c478bd9Sstevel@tonic-gate 			cp = &HANDLE_HOLD_INSTANCE(h)->rd_d;
1744*7c478bd9Sstevel@tonic-gate 			held = RH_HOLD_INSTANCE;
1745*7c478bd9Sstevel@tonic-gate 			break;
1746*7c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
1747*7c478bd9Sstevel@tonic-gate 		default:
1748*7c478bd9Sstevel@tonic-gate 			assert(0);
1749*7c478bd9Sstevel@tonic-gate 			abort();
1750*7c478bd9Sstevel@tonic-gate 		}
1751*7c478bd9Sstevel@tonic-gate 		assert(h == cp->rd_handle);
1752*7c478bd9Sstevel@tonic-gate 
1753*7c478bd9Sstevel@tonic-gate 	} else if (h != cp->rd_handle) {
1754*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1755*7c478bd9Sstevel@tonic-gate 	}
1756*7c478bd9Sstevel@tonic-gate 
1757*7c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
1758*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) {
1759*7c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1760*7c478bd9Sstevel@tonic-gate 		goto err;
1761*7c478bd9Sstevel@tonic-gate 	}
1762*7c478bd9Sstevel@tonic-gate 
1763*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1764*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD;
1765*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
1766*7c478bd9Sstevel@tonic-gate 	request.rpr_childtype = type;
1767*7c478bd9Sstevel@tonic-gate 	request.rpr_childid = cp->rd_entity;
1768*7c478bd9Sstevel@tonic-gate 
1769*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
1770*7c478bd9Sstevel@tonic-gate 	request.rpr_changeid = handle_alloc_changeid(h);
1771*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
1772*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1773*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate 	if (held)
1776*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, held);
1777*7c478bd9Sstevel@tonic-gate 
1778*7c478bd9Sstevel@tonic-gate 	if (r < 0)
1779*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
1780*7c478bd9Sstevel@tonic-gate 
1781*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1782*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
1783*7c478bd9Sstevel@tonic-gate 
1784*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
1785*7c478bd9Sstevel@tonic-gate 
1786*7c478bd9Sstevel@tonic-gate err:
1787*7c478bd9Sstevel@tonic-gate 	if (held)
1788*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, held);
1789*7c478bd9Sstevel@tonic-gate 	return (r);
1790*7c478bd9Sstevel@tonic-gate }
1791*7c478bd9Sstevel@tonic-gate 
1792*7c478bd9Sstevel@tonic-gate static int
1793*7c478bd9Sstevel@tonic-gate datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
1794*7c478bd9Sstevel@tonic-gate     uint32_t flags, scf_datael_t *cp)
1795*7c478bd9Sstevel@tonic-gate {
1796*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1797*7c478bd9Sstevel@tonic-gate 
1798*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_create_pg request;
1799*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
1800*7c478bd9Sstevel@tonic-gate 	ssize_t r;
1801*7c478bd9Sstevel@tonic-gate 
1802*7c478bd9Sstevel@tonic-gate 	int holding_els = 0;
1803*7c478bd9Sstevel@tonic-gate 
1804*7c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
1805*7c478bd9Sstevel@tonic-gate 		holding_els = 1;
1806*7c478bd9Sstevel@tonic-gate 		cp = &HANDLE_HOLD_PG(h)->rd_d;
1807*7c478bd9Sstevel@tonic-gate 		assert(h == cp->rd_handle);
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate 	} else if (h != cp->rd_handle) {
1810*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1811*7c478bd9Sstevel@tonic-gate 	}
1812*7c478bd9Sstevel@tonic-gate 
1813*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG;
1814*7c478bd9Sstevel@tonic-gate 
1815*7c478bd9Sstevel@tonic-gate 	if (name == NULL || strlcpy(request.rpr_name, name,
1816*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) > sizeof (request.rpr_name)) {
1817*7c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1818*7c478bd9Sstevel@tonic-gate 		goto err;
1819*7c478bd9Sstevel@tonic-gate 	}
1820*7c478bd9Sstevel@tonic-gate 
1821*7c478bd9Sstevel@tonic-gate 	if (type == NULL || strlcpy(request.rpr_type, type,
1822*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_type)) > sizeof (request.rpr_type)) {
1823*7c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1824*7c478bd9Sstevel@tonic-gate 		goto err;
1825*7c478bd9Sstevel@tonic-gate 	}
1826*7c478bd9Sstevel@tonic-gate 
1827*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1828*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
1829*7c478bd9Sstevel@tonic-gate 	request.rpr_childid = cp->rd_entity;
1830*7c478bd9Sstevel@tonic-gate 	request.rpr_flags = flags;
1831*7c478bd9Sstevel@tonic-gate 
1832*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
1833*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(cp);
1834*7c478bd9Sstevel@tonic-gate 	request.rpr_changeid = handle_alloc_changeid(h);
1835*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
1836*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1837*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1838*7c478bd9Sstevel@tonic-gate 
1839*7c478bd9Sstevel@tonic-gate 	if (holding_els)
1840*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_PG(h);
1841*7c478bd9Sstevel@tonic-gate 
1842*7c478bd9Sstevel@tonic-gate 	if (r < 0)
1843*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1846*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
1849*7c478bd9Sstevel@tonic-gate 
1850*7c478bd9Sstevel@tonic-gate err:
1851*7c478bd9Sstevel@tonic-gate 	if (holding_els)
1852*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_PG(h);
1853*7c478bd9Sstevel@tonic-gate 	return (r);
1854*7c478bd9Sstevel@tonic-gate }
1855*7c478bd9Sstevel@tonic-gate 
1856*7c478bd9Sstevel@tonic-gate static int
1857*7c478bd9Sstevel@tonic-gate datael_delete(const scf_datael_t *dp)
1858*7c478bd9Sstevel@tonic-gate {
1859*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
1860*7c478bd9Sstevel@tonic-gate 
1861*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_delete request;
1862*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
1863*7c478bd9Sstevel@tonic-gate 	ssize_t r;
1864*7c478bd9Sstevel@tonic-gate 
1865*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1866*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_DELETE;
1867*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
1868*7c478bd9Sstevel@tonic-gate 
1869*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
1870*7c478bd9Sstevel@tonic-gate 	request.rpr_changeid = handle_alloc_changeid(h);
1871*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
1872*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1873*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1874*7c478bd9Sstevel@tonic-gate 
1875*7c478bd9Sstevel@tonic-gate 	if (r < 0)
1876*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
1877*7c478bd9Sstevel@tonic-gate 
1878*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1879*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
1880*7c478bd9Sstevel@tonic-gate 
1881*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
1882*7c478bd9Sstevel@tonic-gate }
1883*7c478bd9Sstevel@tonic-gate 
1884*7c478bd9Sstevel@tonic-gate /*
1885*7c478bd9Sstevel@tonic-gate  * Fails with
1886*7c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - h is NULL
1887*7c478bd9Sstevel@tonic-gate  *   _NO_MEMORY
1888*7c478bd9Sstevel@tonic-gate  *   _HANDLE_DESTROYED - h has been destroyed
1889*7c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
1890*7c478bd9Sstevel@tonic-gate  *		 iter already exists
1891*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
1892*7c478bd9Sstevel@tonic-gate  */
1893*7c478bd9Sstevel@tonic-gate scf_iter_t *
1894*7c478bd9Sstevel@tonic-gate scf_iter_create(scf_handle_t *h)
1895*7c478bd9Sstevel@tonic-gate {
1896*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
1897*7c478bd9Sstevel@tonic-gate 
1898*7c478bd9Sstevel@tonic-gate 	if (h == NULL) {
1899*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1900*7c478bd9Sstevel@tonic-gate 		return (NULL);
1901*7c478bd9Sstevel@tonic-gate 	}
1902*7c478bd9Sstevel@tonic-gate 
1903*7c478bd9Sstevel@tonic-gate 	iter = uu_zalloc(sizeof (*iter));
1904*7c478bd9Sstevel@tonic-gate 	if (iter == NULL) {
1905*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1906*7c478bd9Sstevel@tonic-gate 		return (NULL);
1907*7c478bd9Sstevel@tonic-gate 	}
1908*7c478bd9Sstevel@tonic-gate 
1909*7c478bd9Sstevel@tonic-gate 	uu_list_node_init(iter, &iter->iter_node, iter_pool);
1910*7c478bd9Sstevel@tonic-gate 	iter->iter_handle = h;
1911*7c478bd9Sstevel@tonic-gate 	iter->iter_sequence = 1;
1912*7c478bd9Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1915*7c478bd9Sstevel@tonic-gate 	iter->iter_id = handle_alloc_iterid(h);
1916*7c478bd9Sstevel@tonic-gate 	if (iter_attach(iter) == -1) {
1917*7c478bd9Sstevel@tonic-gate 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
1918*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
1919*7c478bd9Sstevel@tonic-gate 		uu_free(iter);
1920*7c478bd9Sstevel@tonic-gate 		return (NULL);
1921*7c478bd9Sstevel@tonic-gate 	}
1922*7c478bd9Sstevel@tonic-gate 	(void) uu_list_insert_before(h->rh_iters, NULL, iter);
1923*7c478bd9Sstevel@tonic-gate 	h->rh_extrefs++;
1924*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1925*7c478bd9Sstevel@tonic-gate 	return (iter);
1926*7c478bd9Sstevel@tonic-gate }
1927*7c478bd9Sstevel@tonic-gate 
1928*7c478bd9Sstevel@tonic-gate scf_handle_t *
1929*7c478bd9Sstevel@tonic-gate scf_iter_handle(const scf_iter_t *iter)
1930*7c478bd9Sstevel@tonic-gate {
1931*7c478bd9Sstevel@tonic-gate 	return (handle_get(iter->iter_handle));
1932*7c478bd9Sstevel@tonic-gate }
1933*7c478bd9Sstevel@tonic-gate 
1934*7c478bd9Sstevel@tonic-gate static void
1935*7c478bd9Sstevel@tonic-gate scf_iter_reset_locked(scf_iter_t *iter)
1936*7c478bd9Sstevel@tonic-gate {
1937*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_request request;
1938*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
1939*7c478bd9Sstevel@tonic-gate 
1940*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_RESET;
1941*7c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
1942*7c478bd9Sstevel@tonic-gate 
1943*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&iter->iter_handle->rh_lock));
1944*7c478bd9Sstevel@tonic-gate 
1945*7c478bd9Sstevel@tonic-gate 	(void) make_door_call(iter->iter_handle,
1946*7c478bd9Sstevel@tonic-gate 	    &request, sizeof (request), &response, sizeof (response));
1947*7c478bd9Sstevel@tonic-gate 
1948*7c478bd9Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
1949*7c478bd9Sstevel@tonic-gate 	iter->iter_sequence = 1;
1950*7c478bd9Sstevel@tonic-gate }
1951*7c478bd9Sstevel@tonic-gate 
1952*7c478bd9Sstevel@tonic-gate void
1953*7c478bd9Sstevel@tonic-gate scf_iter_reset(scf_iter_t *iter)
1954*7c478bd9Sstevel@tonic-gate {
1955*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&iter->iter_handle->rh_lock);
1956*7c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
1957*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&iter->iter_handle->rh_lock);
1958*7c478bd9Sstevel@tonic-gate }
1959*7c478bd9Sstevel@tonic-gate 
1960*7c478bd9Sstevel@tonic-gate void
1961*7c478bd9Sstevel@tonic-gate scf_iter_destroy(scf_iter_t *iter)
1962*7c478bd9Sstevel@tonic-gate {
1963*7c478bd9Sstevel@tonic-gate 	scf_handle_t *handle;
1964*7c478bd9Sstevel@tonic-gate 
1965*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_request request;
1966*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
1967*7c478bd9Sstevel@tonic-gate 
1968*7c478bd9Sstevel@tonic-gate 	if (iter == NULL)
1969*7c478bd9Sstevel@tonic-gate 		return;
1970*7c478bd9Sstevel@tonic-gate 
1971*7c478bd9Sstevel@tonic-gate 	handle = iter->iter_handle;
1972*7c478bd9Sstevel@tonic-gate 
1973*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
1974*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN;
1975*7c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
1976*7c478bd9Sstevel@tonic-gate 
1977*7c478bd9Sstevel@tonic-gate 	(void) make_door_call(handle, &request, sizeof (request),
1978*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
1979*7c478bd9Sstevel@tonic-gate 
1980*7c478bd9Sstevel@tonic-gate 	uu_list_remove(handle->rh_iters, iter);
1981*7c478bd9Sstevel@tonic-gate 	--handle->rh_extrefs;
1982*7c478bd9Sstevel@tonic-gate 	handle_unrefed(handle);			/* drops h->rh_lock */
1983*7c478bd9Sstevel@tonic-gate 	iter->iter_handle = NULL;
1984*7c478bd9Sstevel@tonic-gate 
1985*7c478bd9Sstevel@tonic-gate 	uu_list_node_fini(iter, &iter->iter_node, iter_pool);
1986*7c478bd9Sstevel@tonic-gate 	uu_free(iter);
1987*7c478bd9Sstevel@tonic-gate }
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate static int
1990*7c478bd9Sstevel@tonic-gate handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out)
1991*7c478bd9Sstevel@tonic-gate {
1992*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_get request;
1993*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_name_response response;
1994*7c478bd9Sstevel@tonic-gate 	ssize_t r;
1995*7c478bd9Sstevel@tonic-gate 
1996*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
1997*7c478bd9Sstevel@tonic-gate 
1998*7c478bd9Sstevel@tonic-gate 	if (handle != out->rd_d.rd_handle)
1999*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2000*7c478bd9Sstevel@tonic-gate 
2001*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_GET;
2002*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = out->rd_d.rd_entity;
2003*7c478bd9Sstevel@tonic-gate 	request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE;
2004*7c478bd9Sstevel@tonic-gate 
2005*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&out->rd_d);
2006*7c478bd9Sstevel@tonic-gate 	r = make_door_call(handle, &request, sizeof (request),
2007*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
2008*7c478bd9Sstevel@tonic-gate 
2009*7c478bd9Sstevel@tonic-gate 	if (r < 0)
2010*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
2011*7c478bd9Sstevel@tonic-gate 
2012*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2013*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
2014*7c478bd9Sstevel@tonic-gate 
2015*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
2016*7c478bd9Sstevel@tonic-gate }
2017*7c478bd9Sstevel@tonic-gate 
2018*7c478bd9Sstevel@tonic-gate int
2019*7c478bd9Sstevel@tonic-gate scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
2020*7c478bd9Sstevel@tonic-gate {
2021*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
2022*7c478bd9Sstevel@tonic-gate 	if (h != handle)
2023*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2024*7c478bd9Sstevel@tonic-gate 
2025*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2026*7c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
2027*7c478bd9Sstevel@tonic-gate 
2028*7c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
2029*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2030*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_BOUND));
2031*7c478bd9Sstevel@tonic-gate 	}
2032*7c478bd9Sstevel@tonic-gate 
2033*7c478bd9Sstevel@tonic-gate 	if (!handle_has_server(h)) {
2034*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2035*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
2036*7c478bd9Sstevel@tonic-gate 	}
2037*7c478bd9Sstevel@tonic-gate 
2038*7c478bd9Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE;
2039*7c478bd9Sstevel@tonic-gate 	iter->iter_sequence = 1;
2040*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2041*7c478bd9Sstevel@tonic-gate 	return (0);
2042*7c478bd9Sstevel@tonic-gate }
2043*7c478bd9Sstevel@tonic-gate 
2044*7c478bd9Sstevel@tonic-gate int
2045*7c478bd9Sstevel@tonic-gate scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out)
2046*7c478bd9Sstevel@tonic-gate {
2047*7c478bd9Sstevel@tonic-gate 	int ret;
2048*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
2049*7c478bd9Sstevel@tonic-gate 
2050*7c478bd9Sstevel@tonic-gate 	if (h != out->rd_d.rd_handle)
2051*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2052*7c478bd9Sstevel@tonic-gate 
2053*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2054*7c478bd9Sstevel@tonic-gate 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
2055*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2056*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
2057*7c478bd9Sstevel@tonic-gate 	}
2058*7c478bd9Sstevel@tonic-gate 	if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) {
2059*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2060*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2061*7c478bd9Sstevel@tonic-gate 	}
2062*7c478bd9Sstevel@tonic-gate 	if (iter->iter_sequence == 1) {
2063*7c478bd9Sstevel@tonic-gate 		if ((ret = handle_get_local_scope_locked(h, out)) ==
2064*7c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
2065*7c478bd9Sstevel@tonic-gate 			iter->iter_sequence++;
2066*7c478bd9Sstevel@tonic-gate 			ret = 1;
2067*7c478bd9Sstevel@tonic-gate 		}
2068*7c478bd9Sstevel@tonic-gate 	} else {
2069*7c478bd9Sstevel@tonic-gate 		datael_reset_locked(&out->rd_d);
2070*7c478bd9Sstevel@tonic-gate 		ret = 0;
2071*7c478bd9Sstevel@tonic-gate 	}
2072*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2073*7c478bd9Sstevel@tonic-gate 	return (ret);
2074*7c478bd9Sstevel@tonic-gate }
2075*7c478bd9Sstevel@tonic-gate 
2076*7c478bd9Sstevel@tonic-gate int
2077*7c478bd9Sstevel@tonic-gate scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out)
2078*7c478bd9Sstevel@tonic-gate {
2079*7c478bd9Sstevel@tonic-gate 	int ret;
2080*7c478bd9Sstevel@tonic-gate 
2081*7c478bd9Sstevel@tonic-gate 	if (h != out->rd_d.rd_handle)
2082*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2083*7c478bd9Sstevel@tonic-gate 
2084*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2085*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, SCF_SCOPE_LOCAL) == 0) {
2086*7c478bd9Sstevel@tonic-gate 		ret = handle_get_local_scope_locked(h, out);
2087*7c478bd9Sstevel@tonic-gate 	} else {
2088*7c478bd9Sstevel@tonic-gate 		datael_reset_locked(&out->rd_d);
2089*7c478bd9Sstevel@tonic-gate 		if (uu_check_name(name, 0) == -1)
2090*7c478bd9Sstevel@tonic-gate 			ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2091*7c478bd9Sstevel@tonic-gate 		else
2092*7c478bd9Sstevel@tonic-gate 			ret = scf_set_error(SCF_ERROR_NOT_FOUND);
2093*7c478bd9Sstevel@tonic-gate 	}
2094*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2095*7c478bd9Sstevel@tonic-gate 	return (ret);
2096*7c478bd9Sstevel@tonic-gate }
2097*7c478bd9Sstevel@tonic-gate 
2098*7c478bd9Sstevel@tonic-gate static int
2099*7c478bd9Sstevel@tonic-gate datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type,
2100*7c478bd9Sstevel@tonic-gate     boolean_t composed)
2101*7c478bd9Sstevel@tonic-gate {
2102*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
2103*7c478bd9Sstevel@tonic-gate 
2104*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_start request;
2105*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
2106*7c478bd9Sstevel@tonic-gate 
2107*7c478bd9Sstevel@tonic-gate 	ssize_t r;
2108*7c478bd9Sstevel@tonic-gate 
2109*7c478bd9Sstevel@tonic-gate 	if (h != iter->iter_handle)
2110*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2111*7c478bd9Sstevel@tonic-gate 
2112*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2113*7c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
2114*7c478bd9Sstevel@tonic-gate 	iter->iter_type = res_type;
2115*7c478bd9Sstevel@tonic-gate 
2116*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_START;
2117*7c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
2118*7c478bd9Sstevel@tonic-gate 	request.rpr_entity = dp->rd_entity;
2119*7c478bd9Sstevel@tonic-gate 	request.rpr_itertype = res_type;
2120*7c478bd9Sstevel@tonic-gate 	request.rpr_flags = RP_ITER_START_ALL |
2121*7c478bd9Sstevel@tonic-gate 	    (composed ? RP_ITER_START_COMPOSED : 0);
2122*7c478bd9Sstevel@tonic-gate 	request.rpr_pattern[0] = 0;
2123*7c478bd9Sstevel@tonic-gate 
2124*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
2125*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
2126*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
2127*7c478bd9Sstevel@tonic-gate 
2128*7c478bd9Sstevel@tonic-gate 	if (r < 0) {
2129*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2130*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
2131*7c478bd9Sstevel@tonic-gate 	}
2132*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2133*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2134*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
2135*7c478bd9Sstevel@tonic-gate 	}
2136*7c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
2137*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2138*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
2139*7c478bd9Sstevel@tonic-gate }
2140*7c478bd9Sstevel@tonic-gate 
2141*7c478bd9Sstevel@tonic-gate static int
2142*7c478bd9Sstevel@tonic-gate datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp,
2143*7c478bd9Sstevel@tonic-gate     const char *pgtype, boolean_t composed)
2144*7c478bd9Sstevel@tonic-gate {
2145*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
2146*7c478bd9Sstevel@tonic-gate 
2147*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_start request;
2148*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
2149*7c478bd9Sstevel@tonic-gate 
2150*7c478bd9Sstevel@tonic-gate 	ssize_t r;
2151*7c478bd9Sstevel@tonic-gate 
2152*7c478bd9Sstevel@tonic-gate 	if (h != iter->iter_handle)
2153*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2154*7c478bd9Sstevel@tonic-gate 
2155*7c478bd9Sstevel@tonic-gate 	if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype,
2156*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
2157*7c478bd9Sstevel@tonic-gate 		scf_iter_reset(iter);
2158*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2159*7c478bd9Sstevel@tonic-gate 	}
2160*7c478bd9Sstevel@tonic-gate 
2161*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2162*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_START;
2163*7c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
2164*7c478bd9Sstevel@tonic-gate 	request.rpr_entity = dp->rd_entity;
2165*7c478bd9Sstevel@tonic-gate 	request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2166*7c478bd9Sstevel@tonic-gate 	request.rpr_flags = RP_ITER_START_PGTYPE |
2167*7c478bd9Sstevel@tonic-gate 	    (composed ? RP_ITER_START_COMPOSED : 0);
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
2170*7c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
2171*7c478bd9Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2172*7c478bd9Sstevel@tonic-gate 
2173*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
2174*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
2175*7c478bd9Sstevel@tonic-gate 
2176*7c478bd9Sstevel@tonic-gate 	if (r < 0) {
2177*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2178*7c478bd9Sstevel@tonic-gate 
2179*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
2180*7c478bd9Sstevel@tonic-gate 	}
2181*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2182*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2183*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
2184*7c478bd9Sstevel@tonic-gate 	}
2185*7c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
2186*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2187*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
2188*7c478bd9Sstevel@tonic-gate }
2189*7c478bd9Sstevel@tonic-gate 
2190*7c478bd9Sstevel@tonic-gate static int
2191*7c478bd9Sstevel@tonic-gate datael_iter_next(scf_iter_t *iter, scf_datael_t *out)
2192*7c478bd9Sstevel@tonic-gate {
2193*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
2194*7c478bd9Sstevel@tonic-gate 
2195*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_read request;
2196*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
2197*7c478bd9Sstevel@tonic-gate 	ssize_t r;
2198*7c478bd9Sstevel@tonic-gate 
2199*7c478bd9Sstevel@tonic-gate 	if (h != out->rd_handle)
2200*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2201*7c478bd9Sstevel@tonic-gate 
2202*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2203*7c478bd9Sstevel@tonic-gate 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE ||
2204*7c478bd9Sstevel@tonic-gate 	    iter->iter_sequence == 1) {
2205*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2206*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
2207*7c478bd9Sstevel@tonic-gate 	}
2208*7c478bd9Sstevel@tonic-gate 
2209*7c478bd9Sstevel@tonic-gate 	if (out->rd_type != iter->iter_type) {
2210*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2211*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2212*7c478bd9Sstevel@tonic-gate 	}
2213*7c478bd9Sstevel@tonic-gate 
2214*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_READ;
2215*7c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
2216*7c478bd9Sstevel@tonic-gate 	request.rpr_sequence = iter->iter_sequence;
2217*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = out->rd_entity;
2218*7c478bd9Sstevel@tonic-gate 
2219*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(out);
2220*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
2221*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
2222*7c478bd9Sstevel@tonic-gate 
2223*7c478bd9Sstevel@tonic-gate 	if (r < 0) {
2224*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2225*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
2226*7c478bd9Sstevel@tonic-gate 	}
2227*7c478bd9Sstevel@tonic-gate 
2228*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE) {
2229*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2230*7c478bd9Sstevel@tonic-gate 		return (0);
2231*7c478bd9Sstevel@tonic-gate 	}
2232*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2233*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2234*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
2235*7c478bd9Sstevel@tonic-gate 	}
2236*7c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
2237*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2238*7c478bd9Sstevel@tonic-gate 
2239*7c478bd9Sstevel@tonic-gate 	return (1);
2240*7c478bd9Sstevel@tonic-gate }
2241*7c478bd9Sstevel@tonic-gate 
2242*7c478bd9Sstevel@tonic-gate int
2243*7c478bd9Sstevel@tonic-gate scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s)
2244*7c478bd9Sstevel@tonic-gate {
2245*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &s->rd_d,
2246*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SERVICE, 0));
2247*7c478bd9Sstevel@tonic-gate }
2248*7c478bd9Sstevel@tonic-gate 
2249*7c478bd9Sstevel@tonic-gate int
2250*7c478bd9Sstevel@tonic-gate scf_iter_next_service(scf_iter_t *iter, scf_service_t *out)
2251*7c478bd9Sstevel@tonic-gate {
2252*7c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
2253*7c478bd9Sstevel@tonic-gate }
2254*7c478bd9Sstevel@tonic-gate 
2255*7c478bd9Sstevel@tonic-gate int
2256*7c478bd9Sstevel@tonic-gate scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc)
2257*7c478bd9Sstevel@tonic-gate {
2258*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &svc->rd_d,
2259*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_INSTANCE, 0));
2260*7c478bd9Sstevel@tonic-gate }
2261*7c478bd9Sstevel@tonic-gate 
2262*7c478bd9Sstevel@tonic-gate int
2263*7c478bd9Sstevel@tonic-gate scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out)
2264*7c478bd9Sstevel@tonic-gate {
2265*7c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
2266*7c478bd9Sstevel@tonic-gate }
2267*7c478bd9Sstevel@tonic-gate 
2268*7c478bd9Sstevel@tonic-gate int
2269*7c478bd9Sstevel@tonic-gate scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc)
2270*7c478bd9Sstevel@tonic-gate {
2271*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &svc->rd_d,
2272*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2273*7c478bd9Sstevel@tonic-gate }
2274*7c478bd9Sstevel@tonic-gate 
2275*7c478bd9Sstevel@tonic-gate int
2276*7c478bd9Sstevel@tonic-gate scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc,
2277*7c478bd9Sstevel@tonic-gate     const char *type)
2278*7c478bd9Sstevel@tonic-gate {
2279*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0));
2280*7c478bd9Sstevel@tonic-gate }
2281*7c478bd9Sstevel@tonic-gate 
2282*7c478bd9Sstevel@tonic-gate int
2283*7c478bd9Sstevel@tonic-gate scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst)
2284*7c478bd9Sstevel@tonic-gate {
2285*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &inst->rd_d,
2286*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SNAPSHOT, 0));
2287*7c478bd9Sstevel@tonic-gate }
2288*7c478bd9Sstevel@tonic-gate 
2289*7c478bd9Sstevel@tonic-gate int
2290*7c478bd9Sstevel@tonic-gate scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out)
2291*7c478bd9Sstevel@tonic-gate {
2292*7c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
2293*7c478bd9Sstevel@tonic-gate }
2294*7c478bd9Sstevel@tonic-gate 
2295*7c478bd9Sstevel@tonic-gate int
2296*7c478bd9Sstevel@tonic-gate scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst)
2297*7c478bd9Sstevel@tonic-gate {
2298*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &inst->rd_d,
2299*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2300*7c478bd9Sstevel@tonic-gate }
2301*7c478bd9Sstevel@tonic-gate 
2302*7c478bd9Sstevel@tonic-gate int
2303*7c478bd9Sstevel@tonic-gate scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst,
2304*7c478bd9Sstevel@tonic-gate     const char *type)
2305*7c478bd9Sstevel@tonic-gate {
2306*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2307*7c478bd9Sstevel@tonic-gate }
2308*7c478bd9Sstevel@tonic-gate 
2309*7c478bd9Sstevel@tonic-gate int
2310*7c478bd9Sstevel@tonic-gate scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst,
2311*7c478bd9Sstevel@tonic-gate     const scf_snapshot_t *snap)
2312*7c478bd9Sstevel@tonic-gate {
2313*7c478bd9Sstevel@tonic-gate 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2314*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2315*7c478bd9Sstevel@tonic-gate 
2316*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d,
2317*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 1));
2318*7c478bd9Sstevel@tonic-gate }
2319*7c478bd9Sstevel@tonic-gate 
2320*7c478bd9Sstevel@tonic-gate int
2321*7c478bd9Sstevel@tonic-gate scf_iter_instance_pgs_typed_composed(scf_iter_t *iter,
2322*7c478bd9Sstevel@tonic-gate     const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type)
2323*7c478bd9Sstevel@tonic-gate {
2324*7c478bd9Sstevel@tonic-gate 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2325*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2326*7c478bd9Sstevel@tonic-gate 
2327*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter,
2328*7c478bd9Sstevel@tonic-gate 	    snap ? &snap->rd_d : &inst->rd_d, type, 1));
2329*7c478bd9Sstevel@tonic-gate }
2330*7c478bd9Sstevel@tonic-gate 
2331*7c478bd9Sstevel@tonic-gate int
2332*7c478bd9Sstevel@tonic-gate scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst)
2333*7c478bd9Sstevel@tonic-gate {
2334*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &inst->rd_d,
2335*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2336*7c478bd9Sstevel@tonic-gate }
2337*7c478bd9Sstevel@tonic-gate 
2338*7c478bd9Sstevel@tonic-gate int
2339*7c478bd9Sstevel@tonic-gate scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst,
2340*7c478bd9Sstevel@tonic-gate     const char *type)
2341*7c478bd9Sstevel@tonic-gate {
2342*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2343*7c478bd9Sstevel@tonic-gate }
2344*7c478bd9Sstevel@tonic-gate 
2345*7c478bd9Sstevel@tonic-gate int
2346*7c478bd9Sstevel@tonic-gate scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out)
2347*7c478bd9Sstevel@tonic-gate {
2348*7c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
2349*7c478bd9Sstevel@tonic-gate }
2350*7c478bd9Sstevel@tonic-gate 
2351*7c478bd9Sstevel@tonic-gate int
2352*7c478bd9Sstevel@tonic-gate scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg)
2353*7c478bd9Sstevel@tonic-gate {
2354*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &pg->rd_d,
2355*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTY, 0));
2356*7c478bd9Sstevel@tonic-gate }
2357*7c478bd9Sstevel@tonic-gate 
2358*7c478bd9Sstevel@tonic-gate int
2359*7c478bd9Sstevel@tonic-gate scf_iter_next_property(scf_iter_t *iter, scf_property_t *out)
2360*7c478bd9Sstevel@tonic-gate {
2361*7c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
2362*7c478bd9Sstevel@tonic-gate }
2363*7c478bd9Sstevel@tonic-gate 
2364*7c478bd9Sstevel@tonic-gate /*
2365*7c478bd9Sstevel@tonic-gate  * Fails with
2366*7c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - handle is NULL
2367*7c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
2368*7c478bd9Sstevel@tonic-gate  *		 entity already set up with different type
2369*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
2370*7c478bd9Sstevel@tonic-gate  *   _NO_MEMORY
2371*7c478bd9Sstevel@tonic-gate  */
2372*7c478bd9Sstevel@tonic-gate scf_scope_t *
2373*7c478bd9Sstevel@tonic-gate scf_scope_create(scf_handle_t *handle)
2374*7c478bd9Sstevel@tonic-gate {
2375*7c478bd9Sstevel@tonic-gate 	scf_scope_t *ret;
2376*7c478bd9Sstevel@tonic-gate 
2377*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
2378*7c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
2379*7c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
2380*7c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SCOPE) == -1) {
2381*7c478bd9Sstevel@tonic-gate 			uu_free(ret);
2382*7c478bd9Sstevel@tonic-gate 			return (NULL);
2383*7c478bd9Sstevel@tonic-gate 		}
2384*7c478bd9Sstevel@tonic-gate 	} else {
2385*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2386*7c478bd9Sstevel@tonic-gate 	}
2387*7c478bd9Sstevel@tonic-gate 
2388*7c478bd9Sstevel@tonic-gate 	return (ret);
2389*7c478bd9Sstevel@tonic-gate }
2390*7c478bd9Sstevel@tonic-gate 
2391*7c478bd9Sstevel@tonic-gate scf_handle_t *
2392*7c478bd9Sstevel@tonic-gate scf_scope_handle(const scf_scope_t *val)
2393*7c478bd9Sstevel@tonic-gate {
2394*7c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
2395*7c478bd9Sstevel@tonic-gate }
2396*7c478bd9Sstevel@tonic-gate 
2397*7c478bd9Sstevel@tonic-gate void
2398*7c478bd9Sstevel@tonic-gate scf_scope_destroy(scf_scope_t *val)
2399*7c478bd9Sstevel@tonic-gate {
2400*7c478bd9Sstevel@tonic-gate 	if (val == NULL)
2401*7c478bd9Sstevel@tonic-gate 		return;
2402*7c478bd9Sstevel@tonic-gate 
2403*7c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
2404*7c478bd9Sstevel@tonic-gate 	uu_free(val);
2405*7c478bd9Sstevel@tonic-gate }
2406*7c478bd9Sstevel@tonic-gate 
2407*7c478bd9Sstevel@tonic-gate ssize_t
2408*7c478bd9Sstevel@tonic-gate scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len)
2409*7c478bd9Sstevel@tonic-gate {
2410*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2411*7c478bd9Sstevel@tonic-gate }
2412*7c478bd9Sstevel@tonic-gate 
2413*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2414*7c478bd9Sstevel@tonic-gate int
2415*7c478bd9Sstevel@tonic-gate scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent)
2416*7c478bd9Sstevel@tonic-gate {
2417*7c478bd9Sstevel@tonic-gate 	char name[1];
2418*7c478bd9Sstevel@tonic-gate 
2419*7c478bd9Sstevel@tonic-gate 	/* fake up the side-effects */
2420*7c478bd9Sstevel@tonic-gate 	datael_reset(&parent->rd_d);
2421*7c478bd9Sstevel@tonic-gate 	if (scf_scope_get_name(child, name, sizeof (name)) < 0)
2422*7c478bd9Sstevel@tonic-gate 		return (-1);
2423*7c478bd9Sstevel@tonic-gate 	return (scf_set_error(SCF_ERROR_NOT_FOUND));
2424*7c478bd9Sstevel@tonic-gate }
2425*7c478bd9Sstevel@tonic-gate 
2426*7c478bd9Sstevel@tonic-gate /*
2427*7c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2428*7c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2429*7c478bd9Sstevel@tonic-gate  */
2430*7c478bd9Sstevel@tonic-gate scf_service_t *
2431*7c478bd9Sstevel@tonic-gate scf_service_create(scf_handle_t *handle)
2432*7c478bd9Sstevel@tonic-gate {
2433*7c478bd9Sstevel@tonic-gate 	scf_service_t *ret;
2434*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
2435*7c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
2436*7c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
2437*7c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SERVICE) == -1) {
2438*7c478bd9Sstevel@tonic-gate 			uu_free(ret);
2439*7c478bd9Sstevel@tonic-gate 			return (NULL);
2440*7c478bd9Sstevel@tonic-gate 		}
2441*7c478bd9Sstevel@tonic-gate 	} else {
2442*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2443*7c478bd9Sstevel@tonic-gate 	}
2444*7c478bd9Sstevel@tonic-gate 
2445*7c478bd9Sstevel@tonic-gate 	return (ret);
2446*7c478bd9Sstevel@tonic-gate }
2447*7c478bd9Sstevel@tonic-gate 
2448*7c478bd9Sstevel@tonic-gate int
2449*7c478bd9Sstevel@tonic-gate scf_scope_add_service(const scf_scope_t *scope, const char *name,
2450*7c478bd9Sstevel@tonic-gate     scf_service_t *svc)
2451*7c478bd9Sstevel@tonic-gate {
2452*7c478bd9Sstevel@tonic-gate 	return (datael_add_child(&scope->rd_d, name,
2453*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL));
2454*7c478bd9Sstevel@tonic-gate }
2455*7c478bd9Sstevel@tonic-gate 
2456*7c478bd9Sstevel@tonic-gate int
2457*7c478bd9Sstevel@tonic-gate scf_scope_get_service(const scf_scope_t *s, const char *name,
2458*7c478bd9Sstevel@tonic-gate     scf_service_t *svc)
2459*7c478bd9Sstevel@tonic-gate {
2460*7c478bd9Sstevel@tonic-gate 	return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE,
2461*7c478bd9Sstevel@tonic-gate 	    svc ? &svc->rd_d : NULL, 0));
2462*7c478bd9Sstevel@tonic-gate }
2463*7c478bd9Sstevel@tonic-gate 
2464*7c478bd9Sstevel@tonic-gate scf_handle_t *
2465*7c478bd9Sstevel@tonic-gate scf_service_handle(const scf_service_t *val)
2466*7c478bd9Sstevel@tonic-gate {
2467*7c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
2468*7c478bd9Sstevel@tonic-gate }
2469*7c478bd9Sstevel@tonic-gate 
2470*7c478bd9Sstevel@tonic-gate int
2471*7c478bd9Sstevel@tonic-gate scf_service_delete(scf_service_t *svc)
2472*7c478bd9Sstevel@tonic-gate {
2473*7c478bd9Sstevel@tonic-gate 	return (datael_delete(&svc->rd_d));
2474*7c478bd9Sstevel@tonic-gate }
2475*7c478bd9Sstevel@tonic-gate 
2476*7c478bd9Sstevel@tonic-gate int
2477*7c478bd9Sstevel@tonic-gate scf_instance_delete(scf_instance_t *inst)
2478*7c478bd9Sstevel@tonic-gate {
2479*7c478bd9Sstevel@tonic-gate 	return (datael_delete(&inst->rd_d));
2480*7c478bd9Sstevel@tonic-gate }
2481*7c478bd9Sstevel@tonic-gate 
2482*7c478bd9Sstevel@tonic-gate int
2483*7c478bd9Sstevel@tonic-gate scf_pg_delete(scf_propertygroup_t *pg)
2484*7c478bd9Sstevel@tonic-gate {
2485*7c478bd9Sstevel@tonic-gate 	return (datael_delete(&pg->rd_d));
2486*7c478bd9Sstevel@tonic-gate }
2487*7c478bd9Sstevel@tonic-gate 
2488*7c478bd9Sstevel@tonic-gate int
2489*7c478bd9Sstevel@tonic-gate _scf_snapshot_delete(scf_snapshot_t *snap)
2490*7c478bd9Sstevel@tonic-gate {
2491*7c478bd9Sstevel@tonic-gate 	return (datael_delete(&snap->rd_d));
2492*7c478bd9Sstevel@tonic-gate }
2493*7c478bd9Sstevel@tonic-gate 
2494*7c478bd9Sstevel@tonic-gate int
2495*7c478bd9Sstevel@tonic-gate scf_service_add_instance(const scf_service_t *svc, const char *name,
2496*7c478bd9Sstevel@tonic-gate     scf_instance_t *instance)
2497*7c478bd9Sstevel@tonic-gate {
2498*7c478bd9Sstevel@tonic-gate 	return (datael_add_child(&svc->rd_d, name,
2499*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_INSTANCE,
2500*7c478bd9Sstevel@tonic-gate 	    (instance != NULL)? &instance->rd_d : NULL));
2501*7c478bd9Sstevel@tonic-gate }
2502*7c478bd9Sstevel@tonic-gate 
2503*7c478bd9Sstevel@tonic-gate int
2504*7c478bd9Sstevel@tonic-gate scf_service_get_instance(const scf_service_t *svc, const char *name,
2505*7c478bd9Sstevel@tonic-gate     scf_instance_t *inst)
2506*7c478bd9Sstevel@tonic-gate {
2507*7c478bd9Sstevel@tonic-gate 	return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE,
2508*7c478bd9Sstevel@tonic-gate 	    inst ? &inst->rd_d : NULL, 0));
2509*7c478bd9Sstevel@tonic-gate }
2510*7c478bd9Sstevel@tonic-gate 
2511*7c478bd9Sstevel@tonic-gate int
2512*7c478bd9Sstevel@tonic-gate scf_service_add_pg(const scf_service_t *svc, const char *name,
2513*7c478bd9Sstevel@tonic-gate     const char *type, uint32_t flags, scf_propertygroup_t *pg)
2514*7c478bd9Sstevel@tonic-gate {
2515*7c478bd9Sstevel@tonic-gate 	return (datael_add_pg(&svc->rd_d, name, type, flags,
2516*7c478bd9Sstevel@tonic-gate 	    (pg != NULL)?&pg->rd_d : NULL));
2517*7c478bd9Sstevel@tonic-gate }
2518*7c478bd9Sstevel@tonic-gate 
2519*7c478bd9Sstevel@tonic-gate int
2520*7c478bd9Sstevel@tonic-gate scf_service_get_pg(const scf_service_t *svc, const char *name,
2521*7c478bd9Sstevel@tonic-gate     scf_propertygroup_t *pg)
2522*7c478bd9Sstevel@tonic-gate {
2523*7c478bd9Sstevel@tonic-gate 	return (datael_get_child(&svc->rd_d, name,
2524*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2525*7c478bd9Sstevel@tonic-gate }
2526*7c478bd9Sstevel@tonic-gate 
2527*7c478bd9Sstevel@tonic-gate int
2528*7c478bd9Sstevel@tonic-gate scf_instance_add_pg(const scf_instance_t *inst, const char *name,
2529*7c478bd9Sstevel@tonic-gate     const char *type, uint32_t flags, scf_propertygroup_t *pg)
2530*7c478bd9Sstevel@tonic-gate {
2531*7c478bd9Sstevel@tonic-gate 	return (datael_add_pg(&inst->rd_d, name, type, flags,
2532*7c478bd9Sstevel@tonic-gate 	    (pg != NULL)?&pg->rd_d : NULL));
2533*7c478bd9Sstevel@tonic-gate }
2534*7c478bd9Sstevel@tonic-gate 
2535*7c478bd9Sstevel@tonic-gate int
2536*7c478bd9Sstevel@tonic-gate scf_instance_get_snapshot(const scf_instance_t *inst, const char *name,
2537*7c478bd9Sstevel@tonic-gate     scf_snapshot_t *pg)
2538*7c478bd9Sstevel@tonic-gate {
2539*7c478bd9Sstevel@tonic-gate 	return (datael_get_child(&inst->rd_d, name,
2540*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0));
2541*7c478bd9Sstevel@tonic-gate }
2542*7c478bd9Sstevel@tonic-gate 
2543*7c478bd9Sstevel@tonic-gate int
2544*7c478bd9Sstevel@tonic-gate scf_instance_get_pg(const scf_instance_t *inst, const char *name,
2545*7c478bd9Sstevel@tonic-gate     scf_propertygroup_t *pg)
2546*7c478bd9Sstevel@tonic-gate {
2547*7c478bd9Sstevel@tonic-gate 	return (datael_get_child(&inst->rd_d, name,
2548*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2549*7c478bd9Sstevel@tonic-gate }
2550*7c478bd9Sstevel@tonic-gate 
2551*7c478bd9Sstevel@tonic-gate int
2552*7c478bd9Sstevel@tonic-gate scf_instance_get_pg_composed(const scf_instance_t *inst,
2553*7c478bd9Sstevel@tonic-gate     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
2554*7c478bd9Sstevel@tonic-gate {
2555*7c478bd9Sstevel@tonic-gate 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2556*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2557*7c478bd9Sstevel@tonic-gate 
2558*7c478bd9Sstevel@tonic-gate 	return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name,
2559*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1));
2560*7c478bd9Sstevel@tonic-gate }
2561*7c478bd9Sstevel@tonic-gate 
2562*7c478bd9Sstevel@tonic-gate int
2563*7c478bd9Sstevel@tonic-gate scf_pg_get_property(const scf_propertygroup_t *pg, const char *name,
2564*7c478bd9Sstevel@tonic-gate     scf_property_t *prop)
2565*7c478bd9Sstevel@tonic-gate {
2566*7c478bd9Sstevel@tonic-gate 	return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY,
2567*7c478bd9Sstevel@tonic-gate 	    prop ? &prop->rd_d : NULL, 0));
2568*7c478bd9Sstevel@tonic-gate }
2569*7c478bd9Sstevel@tonic-gate 
2570*7c478bd9Sstevel@tonic-gate void
2571*7c478bd9Sstevel@tonic-gate scf_service_destroy(scf_service_t *val)
2572*7c478bd9Sstevel@tonic-gate {
2573*7c478bd9Sstevel@tonic-gate 	if (val == NULL)
2574*7c478bd9Sstevel@tonic-gate 		return;
2575*7c478bd9Sstevel@tonic-gate 
2576*7c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
2577*7c478bd9Sstevel@tonic-gate 	uu_free(val);
2578*7c478bd9Sstevel@tonic-gate }
2579*7c478bd9Sstevel@tonic-gate 
2580*7c478bd9Sstevel@tonic-gate ssize_t
2581*7c478bd9Sstevel@tonic-gate scf_service_get_name(const scf_service_t *rep, char *out, size_t len)
2582*7c478bd9Sstevel@tonic-gate {
2583*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2584*7c478bd9Sstevel@tonic-gate }
2585*7c478bd9Sstevel@tonic-gate 
2586*7c478bd9Sstevel@tonic-gate /*
2587*7c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2588*7c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2589*7c478bd9Sstevel@tonic-gate  */
2590*7c478bd9Sstevel@tonic-gate scf_instance_t *
2591*7c478bd9Sstevel@tonic-gate scf_instance_create(scf_handle_t *handle)
2592*7c478bd9Sstevel@tonic-gate {
2593*7c478bd9Sstevel@tonic-gate 	scf_instance_t *ret;
2594*7c478bd9Sstevel@tonic-gate 
2595*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
2596*7c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
2597*7c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
2598*7c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
2599*7c478bd9Sstevel@tonic-gate 			uu_free(ret);
2600*7c478bd9Sstevel@tonic-gate 			return (NULL);
2601*7c478bd9Sstevel@tonic-gate 		}
2602*7c478bd9Sstevel@tonic-gate 	} else {
2603*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2604*7c478bd9Sstevel@tonic-gate 	}
2605*7c478bd9Sstevel@tonic-gate 
2606*7c478bd9Sstevel@tonic-gate 	return (ret);
2607*7c478bd9Sstevel@tonic-gate }
2608*7c478bd9Sstevel@tonic-gate 
2609*7c478bd9Sstevel@tonic-gate scf_handle_t *
2610*7c478bd9Sstevel@tonic-gate scf_instance_handle(const scf_instance_t *val)
2611*7c478bd9Sstevel@tonic-gate {
2612*7c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
2613*7c478bd9Sstevel@tonic-gate }
2614*7c478bd9Sstevel@tonic-gate 
2615*7c478bd9Sstevel@tonic-gate void
2616*7c478bd9Sstevel@tonic-gate scf_instance_destroy(scf_instance_t *val)
2617*7c478bd9Sstevel@tonic-gate {
2618*7c478bd9Sstevel@tonic-gate 	if (val == NULL)
2619*7c478bd9Sstevel@tonic-gate 		return;
2620*7c478bd9Sstevel@tonic-gate 
2621*7c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
2622*7c478bd9Sstevel@tonic-gate 	uu_free(val);
2623*7c478bd9Sstevel@tonic-gate }
2624*7c478bd9Sstevel@tonic-gate 
2625*7c478bd9Sstevel@tonic-gate ssize_t
2626*7c478bd9Sstevel@tonic-gate scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len)
2627*7c478bd9Sstevel@tonic-gate {
2628*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2629*7c478bd9Sstevel@tonic-gate }
2630*7c478bd9Sstevel@tonic-gate 
2631*7c478bd9Sstevel@tonic-gate /*
2632*7c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2633*7c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2634*7c478bd9Sstevel@tonic-gate  */
2635*7c478bd9Sstevel@tonic-gate scf_snapshot_t *
2636*7c478bd9Sstevel@tonic-gate scf_snapshot_create(scf_handle_t *handle)
2637*7c478bd9Sstevel@tonic-gate {
2638*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *ret;
2639*7c478bd9Sstevel@tonic-gate 
2640*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
2641*7c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
2642*7c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
2643*7c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
2644*7c478bd9Sstevel@tonic-gate 			uu_free(ret);
2645*7c478bd9Sstevel@tonic-gate 			return (NULL);
2646*7c478bd9Sstevel@tonic-gate 		}
2647*7c478bd9Sstevel@tonic-gate 	} else {
2648*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2649*7c478bd9Sstevel@tonic-gate 	}
2650*7c478bd9Sstevel@tonic-gate 
2651*7c478bd9Sstevel@tonic-gate 	return (ret);
2652*7c478bd9Sstevel@tonic-gate }
2653*7c478bd9Sstevel@tonic-gate 
2654*7c478bd9Sstevel@tonic-gate scf_handle_t *
2655*7c478bd9Sstevel@tonic-gate scf_snapshot_handle(const scf_snapshot_t *val)
2656*7c478bd9Sstevel@tonic-gate {
2657*7c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
2658*7c478bd9Sstevel@tonic-gate }
2659*7c478bd9Sstevel@tonic-gate 
2660*7c478bd9Sstevel@tonic-gate void
2661*7c478bd9Sstevel@tonic-gate scf_snapshot_destroy(scf_snapshot_t *val)
2662*7c478bd9Sstevel@tonic-gate {
2663*7c478bd9Sstevel@tonic-gate 	if (val == NULL)
2664*7c478bd9Sstevel@tonic-gate 		return;
2665*7c478bd9Sstevel@tonic-gate 
2666*7c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
2667*7c478bd9Sstevel@tonic-gate 	uu_free(val);
2668*7c478bd9Sstevel@tonic-gate }
2669*7c478bd9Sstevel@tonic-gate 
2670*7c478bd9Sstevel@tonic-gate ssize_t
2671*7c478bd9Sstevel@tonic-gate scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len)
2672*7c478bd9Sstevel@tonic-gate {
2673*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2674*7c478bd9Sstevel@tonic-gate }
2675*7c478bd9Sstevel@tonic-gate 
2676*7c478bd9Sstevel@tonic-gate /*
2677*7c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2678*7c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
2679*7c478bd9Sstevel@tonic-gate  */
2680*7c478bd9Sstevel@tonic-gate scf_snaplevel_t *
2681*7c478bd9Sstevel@tonic-gate scf_snaplevel_create(scf_handle_t *handle)
2682*7c478bd9Sstevel@tonic-gate {
2683*7c478bd9Sstevel@tonic-gate 	scf_snaplevel_t *ret;
2684*7c478bd9Sstevel@tonic-gate 
2685*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
2686*7c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
2687*7c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
2688*7c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
2689*7c478bd9Sstevel@tonic-gate 			uu_free(ret);
2690*7c478bd9Sstevel@tonic-gate 			return (NULL);
2691*7c478bd9Sstevel@tonic-gate 		}
2692*7c478bd9Sstevel@tonic-gate 	} else {
2693*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2694*7c478bd9Sstevel@tonic-gate 	}
2695*7c478bd9Sstevel@tonic-gate 
2696*7c478bd9Sstevel@tonic-gate 	return (ret);
2697*7c478bd9Sstevel@tonic-gate }
2698*7c478bd9Sstevel@tonic-gate 
2699*7c478bd9Sstevel@tonic-gate scf_handle_t *
2700*7c478bd9Sstevel@tonic-gate scf_snaplevel_handle(const scf_snaplevel_t *val)
2701*7c478bd9Sstevel@tonic-gate {
2702*7c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
2703*7c478bd9Sstevel@tonic-gate }
2704*7c478bd9Sstevel@tonic-gate 
2705*7c478bd9Sstevel@tonic-gate void
2706*7c478bd9Sstevel@tonic-gate scf_snaplevel_destroy(scf_snaplevel_t *val)
2707*7c478bd9Sstevel@tonic-gate {
2708*7c478bd9Sstevel@tonic-gate 	if (val == NULL)
2709*7c478bd9Sstevel@tonic-gate 		return;
2710*7c478bd9Sstevel@tonic-gate 
2711*7c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
2712*7c478bd9Sstevel@tonic-gate 	uu_free(val);
2713*7c478bd9Sstevel@tonic-gate }
2714*7c478bd9Sstevel@tonic-gate 
2715*7c478bd9Sstevel@tonic-gate ssize_t
2716*7c478bd9Sstevel@tonic-gate scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len)
2717*7c478bd9Sstevel@tonic-gate {
2718*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len,
2719*7c478bd9Sstevel@tonic-gate 	    RP_ENTITY_NAME_SNAPLEVEL_SCOPE));
2720*7c478bd9Sstevel@tonic-gate }
2721*7c478bd9Sstevel@tonic-gate 
2722*7c478bd9Sstevel@tonic-gate ssize_t
2723*7c478bd9Sstevel@tonic-gate scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out,
2724*7c478bd9Sstevel@tonic-gate     size_t len)
2725*7c478bd9Sstevel@tonic-gate {
2726*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len,
2727*7c478bd9Sstevel@tonic-gate 	    RP_ENTITY_NAME_SNAPLEVEL_SERVICE));
2728*7c478bd9Sstevel@tonic-gate }
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate ssize_t
2731*7c478bd9Sstevel@tonic-gate scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out,
2732*7c478bd9Sstevel@tonic-gate     size_t len)
2733*7c478bd9Sstevel@tonic-gate {
2734*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len,
2735*7c478bd9Sstevel@tonic-gate 	    RP_ENTITY_NAME_SNAPLEVEL_INSTANCE));
2736*7c478bd9Sstevel@tonic-gate }
2737*7c478bd9Sstevel@tonic-gate 
2738*7c478bd9Sstevel@tonic-gate int
2739*7c478bd9Sstevel@tonic-gate scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name,
2740*7c478bd9Sstevel@tonic-gate     scf_propertygroup_t *pg)
2741*7c478bd9Sstevel@tonic-gate {
2742*7c478bd9Sstevel@tonic-gate 	return (datael_get_child(&snap->rd_d, name,
2743*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2744*7c478bd9Sstevel@tonic-gate }
2745*7c478bd9Sstevel@tonic-gate 
2746*7c478bd9Sstevel@tonic-gate static int
2747*7c478bd9Sstevel@tonic-gate snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg)
2748*7c478bd9Sstevel@tonic-gate {
2749*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = src->rd_handle;
2750*7c478bd9Sstevel@tonic-gate 	scf_snaplevel_t *dst = dst_arg;
2751*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_pair request;
2752*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
2753*7c478bd9Sstevel@tonic-gate 	int r;
2754*7c478bd9Sstevel@tonic-gate 	int dups = 0;
2755*7c478bd9Sstevel@tonic-gate 
2756*7c478bd9Sstevel@tonic-gate 	if (h != dst->rd_d.rd_handle)
2757*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2758*7c478bd9Sstevel@tonic-gate 
2759*7c478bd9Sstevel@tonic-gate 	if (src == &dst->rd_d) {
2760*7c478bd9Sstevel@tonic-gate 		dups = 1;
2761*7c478bd9Sstevel@tonic-gate 		dst = HANDLE_HOLD_SNAPLVL(h);
2762*7c478bd9Sstevel@tonic-gate 	}
2763*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2764*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL;
2765*7c478bd9Sstevel@tonic-gate 	request.rpr_entity_src = src->rd_entity;
2766*7c478bd9Sstevel@tonic-gate 	request.rpr_entity_dst = dst->rd_d.rd_entity;
2767*7c478bd9Sstevel@tonic-gate 
2768*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(src);
2769*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&dst->rd_d);
2770*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
2771*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
2772*7c478bd9Sstevel@tonic-gate 	/*
2773*7c478bd9Sstevel@tonic-gate 	 * if we succeeded, we need to swap dst and dst_arg's identity.  We
2774*7c478bd9Sstevel@tonic-gate 	 * take advantage of the fact that the only in-library knowledge is
2775*7c478bd9Sstevel@tonic-gate 	 * their entity ids.
2776*7c478bd9Sstevel@tonic-gate 	 */
2777*7c478bd9Sstevel@tonic-gate 	if (dups && r >= 0 &&
2778*7c478bd9Sstevel@tonic-gate 	    (response.rpr_response == REP_PROTOCOL_SUCCESS ||
2779*7c478bd9Sstevel@tonic-gate 	    response.rpr_response == REP_PROTOCOL_DONE)) {
2780*7c478bd9Sstevel@tonic-gate 		int entity = dst->rd_d.rd_entity;
2781*7c478bd9Sstevel@tonic-gate 
2782*7c478bd9Sstevel@tonic-gate 		dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity;
2783*7c478bd9Sstevel@tonic-gate 		dst_arg->rd_d.rd_entity = entity;
2784*7c478bd9Sstevel@tonic-gate 	}
2785*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2786*7c478bd9Sstevel@tonic-gate 
2787*7c478bd9Sstevel@tonic-gate 	if (dups)
2788*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SNAPLVL(h);
2789*7c478bd9Sstevel@tonic-gate 
2790*7c478bd9Sstevel@tonic-gate 	if (r < 0)
2791*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
2792*7c478bd9Sstevel@tonic-gate 
2793*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
2794*7c478bd9Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_DONE) {
2795*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
2796*7c478bd9Sstevel@tonic-gate 	}
2797*7c478bd9Sstevel@tonic-gate 
2798*7c478bd9Sstevel@tonic-gate 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
2799*7c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS : SCF_COMPLETE;
2800*7c478bd9Sstevel@tonic-gate }
2801*7c478bd9Sstevel@tonic-gate 
2802*7c478bd9Sstevel@tonic-gate int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base,
2803*7c478bd9Sstevel@tonic-gate     scf_snaplevel_t *out)
2804*7c478bd9Sstevel@tonic-gate {
2805*7c478bd9Sstevel@tonic-gate 	return (snaplevel_next(&base->rd_d, out));
2806*7c478bd9Sstevel@tonic-gate }
2807*7c478bd9Sstevel@tonic-gate 
2808*7c478bd9Sstevel@tonic-gate int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base,
2809*7c478bd9Sstevel@tonic-gate     scf_snaplevel_t *out)
2810*7c478bd9Sstevel@tonic-gate {
2811*7c478bd9Sstevel@tonic-gate 	return (snaplevel_next(&base->rd_d, out));
2812*7c478bd9Sstevel@tonic-gate }
2813*7c478bd9Sstevel@tonic-gate 
2814*7c478bd9Sstevel@tonic-gate /*
2815*7c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2816*7c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2817*7c478bd9Sstevel@tonic-gate  */
2818*7c478bd9Sstevel@tonic-gate scf_propertygroup_t *
2819*7c478bd9Sstevel@tonic-gate scf_pg_create(scf_handle_t *handle)
2820*7c478bd9Sstevel@tonic-gate {
2821*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *ret;
2822*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
2823*7c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
2824*7c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
2825*7c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
2826*7c478bd9Sstevel@tonic-gate 			uu_free(ret);
2827*7c478bd9Sstevel@tonic-gate 			return (NULL);
2828*7c478bd9Sstevel@tonic-gate 		}
2829*7c478bd9Sstevel@tonic-gate 	} else {
2830*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2831*7c478bd9Sstevel@tonic-gate 	}
2832*7c478bd9Sstevel@tonic-gate 
2833*7c478bd9Sstevel@tonic-gate 	return (ret);
2834*7c478bd9Sstevel@tonic-gate }
2835*7c478bd9Sstevel@tonic-gate 
2836*7c478bd9Sstevel@tonic-gate scf_handle_t *
2837*7c478bd9Sstevel@tonic-gate scf_pg_handle(const scf_propertygroup_t *val)
2838*7c478bd9Sstevel@tonic-gate {
2839*7c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
2840*7c478bd9Sstevel@tonic-gate }
2841*7c478bd9Sstevel@tonic-gate 
2842*7c478bd9Sstevel@tonic-gate void
2843*7c478bd9Sstevel@tonic-gate scf_pg_destroy(scf_propertygroup_t *val)
2844*7c478bd9Sstevel@tonic-gate {
2845*7c478bd9Sstevel@tonic-gate 	if (val == NULL)
2846*7c478bd9Sstevel@tonic-gate 		return;
2847*7c478bd9Sstevel@tonic-gate 
2848*7c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
2849*7c478bd9Sstevel@tonic-gate 	uu_free(val);
2850*7c478bd9Sstevel@tonic-gate }
2851*7c478bd9Sstevel@tonic-gate 
2852*7c478bd9Sstevel@tonic-gate ssize_t
2853*7c478bd9Sstevel@tonic-gate scf_pg_get_name(const scf_propertygroup_t *pg,  char *out, size_t len)
2854*7c478bd9Sstevel@tonic-gate {
2855*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME));
2856*7c478bd9Sstevel@tonic-gate }
2857*7c478bd9Sstevel@tonic-gate 
2858*7c478bd9Sstevel@tonic-gate ssize_t
2859*7c478bd9Sstevel@tonic-gate scf_pg_get_type(const scf_propertygroup_t *pg,  char *out, size_t len)
2860*7c478bd9Sstevel@tonic-gate {
2861*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_PGTYPE));
2862*7c478bd9Sstevel@tonic-gate }
2863*7c478bd9Sstevel@tonic-gate 
2864*7c478bd9Sstevel@tonic-gate int
2865*7c478bd9Sstevel@tonic-gate scf_pg_get_flags(const scf_propertygroup_t *pg, uint32_t *out)
2866*7c478bd9Sstevel@tonic-gate {
2867*7c478bd9Sstevel@tonic-gate 	char buf[REP_PROTOCOL_NAME_LEN];
2868*7c478bd9Sstevel@tonic-gate 	ssize_t res;
2869*7c478bd9Sstevel@tonic-gate 
2870*7c478bd9Sstevel@tonic-gate 	res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
2871*7c478bd9Sstevel@tonic-gate 	    RP_ENTITY_NAME_PGFLAGS);
2872*7c478bd9Sstevel@tonic-gate 
2873*7c478bd9Sstevel@tonic-gate 	if (res == -1)
2874*7c478bd9Sstevel@tonic-gate 		return (-1);
2875*7c478bd9Sstevel@tonic-gate 
2876*7c478bd9Sstevel@tonic-gate 	if (uu_strtouint(buf, out, sizeof (*out), 0, 0, UINT32_MAX) == -1)
2877*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
2878*7c478bd9Sstevel@tonic-gate 
2879*7c478bd9Sstevel@tonic-gate 	return (0);
2880*7c478bd9Sstevel@tonic-gate }
2881*7c478bd9Sstevel@tonic-gate 
2882*7c478bd9Sstevel@tonic-gate static int
2883*7c478bd9Sstevel@tonic-gate datael_update(scf_datael_t *dp)
2884*7c478bd9Sstevel@tonic-gate {
2885*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
2886*7c478bd9Sstevel@tonic-gate 
2887*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_update request;
2888*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
2889*7c478bd9Sstevel@tonic-gate 
2890*7c478bd9Sstevel@tonic-gate 	int r;
2891*7c478bd9Sstevel@tonic-gate 
2892*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2893*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_UPDATE;
2894*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
2895*7c478bd9Sstevel@tonic-gate 
2896*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
2897*7c478bd9Sstevel@tonic-gate 	request.rpr_changeid = handle_alloc_changeid(h);
2898*7c478bd9Sstevel@tonic-gate 
2899*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
2900*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
2901*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2902*7c478bd9Sstevel@tonic-gate 
2903*7c478bd9Sstevel@tonic-gate 	if (r < 0)
2904*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
2905*7c478bd9Sstevel@tonic-gate 
2906*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
2907*7c478bd9Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_DONE) {
2908*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
2909*7c478bd9Sstevel@tonic-gate 	}
2910*7c478bd9Sstevel@tonic-gate 
2911*7c478bd9Sstevel@tonic-gate 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
2912*7c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS : SCF_COMPLETE;
2913*7c478bd9Sstevel@tonic-gate }
2914*7c478bd9Sstevel@tonic-gate 
2915*7c478bd9Sstevel@tonic-gate int
2916*7c478bd9Sstevel@tonic-gate scf_pg_update(scf_propertygroup_t *pg)
2917*7c478bd9Sstevel@tonic-gate {
2918*7c478bd9Sstevel@tonic-gate 	return (datael_update(&pg->rd_d));
2919*7c478bd9Sstevel@tonic-gate }
2920*7c478bd9Sstevel@tonic-gate 
2921*7c478bd9Sstevel@tonic-gate int
2922*7c478bd9Sstevel@tonic-gate scf_snapshot_update(scf_snapshot_t *snap)
2923*7c478bd9Sstevel@tonic-gate {
2924*7c478bd9Sstevel@tonic-gate 	return (datael_update(&snap->rd_d));
2925*7c478bd9Sstevel@tonic-gate }
2926*7c478bd9Sstevel@tonic-gate 
2927*7c478bd9Sstevel@tonic-gate int
2928*7c478bd9Sstevel@tonic-gate _scf_pg_wait(scf_propertygroup_t *pg, int timeout)
2929*7c478bd9Sstevel@tonic-gate {
2930*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
2931*7c478bd9Sstevel@tonic-gate 
2932*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_propertygrp_request request;
2933*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
2934*7c478bd9Sstevel@tonic-gate 
2935*7c478bd9Sstevel@tonic-gate 	struct pollfd pollfd;
2936*7c478bd9Sstevel@tonic-gate 
2937*7c478bd9Sstevel@tonic-gate 	int r;
2938*7c478bd9Sstevel@tonic-gate 
2939*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2940*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT;
2941*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
2942*7c478bd9Sstevel@tonic-gate 
2943*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
2944*7c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
2945*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
2946*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
2947*7c478bd9Sstevel@tonic-gate 	}
2948*7c478bd9Sstevel@tonic-gate 	r = make_door_call_retfd(h->rh_doorfd, &request, sizeof (request),
2949*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response), &pollfd.fd);
2950*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2951*7c478bd9Sstevel@tonic-gate 
2952*7c478bd9Sstevel@tonic-gate 	if (r < 0)
2953*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
2954*7c478bd9Sstevel@tonic-gate 
2955*7c478bd9Sstevel@tonic-gate 	assert((response.rpr_response == REP_PROTOCOL_SUCCESS) ==
2956*7c478bd9Sstevel@tonic-gate 	    (pollfd.fd != -1));
2957*7c478bd9Sstevel@tonic-gate 
2958*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_LATEST)
2959*7c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);
2960*7c478bd9Sstevel@tonic-gate 
2961*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2962*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
2963*7c478bd9Sstevel@tonic-gate 
2964*7c478bd9Sstevel@tonic-gate 	pollfd.events = 0;
2965*7c478bd9Sstevel@tonic-gate 	pollfd.revents = 0;
2966*7c478bd9Sstevel@tonic-gate 
2967*7c478bd9Sstevel@tonic-gate 	r = poll(&pollfd, 1, timeout * MILLISEC);
2968*7c478bd9Sstevel@tonic-gate 
2969*7c478bd9Sstevel@tonic-gate 	(void) close(pollfd.fd);
2970*7c478bd9Sstevel@tonic-gate 	return (pollfd.revents ? SCF_SUCCESS : SCF_COMPLETE);
2971*7c478bd9Sstevel@tonic-gate }
2972*7c478bd9Sstevel@tonic-gate 
2973*7c478bd9Sstevel@tonic-gate static int
2974*7c478bd9Sstevel@tonic-gate scf_notify_add_pattern(scf_handle_t *h, int type, const char *name)
2975*7c478bd9Sstevel@tonic-gate {
2976*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_notify_request request;
2977*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
2978*7c478bd9Sstevel@tonic-gate 	int r;
2979*7c478bd9Sstevel@tonic-gate 
2980*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
2981*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_CLIENT_ADD_NOTIFY;
2982*7c478bd9Sstevel@tonic-gate 	request.rpr_type = type;
2983*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(request.rpr_pattern, name, sizeof (request.rpr_pattern));
2984*7c478bd9Sstevel@tonic-gate 
2985*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
2986*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
2987*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
2988*7c478bd9Sstevel@tonic-gate 
2989*7c478bd9Sstevel@tonic-gate 	if (r < 0)
2990*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
2991*7c478bd9Sstevel@tonic-gate 
2992*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2993*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
2994*7c478bd9Sstevel@tonic-gate 
2995*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
2996*7c478bd9Sstevel@tonic-gate }
2997*7c478bd9Sstevel@tonic-gate 
2998*7c478bd9Sstevel@tonic-gate int
2999*7c478bd9Sstevel@tonic-gate _scf_notify_add_pgname(scf_handle_t *h, const char *name)
3000*7c478bd9Sstevel@tonic-gate {
3001*7c478bd9Sstevel@tonic-gate 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGNAME, name));
3002*7c478bd9Sstevel@tonic-gate }
3003*7c478bd9Sstevel@tonic-gate 
3004*7c478bd9Sstevel@tonic-gate int
3005*7c478bd9Sstevel@tonic-gate _scf_notify_add_pgtype(scf_handle_t *h, const char *type)
3006*7c478bd9Sstevel@tonic-gate {
3007*7c478bd9Sstevel@tonic-gate 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGTYPE, type));
3008*7c478bd9Sstevel@tonic-gate }
3009*7c478bd9Sstevel@tonic-gate 
3010*7c478bd9Sstevel@tonic-gate int
3011*7c478bd9Sstevel@tonic-gate _scf_notify_wait(scf_propertygroup_t *pg, char *out, size_t sz)
3012*7c478bd9Sstevel@tonic-gate {
3013*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_wait_request request;
3014*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_fmri_response response;
3015*7c478bd9Sstevel@tonic-gate 
3016*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
3017*7c478bd9Sstevel@tonic-gate 	int dummy;
3018*7c478bd9Sstevel@tonic-gate 	int fd;
3019*7c478bd9Sstevel@tonic-gate 	int r;
3020*7c478bd9Sstevel@tonic-gate 
3021*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3022*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
3023*7c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
3024*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3025*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
3026*7c478bd9Sstevel@tonic-gate 	}
3027*7c478bd9Sstevel@tonic-gate 	fd = h->rh_doorfd;
3028*7c478bd9Sstevel@tonic-gate 	++h->rh_fd_users;
3029*7c478bd9Sstevel@tonic-gate 	assert(h->rh_fd_users > 0);
3030*7c478bd9Sstevel@tonic-gate 
3031*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_CLIENT_WAIT;
3032*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
3033*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3034*7c478bd9Sstevel@tonic-gate 
3035*7c478bd9Sstevel@tonic-gate 	r = make_door_call_retfd(fd, &request, sizeof (request),
3036*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response), &dummy);
3037*7c478bd9Sstevel@tonic-gate 
3038*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3039*7c478bd9Sstevel@tonic-gate 	assert(h->rh_fd_users > 0);
3040*7c478bd9Sstevel@tonic-gate 	if (--h->rh_fd_users == 0) {
3041*7c478bd9Sstevel@tonic-gate 		(void) pthread_cond_broadcast(&h->rh_cv);
3042*7c478bd9Sstevel@tonic-gate 		/*
3043*7c478bd9Sstevel@tonic-gate 		 * check for a delayed close, now that there are no other
3044*7c478bd9Sstevel@tonic-gate 		 * users.
3045*7c478bd9Sstevel@tonic-gate 		 */
3046*7c478bd9Sstevel@tonic-gate 		if (h->rh_doorfd_old != -1) {
3047*7c478bd9Sstevel@tonic-gate 			assert(h->rh_doorfd == -1);
3048*7c478bd9Sstevel@tonic-gate 			assert(fd == h->rh_doorfd_old);
3049*7c478bd9Sstevel@tonic-gate 			(void) close(h->rh_doorfd_old);
3050*7c478bd9Sstevel@tonic-gate 			h->rh_doorfd_old = -1;
3051*7c478bd9Sstevel@tonic-gate 		}
3052*7c478bd9Sstevel@tonic-gate 	}
3053*7c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
3054*7c478bd9Sstevel@tonic-gate 
3055*7c478bd9Sstevel@tonic-gate 	if (r < 0)
3056*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
3057*7c478bd9Sstevel@tonic-gate 
3058*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE)
3059*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
3060*7c478bd9Sstevel@tonic-gate 
3061*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3062*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
3063*7c478bd9Sstevel@tonic-gate 
3064*7c478bd9Sstevel@tonic-gate 	/* the following will be non-zero for delete notifications */
3065*7c478bd9Sstevel@tonic-gate 	return (strlcpy(out, response.rpr_fmri, sz));
3066*7c478bd9Sstevel@tonic-gate }
3067*7c478bd9Sstevel@tonic-gate 
3068*7c478bd9Sstevel@tonic-gate static int
3069*7c478bd9Sstevel@tonic-gate _scf_snapshot_take(scf_instance_t *inst, const char *name,
3070*7c478bd9Sstevel@tonic-gate     scf_snapshot_t *snap, int flags)
3071*7c478bd9Sstevel@tonic-gate {
3072*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = inst->rd_d.rd_handle;
3073*7c478bd9Sstevel@tonic-gate 
3074*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_snapshot_take request;
3075*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
3076*7c478bd9Sstevel@tonic-gate 
3077*7c478bd9Sstevel@tonic-gate 	int r;
3078*7c478bd9Sstevel@tonic-gate 
3079*7c478bd9Sstevel@tonic-gate 	if (h != snap->rd_d.rd_handle)
3080*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3081*7c478bd9Sstevel@tonic-gate 
3082*7c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, (name != NULL)? name : "",
3083*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3084*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3085*7c478bd9Sstevel@tonic-gate 
3086*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3087*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE;
3088*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid_src = inst->rd_d.rd_entity;
3089*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
3090*7c478bd9Sstevel@tonic-gate 	request.rpr_flags = flags;
3091*7c478bd9Sstevel@tonic-gate 
3092*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&inst->rd_d);
3093*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&snap->rd_d);
3094*7c478bd9Sstevel@tonic-gate 
3095*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
3096*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
3097*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3098*7c478bd9Sstevel@tonic-gate 
3099*7c478bd9Sstevel@tonic-gate 	if (r < 0)
3100*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
3101*7c478bd9Sstevel@tonic-gate 
3102*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3103*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
3104*7c478bd9Sstevel@tonic-gate 
3105*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
3106*7c478bd9Sstevel@tonic-gate }
3107*7c478bd9Sstevel@tonic-gate 
3108*7c478bd9Sstevel@tonic-gate int
3109*7c478bd9Sstevel@tonic-gate _scf_snapshot_take_new_named(scf_instance_t *inst,
3110*7c478bd9Sstevel@tonic-gate     const char *svcname, const char *instname, const char *snapname,
3111*7c478bd9Sstevel@tonic-gate     scf_snapshot_t *snap)
3112*7c478bd9Sstevel@tonic-gate {
3113*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = inst->rd_d.rd_handle;
3114*7c478bd9Sstevel@tonic-gate 
3115*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_snapshot_take_named request;
3116*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
3117*7c478bd9Sstevel@tonic-gate 
3118*7c478bd9Sstevel@tonic-gate 	int r;
3119*7c478bd9Sstevel@tonic-gate 
3120*7c478bd9Sstevel@tonic-gate 	if (h != snap->rd_d.rd_handle)
3121*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3122*7c478bd9Sstevel@tonic-gate 
3123*7c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_svcname, svcname,
3124*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_svcname)) >= sizeof (request.rpr_svcname))
3125*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3126*7c478bd9Sstevel@tonic-gate 
3127*7c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_instname, instname,
3128*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_instname)) >= sizeof (request.rpr_instname))
3129*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3130*7c478bd9Sstevel@tonic-gate 
3131*7c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, snapname,
3132*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3133*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3134*7c478bd9Sstevel@tonic-gate 
3135*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3136*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE_NAMED;
3137*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid_src = inst->rd_d.rd_entity;
3138*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
3139*7c478bd9Sstevel@tonic-gate 
3140*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&inst->rd_d);
3141*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&snap->rd_d);
3142*7c478bd9Sstevel@tonic-gate 
3143*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
3144*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
3145*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3146*7c478bd9Sstevel@tonic-gate 
3147*7c478bd9Sstevel@tonic-gate 	if (r < 0)
3148*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
3149*7c478bd9Sstevel@tonic-gate 
3150*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
3151*7c478bd9Sstevel@tonic-gate 		assert(response.rpr_response !=
3152*7c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
3153*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
3154*7c478bd9Sstevel@tonic-gate 	}
3155*7c478bd9Sstevel@tonic-gate 
3156*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
3157*7c478bd9Sstevel@tonic-gate }
3158*7c478bd9Sstevel@tonic-gate 
3159*7c478bd9Sstevel@tonic-gate int
3160*7c478bd9Sstevel@tonic-gate _scf_snapshot_take_new(scf_instance_t *inst, const char *name,
3161*7c478bd9Sstevel@tonic-gate     scf_snapshot_t *snap)
3162*7c478bd9Sstevel@tonic-gate {
3163*7c478bd9Sstevel@tonic-gate 	return (_scf_snapshot_take(inst, name, snap, REP_SNAPSHOT_NEW));
3164*7c478bd9Sstevel@tonic-gate }
3165*7c478bd9Sstevel@tonic-gate 
3166*7c478bd9Sstevel@tonic-gate int
3167*7c478bd9Sstevel@tonic-gate _scf_snapshot_take_attach(scf_instance_t *inst, scf_snapshot_t *snap)
3168*7c478bd9Sstevel@tonic-gate {
3169*7c478bd9Sstevel@tonic-gate 	return (_scf_snapshot_take(inst, NULL, snap, REP_SNAPSHOT_ATTACH));
3170*7c478bd9Sstevel@tonic-gate }
3171*7c478bd9Sstevel@tonic-gate 
3172*7c478bd9Sstevel@tonic-gate int
3173*7c478bd9Sstevel@tonic-gate _scf_snapshot_attach(scf_snapshot_t *src, scf_snapshot_t *dest)
3174*7c478bd9Sstevel@tonic-gate {
3175*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dest->rd_d.rd_handle;
3176*7c478bd9Sstevel@tonic-gate 
3177*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_snapshot_attach request;
3178*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
3179*7c478bd9Sstevel@tonic-gate 
3180*7c478bd9Sstevel@tonic-gate 	int r;
3181*7c478bd9Sstevel@tonic-gate 
3182*7c478bd9Sstevel@tonic-gate 	if (h != src->rd_d.rd_handle)
3183*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3184*7c478bd9Sstevel@tonic-gate 
3185*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3186*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_ATTACH;
3187*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid_src = src->rd_d.rd_entity;
3188*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid_dest = dest->rd_d.rd_entity;
3189*7c478bd9Sstevel@tonic-gate 
3190*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&src->rd_d);
3191*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&dest->rd_d);
3192*7c478bd9Sstevel@tonic-gate 
3193*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
3194*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
3195*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3196*7c478bd9Sstevel@tonic-gate 
3197*7c478bd9Sstevel@tonic-gate 	if (r < 0)
3198*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
3199*7c478bd9Sstevel@tonic-gate 
3200*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3201*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
3202*7c478bd9Sstevel@tonic-gate 
3203*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
3204*7c478bd9Sstevel@tonic-gate }
3205*7c478bd9Sstevel@tonic-gate 
3206*7c478bd9Sstevel@tonic-gate /*
3207*7c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3208*7c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3209*7c478bd9Sstevel@tonic-gate  */
3210*7c478bd9Sstevel@tonic-gate scf_property_t *
3211*7c478bd9Sstevel@tonic-gate scf_property_create(scf_handle_t *handle)
3212*7c478bd9Sstevel@tonic-gate {
3213*7c478bd9Sstevel@tonic-gate 	scf_property_t *ret;
3214*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
3215*7c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
3216*7c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
3217*7c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_PROPERTY) == -1) {
3218*7c478bd9Sstevel@tonic-gate 			uu_free(ret);
3219*7c478bd9Sstevel@tonic-gate 			return (NULL);
3220*7c478bd9Sstevel@tonic-gate 		}
3221*7c478bd9Sstevel@tonic-gate 	} else {
3222*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3223*7c478bd9Sstevel@tonic-gate 	}
3224*7c478bd9Sstevel@tonic-gate 
3225*7c478bd9Sstevel@tonic-gate 	return (ret);
3226*7c478bd9Sstevel@tonic-gate }
3227*7c478bd9Sstevel@tonic-gate 
3228*7c478bd9Sstevel@tonic-gate scf_handle_t *
3229*7c478bd9Sstevel@tonic-gate scf_property_handle(const scf_property_t *val)
3230*7c478bd9Sstevel@tonic-gate {
3231*7c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
3232*7c478bd9Sstevel@tonic-gate }
3233*7c478bd9Sstevel@tonic-gate 
3234*7c478bd9Sstevel@tonic-gate void
3235*7c478bd9Sstevel@tonic-gate scf_property_destroy(scf_property_t *val)
3236*7c478bd9Sstevel@tonic-gate {
3237*7c478bd9Sstevel@tonic-gate 	if (val == NULL)
3238*7c478bd9Sstevel@tonic-gate 		return;
3239*7c478bd9Sstevel@tonic-gate 
3240*7c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
3241*7c478bd9Sstevel@tonic-gate 	uu_free(val);
3242*7c478bd9Sstevel@tonic-gate }
3243*7c478bd9Sstevel@tonic-gate 
3244*7c478bd9Sstevel@tonic-gate static int
3245*7c478bd9Sstevel@tonic-gate property_type_locked(const scf_property_t *prop,
3246*7c478bd9Sstevel@tonic-gate     rep_protocol_value_type_t *out)
3247*7c478bd9Sstevel@tonic-gate {
3248*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
3249*7c478bd9Sstevel@tonic-gate 
3250*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_property_request request;
3251*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_integer_response response;
3252*7c478bd9Sstevel@tonic-gate 
3253*7c478bd9Sstevel@tonic-gate 	int r;
3254*7c478bd9Sstevel@tonic-gate 
3255*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
3256*7c478bd9Sstevel@tonic-gate 
3257*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_TYPE;
3258*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = prop->rd_d.rd_entity;
3259*7c478bd9Sstevel@tonic-gate 
3260*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&prop->rd_d);
3261*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
3262*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
3263*7c478bd9Sstevel@tonic-gate 
3264*7c478bd9Sstevel@tonic-gate 	if (r < 0)
3265*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
3266*7c478bd9Sstevel@tonic-gate 
3267*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3268*7c478bd9Sstevel@tonic-gate 	    r < sizeof (response)) {
3269*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
3270*7c478bd9Sstevel@tonic-gate 	}
3271*7c478bd9Sstevel@tonic-gate 	*out = response.rpr_value;
3272*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
3273*7c478bd9Sstevel@tonic-gate }
3274*7c478bd9Sstevel@tonic-gate 
3275*7c478bd9Sstevel@tonic-gate int
3276*7c478bd9Sstevel@tonic-gate scf_property_type(const scf_property_t *prop, scf_type_t *out)
3277*7c478bd9Sstevel@tonic-gate {
3278*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
3279*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t out_raw;
3280*7c478bd9Sstevel@tonic-gate 	int ret;
3281*7c478bd9Sstevel@tonic-gate 
3282*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3283*7c478bd9Sstevel@tonic-gate 	ret = property_type_locked(prop, &out_raw);
3284*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3285*7c478bd9Sstevel@tonic-gate 
3286*7c478bd9Sstevel@tonic-gate 	if (ret == SCF_SUCCESS)
3287*7c478bd9Sstevel@tonic-gate 		*out = scf_protocol_type_to_type(out_raw);
3288*7c478bd9Sstevel@tonic-gate 
3289*7c478bd9Sstevel@tonic-gate 	return (ret);
3290*7c478bd9Sstevel@tonic-gate }
3291*7c478bd9Sstevel@tonic-gate 
3292*7c478bd9Sstevel@tonic-gate int
3293*7c478bd9Sstevel@tonic-gate scf_property_is_type(const scf_property_t *prop, scf_type_t base_arg)
3294*7c478bd9Sstevel@tonic-gate {
3295*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
3296*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3297*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t type;
3298*7c478bd9Sstevel@tonic-gate 	int ret;
3299*7c478bd9Sstevel@tonic-gate 
3300*7c478bd9Sstevel@tonic-gate 	if (base == REP_PROTOCOL_TYPE_INVALID)
3301*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3302*7c478bd9Sstevel@tonic-gate 
3303*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3304*7c478bd9Sstevel@tonic-gate 	ret = property_type_locked(prop, &type);
3305*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3306*7c478bd9Sstevel@tonic-gate 
3307*7c478bd9Sstevel@tonic-gate 	if (ret == SCF_SUCCESS) {
3308*7c478bd9Sstevel@tonic-gate 		if (!scf_is_compatible_type(base, type))
3309*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3310*7c478bd9Sstevel@tonic-gate 	}
3311*7c478bd9Sstevel@tonic-gate 	return (ret);
3312*7c478bd9Sstevel@tonic-gate }
3313*7c478bd9Sstevel@tonic-gate 
3314*7c478bd9Sstevel@tonic-gate ssize_t
3315*7c478bd9Sstevel@tonic-gate scf_property_get_name(const scf_property_t *prop, char *out, size_t len)
3316*7c478bd9Sstevel@tonic-gate {
3317*7c478bd9Sstevel@tonic-gate 	return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME));
3318*7c478bd9Sstevel@tonic-gate }
3319*7c478bd9Sstevel@tonic-gate 
3320*7c478bd9Sstevel@tonic-gate /*
3321*7c478bd9Sstevel@tonic-gate  * transaction functions
3322*7c478bd9Sstevel@tonic-gate  */
3323*7c478bd9Sstevel@tonic-gate 
3324*7c478bd9Sstevel@tonic-gate /*
3325*7c478bd9Sstevel@tonic-gate  * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
3326*7c478bd9Sstevel@tonic-gate  * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
3327*7c478bd9Sstevel@tonic-gate  */
3328*7c478bd9Sstevel@tonic-gate scf_transaction_t *
3329*7c478bd9Sstevel@tonic-gate scf_transaction_create(scf_handle_t *handle)
3330*7c478bd9Sstevel@tonic-gate {
3331*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *ret;
3332*7c478bd9Sstevel@tonic-gate 
3333*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (scf_transaction_t));
3334*7c478bd9Sstevel@tonic-gate 	if (ret == NULL) {
3335*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3336*7c478bd9Sstevel@tonic-gate 		return (NULL);
3337*7c478bd9Sstevel@tonic-gate 	}
3338*7c478bd9Sstevel@tonic-gate 	if (datael_init(&ret->tran_pg.rd_d, handle,
3339*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
3340*7c478bd9Sstevel@tonic-gate 		uu_free(ret);
3341*7c478bd9Sstevel@tonic-gate 		return (NULL);			/* error already set */
3342*7c478bd9Sstevel@tonic-gate 	}
3343*7c478bd9Sstevel@tonic-gate 	ret->tran_state = TRAN_STATE_NEW;
3344*7c478bd9Sstevel@tonic-gate 	ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED);
3345*7c478bd9Sstevel@tonic-gate 	if (ret->tran_props == NULL) {
3346*7c478bd9Sstevel@tonic-gate 		datael_destroy(&ret->tran_pg.rd_d);
3347*7c478bd9Sstevel@tonic-gate 		uu_free(ret);
3348*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3349*7c478bd9Sstevel@tonic-gate 		return (NULL);
3350*7c478bd9Sstevel@tonic-gate 	}
3351*7c478bd9Sstevel@tonic-gate 
3352*7c478bd9Sstevel@tonic-gate 	return (ret);
3353*7c478bd9Sstevel@tonic-gate }
3354*7c478bd9Sstevel@tonic-gate 
3355*7c478bd9Sstevel@tonic-gate scf_handle_t *
3356*7c478bd9Sstevel@tonic-gate scf_transaction_handle(const scf_transaction_t *val)
3357*7c478bd9Sstevel@tonic-gate {
3358*7c478bd9Sstevel@tonic-gate 	return (handle_get(val->tran_pg.rd_d.rd_handle));
3359*7c478bd9Sstevel@tonic-gate }
3360*7c478bd9Sstevel@tonic-gate 
3361*7c478bd9Sstevel@tonic-gate int
3362*7c478bd9Sstevel@tonic-gate scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg)
3363*7c478bd9Sstevel@tonic-gate {
3364*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3365*7c478bd9Sstevel@tonic-gate 
3366*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_transaction_start request;
3367*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
3368*7c478bd9Sstevel@tonic-gate 	int r;
3369*7c478bd9Sstevel@tonic-gate 
3370*7c478bd9Sstevel@tonic-gate 	if (h != pg->rd_d.rd_handle)
3371*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3372*7c478bd9Sstevel@tonic-gate 
3373*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3374*7c478bd9Sstevel@tonic-gate 	if (tran->tran_state != TRAN_STATE_NEW) {
3375*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3376*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
3377*7c478bd9Sstevel@tonic-gate 	}
3378*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START;
3379*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity;
3380*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
3381*7c478bd9Sstevel@tonic-gate 
3382*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&tran->tran_pg.rd_d);
3383*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
3384*7c478bd9Sstevel@tonic-gate 
3385*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
3386*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
3387*7c478bd9Sstevel@tonic-gate 
3388*7c478bd9Sstevel@tonic-gate 	if (r < 0) {
3389*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3390*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
3391*7c478bd9Sstevel@tonic-gate 	}
3392*7c478bd9Sstevel@tonic-gate 
3393*7c478bd9Sstevel@tonic-gate 	/* r < sizeof (response) cannot happen because sizeof (response) == 4 */
3394*7c478bd9Sstevel@tonic-gate 
3395*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3396*7c478bd9Sstevel@tonic-gate 	    r < sizeof (response)) {
3397*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3398*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
3399*7c478bd9Sstevel@tonic-gate 	}
3400*7c478bd9Sstevel@tonic-gate 
3401*7c478bd9Sstevel@tonic-gate 	tran->tran_state = TRAN_STATE_SETUP;
3402*7c478bd9Sstevel@tonic-gate 	tran->tran_invalid = 0;
3403*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3404*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
3405*7c478bd9Sstevel@tonic-gate }
3406*7c478bd9Sstevel@tonic-gate 
3407*7c478bd9Sstevel@tonic-gate static void
3408*7c478bd9Sstevel@tonic-gate entry_invalidate(scf_transaction_entry_t *cur, int and_destroy,
3409*7c478bd9Sstevel@tonic-gate     int and_reset_value)
3410*7c478bd9Sstevel@tonic-gate {
3411*7c478bd9Sstevel@tonic-gate 	scf_value_t *v, *next;
3412*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
3413*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = cur->entry_handle;
3414*7c478bd9Sstevel@tonic-gate 
3415*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
3416*7c478bd9Sstevel@tonic-gate 
3417*7c478bd9Sstevel@tonic-gate 	if ((tx = cur->entry_tx) != NULL) {
3418*7c478bd9Sstevel@tonic-gate 		tx->tran_invalid = 1;
3419*7c478bd9Sstevel@tonic-gate 		uu_list_remove(tx->tran_props, cur);
3420*7c478bd9Sstevel@tonic-gate 		cur->entry_tx = NULL;
3421*7c478bd9Sstevel@tonic-gate 	}
3422*7c478bd9Sstevel@tonic-gate 
3423*7c478bd9Sstevel@tonic-gate 	cur->entry_property = NULL;
3424*7c478bd9Sstevel@tonic-gate 	cur->entry_state = ENTRY_STATE_INVALID;
3425*7c478bd9Sstevel@tonic-gate 	cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
3426*7c478bd9Sstevel@tonic-gate 	cur->entry_type = REP_PROTOCOL_TYPE_INVALID;
3427*7c478bd9Sstevel@tonic-gate 
3428*7c478bd9Sstevel@tonic-gate 	for (v = cur->entry_head; v != NULL; v = next) {
3429*7c478bd9Sstevel@tonic-gate 		next = v->value_next;
3430*7c478bd9Sstevel@tonic-gate 		v->value_tx = NULL;
3431*7c478bd9Sstevel@tonic-gate 		v->value_next = NULL;
3432*7c478bd9Sstevel@tonic-gate 		if (and_destroy || and_reset_value)
3433*7c478bd9Sstevel@tonic-gate 			scf_value_reset_locked(v, and_destroy);
3434*7c478bd9Sstevel@tonic-gate 	}
3435*7c478bd9Sstevel@tonic-gate 	cur->entry_head = NULL;
3436*7c478bd9Sstevel@tonic-gate }
3437*7c478bd9Sstevel@tonic-gate 
3438*7c478bd9Sstevel@tonic-gate static void
3439*7c478bd9Sstevel@tonic-gate entry_destroy_locked(scf_transaction_entry_t *entry)
3440*7c478bd9Sstevel@tonic-gate {
3441*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
3442*7c478bd9Sstevel@tonic-gate 
3443*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
3444*7c478bd9Sstevel@tonic-gate 
3445*7c478bd9Sstevel@tonic-gate 	entry_invalidate(entry, 0, 0);
3446*7c478bd9Sstevel@tonic-gate 
3447*7c478bd9Sstevel@tonic-gate 	entry->entry_handle = NULL;
3448*7c478bd9Sstevel@tonic-gate 	assert(h->rh_entries > 0);
3449*7c478bd9Sstevel@tonic-gate 	--h->rh_entries;
3450*7c478bd9Sstevel@tonic-gate 	--h->rh_extrefs;
3451*7c478bd9Sstevel@tonic-gate 	uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool);
3452*7c478bd9Sstevel@tonic-gate 	uu_free(entry);
3453*7c478bd9Sstevel@tonic-gate }
3454*7c478bd9Sstevel@tonic-gate 
3455*7c478bd9Sstevel@tonic-gate static int
3456*7c478bd9Sstevel@tonic-gate transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry,
3457*7c478bd9Sstevel@tonic-gate     enum rep_protocol_transaction_action action,
3458*7c478bd9Sstevel@tonic-gate     const char *prop, rep_protocol_value_type_t type)
3459*7c478bd9Sstevel@tonic-gate {
3460*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3461*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *old;
3462*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop_p;
3463*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t oldtype;
3464*7c478bd9Sstevel@tonic-gate 	scf_error_t error = SCF_ERROR_NONE;
3465*7c478bd9Sstevel@tonic-gate 	int ret;
3466*7c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
3467*7c478bd9Sstevel@tonic-gate 
3468*7c478bd9Sstevel@tonic-gate 	if (h != entry->entry_handle)
3469*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3470*7c478bd9Sstevel@tonic-gate 
3471*7c478bd9Sstevel@tonic-gate 	if (action == REP_PROTOCOL_TX_ENTRY_DELETE)
3472*7c478bd9Sstevel@tonic-gate 		assert(type == REP_PROTOCOL_TYPE_INVALID);
3473*7c478bd9Sstevel@tonic-gate 	else if (type == REP_PROTOCOL_TYPE_INVALID)
3474*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3475*7c478bd9Sstevel@tonic-gate 
3476*7c478bd9Sstevel@tonic-gate 	prop_p = HANDLE_HOLD_PROPERTY(h);
3477*7c478bd9Sstevel@tonic-gate 
3478*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3479*7c478bd9Sstevel@tonic-gate 	if (tran->tran_state != TRAN_STATE_SETUP) {
3480*7c478bd9Sstevel@tonic-gate 		error = SCF_ERROR_NOT_SET;
3481*7c478bd9Sstevel@tonic-gate 		goto error;
3482*7c478bd9Sstevel@tonic-gate 	}
3483*7c478bd9Sstevel@tonic-gate 	if (tran->tran_invalid) {
3484*7c478bd9Sstevel@tonic-gate 		error = SCF_ERROR_NOT_SET;
3485*7c478bd9Sstevel@tonic-gate 		goto error;
3486*7c478bd9Sstevel@tonic-gate 	}
3487*7c478bd9Sstevel@tonic-gate 
3488*7c478bd9Sstevel@tonic-gate 	if (entry->entry_state != ENTRY_STATE_INVALID)
3489*7c478bd9Sstevel@tonic-gate 		entry_invalidate(entry, 0, 0);
3490*7c478bd9Sstevel@tonic-gate 
3491*7c478bd9Sstevel@tonic-gate 	old = uu_list_find(tran->tran_props, &prop, NULL, &idx);
3492*7c478bd9Sstevel@tonic-gate 	if (old != NULL) {
3493*7c478bd9Sstevel@tonic-gate 		error = SCF_ERROR_IN_USE;
3494*7c478bd9Sstevel@tonic-gate 		goto error;
3495*7c478bd9Sstevel@tonic-gate 	}
3496*7c478bd9Sstevel@tonic-gate 
3497*7c478bd9Sstevel@tonic-gate 	ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop,
3498*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d);
3499*7c478bd9Sstevel@tonic-gate 	if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) {
3500*7c478bd9Sstevel@tonic-gate 		goto error;
3501*7c478bd9Sstevel@tonic-gate 	}
3502*7c478bd9Sstevel@tonic-gate 
3503*7c478bd9Sstevel@tonic-gate 	switch (action) {
3504*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_DELETE:
3505*7c478bd9Sstevel@tonic-gate 		if (ret == -1) {
3506*7c478bd9Sstevel@tonic-gate 			error = SCF_ERROR_NOT_FOUND;
3507*7c478bd9Sstevel@tonic-gate 			goto error;
3508*7c478bd9Sstevel@tonic-gate 		}
3509*7c478bd9Sstevel@tonic-gate 		break;
3510*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_NEW:
3511*7c478bd9Sstevel@tonic-gate 		if (ret != -1) {
3512*7c478bd9Sstevel@tonic-gate 			error = SCF_ERROR_EXISTS;
3513*7c478bd9Sstevel@tonic-gate 			goto error;
3514*7c478bd9Sstevel@tonic-gate 		}
3515*7c478bd9Sstevel@tonic-gate 		break;
3516*7c478bd9Sstevel@tonic-gate 
3517*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_CLEAR:
3518*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_REPLACE:
3519*7c478bd9Sstevel@tonic-gate 		if (ret == -1) {
3520*7c478bd9Sstevel@tonic-gate 			error = SCF_ERROR_NOT_FOUND;
3521*7c478bd9Sstevel@tonic-gate 			goto error;
3522*7c478bd9Sstevel@tonic-gate 		}
3523*7c478bd9Sstevel@tonic-gate 		if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) {
3524*7c478bd9Sstevel@tonic-gate 			if (property_type_locked(prop_p, &oldtype) == -1) {
3525*7c478bd9Sstevel@tonic-gate 				error = scf_error();
3526*7c478bd9Sstevel@tonic-gate 				goto error;
3527*7c478bd9Sstevel@tonic-gate 			}
3528*7c478bd9Sstevel@tonic-gate 			if (oldtype != type) {
3529*7c478bd9Sstevel@tonic-gate 				error = SCF_ERROR_TYPE_MISMATCH;
3530*7c478bd9Sstevel@tonic-gate 				goto error;
3531*7c478bd9Sstevel@tonic-gate 			}
3532*7c478bd9Sstevel@tonic-gate 		}
3533*7c478bd9Sstevel@tonic-gate 		break;
3534*7c478bd9Sstevel@tonic-gate 	default:
3535*7c478bd9Sstevel@tonic-gate 		assert(0);
3536*7c478bd9Sstevel@tonic-gate 		abort();
3537*7c478bd9Sstevel@tonic-gate 	}
3538*7c478bd9Sstevel@tonic-gate 
3539*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(entry->entry_namebuf, prop,
3540*7c478bd9Sstevel@tonic-gate 	    sizeof (entry->entry_namebuf));
3541*7c478bd9Sstevel@tonic-gate 	entry->entry_property = entry->entry_namebuf;
3542*7c478bd9Sstevel@tonic-gate 	entry->entry_action = action;
3543*7c478bd9Sstevel@tonic-gate 	entry->entry_type = type;
3544*7c478bd9Sstevel@tonic-gate 
3545*7c478bd9Sstevel@tonic-gate 	entry->entry_state = ENTRY_STATE_IN_TX_ACTION;
3546*7c478bd9Sstevel@tonic-gate 	entry->entry_tx = tran;
3547*7c478bd9Sstevel@tonic-gate 	uu_list_insert(tran->tran_props, entry, idx);
3548*7c478bd9Sstevel@tonic-gate 
3549*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3550*7c478bd9Sstevel@tonic-gate 
3551*7c478bd9Sstevel@tonic-gate 	HANDLE_RELE_PROPERTY(h);
3552*7c478bd9Sstevel@tonic-gate 
3553*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
3554*7c478bd9Sstevel@tonic-gate 
3555*7c478bd9Sstevel@tonic-gate error:
3556*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3557*7c478bd9Sstevel@tonic-gate 
3558*7c478bd9Sstevel@tonic-gate 	HANDLE_RELE_PROPERTY(h);
3559*7c478bd9Sstevel@tonic-gate 
3560*7c478bd9Sstevel@tonic-gate 	return (scf_set_error(error));
3561*7c478bd9Sstevel@tonic-gate }
3562*7c478bd9Sstevel@tonic-gate 
3563*7c478bd9Sstevel@tonic-gate int
3564*7c478bd9Sstevel@tonic-gate scf_transaction_property_new(scf_transaction_t *tx,
3565*7c478bd9Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3566*7c478bd9Sstevel@tonic-gate {
3567*7c478bd9Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW,
3568*7c478bd9Sstevel@tonic-gate 	    prop, scf_type_to_protocol_type(type)));
3569*7c478bd9Sstevel@tonic-gate }
3570*7c478bd9Sstevel@tonic-gate 
3571*7c478bd9Sstevel@tonic-gate int
3572*7c478bd9Sstevel@tonic-gate scf_transaction_property_change(scf_transaction_t *tx,
3573*7c478bd9Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3574*7c478bd9Sstevel@tonic-gate {
3575*7c478bd9Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR,
3576*7c478bd9Sstevel@tonic-gate 	    prop, scf_type_to_protocol_type(type)));
3577*7c478bd9Sstevel@tonic-gate }
3578*7c478bd9Sstevel@tonic-gate 
3579*7c478bd9Sstevel@tonic-gate int
3580*7c478bd9Sstevel@tonic-gate scf_transaction_property_change_type(scf_transaction_t *tx,
3581*7c478bd9Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3582*7c478bd9Sstevel@tonic-gate {
3583*7c478bd9Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE,
3584*7c478bd9Sstevel@tonic-gate 	    prop, scf_type_to_protocol_type(type)));
3585*7c478bd9Sstevel@tonic-gate }
3586*7c478bd9Sstevel@tonic-gate 
3587*7c478bd9Sstevel@tonic-gate int
3588*7c478bd9Sstevel@tonic-gate scf_transaction_property_delete(scf_transaction_t *tx,
3589*7c478bd9Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop)
3590*7c478bd9Sstevel@tonic-gate {
3591*7c478bd9Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE,
3592*7c478bd9Sstevel@tonic-gate 	    prop, REP_PROTOCOL_TYPE_INVALID));
3593*7c478bd9Sstevel@tonic-gate }
3594*7c478bd9Sstevel@tonic-gate 
3595*7c478bd9Sstevel@tonic-gate #define	BAD_SIZE (-1UL)
3596*7c478bd9Sstevel@tonic-gate 
3597*7c478bd9Sstevel@tonic-gate static size_t
3598*7c478bd9Sstevel@tonic-gate commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t)
3599*7c478bd9Sstevel@tonic-gate {
3600*7c478bd9Sstevel@tonic-gate 	size_t len;
3601*7c478bd9Sstevel@tonic-gate 
3602*7c478bd9Sstevel@tonic-gate 	assert(val->value_type == t);
3603*7c478bd9Sstevel@tonic-gate 
3604*7c478bd9Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_OPAQUE) {
3605*7c478bd9Sstevel@tonic-gate 		len = scf_opaque_encode(data, val->value_value,
3606*7c478bd9Sstevel@tonic-gate 		    val->value_size);
3607*7c478bd9Sstevel@tonic-gate 	} else {
3608*7c478bd9Sstevel@tonic-gate 		if (data != NULL)
3609*7c478bd9Sstevel@tonic-gate 			len = strlcpy(data, val->value_value,
3610*7c478bd9Sstevel@tonic-gate 			    REP_PROTOCOL_VALUE_LEN);
3611*7c478bd9Sstevel@tonic-gate 		else
3612*7c478bd9Sstevel@tonic-gate 			len = strlen(val->value_value);
3613*7c478bd9Sstevel@tonic-gate 		if (len >= REP_PROTOCOL_VALUE_LEN)
3614*7c478bd9Sstevel@tonic-gate 			return (BAD_SIZE);
3615*7c478bd9Sstevel@tonic-gate 	}
3616*7c478bd9Sstevel@tonic-gate 	return (len + 1);	/* count the '\0' */
3617*7c478bd9Sstevel@tonic-gate }
3618*7c478bd9Sstevel@tonic-gate 
3619*7c478bd9Sstevel@tonic-gate static size_t
3620*7c478bd9Sstevel@tonic-gate commit_process(scf_transaction_entry_t *cur,
3621*7c478bd9Sstevel@tonic-gate     struct rep_protocol_transaction_cmd *out)
3622*7c478bd9Sstevel@tonic-gate {
3623*7c478bd9Sstevel@tonic-gate 	scf_value_t *child;
3624*7c478bd9Sstevel@tonic-gate 	size_t sz = 0;
3625*7c478bd9Sstevel@tonic-gate 	size_t len;
3626*7c478bd9Sstevel@tonic-gate 	caddr_t data = (caddr_t)out->rptc_data;
3627*7c478bd9Sstevel@tonic-gate 	caddr_t val_data;
3628*7c478bd9Sstevel@tonic-gate 
3629*7c478bd9Sstevel@tonic-gate 	if (out != NULL) {
3630*7c478bd9Sstevel@tonic-gate 		len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN);
3631*7c478bd9Sstevel@tonic-gate 
3632*7c478bd9Sstevel@tonic-gate 		out->rptc_action = cur->entry_action;
3633*7c478bd9Sstevel@tonic-gate 		out->rptc_type = cur->entry_type;
3634*7c478bd9Sstevel@tonic-gate 		out->rptc_name_len = len + 1;
3635*7c478bd9Sstevel@tonic-gate 	} else {
3636*7c478bd9Sstevel@tonic-gate 		len = strlen(cur->entry_property);
3637*7c478bd9Sstevel@tonic-gate 	}
3638*7c478bd9Sstevel@tonic-gate 
3639*7c478bd9Sstevel@tonic-gate 	if (len >= REP_PROTOCOL_NAME_LEN)
3640*7c478bd9Sstevel@tonic-gate 		return (BAD_SIZE);
3641*7c478bd9Sstevel@tonic-gate 
3642*7c478bd9Sstevel@tonic-gate 	len = TX_SIZE(len + 1);
3643*7c478bd9Sstevel@tonic-gate 
3644*7c478bd9Sstevel@tonic-gate 	sz += len;
3645*7c478bd9Sstevel@tonic-gate 	val_data = data + len;
3646*7c478bd9Sstevel@tonic-gate 
3647*7c478bd9Sstevel@tonic-gate 	for (child = cur->entry_head; child != NULL;
3648*7c478bd9Sstevel@tonic-gate 	    child = child->value_next) {
3649*7c478bd9Sstevel@tonic-gate 		assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE);
3650*7c478bd9Sstevel@tonic-gate 		if (out != NULL) {
3651*7c478bd9Sstevel@tonic-gate 			len = commit_value(val_data + sizeof (uint32_t), child,
3652*7c478bd9Sstevel@tonic-gate 			    cur->entry_type);
3653*7c478bd9Sstevel@tonic-gate 			/* LINTED alignment */
3654*7c478bd9Sstevel@tonic-gate 			*(uint32_t *)val_data = len;
3655*7c478bd9Sstevel@tonic-gate 		} else
3656*7c478bd9Sstevel@tonic-gate 			len = commit_value(NULL, child, cur->entry_type);
3657*7c478bd9Sstevel@tonic-gate 
3658*7c478bd9Sstevel@tonic-gate 		if (len == BAD_SIZE)
3659*7c478bd9Sstevel@tonic-gate 			return (BAD_SIZE);
3660*7c478bd9Sstevel@tonic-gate 
3661*7c478bd9Sstevel@tonic-gate 		len += sizeof (uint32_t);
3662*7c478bd9Sstevel@tonic-gate 		len = TX_SIZE(len);
3663*7c478bd9Sstevel@tonic-gate 
3664*7c478bd9Sstevel@tonic-gate 		sz += len;
3665*7c478bd9Sstevel@tonic-gate 		val_data += len;
3666*7c478bd9Sstevel@tonic-gate 	}
3667*7c478bd9Sstevel@tonic-gate 
3668*7c478bd9Sstevel@tonic-gate 	assert(val_data - data == sz);
3669*7c478bd9Sstevel@tonic-gate 
3670*7c478bd9Sstevel@tonic-gate 	if (out != NULL)
3671*7c478bd9Sstevel@tonic-gate 		out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz);
3672*7c478bd9Sstevel@tonic-gate 
3673*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz));
3674*7c478bd9Sstevel@tonic-gate }
3675*7c478bd9Sstevel@tonic-gate 
3676*7c478bd9Sstevel@tonic-gate int
3677*7c478bd9Sstevel@tonic-gate scf_transaction_commit(scf_transaction_t *tran)
3678*7c478bd9Sstevel@tonic-gate {
3679*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3680*7c478bd9Sstevel@tonic-gate 
3681*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_transaction_commit *request;
3682*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
3683*7c478bd9Sstevel@tonic-gate 	uintptr_t cmd;
3684*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *cur;
3685*7c478bd9Sstevel@tonic-gate 	size_t total, size;
3686*7c478bd9Sstevel@tonic-gate 	size_t request_size;
3687*7c478bd9Sstevel@tonic-gate 	size_t new_total;
3688*7c478bd9Sstevel@tonic-gate 	int r;
3689*7c478bd9Sstevel@tonic-gate 
3690*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3691*7c478bd9Sstevel@tonic-gate 	if (tran->tran_state != TRAN_STATE_SETUP ||
3692*7c478bd9Sstevel@tonic-gate 	    tran->tran_invalid) {
3693*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3694*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3695*7c478bd9Sstevel@tonic-gate 	}
3696*7c478bd9Sstevel@tonic-gate 
3697*7c478bd9Sstevel@tonic-gate 	total = 0;
3698*7c478bd9Sstevel@tonic-gate 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
3699*7c478bd9Sstevel@tonic-gate 	    cur = uu_list_next(tran->tran_props, cur)) {
3700*7c478bd9Sstevel@tonic-gate 		size = commit_process(cur, NULL);
3701*7c478bd9Sstevel@tonic-gate 		if (size == BAD_SIZE) {
3702*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&h->rh_lock);
3703*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INTERNAL));
3704*7c478bd9Sstevel@tonic-gate 		}
3705*7c478bd9Sstevel@tonic-gate 		assert(TX_SIZE(size) == size);
3706*7c478bd9Sstevel@tonic-gate 		total += size;
3707*7c478bd9Sstevel@tonic-gate 	}
3708*7c478bd9Sstevel@tonic-gate 
3709*7c478bd9Sstevel@tonic-gate 	request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total);
3710*7c478bd9Sstevel@tonic-gate 	request = alloca(request_size);
3711*7c478bd9Sstevel@tonic-gate 	(void) memset(request, '\0', request_size);
3712*7c478bd9Sstevel@tonic-gate 	request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT;
3713*7c478bd9Sstevel@tonic-gate 	request->rpr_entityid = tran->tran_pg.rd_d.rd_entity;
3714*7c478bd9Sstevel@tonic-gate 	request->rpr_size = request_size;
3715*7c478bd9Sstevel@tonic-gate 	cmd = (uintptr_t)request->rpr_cmd;
3716*7c478bd9Sstevel@tonic-gate 
3717*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&tran->tran_pg.rd_d);
3718*7c478bd9Sstevel@tonic-gate 
3719*7c478bd9Sstevel@tonic-gate 	new_total = 0;
3720*7c478bd9Sstevel@tonic-gate 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
3721*7c478bd9Sstevel@tonic-gate 	    cur = uu_list_next(tran->tran_props, cur)) {
3722*7c478bd9Sstevel@tonic-gate 		size = commit_process(cur, (void *)cmd);
3723*7c478bd9Sstevel@tonic-gate 		if (size == BAD_SIZE) {
3724*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&h->rh_lock);
3725*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INTERNAL));
3726*7c478bd9Sstevel@tonic-gate 		}
3727*7c478bd9Sstevel@tonic-gate 		cmd += size;
3728*7c478bd9Sstevel@tonic-gate 		new_total += size;
3729*7c478bd9Sstevel@tonic-gate 	}
3730*7c478bd9Sstevel@tonic-gate 	assert(new_total == total);
3731*7c478bd9Sstevel@tonic-gate 
3732*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, request, request_size,
3733*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
3734*7c478bd9Sstevel@tonic-gate 
3735*7c478bd9Sstevel@tonic-gate 	if (r < 0) {
3736*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3737*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
3738*7c478bd9Sstevel@tonic-gate 	}
3739*7c478bd9Sstevel@tonic-gate 
3740*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
3741*7c478bd9Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) {
3742*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3743*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
3744*7c478bd9Sstevel@tonic-gate 	}
3745*7c478bd9Sstevel@tonic-gate 
3746*7c478bd9Sstevel@tonic-gate 	tran->tran_state = TRAN_STATE_COMMITTED;
3747*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3748*7c478bd9Sstevel@tonic-gate 	return (response.rpr_response == REP_PROTOCOL_SUCCESS);
3749*7c478bd9Sstevel@tonic-gate }
3750*7c478bd9Sstevel@tonic-gate 
3751*7c478bd9Sstevel@tonic-gate static void
3752*7c478bd9Sstevel@tonic-gate transaction_reset(scf_transaction_t *tran)
3753*7c478bd9Sstevel@tonic-gate {
3754*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock));
3755*7c478bd9Sstevel@tonic-gate 
3756*7c478bd9Sstevel@tonic-gate 	tran->tran_state = TRAN_STATE_NEW;
3757*7c478bd9Sstevel@tonic-gate 	datael_reset_locked(&tran->tran_pg.rd_d);
3758*7c478bd9Sstevel@tonic-gate }
3759*7c478bd9Sstevel@tonic-gate 
3760*7c478bd9Sstevel@tonic-gate static void
3761*7c478bd9Sstevel@tonic-gate scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy,
3762*7c478bd9Sstevel@tonic-gate     int and_reset_value)
3763*7c478bd9Sstevel@tonic-gate {
3764*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *cur;
3765*7c478bd9Sstevel@tonic-gate 	void *cookie;
3766*7c478bd9Sstevel@tonic-gate 
3767*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&tran->tran_pg.rd_d.rd_handle->rh_lock);
3768*7c478bd9Sstevel@tonic-gate 	cookie = NULL;
3769*7c478bd9Sstevel@tonic-gate 	while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) {
3770*7c478bd9Sstevel@tonic-gate 		cur->entry_tx = NULL;
3771*7c478bd9Sstevel@tonic-gate 
3772*7c478bd9Sstevel@tonic-gate 		assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION);
3773*7c478bd9Sstevel@tonic-gate 		cur->entry_state = ENTRY_STATE_INVALID;
3774*7c478bd9Sstevel@tonic-gate 
3775*7c478bd9Sstevel@tonic-gate 		entry_invalidate(cur, and_destroy, and_reset_value);
3776*7c478bd9Sstevel@tonic-gate 		if (and_destroy)
3777*7c478bd9Sstevel@tonic-gate 			entry_destroy_locked(cur);
3778*7c478bd9Sstevel@tonic-gate 	}
3779*7c478bd9Sstevel@tonic-gate 	transaction_reset(tran);
3780*7c478bd9Sstevel@tonic-gate 	handle_unrefed(tran->tran_pg.rd_d.rd_handle);
3781*7c478bd9Sstevel@tonic-gate }
3782*7c478bd9Sstevel@tonic-gate 
3783*7c478bd9Sstevel@tonic-gate void
3784*7c478bd9Sstevel@tonic-gate scf_transaction_reset(scf_transaction_t *tran)
3785*7c478bd9Sstevel@tonic-gate {
3786*7c478bd9Sstevel@tonic-gate 	scf_transaction_reset_impl(tran, 0, 0);
3787*7c478bd9Sstevel@tonic-gate }
3788*7c478bd9Sstevel@tonic-gate 
3789*7c478bd9Sstevel@tonic-gate void
3790*7c478bd9Sstevel@tonic-gate scf_transaction_reset_all(scf_transaction_t *tran)
3791*7c478bd9Sstevel@tonic-gate {
3792*7c478bd9Sstevel@tonic-gate 	scf_transaction_reset_impl(tran, 0, 1);
3793*7c478bd9Sstevel@tonic-gate }
3794*7c478bd9Sstevel@tonic-gate 
3795*7c478bd9Sstevel@tonic-gate void
3796*7c478bd9Sstevel@tonic-gate scf_transaction_destroy(scf_transaction_t *val)
3797*7c478bd9Sstevel@tonic-gate {
3798*7c478bd9Sstevel@tonic-gate 	if (val == NULL)
3799*7c478bd9Sstevel@tonic-gate 		return;
3800*7c478bd9Sstevel@tonic-gate 
3801*7c478bd9Sstevel@tonic-gate 	scf_transaction_reset(val);
3802*7c478bd9Sstevel@tonic-gate 
3803*7c478bd9Sstevel@tonic-gate 	datael_destroy(&val->tran_pg.rd_d);
3804*7c478bd9Sstevel@tonic-gate 
3805*7c478bd9Sstevel@tonic-gate 	uu_list_destroy(val->tran_props);
3806*7c478bd9Sstevel@tonic-gate 	uu_free(val);
3807*7c478bd9Sstevel@tonic-gate }
3808*7c478bd9Sstevel@tonic-gate 
3809*7c478bd9Sstevel@tonic-gate void
3810*7c478bd9Sstevel@tonic-gate scf_transaction_destroy_children(scf_transaction_t *tran)
3811*7c478bd9Sstevel@tonic-gate {
3812*7c478bd9Sstevel@tonic-gate 	scf_transaction_reset_impl(tran, 1, 0);
3813*7c478bd9Sstevel@tonic-gate }
3814*7c478bd9Sstevel@tonic-gate 
3815*7c478bd9Sstevel@tonic-gate scf_transaction_entry_t *
3816*7c478bd9Sstevel@tonic-gate scf_entry_create(scf_handle_t *h)
3817*7c478bd9Sstevel@tonic-gate {
3818*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ret;
3819*7c478bd9Sstevel@tonic-gate 
3820*7c478bd9Sstevel@tonic-gate 	if (h == NULL) {
3821*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
3822*7c478bd9Sstevel@tonic-gate 		return (NULL);
3823*7c478bd9Sstevel@tonic-gate 	}
3824*7c478bd9Sstevel@tonic-gate 
3825*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (scf_transaction_entry_t));
3826*7c478bd9Sstevel@tonic-gate 	if (ret == NULL) {
3827*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3828*7c478bd9Sstevel@tonic-gate 		return (NULL);
3829*7c478bd9Sstevel@tonic-gate 	}
3830*7c478bd9Sstevel@tonic-gate 	ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
3831*7c478bd9Sstevel@tonic-gate 	ret->entry_handle = h;
3832*7c478bd9Sstevel@tonic-gate 
3833*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3834*7c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD) {
3835*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3836*7c478bd9Sstevel@tonic-gate 		uu_free(ret);
3837*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
3838*7c478bd9Sstevel@tonic-gate 		return (NULL);
3839*7c478bd9Sstevel@tonic-gate 	}
3840*7c478bd9Sstevel@tonic-gate 	h->rh_entries++;
3841*7c478bd9Sstevel@tonic-gate 	h->rh_extrefs++;
3842*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3843*7c478bd9Sstevel@tonic-gate 
3844*7c478bd9Sstevel@tonic-gate 	uu_list_node_init(ret, &ret->entry_link, tran_entry_pool);
3845*7c478bd9Sstevel@tonic-gate 
3846*7c478bd9Sstevel@tonic-gate 	return (ret);
3847*7c478bd9Sstevel@tonic-gate }
3848*7c478bd9Sstevel@tonic-gate 
3849*7c478bd9Sstevel@tonic-gate scf_handle_t *
3850*7c478bd9Sstevel@tonic-gate scf_entry_handle(const scf_transaction_entry_t *val)
3851*7c478bd9Sstevel@tonic-gate {
3852*7c478bd9Sstevel@tonic-gate 	return (handle_get(val->entry_handle));
3853*7c478bd9Sstevel@tonic-gate }
3854*7c478bd9Sstevel@tonic-gate 
3855*7c478bd9Sstevel@tonic-gate void
3856*7c478bd9Sstevel@tonic-gate scf_entry_reset(scf_transaction_entry_t *entry)
3857*7c478bd9Sstevel@tonic-gate {
3858*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
3859*7c478bd9Sstevel@tonic-gate 
3860*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3861*7c478bd9Sstevel@tonic-gate 	entry_invalidate(entry, 0, 0);
3862*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3863*7c478bd9Sstevel@tonic-gate }
3864*7c478bd9Sstevel@tonic-gate 
3865*7c478bd9Sstevel@tonic-gate void
3866*7c478bd9Sstevel@tonic-gate scf_entry_destroy_children(scf_transaction_entry_t *entry)
3867*7c478bd9Sstevel@tonic-gate {
3868*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
3869*7c478bd9Sstevel@tonic-gate 
3870*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3871*7c478bd9Sstevel@tonic-gate 	entry_invalidate(entry, 1, 0);
3872*7c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
3873*7c478bd9Sstevel@tonic-gate }
3874*7c478bd9Sstevel@tonic-gate 
3875*7c478bd9Sstevel@tonic-gate void
3876*7c478bd9Sstevel@tonic-gate scf_entry_destroy(scf_transaction_entry_t *entry)
3877*7c478bd9Sstevel@tonic-gate {
3878*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
3879*7c478bd9Sstevel@tonic-gate 
3880*7c478bd9Sstevel@tonic-gate 	if (entry == NULL)
3881*7c478bd9Sstevel@tonic-gate 		return;
3882*7c478bd9Sstevel@tonic-gate 
3883*7c478bd9Sstevel@tonic-gate 	h = entry->entry_handle;
3884*7c478bd9Sstevel@tonic-gate 
3885*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3886*7c478bd9Sstevel@tonic-gate 	entry_destroy_locked(entry);
3887*7c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
3888*7c478bd9Sstevel@tonic-gate }
3889*7c478bd9Sstevel@tonic-gate 
3890*7c478bd9Sstevel@tonic-gate /*
3891*7c478bd9Sstevel@tonic-gate  * Fails with
3892*7c478bd9Sstevel@tonic-gate  *   _HANDLE_MISMATCH
3893*7c478bd9Sstevel@tonic-gate  *   _NOT_SET - has not been added to a transaction
3894*7c478bd9Sstevel@tonic-gate  *   _INTERNAL - entry is corrupt
3895*7c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - entry's transaction is not started or corrupt
3896*7c478bd9Sstevel@tonic-gate  *			 entry is set to delete a property
3897*7c478bd9Sstevel@tonic-gate  *			 v is reset or corrupt
3898*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - entry & v's types aren't compatible
3899*7c478bd9Sstevel@tonic-gate  *   _IN_USE - v has been added to another entry
3900*7c478bd9Sstevel@tonic-gate  */
3901*7c478bd9Sstevel@tonic-gate int
3902*7c478bd9Sstevel@tonic-gate scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v)
3903*7c478bd9Sstevel@tonic-gate {
3904*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
3905*7c478bd9Sstevel@tonic-gate 
3906*7c478bd9Sstevel@tonic-gate 	if (h != v->value_handle)
3907*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3908*7c478bd9Sstevel@tonic-gate 
3909*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
3910*7c478bd9Sstevel@tonic-gate 
3911*7c478bd9Sstevel@tonic-gate 	if (entry->entry_state == ENTRY_STATE_INVALID) {
3912*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3913*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
3914*7c478bd9Sstevel@tonic-gate 	}
3915*7c478bd9Sstevel@tonic-gate 	assert(entry->entry_state == ENTRY_STATE_IN_TX_ACTION);
3916*7c478bd9Sstevel@tonic-gate 
3917*7c478bd9Sstevel@tonic-gate 	if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) {
3918*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3919*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3920*7c478bd9Sstevel@tonic-gate 	}
3921*7c478bd9Sstevel@tonic-gate 
3922*7c478bd9Sstevel@tonic-gate 	if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) {
3923*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3924*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3925*7c478bd9Sstevel@tonic-gate 	}
3926*7c478bd9Sstevel@tonic-gate 
3927*7c478bd9Sstevel@tonic-gate 	if (v->value_type == REP_PROTOCOL_TYPE_INVALID) {
3928*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3929*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3930*7c478bd9Sstevel@tonic-gate 	}
3931*7c478bd9Sstevel@tonic-gate 
3932*7c478bd9Sstevel@tonic-gate 	if (!scf_is_compatible_type(entry->entry_type, v->value_type)) {
3933*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3934*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3935*7c478bd9Sstevel@tonic-gate 	}
3936*7c478bd9Sstevel@tonic-gate 
3937*7c478bd9Sstevel@tonic-gate 	if (v->value_tx != NULL) {
3938*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3939*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
3940*7c478bd9Sstevel@tonic-gate 	}
3941*7c478bd9Sstevel@tonic-gate 
3942*7c478bd9Sstevel@tonic-gate 	v->value_tx = entry;
3943*7c478bd9Sstevel@tonic-gate 	v->value_next = entry->entry_head;
3944*7c478bd9Sstevel@tonic-gate 	entry->entry_head = v;
3945*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
3946*7c478bd9Sstevel@tonic-gate 
3947*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
3948*7c478bd9Sstevel@tonic-gate }
3949*7c478bd9Sstevel@tonic-gate 
3950*7c478bd9Sstevel@tonic-gate /*
3951*7c478bd9Sstevel@tonic-gate  * value functions
3952*7c478bd9Sstevel@tonic-gate  */
3953*7c478bd9Sstevel@tonic-gate scf_value_t *
3954*7c478bd9Sstevel@tonic-gate scf_value_create(scf_handle_t *h)
3955*7c478bd9Sstevel@tonic-gate {
3956*7c478bd9Sstevel@tonic-gate 	scf_value_t *ret;
3957*7c478bd9Sstevel@tonic-gate 
3958*7c478bd9Sstevel@tonic-gate 	if (h == NULL) {
3959*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
3960*7c478bd9Sstevel@tonic-gate 		return (NULL);
3961*7c478bd9Sstevel@tonic-gate 	}
3962*7c478bd9Sstevel@tonic-gate 
3963*7c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
3964*7c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
3965*7c478bd9Sstevel@tonic-gate 		ret->value_type = REP_PROTOCOL_TYPE_INVALID;
3966*7c478bd9Sstevel@tonic-gate 		ret->value_handle = h;
3967*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&h->rh_lock);
3968*7c478bd9Sstevel@tonic-gate 		if (h->rh_flags & HANDLE_DEAD) {
3969*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&h->rh_lock);
3970*7c478bd9Sstevel@tonic-gate 			uu_free(ret);
3971*7c478bd9Sstevel@tonic-gate 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
3972*7c478bd9Sstevel@tonic-gate 			return (NULL);
3973*7c478bd9Sstevel@tonic-gate 		}
3974*7c478bd9Sstevel@tonic-gate 		h->rh_values++;
3975*7c478bd9Sstevel@tonic-gate 		h->rh_extrefs++;
3976*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
3977*7c478bd9Sstevel@tonic-gate 	} else {
3978*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3979*7c478bd9Sstevel@tonic-gate 	}
3980*7c478bd9Sstevel@tonic-gate 
3981*7c478bd9Sstevel@tonic-gate 	return (ret);
3982*7c478bd9Sstevel@tonic-gate }
3983*7c478bd9Sstevel@tonic-gate 
3984*7c478bd9Sstevel@tonic-gate static void
3985*7c478bd9Sstevel@tonic-gate scf_value_reset_locked(scf_value_t *val, int and_destroy)
3986*7c478bd9Sstevel@tonic-gate {
3987*7c478bd9Sstevel@tonic-gate 	scf_value_t **curp;
3988*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *te;
3989*7c478bd9Sstevel@tonic-gate 
3990*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
3991*7c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
3992*7c478bd9Sstevel@tonic-gate 	if (val->value_tx != NULL) {
3993*7c478bd9Sstevel@tonic-gate 		te = val->value_tx;
3994*7c478bd9Sstevel@tonic-gate 		te->entry_tx->tran_invalid = 1;
3995*7c478bd9Sstevel@tonic-gate 
3996*7c478bd9Sstevel@tonic-gate 		val->value_tx = NULL;
3997*7c478bd9Sstevel@tonic-gate 
3998*7c478bd9Sstevel@tonic-gate 		for (curp = &te->entry_head; *curp != NULL;
3999*7c478bd9Sstevel@tonic-gate 		    curp = &(*curp)->value_next) {
4000*7c478bd9Sstevel@tonic-gate 			if (*curp == val) {
4001*7c478bd9Sstevel@tonic-gate 				*curp = val->value_next;
4002*7c478bd9Sstevel@tonic-gate 				curp = NULL;
4003*7c478bd9Sstevel@tonic-gate 				break;
4004*7c478bd9Sstevel@tonic-gate 			}
4005*7c478bd9Sstevel@tonic-gate 		}
4006*7c478bd9Sstevel@tonic-gate 		assert(curp == NULL);
4007*7c478bd9Sstevel@tonic-gate 	}
4008*7c478bd9Sstevel@tonic-gate 	val->value_type = REP_PROTOCOL_TYPE_INVALID;
4009*7c478bd9Sstevel@tonic-gate 
4010*7c478bd9Sstevel@tonic-gate 	if (and_destroy) {
4011*7c478bd9Sstevel@tonic-gate 		val->value_handle = NULL;
4012*7c478bd9Sstevel@tonic-gate 		assert(h->rh_values > 0);
4013*7c478bd9Sstevel@tonic-gate 		--h->rh_values;
4014*7c478bd9Sstevel@tonic-gate 		--h->rh_extrefs;
4015*7c478bd9Sstevel@tonic-gate 		uu_free(val);
4016*7c478bd9Sstevel@tonic-gate 	}
4017*7c478bd9Sstevel@tonic-gate }
4018*7c478bd9Sstevel@tonic-gate 
4019*7c478bd9Sstevel@tonic-gate void
4020*7c478bd9Sstevel@tonic-gate scf_value_reset(scf_value_t *val)
4021*7c478bd9Sstevel@tonic-gate {
4022*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4023*7c478bd9Sstevel@tonic-gate 
4024*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4025*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(val, 0);
4026*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4027*7c478bd9Sstevel@tonic-gate }
4028*7c478bd9Sstevel@tonic-gate 
4029*7c478bd9Sstevel@tonic-gate scf_handle_t *
4030*7c478bd9Sstevel@tonic-gate scf_value_handle(const scf_value_t *val)
4031*7c478bd9Sstevel@tonic-gate {
4032*7c478bd9Sstevel@tonic-gate 	return (handle_get(val->value_handle));
4033*7c478bd9Sstevel@tonic-gate }
4034*7c478bd9Sstevel@tonic-gate 
4035*7c478bd9Sstevel@tonic-gate void
4036*7c478bd9Sstevel@tonic-gate scf_value_destroy(scf_value_t *val)
4037*7c478bd9Sstevel@tonic-gate {
4038*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
4039*7c478bd9Sstevel@tonic-gate 
4040*7c478bd9Sstevel@tonic-gate 	if (val == NULL)
4041*7c478bd9Sstevel@tonic-gate 		return;
4042*7c478bd9Sstevel@tonic-gate 
4043*7c478bd9Sstevel@tonic-gate 	h = val->value_handle;
4044*7c478bd9Sstevel@tonic-gate 
4045*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4046*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(val, 1);
4047*7c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
4048*7c478bd9Sstevel@tonic-gate }
4049*7c478bd9Sstevel@tonic-gate 
4050*7c478bd9Sstevel@tonic-gate scf_type_t
4051*7c478bd9Sstevel@tonic-gate scf_value_base_type(const scf_value_t *val)
4052*7c478bd9Sstevel@tonic-gate {
4053*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t, cur;
4054*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4055*7c478bd9Sstevel@tonic-gate 
4056*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4057*7c478bd9Sstevel@tonic-gate 	t = val->value_type;
4058*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4059*7c478bd9Sstevel@tonic-gate 
4060*7c478bd9Sstevel@tonic-gate 	for (;;) {
4061*7c478bd9Sstevel@tonic-gate 		cur = scf_proto_underlying_type(t);
4062*7c478bd9Sstevel@tonic-gate 		if (cur == t)
4063*7c478bd9Sstevel@tonic-gate 			break;
4064*7c478bd9Sstevel@tonic-gate 		t = cur;
4065*7c478bd9Sstevel@tonic-gate 	}
4066*7c478bd9Sstevel@tonic-gate 
4067*7c478bd9Sstevel@tonic-gate 	return (scf_protocol_type_to_type(t));
4068*7c478bd9Sstevel@tonic-gate }
4069*7c478bd9Sstevel@tonic-gate 
4070*7c478bd9Sstevel@tonic-gate scf_type_t
4071*7c478bd9Sstevel@tonic-gate scf_value_type(const scf_value_t *val)
4072*7c478bd9Sstevel@tonic-gate {
4073*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t;
4074*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4075*7c478bd9Sstevel@tonic-gate 
4076*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4077*7c478bd9Sstevel@tonic-gate 	t = val->value_type;
4078*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4079*7c478bd9Sstevel@tonic-gate 
4080*7c478bd9Sstevel@tonic-gate 	return (scf_protocol_type_to_type(t));
4081*7c478bd9Sstevel@tonic-gate }
4082*7c478bd9Sstevel@tonic-gate 
4083*7c478bd9Sstevel@tonic-gate int
4084*7c478bd9Sstevel@tonic-gate scf_value_is_type(const scf_value_t *val, scf_type_t base_arg)
4085*7c478bd9Sstevel@tonic-gate {
4086*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t;
4087*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
4088*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4089*7c478bd9Sstevel@tonic-gate 
4090*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4091*7c478bd9Sstevel@tonic-gate 	t = val->value_type;
4092*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4093*7c478bd9Sstevel@tonic-gate 
4094*7c478bd9Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_INVALID)
4095*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
4096*7c478bd9Sstevel@tonic-gate 	if (base == REP_PROTOCOL_TYPE_INVALID)
4097*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4098*7c478bd9Sstevel@tonic-gate 	if (!scf_is_compatible_type(base, t))
4099*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4100*7c478bd9Sstevel@tonic-gate 
4101*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
4102*7c478bd9Sstevel@tonic-gate }
4103*7c478bd9Sstevel@tonic-gate 
4104*7c478bd9Sstevel@tonic-gate /*
4105*7c478bd9Sstevel@tonic-gate  * Fails with
4106*7c478bd9Sstevel@tonic-gate  *   _NOT_SET - val is reset
4107*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - val's type is not compatible with t
4108*7c478bd9Sstevel@tonic-gate  */
4109*7c478bd9Sstevel@tonic-gate static int
4110*7c478bd9Sstevel@tonic-gate scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t)
4111*7c478bd9Sstevel@tonic-gate {
4112*7c478bd9Sstevel@tonic-gate 	if (val->value_type == REP_PROTOCOL_TYPE_INVALID) {
4113*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NOT_SET);
4114*7c478bd9Sstevel@tonic-gate 		return (0);
4115*7c478bd9Sstevel@tonic-gate 	}
4116*7c478bd9Sstevel@tonic-gate 	if (!scf_is_compatible_type(t, val->value_type)) {
4117*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
4118*7c478bd9Sstevel@tonic-gate 		return (0);
4119*7c478bd9Sstevel@tonic-gate 	}
4120*7c478bd9Sstevel@tonic-gate 	return (1);
4121*7c478bd9Sstevel@tonic-gate }
4122*7c478bd9Sstevel@tonic-gate 
4123*7c478bd9Sstevel@tonic-gate /*
4124*7c478bd9Sstevel@tonic-gate  * Fails with
4125*7c478bd9Sstevel@tonic-gate  *   _NOT_SET - val is reset
4126*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
4127*7c478bd9Sstevel@tonic-gate  */
4128*7c478bd9Sstevel@tonic-gate int
4129*7c478bd9Sstevel@tonic-gate scf_value_get_boolean(const scf_value_t *val, uint8_t *out)
4130*7c478bd9Sstevel@tonic-gate {
4131*7c478bd9Sstevel@tonic-gate 	char c;
4132*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4133*7c478bd9Sstevel@tonic-gate 	uint8_t o;
4134*7c478bd9Sstevel@tonic-gate 
4135*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4136*7c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) {
4137*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4138*7c478bd9Sstevel@tonic-gate 		return (-1);
4139*7c478bd9Sstevel@tonic-gate 	}
4140*7c478bd9Sstevel@tonic-gate 
4141*7c478bd9Sstevel@tonic-gate 	c = val->value_value[0];
4142*7c478bd9Sstevel@tonic-gate 	assert((c == '0' || c == '1') && val->value_value[1] == 0);
4143*7c478bd9Sstevel@tonic-gate 
4144*7c478bd9Sstevel@tonic-gate 	o = (c != '0');
4145*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4146*7c478bd9Sstevel@tonic-gate 	if (out != NULL)
4147*7c478bd9Sstevel@tonic-gate 		*out = o;
4148*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
4149*7c478bd9Sstevel@tonic-gate }
4150*7c478bd9Sstevel@tonic-gate 
4151*7c478bd9Sstevel@tonic-gate int
4152*7c478bd9Sstevel@tonic-gate scf_value_get_count(const scf_value_t *val, uint64_t *out)
4153*7c478bd9Sstevel@tonic-gate {
4154*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4155*7c478bd9Sstevel@tonic-gate 	uint64_t o;
4156*7c478bd9Sstevel@tonic-gate 
4157*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4158*7c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) {
4159*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4160*7c478bd9Sstevel@tonic-gate 		return (-1);
4161*7c478bd9Sstevel@tonic-gate 	}
4162*7c478bd9Sstevel@tonic-gate 
4163*7c478bd9Sstevel@tonic-gate 	o = strtoull(val->value_value, NULL, 10);
4164*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4165*7c478bd9Sstevel@tonic-gate 	if (out != NULL)
4166*7c478bd9Sstevel@tonic-gate 		*out = o;
4167*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
4168*7c478bd9Sstevel@tonic-gate }
4169*7c478bd9Sstevel@tonic-gate 
4170*7c478bd9Sstevel@tonic-gate int
4171*7c478bd9Sstevel@tonic-gate scf_value_get_integer(const scf_value_t *val, int64_t *out)
4172*7c478bd9Sstevel@tonic-gate {
4173*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4174*7c478bd9Sstevel@tonic-gate 	int64_t o;
4175*7c478bd9Sstevel@tonic-gate 
4176*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4177*7c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) {
4178*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4179*7c478bd9Sstevel@tonic-gate 		return (-1);
4180*7c478bd9Sstevel@tonic-gate 	}
4181*7c478bd9Sstevel@tonic-gate 
4182*7c478bd9Sstevel@tonic-gate 	o = strtoll(val->value_value, NULL, 10);
4183*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4184*7c478bd9Sstevel@tonic-gate 	if (out != NULL)
4185*7c478bd9Sstevel@tonic-gate 		*out = o;
4186*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
4187*7c478bd9Sstevel@tonic-gate }
4188*7c478bd9Sstevel@tonic-gate 
4189*7c478bd9Sstevel@tonic-gate int
4190*7c478bd9Sstevel@tonic-gate scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out)
4191*7c478bd9Sstevel@tonic-gate {
4192*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4193*7c478bd9Sstevel@tonic-gate 	char *p;
4194*7c478bd9Sstevel@tonic-gate 	int64_t os;
4195*7c478bd9Sstevel@tonic-gate 	int32_t ons;
4196*7c478bd9Sstevel@tonic-gate 
4197*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4198*7c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) {
4199*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4200*7c478bd9Sstevel@tonic-gate 		return (-1);
4201*7c478bd9Sstevel@tonic-gate 	}
4202*7c478bd9Sstevel@tonic-gate 
4203*7c478bd9Sstevel@tonic-gate 	os = strtoll(val->value_value, &p, 10);
4204*7c478bd9Sstevel@tonic-gate 	if (*p == '.')
4205*7c478bd9Sstevel@tonic-gate 		ons = strtoul(p + 1, NULL, 10);
4206*7c478bd9Sstevel@tonic-gate 	else
4207*7c478bd9Sstevel@tonic-gate 		ons = 0;
4208*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4209*7c478bd9Sstevel@tonic-gate 	if (sec_out != NULL)
4210*7c478bd9Sstevel@tonic-gate 		*sec_out = os;
4211*7c478bd9Sstevel@tonic-gate 	if (nsec_out != NULL)
4212*7c478bd9Sstevel@tonic-gate 		*nsec_out = ons;
4213*7c478bd9Sstevel@tonic-gate 
4214*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
4215*7c478bd9Sstevel@tonic-gate }
4216*7c478bd9Sstevel@tonic-gate 
4217*7c478bd9Sstevel@tonic-gate /*
4218*7c478bd9Sstevel@tonic-gate  * Fails with
4219*7c478bd9Sstevel@tonic-gate  *   _NOT_SET - val is reset
4220*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
4221*7c478bd9Sstevel@tonic-gate  */
4222*7c478bd9Sstevel@tonic-gate ssize_t
4223*7c478bd9Sstevel@tonic-gate scf_value_get_astring(const scf_value_t *val, char *out, size_t len)
4224*7c478bd9Sstevel@tonic-gate {
4225*7c478bd9Sstevel@tonic-gate 	ssize_t ret;
4226*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4227*7c478bd9Sstevel@tonic-gate 
4228*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4229*7c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) {
4230*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4231*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)-1);
4232*7c478bd9Sstevel@tonic-gate 	}
4233*7c478bd9Sstevel@tonic-gate 	ret = (ssize_t)strlcpy(out, val->value_value, len);
4234*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4235*7c478bd9Sstevel@tonic-gate 	return (ret);
4236*7c478bd9Sstevel@tonic-gate }
4237*7c478bd9Sstevel@tonic-gate 
4238*7c478bd9Sstevel@tonic-gate ssize_t
4239*7c478bd9Sstevel@tonic-gate scf_value_get_ustring(const scf_value_t *val, char *out, size_t len)
4240*7c478bd9Sstevel@tonic-gate {
4241*7c478bd9Sstevel@tonic-gate 	ssize_t ret;
4242*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
4243*7c478bd9Sstevel@tonic-gate 
4244*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4245*7c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) {
4246*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4247*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)-1);
4248*7c478bd9Sstevel@tonic-gate 	}
4249*7c478bd9Sstevel@tonic-gate 	ret = (ssize_t)strlcpy(out, val->value_value, len);
4250*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4251*7c478bd9Sstevel@tonic-gate 	return (ret);
4252*7c478bd9Sstevel@tonic-gate }
4253*7c478bd9Sstevel@tonic-gate 
4254*7c478bd9Sstevel@tonic-gate ssize_t
4255*7c478bd9Sstevel@tonic-gate scf_value_get_opaque(const scf_value_t *v, void *out, size_t len)
4256*7c478bd9Sstevel@tonic-gate {
4257*7c478bd9Sstevel@tonic-gate 	ssize_t ret;
4258*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
4259*7c478bd9Sstevel@tonic-gate 
4260*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4261*7c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) {
4262*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4263*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)-1);
4264*7c478bd9Sstevel@tonic-gate 	}
4265*7c478bd9Sstevel@tonic-gate 	if (len > v->value_size)
4266*7c478bd9Sstevel@tonic-gate 		len = v->value_size;
4267*7c478bd9Sstevel@tonic-gate 	ret = len;
4268*7c478bd9Sstevel@tonic-gate 
4269*7c478bd9Sstevel@tonic-gate 	(void) memcpy(out, v->value_value, len);
4270*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4271*7c478bd9Sstevel@tonic-gate 	return (ret);
4272*7c478bd9Sstevel@tonic-gate }
4273*7c478bd9Sstevel@tonic-gate 
4274*7c478bd9Sstevel@tonic-gate void
4275*7c478bd9Sstevel@tonic-gate scf_value_set_boolean(scf_value_t *v, uint8_t new)
4276*7c478bd9Sstevel@tonic-gate {
4277*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
4278*7c478bd9Sstevel@tonic-gate 
4279*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4280*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
4281*7c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_BOOLEAN;
4282*7c478bd9Sstevel@tonic-gate 	(void) sprintf(v->value_value, "%d", (new != 0));
4283*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4284*7c478bd9Sstevel@tonic-gate }
4285*7c478bd9Sstevel@tonic-gate 
4286*7c478bd9Sstevel@tonic-gate void
4287*7c478bd9Sstevel@tonic-gate scf_value_set_count(scf_value_t *v, uint64_t new)
4288*7c478bd9Sstevel@tonic-gate {
4289*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
4290*7c478bd9Sstevel@tonic-gate 
4291*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4292*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
4293*7c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_COUNT;
4294*7c478bd9Sstevel@tonic-gate 	(void) sprintf(v->value_value, "%llu", (unsigned long long)new);
4295*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4296*7c478bd9Sstevel@tonic-gate }
4297*7c478bd9Sstevel@tonic-gate 
4298*7c478bd9Sstevel@tonic-gate void
4299*7c478bd9Sstevel@tonic-gate scf_value_set_integer(scf_value_t *v, int64_t new)
4300*7c478bd9Sstevel@tonic-gate {
4301*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
4302*7c478bd9Sstevel@tonic-gate 
4303*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4304*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
4305*7c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_INTEGER;
4306*7c478bd9Sstevel@tonic-gate 	(void) sprintf(v->value_value, "%lld", (long long)new);
4307*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4308*7c478bd9Sstevel@tonic-gate }
4309*7c478bd9Sstevel@tonic-gate 
4310*7c478bd9Sstevel@tonic-gate int
4311*7c478bd9Sstevel@tonic-gate scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec)
4312*7c478bd9Sstevel@tonic-gate {
4313*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
4314*7c478bd9Sstevel@tonic-gate 
4315*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4316*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
4317*7c478bd9Sstevel@tonic-gate 	if (new_nsec < 0 || new_nsec >= NANOSEC) {
4318*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4319*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4320*7c478bd9Sstevel@tonic-gate 	}
4321*7c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_TIME;
4322*7c478bd9Sstevel@tonic-gate 	if (new_nsec == 0)
4323*7c478bd9Sstevel@tonic-gate 		(void) sprintf(v->value_value, "%lld", (long long)new_sec);
4324*7c478bd9Sstevel@tonic-gate 	else
4325*7c478bd9Sstevel@tonic-gate 		(void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec,
4326*7c478bd9Sstevel@tonic-gate 		    (unsigned)new_nsec);
4327*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4328*7c478bd9Sstevel@tonic-gate 	return (0);
4329*7c478bd9Sstevel@tonic-gate }
4330*7c478bd9Sstevel@tonic-gate 
4331*7c478bd9Sstevel@tonic-gate int
4332*7c478bd9Sstevel@tonic-gate scf_value_set_astring(scf_value_t *v, const char *new)
4333*7c478bd9Sstevel@tonic-gate {
4334*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
4335*7c478bd9Sstevel@tonic-gate 
4336*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4337*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
4338*7c478bd9Sstevel@tonic-gate 	if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) {
4339*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4340*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4341*7c478bd9Sstevel@tonic-gate 	}
4342*7c478bd9Sstevel@tonic-gate 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4343*7c478bd9Sstevel@tonic-gate 	    sizeof (v->value_value)) {
4344*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4345*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4346*7c478bd9Sstevel@tonic-gate 	}
4347*7c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_STRING;
4348*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4349*7c478bd9Sstevel@tonic-gate 	return (0);
4350*7c478bd9Sstevel@tonic-gate }
4351*7c478bd9Sstevel@tonic-gate 
4352*7c478bd9Sstevel@tonic-gate int
4353*7c478bd9Sstevel@tonic-gate scf_value_set_ustring(scf_value_t *v, const char *new)
4354*7c478bd9Sstevel@tonic-gate {
4355*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
4356*7c478bd9Sstevel@tonic-gate 
4357*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4358*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
4359*7c478bd9Sstevel@tonic-gate 	if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) {
4360*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4361*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4362*7c478bd9Sstevel@tonic-gate 	}
4363*7c478bd9Sstevel@tonic-gate 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4364*7c478bd9Sstevel@tonic-gate 	    sizeof (v->value_value)) {
4365*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4366*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4367*7c478bd9Sstevel@tonic-gate 	}
4368*7c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_SUBTYPE_USTRING;
4369*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4370*7c478bd9Sstevel@tonic-gate 	return (0);
4371*7c478bd9Sstevel@tonic-gate }
4372*7c478bd9Sstevel@tonic-gate 
4373*7c478bd9Sstevel@tonic-gate int
4374*7c478bd9Sstevel@tonic-gate scf_value_set_opaque(scf_value_t *v, const void *new, size_t len)
4375*7c478bd9Sstevel@tonic-gate {
4376*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
4377*7c478bd9Sstevel@tonic-gate 
4378*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4379*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
4380*7c478bd9Sstevel@tonic-gate 	if (len > sizeof (v->value_value)) {
4381*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4382*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4383*7c478bd9Sstevel@tonic-gate 	}
4384*7c478bd9Sstevel@tonic-gate 	(void) memcpy(v->value_value, new, len);
4385*7c478bd9Sstevel@tonic-gate 	v->value_size = len;
4386*7c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_OPAQUE;
4387*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4388*7c478bd9Sstevel@tonic-gate 	return (0);
4389*7c478bd9Sstevel@tonic-gate }
4390*7c478bd9Sstevel@tonic-gate 
4391*7c478bd9Sstevel@tonic-gate /*
4392*7c478bd9Sstevel@tonic-gate  * Fails with
4393*7c478bd9Sstevel@tonic-gate  *   _NOT_SET - v_arg is reset
4394*7c478bd9Sstevel@tonic-gate  *   _INTERNAL - v_arg is corrupt
4395*7c478bd9Sstevel@tonic-gate  *
4396*7c478bd9Sstevel@tonic-gate  * If t is not _TYPE_INVALID, fails with
4397*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - v_arg's type is not compatible with t
4398*7c478bd9Sstevel@tonic-gate  */
4399*7c478bd9Sstevel@tonic-gate static ssize_t
4400*7c478bd9Sstevel@tonic-gate scf_value_get_as_string_common(const scf_value_t *v_arg,
4401*7c478bd9Sstevel@tonic-gate     rep_protocol_value_type_t t, char *buf, size_t bufsz)
4402*7c478bd9Sstevel@tonic-gate {
4403*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v_arg->value_handle;
4404*7c478bd9Sstevel@tonic-gate 	scf_value_t v_s;
4405*7c478bd9Sstevel@tonic-gate 	scf_value_t *v = &v_s;
4406*7c478bd9Sstevel@tonic-gate 	ssize_t r;
4407*7c478bd9Sstevel@tonic-gate 	uint8_t b;
4408*7c478bd9Sstevel@tonic-gate 
4409*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4410*7c478bd9Sstevel@tonic-gate 	if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) {
4411*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4412*7c478bd9Sstevel@tonic-gate 		return (-1);
4413*7c478bd9Sstevel@tonic-gate 	}
4414*7c478bd9Sstevel@tonic-gate 
4415*7c478bd9Sstevel@tonic-gate 	v_s = *v_arg;			/* copy locally so we can unlock */
4416*7c478bd9Sstevel@tonic-gate 	h->rh_values++;			/* keep the handle from going away */
4417*7c478bd9Sstevel@tonic-gate 	h->rh_extrefs++;
4418*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4419*7c478bd9Sstevel@tonic-gate 
4420*7c478bd9Sstevel@tonic-gate 
4421*7c478bd9Sstevel@tonic-gate 	switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) {
4422*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_BOOLEAN:
4423*7c478bd9Sstevel@tonic-gate 		r = scf_value_get_boolean(v, &b);
4424*7c478bd9Sstevel@tonic-gate 		assert(r == SCF_SUCCESS);
4425*7c478bd9Sstevel@tonic-gate 
4426*7c478bd9Sstevel@tonic-gate 		r = strlcpy(buf, b ? "true" : "false", bufsz);
4427*7c478bd9Sstevel@tonic-gate 		break;
4428*7c478bd9Sstevel@tonic-gate 
4429*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_COUNT:
4430*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_INTEGER:
4431*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_TIME:
4432*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_STRING:
4433*7c478bd9Sstevel@tonic-gate 		r = strlcpy(buf, v->value_value, bufsz);
4434*7c478bd9Sstevel@tonic-gate 		break;
4435*7c478bd9Sstevel@tonic-gate 
4436*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_OPAQUE:
4437*7c478bd9Sstevel@tonic-gate 		/*
4438*7c478bd9Sstevel@tonic-gate 		 * Note that we only write out full hex bytes -- if they're
4439*7c478bd9Sstevel@tonic-gate 		 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
4440*7c478bd9Sstevel@tonic-gate 		 * with data.
4441*7c478bd9Sstevel@tonic-gate 		 */
4442*7c478bd9Sstevel@tonic-gate 		if (bufsz > 0)
4443*7c478bd9Sstevel@tonic-gate 			(void) scf_opaque_encode(buf, v->value_value,
4444*7c478bd9Sstevel@tonic-gate 			    MIN(v->value_size, (bufsz - 1)/2));
4445*7c478bd9Sstevel@tonic-gate 		r = (v->value_size * 2);
4446*7c478bd9Sstevel@tonic-gate 		break;
4447*7c478bd9Sstevel@tonic-gate 
4448*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_INVALID:
4449*7c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_NOT_SET);
4450*7c478bd9Sstevel@tonic-gate 		break;
4451*7c478bd9Sstevel@tonic-gate 
4452*7c478bd9Sstevel@tonic-gate 	default:
4453*7c478bd9Sstevel@tonic-gate 		r = (scf_set_error(SCF_ERROR_INTERNAL));
4454*7c478bd9Sstevel@tonic-gate 		break;
4455*7c478bd9Sstevel@tonic-gate 	}
4456*7c478bd9Sstevel@tonic-gate 
4457*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4458*7c478bd9Sstevel@tonic-gate 	h->rh_values--;
4459*7c478bd9Sstevel@tonic-gate 	h->rh_extrefs--;
4460*7c478bd9Sstevel@tonic-gate 	handle_unrefed(h);
4461*7c478bd9Sstevel@tonic-gate 
4462*7c478bd9Sstevel@tonic-gate 	return (r);
4463*7c478bd9Sstevel@tonic-gate }
4464*7c478bd9Sstevel@tonic-gate 
4465*7c478bd9Sstevel@tonic-gate ssize_t
4466*7c478bd9Sstevel@tonic-gate scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz)
4467*7c478bd9Sstevel@tonic-gate {
4468*7c478bd9Sstevel@tonic-gate 	return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID,
4469*7c478bd9Sstevel@tonic-gate 	    buf, bufsz));
4470*7c478bd9Sstevel@tonic-gate }
4471*7c478bd9Sstevel@tonic-gate 
4472*7c478bd9Sstevel@tonic-gate ssize_t
4473*7c478bd9Sstevel@tonic-gate scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type,
4474*7c478bd9Sstevel@tonic-gate     char *buf, size_t bufsz)
4475*7c478bd9Sstevel@tonic-gate {
4476*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t ty = scf_type_to_protocol_type(type);
4477*7c478bd9Sstevel@tonic-gate 	if (ty == REP_PROTOCOL_TYPE_INVALID)
4478*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4479*7c478bd9Sstevel@tonic-gate 
4480*7c478bd9Sstevel@tonic-gate 	return (scf_value_get_as_string_common(v, ty, buf, bufsz));
4481*7c478bd9Sstevel@tonic-gate }
4482*7c478bd9Sstevel@tonic-gate 
4483*7c478bd9Sstevel@tonic-gate int
4484*7c478bd9Sstevel@tonic-gate scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str)
4485*7c478bd9Sstevel@tonic-gate {
4486*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
4487*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t ty;
4488*7c478bd9Sstevel@tonic-gate 
4489*7c478bd9Sstevel@tonic-gate 	switch (type) {
4490*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN: {
4491*7c478bd9Sstevel@tonic-gate 		uint8_t b;
4492*7c478bd9Sstevel@tonic-gate 
4493*7c478bd9Sstevel@tonic-gate 		if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 ||
4494*7c478bd9Sstevel@tonic-gate 		    strcmp(str, "1") == 0)
4495*7c478bd9Sstevel@tonic-gate 			b = 1;
4496*7c478bd9Sstevel@tonic-gate 		else if (strcmp(str, "false") == 0 ||
4497*7c478bd9Sstevel@tonic-gate 		    strcmp(str, "f") == 0 || strcmp(str, "0") == 0)
4498*7c478bd9Sstevel@tonic-gate 			b = 0;
4499*7c478bd9Sstevel@tonic-gate 		else {
4500*7c478bd9Sstevel@tonic-gate 			goto bad;
4501*7c478bd9Sstevel@tonic-gate 		}
4502*7c478bd9Sstevel@tonic-gate 
4503*7c478bd9Sstevel@tonic-gate 		scf_value_set_boolean(v, b);
4504*7c478bd9Sstevel@tonic-gate 		return (0);
4505*7c478bd9Sstevel@tonic-gate 	}
4506*7c478bd9Sstevel@tonic-gate 
4507*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_COUNT: {
4508*7c478bd9Sstevel@tonic-gate 		uint64_t c;
4509*7c478bd9Sstevel@tonic-gate 		char *endp;
4510*7c478bd9Sstevel@tonic-gate 
4511*7c478bd9Sstevel@tonic-gate 		errno = 0;
4512*7c478bd9Sstevel@tonic-gate 		c = strtoul(str, &endp, 0);
4513*7c478bd9Sstevel@tonic-gate 
4514*7c478bd9Sstevel@tonic-gate 		if (errno != 0 || endp == str || *endp != '\0')
4515*7c478bd9Sstevel@tonic-gate 			goto bad;
4516*7c478bd9Sstevel@tonic-gate 
4517*7c478bd9Sstevel@tonic-gate 		scf_value_set_count(v, c);
4518*7c478bd9Sstevel@tonic-gate 		return (0);
4519*7c478bd9Sstevel@tonic-gate 	}
4520*7c478bd9Sstevel@tonic-gate 
4521*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_INTEGER: {
4522*7c478bd9Sstevel@tonic-gate 		int64_t i;
4523*7c478bd9Sstevel@tonic-gate 		char *endp;
4524*7c478bd9Sstevel@tonic-gate 
4525*7c478bd9Sstevel@tonic-gate 		errno = 0;
4526*7c478bd9Sstevel@tonic-gate 		i = strtol(str, &endp, 0);
4527*7c478bd9Sstevel@tonic-gate 
4528*7c478bd9Sstevel@tonic-gate 		if (errno != 0 || endp == str || *endp != '\0')
4529*7c478bd9Sstevel@tonic-gate 			goto bad;
4530*7c478bd9Sstevel@tonic-gate 
4531*7c478bd9Sstevel@tonic-gate 		scf_value_set_integer(v, i);
4532*7c478bd9Sstevel@tonic-gate 		return (0);
4533*7c478bd9Sstevel@tonic-gate 	}
4534*7c478bd9Sstevel@tonic-gate 
4535*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_TIME: {
4536*7c478bd9Sstevel@tonic-gate 		int64_t s;
4537*7c478bd9Sstevel@tonic-gate 		uint32_t ns = 0;
4538*7c478bd9Sstevel@tonic-gate 		char *endp, *ns_str;
4539*7c478bd9Sstevel@tonic-gate 		size_t len;
4540*7c478bd9Sstevel@tonic-gate 
4541*7c478bd9Sstevel@tonic-gate 		errno = 0;
4542*7c478bd9Sstevel@tonic-gate 		s = strtoll(str, &endp, 10);
4543*7c478bd9Sstevel@tonic-gate 		if (errno != 0 || endp == str ||
4544*7c478bd9Sstevel@tonic-gate 		    (*endp != '\0' && *endp != '.'))
4545*7c478bd9Sstevel@tonic-gate 			goto bad;
4546*7c478bd9Sstevel@tonic-gate 
4547*7c478bd9Sstevel@tonic-gate 		if (*endp == '.') {
4548*7c478bd9Sstevel@tonic-gate 			ns_str = endp + 1;
4549*7c478bd9Sstevel@tonic-gate 			len = strlen(ns_str);
4550*7c478bd9Sstevel@tonic-gate 			if (len == 0 || len > 9)
4551*7c478bd9Sstevel@tonic-gate 				goto bad;
4552*7c478bd9Sstevel@tonic-gate 
4553*7c478bd9Sstevel@tonic-gate 			ns = strtoul(ns_str, &endp, 10);
4554*7c478bd9Sstevel@tonic-gate 			if (errno != 0 || endp == ns_str || *endp != '\0')
4555*7c478bd9Sstevel@tonic-gate 				goto bad;
4556*7c478bd9Sstevel@tonic-gate 
4557*7c478bd9Sstevel@tonic-gate 			while (len++ < 9)
4558*7c478bd9Sstevel@tonic-gate 				ns *= 10;
4559*7c478bd9Sstevel@tonic-gate 			assert(ns < NANOSEC);
4560*7c478bd9Sstevel@tonic-gate 		}
4561*7c478bd9Sstevel@tonic-gate 
4562*7c478bd9Sstevel@tonic-gate 		return (scf_value_set_time(v, s, ns));
4563*7c478bd9Sstevel@tonic-gate 	}
4564*7c478bd9Sstevel@tonic-gate 
4565*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
4566*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_USTRING:
4567*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_OPAQUE:
4568*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_URI:
4569*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_FMRI:
4570*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_HOST:
4571*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_HOSTNAME:
4572*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V4:
4573*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V6:
4574*7c478bd9Sstevel@tonic-gate 		ty = scf_type_to_protocol_type(type);
4575*7c478bd9Sstevel@tonic-gate 
4576*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&h->rh_lock);
4577*7c478bd9Sstevel@tonic-gate 		scf_value_reset_locked(v, 0);
4578*7c478bd9Sstevel@tonic-gate 		if (type == SCF_TYPE_OPAQUE) {
4579*7c478bd9Sstevel@tonic-gate 			v->value_size = scf_opaque_decode(v->value_value,
4580*7c478bd9Sstevel@tonic-gate 			    str, sizeof (v->value_value));
4581*7c478bd9Sstevel@tonic-gate 			if (!scf_validate_encoded_value(ty, str)) {
4582*7c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_lock(&h->rh_lock);
4583*7c478bd9Sstevel@tonic-gate 				goto bad;
4584*7c478bd9Sstevel@tonic-gate 			}
4585*7c478bd9Sstevel@tonic-gate 		} else {
4586*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(v->value_value, str,
4587*7c478bd9Sstevel@tonic-gate 			    sizeof (v->value_value));
4588*7c478bd9Sstevel@tonic-gate 			if (!scf_validate_encoded_value(ty, v->value_value)) {
4589*7c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_lock(&h->rh_lock);
4590*7c478bd9Sstevel@tonic-gate 				goto bad;
4591*7c478bd9Sstevel@tonic-gate 			}
4592*7c478bd9Sstevel@tonic-gate 		}
4593*7c478bd9Sstevel@tonic-gate 		v->value_type = ty;
4594*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4595*7c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);
4596*7c478bd9Sstevel@tonic-gate 
4597*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_INVALID:
4598*7c478bd9Sstevel@tonic-gate 	default:
4599*7c478bd9Sstevel@tonic-gate 		scf_value_reset(v);
4600*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4601*7c478bd9Sstevel@tonic-gate 	}
4602*7c478bd9Sstevel@tonic-gate bad:
4603*7c478bd9Sstevel@tonic-gate 	scf_value_reset(v);
4604*7c478bd9Sstevel@tonic-gate 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4605*7c478bd9Sstevel@tonic-gate }
4606*7c478bd9Sstevel@tonic-gate 
4607*7c478bd9Sstevel@tonic-gate int
4608*7c478bd9Sstevel@tonic-gate scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop)
4609*7c478bd9Sstevel@tonic-gate {
4610*7c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &prop->rd_d,
4611*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_VALUE, 0));
4612*7c478bd9Sstevel@tonic-gate }
4613*7c478bd9Sstevel@tonic-gate 
4614*7c478bd9Sstevel@tonic-gate int
4615*7c478bd9Sstevel@tonic-gate scf_iter_next_value(scf_iter_t *iter, scf_value_t *v)
4616*7c478bd9Sstevel@tonic-gate {
4617*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
4618*7c478bd9Sstevel@tonic-gate 
4619*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_read_value request;
4620*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_value_response response;
4621*7c478bd9Sstevel@tonic-gate 
4622*7c478bd9Sstevel@tonic-gate 	int r;
4623*7c478bd9Sstevel@tonic-gate 
4624*7c478bd9Sstevel@tonic-gate 	if (h != v->value_handle)
4625*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
4626*7c478bd9Sstevel@tonic-gate 
4627*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4628*7c478bd9Sstevel@tonic-gate 
4629*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
4630*7c478bd9Sstevel@tonic-gate 
4631*7c478bd9Sstevel@tonic-gate 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
4632*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4633*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
4634*7c478bd9Sstevel@tonic-gate 	}
4635*7c478bd9Sstevel@tonic-gate 
4636*7c478bd9Sstevel@tonic-gate 	if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) {
4637*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4638*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4639*7c478bd9Sstevel@tonic-gate 	}
4640*7c478bd9Sstevel@tonic-gate 
4641*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE;
4642*7c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
4643*7c478bd9Sstevel@tonic-gate 	request.rpr_sequence = iter->iter_sequence;
4644*7c478bd9Sstevel@tonic-gate 
4645*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
4646*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
4647*7c478bd9Sstevel@tonic-gate 
4648*7c478bd9Sstevel@tonic-gate 	if (r < 0) {
4649*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4650*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
4651*7c478bd9Sstevel@tonic-gate 	}
4652*7c478bd9Sstevel@tonic-gate 
4653*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE) {
4654*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4655*7c478bd9Sstevel@tonic-gate 		return (0);
4656*7c478bd9Sstevel@tonic-gate 	}
4657*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
4658*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4659*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
4660*7c478bd9Sstevel@tonic-gate 	}
4661*7c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
4662*7c478bd9Sstevel@tonic-gate 
4663*7c478bd9Sstevel@tonic-gate 	v->value_type = response.rpr_type;
4664*7c478bd9Sstevel@tonic-gate 
4665*7c478bd9Sstevel@tonic-gate 	assert(scf_validate_encoded_value(response.rpr_type,
4666*7c478bd9Sstevel@tonic-gate 	    response.rpr_value));
4667*7c478bd9Sstevel@tonic-gate 
4668*7c478bd9Sstevel@tonic-gate 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
4669*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(v->value_value, response.rpr_value,
4670*7c478bd9Sstevel@tonic-gate 		    sizeof (v->value_value));
4671*7c478bd9Sstevel@tonic-gate 	} else {
4672*7c478bd9Sstevel@tonic-gate 		v->value_size = scf_opaque_decode(v->value_value,
4673*7c478bd9Sstevel@tonic-gate 		    response.rpr_value, sizeof (v->value_value));
4674*7c478bd9Sstevel@tonic-gate 	}
4675*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4676*7c478bd9Sstevel@tonic-gate 
4677*7c478bd9Sstevel@tonic-gate 	return (1);
4678*7c478bd9Sstevel@tonic-gate }
4679*7c478bd9Sstevel@tonic-gate 
4680*7c478bd9Sstevel@tonic-gate int
4681*7c478bd9Sstevel@tonic-gate scf_property_get_value(const scf_property_t *prop, scf_value_t *v)
4682*7c478bd9Sstevel@tonic-gate {
4683*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
4684*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_property_request request;
4685*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_value_response response;
4686*7c478bd9Sstevel@tonic-gate 	int r;
4687*7c478bd9Sstevel@tonic-gate 
4688*7c478bd9Sstevel@tonic-gate 	if (h != v->value_handle)
4689*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
4690*7c478bd9Sstevel@tonic-gate 
4691*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
4692*7c478bd9Sstevel@tonic-gate 
4693*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE;
4694*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = prop->rd_d.rd_entity;
4695*7c478bd9Sstevel@tonic-gate 
4696*7c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
4697*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&prop->rd_d);
4698*7c478bd9Sstevel@tonic-gate 
4699*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
4700*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
4701*7c478bd9Sstevel@tonic-gate 
4702*7c478bd9Sstevel@tonic-gate 	if (r < 0) {
4703*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4704*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
4705*7c478bd9Sstevel@tonic-gate 	}
4706*7c478bd9Sstevel@tonic-gate 
4707*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
4708*7c478bd9Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) {
4709*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
4710*7c478bd9Sstevel@tonic-gate 		assert(response.rpr_response !=
4711*7c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
4712*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
4713*7c478bd9Sstevel@tonic-gate 	}
4714*7c478bd9Sstevel@tonic-gate 
4715*7c478bd9Sstevel@tonic-gate 	v->value_type = response.rpr_type;
4716*7c478bd9Sstevel@tonic-gate 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
4717*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(v->value_value, response.rpr_value,
4718*7c478bd9Sstevel@tonic-gate 		    sizeof (v->value_value));
4719*7c478bd9Sstevel@tonic-gate 	} else {
4720*7c478bd9Sstevel@tonic-gate 		v->value_size = scf_opaque_decode(v->value_value,
4721*7c478bd9Sstevel@tonic-gate 		    response.rpr_value, sizeof (v->value_value));
4722*7c478bd9Sstevel@tonic-gate 	}
4723*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
4724*7c478bd9Sstevel@tonic-gate 	return ((response.rpr_response == REP_PROTOCOL_SUCCESS)?
4725*7c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
4726*7c478bd9Sstevel@tonic-gate }
4727*7c478bd9Sstevel@tonic-gate 
4728*7c478bd9Sstevel@tonic-gate int
4729*7c478bd9Sstevel@tonic-gate scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc)
4730*7c478bd9Sstevel@tonic-gate {
4731*7c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&pg->rd_d, &svc->rd_d));
4732*7c478bd9Sstevel@tonic-gate }
4733*7c478bd9Sstevel@tonic-gate 
4734*7c478bd9Sstevel@tonic-gate int
4735*7c478bd9Sstevel@tonic-gate scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst)
4736*7c478bd9Sstevel@tonic-gate {
4737*7c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&pg->rd_d, &inst->rd_d));
4738*7c478bd9Sstevel@tonic-gate }
4739*7c478bd9Sstevel@tonic-gate 
4740*7c478bd9Sstevel@tonic-gate int
4741*7c478bd9Sstevel@tonic-gate scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg,
4742*7c478bd9Sstevel@tonic-gate     scf_snaplevel_t *level)
4743*7c478bd9Sstevel@tonic-gate {
4744*7c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&pg->rd_d, &level->rd_d));
4745*7c478bd9Sstevel@tonic-gate }
4746*7c478bd9Sstevel@tonic-gate 
4747*7c478bd9Sstevel@tonic-gate int
4748*7c478bd9Sstevel@tonic-gate scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s)
4749*7c478bd9Sstevel@tonic-gate {
4750*7c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&svc->rd_d, &s->rd_d));
4751*7c478bd9Sstevel@tonic-gate }
4752*7c478bd9Sstevel@tonic-gate 
4753*7c478bd9Sstevel@tonic-gate int
4754*7c478bd9Sstevel@tonic-gate scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc)
4755*7c478bd9Sstevel@tonic-gate {
4756*7c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
4757*7c478bd9Sstevel@tonic-gate }
4758*7c478bd9Sstevel@tonic-gate 
4759*7c478bd9Sstevel@tonic-gate int
4760*7c478bd9Sstevel@tonic-gate scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc)
4761*7c478bd9Sstevel@tonic-gate {
4762*7c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
4763*7c478bd9Sstevel@tonic-gate }
4764*7c478bd9Sstevel@tonic-gate 
4765*7c478bd9Sstevel@tonic-gate int
4766*7c478bd9Sstevel@tonic-gate scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc)
4767*7c478bd9Sstevel@tonic-gate {
4768*7c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
4769*7c478bd9Sstevel@tonic-gate }
4770*7c478bd9Sstevel@tonic-gate 
4771*7c478bd9Sstevel@tonic-gate /*
4772*7c478bd9Sstevel@tonic-gate  * FMRI functions
4773*7c478bd9Sstevel@tonic-gate  *
4774*7c478bd9Sstevel@tonic-gate  * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
4775*7c478bd9Sstevel@tonic-gate  * scf_parse_fmri(), fmri isn't const because that would require
4776*7c478bd9Sstevel@tonic-gate  * allocating memory. Also, note that scope, at least, is not necessarily
4777*7c478bd9Sstevel@tonic-gate  * in the passed in fmri.
4778*7c478bd9Sstevel@tonic-gate  */
4779*7c478bd9Sstevel@tonic-gate 
4780*7c478bd9Sstevel@tonic-gate int
4781*7c478bd9Sstevel@tonic-gate scf_parse_svc_fmri(char *fmri, const char **scope, const char **service,
4782*7c478bd9Sstevel@tonic-gate     const char **instance, const char **propertygroup, const char **property)
4783*7c478bd9Sstevel@tonic-gate {
4784*7c478bd9Sstevel@tonic-gate 	char *s, *e, *te, *tpg;
4785*7c478bd9Sstevel@tonic-gate 	char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL;
4786*7c478bd9Sstevel@tonic-gate 
4787*7c478bd9Sstevel@tonic-gate 	if (scope != NULL)
4788*7c478bd9Sstevel@tonic-gate 		*scope = NULL;
4789*7c478bd9Sstevel@tonic-gate 	if (service != NULL)
4790*7c478bd9Sstevel@tonic-gate 		*service = NULL;
4791*7c478bd9Sstevel@tonic-gate 	if (instance != NULL)
4792*7c478bd9Sstevel@tonic-gate 		*instance = NULL;
4793*7c478bd9Sstevel@tonic-gate 	if (propertygroup != NULL)
4794*7c478bd9Sstevel@tonic-gate 		*propertygroup = NULL;
4795*7c478bd9Sstevel@tonic-gate 	if (property != NULL)
4796*7c478bd9Sstevel@tonic-gate 		*property = NULL;
4797*7c478bd9Sstevel@tonic-gate 
4798*7c478bd9Sstevel@tonic-gate 	s = fmri;
4799*7c478bd9Sstevel@tonic-gate 	e = strchr(s, '\0');
4800*7c478bd9Sstevel@tonic-gate 
4801*7c478bd9Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_SVC_PREFIX,
4802*7c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0)
4803*7c478bd9Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_SVC_PREFIX) - 1;
4804*7c478bd9Sstevel@tonic-gate 
4805*7c478bd9Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
4806*7c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
4807*7c478bd9Sstevel@tonic-gate 		char *my_scope;
4808*7c478bd9Sstevel@tonic-gate 
4809*7c478bd9Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
4810*7c478bd9Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
4811*7c478bd9Sstevel@tonic-gate 		if (te == NULL)
4812*7c478bd9Sstevel@tonic-gate 			te = e;
4813*7c478bd9Sstevel@tonic-gate 
4814*7c478bd9Sstevel@tonic-gate 		*te = 0;
4815*7c478bd9Sstevel@tonic-gate 		my_scope = s;
4816*7c478bd9Sstevel@tonic-gate 
4817*7c478bd9Sstevel@tonic-gate 		s = te;
4818*7c478bd9Sstevel@tonic-gate 		if (s < e)
4819*7c478bd9Sstevel@tonic-gate 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
4820*7c478bd9Sstevel@tonic-gate 
4821*7c478bd9Sstevel@tonic-gate 		/* If the scope ends with the suffix, remove it. */
4822*7c478bd9Sstevel@tonic-gate 		te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX);
4823*7c478bd9Sstevel@tonic-gate 		if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0)
4824*7c478bd9Sstevel@tonic-gate 			*te = 0;
4825*7c478bd9Sstevel@tonic-gate 
4826*7c478bd9Sstevel@tonic-gate 		/* Validate the scope. */
4827*7c478bd9Sstevel@tonic-gate 		if (my_scope[0] == '\0')
4828*7c478bd9Sstevel@tonic-gate 			my_scope = SCF_FMRI_LOCAL_SCOPE;
4829*7c478bd9Sstevel@tonic-gate 		else if (uu_check_name(my_scope, 0) == -1) {
4830*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4831*7c478bd9Sstevel@tonic-gate 		}
4832*7c478bd9Sstevel@tonic-gate 
4833*7c478bd9Sstevel@tonic-gate 		if (scope != NULL)
4834*7c478bd9Sstevel@tonic-gate 			*scope = my_scope;
4835*7c478bd9Sstevel@tonic-gate 	} else {
4836*7c478bd9Sstevel@tonic-gate 		if (scope != NULL)
4837*7c478bd9Sstevel@tonic-gate 			*scope = SCF_FMRI_LOCAL_SCOPE;
4838*7c478bd9Sstevel@tonic-gate 	}
4839*7c478bd9Sstevel@tonic-gate 
4840*7c478bd9Sstevel@tonic-gate 	if (s[0] != 0) {
4841*7c478bd9Sstevel@tonic-gate 		if (strncmp(s, SCF_FMRI_SERVICE_PREFIX,
4842*7c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0)
4843*7c478bd9Sstevel@tonic-gate 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
4844*7c478bd9Sstevel@tonic-gate 
4845*7c478bd9Sstevel@tonic-gate 		/*
4846*7c478bd9Sstevel@tonic-gate 		 * Can't validate service here because it might not be null
4847*7c478bd9Sstevel@tonic-gate 		 * terminated.
4848*7c478bd9Sstevel@tonic-gate 		 */
4849*7c478bd9Sstevel@tonic-gate 		my_s = s;
4850*7c478bd9Sstevel@tonic-gate 	}
4851*7c478bd9Sstevel@tonic-gate 
4852*7c478bd9Sstevel@tonic-gate 	tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
4853*7c478bd9Sstevel@tonic-gate 	te = strstr(s, SCF_FMRI_INSTANCE_PREFIX);
4854*7c478bd9Sstevel@tonic-gate 	if (te != NULL && (tpg == NULL || te < tpg)) {
4855*7c478bd9Sstevel@tonic-gate 		*te = 0;
4856*7c478bd9Sstevel@tonic-gate 		te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
4857*7c478bd9Sstevel@tonic-gate 
4858*7c478bd9Sstevel@tonic-gate 		/* Can't validate instance here either. */
4859*7c478bd9Sstevel@tonic-gate 		my_i = s = te;
4860*7c478bd9Sstevel@tonic-gate 
4861*7c478bd9Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
4862*7c478bd9Sstevel@tonic-gate 	} else {
4863*7c478bd9Sstevel@tonic-gate 		te = tpg;
4864*7c478bd9Sstevel@tonic-gate 	}
4865*7c478bd9Sstevel@tonic-gate 
4866*7c478bd9Sstevel@tonic-gate 	if (te != NULL) {
4867*7c478bd9Sstevel@tonic-gate 		*te = 0;
4868*7c478bd9Sstevel@tonic-gate 		te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
4869*7c478bd9Sstevel@tonic-gate 
4870*7c478bd9Sstevel@tonic-gate 		my_pg = s = te;
4871*7c478bd9Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_PROPERTY_PREFIX);
4872*7c478bd9Sstevel@tonic-gate 		if (te != NULL) {
4873*7c478bd9Sstevel@tonic-gate 			*te = 0;
4874*7c478bd9Sstevel@tonic-gate 			te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
4875*7c478bd9Sstevel@tonic-gate 
4876*7c478bd9Sstevel@tonic-gate 			my_p = te;
4877*7c478bd9Sstevel@tonic-gate 			s = te;
4878*7c478bd9Sstevel@tonic-gate 		}
4879*7c478bd9Sstevel@tonic-gate 	}
4880*7c478bd9Sstevel@tonic-gate 
4881*7c478bd9Sstevel@tonic-gate 	if (my_s != NULL) {
4882*7c478bd9Sstevel@tonic-gate 		if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1)
4883*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4884*7c478bd9Sstevel@tonic-gate 
4885*7c478bd9Sstevel@tonic-gate 		if (service != NULL)
4886*7c478bd9Sstevel@tonic-gate 			*service = my_s;
4887*7c478bd9Sstevel@tonic-gate 	}
4888*7c478bd9Sstevel@tonic-gate 
4889*7c478bd9Sstevel@tonic-gate 	if (my_i != NULL) {
4890*7c478bd9Sstevel@tonic-gate 		if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1)
4891*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4892*7c478bd9Sstevel@tonic-gate 
4893*7c478bd9Sstevel@tonic-gate 		if (instance != NULL)
4894*7c478bd9Sstevel@tonic-gate 			*instance = my_i;
4895*7c478bd9Sstevel@tonic-gate 	}
4896*7c478bd9Sstevel@tonic-gate 
4897*7c478bd9Sstevel@tonic-gate 	if (my_pg != NULL) {
4898*7c478bd9Sstevel@tonic-gate 		if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1)
4899*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4900*7c478bd9Sstevel@tonic-gate 
4901*7c478bd9Sstevel@tonic-gate 		if (propertygroup != NULL)
4902*7c478bd9Sstevel@tonic-gate 			*propertygroup = my_pg;
4903*7c478bd9Sstevel@tonic-gate 	}
4904*7c478bd9Sstevel@tonic-gate 
4905*7c478bd9Sstevel@tonic-gate 	if (my_p != NULL) {
4906*7c478bd9Sstevel@tonic-gate 		if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1)
4907*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4908*7c478bd9Sstevel@tonic-gate 
4909*7c478bd9Sstevel@tonic-gate 		if (property != NULL)
4910*7c478bd9Sstevel@tonic-gate 			*property = my_p;
4911*7c478bd9Sstevel@tonic-gate 	}
4912*7c478bd9Sstevel@tonic-gate 
4913*7c478bd9Sstevel@tonic-gate 	return (0);
4914*7c478bd9Sstevel@tonic-gate }
4915*7c478bd9Sstevel@tonic-gate 
4916*7c478bd9Sstevel@tonic-gate int
4917*7c478bd9Sstevel@tonic-gate scf_parse_file_fmri(char *fmri, const char **scope, const char **path)
4918*7c478bd9Sstevel@tonic-gate {
4919*7c478bd9Sstevel@tonic-gate 	char *s, *e, *te;
4920*7c478bd9Sstevel@tonic-gate 
4921*7c478bd9Sstevel@tonic-gate 	if (scope != NULL)
4922*7c478bd9Sstevel@tonic-gate 		*scope = NULL;
4923*7c478bd9Sstevel@tonic-gate 
4924*7c478bd9Sstevel@tonic-gate 	s = fmri;
4925*7c478bd9Sstevel@tonic-gate 	e = strchr(s, '\0');
4926*7c478bd9Sstevel@tonic-gate 
4927*7c478bd9Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_FILE_PREFIX,
4928*7c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0)
4929*7c478bd9Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_FILE_PREFIX) - 1;
4930*7c478bd9Sstevel@tonic-gate 
4931*7c478bd9Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
4932*7c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
4933*7c478bd9Sstevel@tonic-gate 		char *my_scope;
4934*7c478bd9Sstevel@tonic-gate 
4935*7c478bd9Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
4936*7c478bd9Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
4937*7c478bd9Sstevel@tonic-gate 		if (te == NULL)
4938*7c478bd9Sstevel@tonic-gate 			te = e;
4939*7c478bd9Sstevel@tonic-gate 
4940*7c478bd9Sstevel@tonic-gate 		*te = 0;
4941*7c478bd9Sstevel@tonic-gate 		my_scope = s;
4942*7c478bd9Sstevel@tonic-gate 
4943*7c478bd9Sstevel@tonic-gate 		s = te;
4944*7c478bd9Sstevel@tonic-gate 
4945*7c478bd9Sstevel@tonic-gate 		/* Validate the scope. */
4946*7c478bd9Sstevel@tonic-gate 		if (my_scope[0] != '\0' &&
4947*7c478bd9Sstevel@tonic-gate 		    strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
4948*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4949*7c478bd9Sstevel@tonic-gate 		}
4950*7c478bd9Sstevel@tonic-gate 
4951*7c478bd9Sstevel@tonic-gate 		if (scope != NULL)
4952*7c478bd9Sstevel@tonic-gate 			*scope = my_scope;
4953*7c478bd9Sstevel@tonic-gate 	} else {
4954*7c478bd9Sstevel@tonic-gate 		/*
4955*7c478bd9Sstevel@tonic-gate 		 * FMRI paths must be absolute
4956*7c478bd9Sstevel@tonic-gate 		 */
4957*7c478bd9Sstevel@tonic-gate 		if (s[0] != '/')
4958*7c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4959*7c478bd9Sstevel@tonic-gate 	}
4960*7c478bd9Sstevel@tonic-gate 
4961*7c478bd9Sstevel@tonic-gate 	s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
4962*7c478bd9Sstevel@tonic-gate 
4963*7c478bd9Sstevel@tonic-gate 	if (s >= e)
4964*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4965*7c478bd9Sstevel@tonic-gate 
4966*7c478bd9Sstevel@tonic-gate 	/*
4967*7c478bd9Sstevel@tonic-gate 	 * If the user requests it, return the full path of the file.
4968*7c478bd9Sstevel@tonic-gate 	 */
4969*7c478bd9Sstevel@tonic-gate 	if (path != NULL) {
4970*7c478bd9Sstevel@tonic-gate 		assert(s > fmri);
4971*7c478bd9Sstevel@tonic-gate 		s[-1] = '/';
4972*7c478bd9Sstevel@tonic-gate 		*path = s - 1;
4973*7c478bd9Sstevel@tonic-gate 	}
4974*7c478bd9Sstevel@tonic-gate 
4975*7c478bd9Sstevel@tonic-gate 	return (0);
4976*7c478bd9Sstevel@tonic-gate }
4977*7c478bd9Sstevel@tonic-gate 
4978*7c478bd9Sstevel@tonic-gate int
4979*7c478bd9Sstevel@tonic-gate scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service,
4980*7c478bd9Sstevel@tonic-gate     const char **instance, const char **propertygroup, const char **property)
4981*7c478bd9Sstevel@tonic-gate {
4982*7c478bd9Sstevel@tonic-gate 	if (strncmp(fmri, SCF_FMRI_SVC_PREFIX,
4983*7c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
4984*7c478bd9Sstevel@tonic-gate 		if (type)
4985*7c478bd9Sstevel@tonic-gate 			*type = SCF_FMRI_TYPE_SVC;
4986*7c478bd9Sstevel@tonic-gate 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
4987*7c478bd9Sstevel@tonic-gate 			    propertygroup, property));
4988*7c478bd9Sstevel@tonic-gate 	} else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX,
4989*7c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
4990*7c478bd9Sstevel@tonic-gate 		if (type)
4991*7c478bd9Sstevel@tonic-gate 			*type = SCF_FMRI_TYPE_FILE;
4992*7c478bd9Sstevel@tonic-gate 		return (scf_parse_file_fmri(fmri, scope, NULL));
4993*7c478bd9Sstevel@tonic-gate 	} else {
4994*7c478bd9Sstevel@tonic-gate 		/*
4995*7c478bd9Sstevel@tonic-gate 		 * Parse as a svc if the fmri type is not explicitly
4996*7c478bd9Sstevel@tonic-gate 		 * specified.
4997*7c478bd9Sstevel@tonic-gate 		 */
4998*7c478bd9Sstevel@tonic-gate 		if (type)
4999*7c478bd9Sstevel@tonic-gate 			*type = SCF_FMRI_TYPE_SVC;
5000*7c478bd9Sstevel@tonic-gate 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
5001*7c478bd9Sstevel@tonic-gate 		    propertygroup, property));
5002*7c478bd9Sstevel@tonic-gate 	}
5003*7c478bd9Sstevel@tonic-gate }
5004*7c478bd9Sstevel@tonic-gate 
5005*7c478bd9Sstevel@tonic-gate /*
5006*7c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT.  fmri and buf may be equal.
5007*7c478bd9Sstevel@tonic-gate  */
5008*7c478bd9Sstevel@tonic-gate ssize_t
5009*7c478bd9Sstevel@tonic-gate scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz)
5010*7c478bd9Sstevel@tonic-gate {
5011*7c478bd9Sstevel@tonic-gate 	const char *scope, *service, *instance, *pg, *property;
5012*7c478bd9Sstevel@tonic-gate 	char local[6 * REP_PROTOCOL_NAME_LEN];
5013*7c478bd9Sstevel@tonic-gate 	int r;
5014*7c478bd9Sstevel@tonic-gate 	size_t len;
5015*7c478bd9Sstevel@tonic-gate 
5016*7c478bd9Sstevel@tonic-gate 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5017*7c478bd9Sstevel@tonic-gate 		/* Should this be CONSTRAINT_VIOLATED? */
5018*7c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5019*7c478bd9Sstevel@tonic-gate 		return (-1);
5020*7c478bd9Sstevel@tonic-gate 	}
5021*7c478bd9Sstevel@tonic-gate 
5022*7c478bd9Sstevel@tonic-gate 
5023*7c478bd9Sstevel@tonic-gate 	r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg,
5024*7c478bd9Sstevel@tonic-gate 	    &property);
5025*7c478bd9Sstevel@tonic-gate 	if (r != 0)
5026*7c478bd9Sstevel@tonic-gate 		return (-1);
5027*7c478bd9Sstevel@tonic-gate 
5028*7c478bd9Sstevel@tonic-gate 	len = strlcpy(buf, "svc:/", bufsz);
5029*7c478bd9Sstevel@tonic-gate 
5030*7c478bd9Sstevel@tonic-gate 	if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) {
5031*7c478bd9Sstevel@tonic-gate 		len += strlcat(buf, "/", bufsz);
5032*7c478bd9Sstevel@tonic-gate 		len += strlcat(buf, scope, bufsz);
5033*7c478bd9Sstevel@tonic-gate 	}
5034*7c478bd9Sstevel@tonic-gate 
5035*7c478bd9Sstevel@tonic-gate 	if (service)
5036*7c478bd9Sstevel@tonic-gate 		len += strlcat(buf, service, bufsz);
5037*7c478bd9Sstevel@tonic-gate 
5038*7c478bd9Sstevel@tonic-gate 	if (instance) {
5039*7c478bd9Sstevel@tonic-gate 		len += strlcat(buf, ":", bufsz);
5040*7c478bd9Sstevel@tonic-gate 		len += strlcat(buf, instance, bufsz);
5041*7c478bd9Sstevel@tonic-gate 	}
5042*7c478bd9Sstevel@tonic-gate 
5043*7c478bd9Sstevel@tonic-gate 	if (pg) {
5044*7c478bd9Sstevel@tonic-gate 		len += strlcat(buf, "/:properties/", bufsz);
5045*7c478bd9Sstevel@tonic-gate 		len += strlcat(buf, pg, bufsz);
5046*7c478bd9Sstevel@tonic-gate 	}
5047*7c478bd9Sstevel@tonic-gate 
5048*7c478bd9Sstevel@tonic-gate 	if (property) {
5049*7c478bd9Sstevel@tonic-gate 		len += strlcat(buf, "/", bufsz);
5050*7c478bd9Sstevel@tonic-gate 		len += strlcat(buf, property, bufsz);
5051*7c478bd9Sstevel@tonic-gate 	}
5052*7c478bd9Sstevel@tonic-gate 
5053*7c478bd9Sstevel@tonic-gate 	return (len);
5054*7c478bd9Sstevel@tonic-gate }
5055*7c478bd9Sstevel@tonic-gate 
5056*7c478bd9Sstevel@tonic-gate int
5057*7c478bd9Sstevel@tonic-gate scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc,
5058*7c478bd9Sstevel@tonic-gate     scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg,
5059*7c478bd9Sstevel@tonic-gate     scf_property_t *prop, int flags)
5060*7c478bd9Sstevel@tonic-gate {
5061*7c478bd9Sstevel@tonic-gate 	const char *scope, *service, *instance, *propertygroup, *property;
5062*7c478bd9Sstevel@tonic-gate 	int last;
5063*7c478bd9Sstevel@tonic-gate 	char local[6 * REP_PROTOCOL_NAME_LEN];
5064*7c478bd9Sstevel@tonic-gate 	int ret;
5065*7c478bd9Sstevel@tonic-gate 	const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE |
5066*7c478bd9Sstevel@tonic-gate 	    RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY;
5067*7c478bd9Sstevel@tonic-gate 
5068*7c478bd9Sstevel@tonic-gate 	/*
5069*7c478bd9Sstevel@tonic-gate 	 * verify that all handles match
5070*7c478bd9Sstevel@tonic-gate 	 */
5071*7c478bd9Sstevel@tonic-gate 	if ((sc != NULL && h != sc->rd_d.rd_handle) ||
5072*7c478bd9Sstevel@tonic-gate 	    (svc != NULL && h != svc->rd_d.rd_handle) ||
5073*7c478bd9Sstevel@tonic-gate 	    (inst != NULL && h != inst->rd_d.rd_handle) ||
5074*7c478bd9Sstevel@tonic-gate 	    (pg != NULL && h != pg->rd_d.rd_handle) ||
5075*7c478bd9Sstevel@tonic-gate 	    (prop != NULL && h != prop->rd_d.rd_handle))
5076*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5077*7c478bd9Sstevel@tonic-gate 
5078*7c478bd9Sstevel@tonic-gate 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5079*7c478bd9Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5080*7c478bd9Sstevel@tonic-gate 		goto reset_args;
5081*7c478bd9Sstevel@tonic-gate 	}
5082*7c478bd9Sstevel@tonic-gate 
5083*7c478bd9Sstevel@tonic-gate 	/*
5084*7c478bd9Sstevel@tonic-gate 	 * We can simply return from an error in parsing, because
5085*7c478bd9Sstevel@tonic-gate 	 * scf_parse_fmri sets the error code correctly.
5086*7c478bd9Sstevel@tonic-gate 	 */
5087*7c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(local, &scope, &service, &instance,
5088*7c478bd9Sstevel@tonic-gate 	    &propertygroup, &property) == -1) {
5089*7c478bd9Sstevel@tonic-gate 		ret = -1;
5090*7c478bd9Sstevel@tonic-gate 		goto reset_args;
5091*7c478bd9Sstevel@tonic-gate 	}
5092*7c478bd9Sstevel@tonic-gate 
5093*7c478bd9Sstevel@tonic-gate 	/*
5094*7c478bd9Sstevel@tonic-gate 	 * the FMRI looks valid at this point -- do constraint checks.
5095*7c478bd9Sstevel@tonic-gate 	 */
5096*7c478bd9Sstevel@tonic-gate 
5097*7c478bd9Sstevel@tonic-gate 	if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) {
5098*7c478bd9Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5099*7c478bd9Sstevel@tonic-gate 		goto reset_args;
5100*7c478bd9Sstevel@tonic-gate 	}
5101*7c478bd9Sstevel@tonic-gate 	if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) {
5102*7c478bd9Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5103*7c478bd9Sstevel@tonic-gate 		goto reset_args;
5104*7c478bd9Sstevel@tonic-gate 	}
5105*7c478bd9Sstevel@tonic-gate 
5106*7c478bd9Sstevel@tonic-gate 	if (prop != NULL)
5107*7c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_PROPERTY;
5108*7c478bd9Sstevel@tonic-gate 	else if (pg != NULL)
5109*7c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5110*7c478bd9Sstevel@tonic-gate 	else if (inst != NULL)
5111*7c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_INSTANCE;
5112*7c478bd9Sstevel@tonic-gate 	else if (svc != NULL)
5113*7c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_SERVICE;
5114*7c478bd9Sstevel@tonic-gate 	else if (sc != NULL)
5115*7c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_SCOPE;
5116*7c478bd9Sstevel@tonic-gate 	else
5117*7c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_NONE;
5118*7c478bd9Sstevel@tonic-gate 
5119*7c478bd9Sstevel@tonic-gate 	if (flags & SCF_DECODE_FMRI_EXACT) {
5120*7c478bd9Sstevel@tonic-gate 		int last_fmri;
5121*7c478bd9Sstevel@tonic-gate 
5122*7c478bd9Sstevel@tonic-gate 		if (property != NULL)
5123*7c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTY;
5124*7c478bd9Sstevel@tonic-gate 		else if (propertygroup != NULL)
5125*7c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5126*7c478bd9Sstevel@tonic-gate 		else if (instance != NULL)
5127*7c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_INSTANCE;
5128*7c478bd9Sstevel@tonic-gate 		else if (service != NULL)
5129*7c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_SERVICE;
5130*7c478bd9Sstevel@tonic-gate 		else if (scope != NULL)
5131*7c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_SCOPE;
5132*7c478bd9Sstevel@tonic-gate 		else
5133*7c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_NONE;
5134*7c478bd9Sstevel@tonic-gate 
5135*7c478bd9Sstevel@tonic-gate 		if (last != last_fmri) {
5136*7c478bd9Sstevel@tonic-gate 			ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5137*7c478bd9Sstevel@tonic-gate 			goto reset_args;
5138*7c478bd9Sstevel@tonic-gate 		}
5139*7c478bd9Sstevel@tonic-gate 	}
5140*7c478bd9Sstevel@tonic-gate 
5141*7c478bd9Sstevel@tonic-gate 	if ((flags & SCF_DECODE_FMRI_TRUNCATE) &&
5142*7c478bd9Sstevel@tonic-gate 	    last == REP_PROTOCOL_ENTITY_NONE) {
5143*7c478bd9Sstevel@tonic-gate 		ret = 0;				/* nothing to do */
5144*7c478bd9Sstevel@tonic-gate 		goto reset_args;
5145*7c478bd9Sstevel@tonic-gate 	}
5146*7c478bd9Sstevel@tonic-gate 
5147*7c478bd9Sstevel@tonic-gate 	if (!(flags & SCF_DECODE_FMRI_TRUNCATE))
5148*7c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_NONE;	/* never stop */
5149*7c478bd9Sstevel@tonic-gate 
5150*7c478bd9Sstevel@tonic-gate 	/*
5151*7c478bd9Sstevel@tonic-gate 	 * passed the constraint checks -- try to grab the thing itself.
5152*7c478bd9Sstevel@tonic-gate 	 */
5153*7c478bd9Sstevel@tonic-gate 
5154*7c478bd9Sstevel@tonic-gate 	handle_hold_subhandles(h, holds);
5155*7c478bd9Sstevel@tonic-gate 	if (sc == NULL)
5156*7c478bd9Sstevel@tonic-gate 		sc = h->rh_scope;
5157*7c478bd9Sstevel@tonic-gate 	else
5158*7c478bd9Sstevel@tonic-gate 		datael_reset(&sc->rd_d);
5159*7c478bd9Sstevel@tonic-gate 
5160*7c478bd9Sstevel@tonic-gate 	if (svc == NULL)
5161*7c478bd9Sstevel@tonic-gate 		svc = h->rh_service;
5162*7c478bd9Sstevel@tonic-gate 	else
5163*7c478bd9Sstevel@tonic-gate 		datael_reset(&svc->rd_d);
5164*7c478bd9Sstevel@tonic-gate 
5165*7c478bd9Sstevel@tonic-gate 	if (inst == NULL)
5166*7c478bd9Sstevel@tonic-gate 		inst = h->rh_instance;
5167*7c478bd9Sstevel@tonic-gate 	else
5168*7c478bd9Sstevel@tonic-gate 		datael_reset(&inst->rd_d);
5169*7c478bd9Sstevel@tonic-gate 
5170*7c478bd9Sstevel@tonic-gate 	if (pg == NULL)
5171*7c478bd9Sstevel@tonic-gate 		pg = h->rh_pg;
5172*7c478bd9Sstevel@tonic-gate 	else
5173*7c478bd9Sstevel@tonic-gate 		datael_reset(&pg->rd_d);
5174*7c478bd9Sstevel@tonic-gate 
5175*7c478bd9Sstevel@tonic-gate 	if (prop == NULL)
5176*7c478bd9Sstevel@tonic-gate 		prop = h->rh_property;
5177*7c478bd9Sstevel@tonic-gate 	else
5178*7c478bd9Sstevel@tonic-gate 		datael_reset(&prop->rd_d);
5179*7c478bd9Sstevel@tonic-gate 
5180*7c478bd9Sstevel@tonic-gate 	/*
5181*7c478bd9Sstevel@tonic-gate 	 * We only support local scopes, but we check *after* getting
5182*7c478bd9Sstevel@tonic-gate 	 * the local scope, so that any repository-related errors take
5183*7c478bd9Sstevel@tonic-gate 	 * precedence.
5184*7c478bd9Sstevel@tonic-gate 	 */
5185*7c478bd9Sstevel@tonic-gate 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) {
5186*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
5187*7c478bd9Sstevel@tonic-gate 		ret = -1;
5188*7c478bd9Sstevel@tonic-gate 		goto reset_args;
5189*7c478bd9Sstevel@tonic-gate 	}
5190*7c478bd9Sstevel@tonic-gate 
5191*7c478bd9Sstevel@tonic-gate 	if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
5192*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
5193*7c478bd9Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_NOT_FOUND);
5194*7c478bd9Sstevel@tonic-gate 		goto reset_args;
5195*7c478bd9Sstevel@tonic-gate 	}
5196*7c478bd9Sstevel@tonic-gate 
5197*7c478bd9Sstevel@tonic-gate 
5198*7c478bd9Sstevel@tonic-gate 	if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) {
5199*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
5200*7c478bd9Sstevel@tonic-gate 		return (0);
5201*7c478bd9Sstevel@tonic-gate 	}
5202*7c478bd9Sstevel@tonic-gate 
5203*7c478bd9Sstevel@tonic-gate 	if (scf_scope_get_service(sc, service, svc) == -1) {
5204*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
5205*7c478bd9Sstevel@tonic-gate 		ret = -1;
5206*7c478bd9Sstevel@tonic-gate 		assert(scf_error() != SCF_ERROR_NOT_SET);
5207*7c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_DELETED)
5208*7c478bd9Sstevel@tonic-gate 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5209*7c478bd9Sstevel@tonic-gate 		goto reset_args;
5210*7c478bd9Sstevel@tonic-gate 	}
5211*7c478bd9Sstevel@tonic-gate 
5212*7c478bd9Sstevel@tonic-gate 	if (last == REP_PROTOCOL_ENTITY_SERVICE) {
5213*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
5214*7c478bd9Sstevel@tonic-gate 		return (0);
5215*7c478bd9Sstevel@tonic-gate 	}
5216*7c478bd9Sstevel@tonic-gate 
5217*7c478bd9Sstevel@tonic-gate 	if (instance == NULL) {
5218*7c478bd9Sstevel@tonic-gate 		if (propertygroup == NULL ||
5219*7c478bd9Sstevel@tonic-gate 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
5220*7c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
5221*7c478bd9Sstevel@tonic-gate 			return (0);
5222*7c478bd9Sstevel@tonic-gate 		}
5223*7c478bd9Sstevel@tonic-gate 
5224*7c478bd9Sstevel@tonic-gate 		if (scf_service_get_pg(svc, propertygroup, pg) == -1) {
5225*7c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
5226*7c478bd9Sstevel@tonic-gate 			ret = -1;
5227*7c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_NOT_SET);
5228*7c478bd9Sstevel@tonic-gate 			if (scf_error() == SCF_ERROR_DELETED)
5229*7c478bd9Sstevel@tonic-gate 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5230*7c478bd9Sstevel@tonic-gate 			goto reset_args;
5231*7c478bd9Sstevel@tonic-gate 		}
5232*7c478bd9Sstevel@tonic-gate 	} else {
5233*7c478bd9Sstevel@tonic-gate 		if (scf_service_get_instance(svc, instance, inst) == -1) {
5234*7c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
5235*7c478bd9Sstevel@tonic-gate 			ret = -1;
5236*7c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_NOT_SET);
5237*7c478bd9Sstevel@tonic-gate 			if (scf_error() == SCF_ERROR_DELETED)
5238*7c478bd9Sstevel@tonic-gate 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5239*7c478bd9Sstevel@tonic-gate 			goto reset_args;
5240*7c478bd9Sstevel@tonic-gate 		}
5241*7c478bd9Sstevel@tonic-gate 
5242*7c478bd9Sstevel@tonic-gate 		if (propertygroup == NULL ||
5243*7c478bd9Sstevel@tonic-gate 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
5244*7c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
5245*7c478bd9Sstevel@tonic-gate 			return (0);
5246*7c478bd9Sstevel@tonic-gate 		}
5247*7c478bd9Sstevel@tonic-gate 
5248*7c478bd9Sstevel@tonic-gate 		if (scf_instance_get_pg(inst, propertygroup, pg) == -1) {
5249*7c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
5250*7c478bd9Sstevel@tonic-gate 			ret = -1;
5251*7c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_NOT_SET);
5252*7c478bd9Sstevel@tonic-gate 			if (scf_error() == SCF_ERROR_DELETED)
5253*7c478bd9Sstevel@tonic-gate 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5254*7c478bd9Sstevel@tonic-gate 			goto reset_args;
5255*7c478bd9Sstevel@tonic-gate 		}
5256*7c478bd9Sstevel@tonic-gate 	}
5257*7c478bd9Sstevel@tonic-gate 
5258*7c478bd9Sstevel@tonic-gate 	if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
5259*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
5260*7c478bd9Sstevel@tonic-gate 		return (0);
5261*7c478bd9Sstevel@tonic-gate 	}
5262*7c478bd9Sstevel@tonic-gate 
5263*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, property, prop) == -1) {
5264*7c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
5265*7c478bd9Sstevel@tonic-gate 		ret = -1;
5266*7c478bd9Sstevel@tonic-gate 		assert(scf_error() != SCF_ERROR_NOT_SET);
5267*7c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_DELETED)
5268*7c478bd9Sstevel@tonic-gate 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5269*7c478bd9Sstevel@tonic-gate 		goto reset_args;
5270*7c478bd9Sstevel@tonic-gate 	}
5271*7c478bd9Sstevel@tonic-gate 
5272*7c478bd9Sstevel@tonic-gate 	handle_rele_subhandles(h, holds);
5273*7c478bd9Sstevel@tonic-gate 	return (0);
5274*7c478bd9Sstevel@tonic-gate 
5275*7c478bd9Sstevel@tonic-gate reset_args:
5276*7c478bd9Sstevel@tonic-gate 	if (sc != NULL)
5277*7c478bd9Sstevel@tonic-gate 		datael_reset(&sc->rd_d);
5278*7c478bd9Sstevel@tonic-gate 	if (svc != NULL)
5279*7c478bd9Sstevel@tonic-gate 		datael_reset(&svc->rd_d);
5280*7c478bd9Sstevel@tonic-gate 	if (inst != NULL)
5281*7c478bd9Sstevel@tonic-gate 		datael_reset(&inst->rd_d);
5282*7c478bd9Sstevel@tonic-gate 	if (pg != NULL)
5283*7c478bd9Sstevel@tonic-gate 		datael_reset(&pg->rd_d);
5284*7c478bd9Sstevel@tonic-gate 	if (prop != NULL)
5285*7c478bd9Sstevel@tonic-gate 		datael_reset(&prop->rd_d);
5286*7c478bd9Sstevel@tonic-gate 
5287*7c478bd9Sstevel@tonic-gate 	return (ret);
5288*7c478bd9Sstevel@tonic-gate }
5289*7c478bd9Sstevel@tonic-gate 
5290*7c478bd9Sstevel@tonic-gate /*
5291*7c478bd9Sstevel@tonic-gate  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5292*7c478bd9Sstevel@tonic-gate  * big, bad entity id, request not applicable to entity, name too long for
5293*7c478bd9Sstevel@tonic-gate  * buffer), _NOT_SET, or _DELETED.
5294*7c478bd9Sstevel@tonic-gate  */
5295*7c478bd9Sstevel@tonic-gate ssize_t
5296*7c478bd9Sstevel@tonic-gate scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz)
5297*7c478bd9Sstevel@tonic-gate {
5298*7c478bd9Sstevel@tonic-gate 	ssize_t r, len;
5299*7c478bd9Sstevel@tonic-gate 
5300*7c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
5301*7c478bd9Sstevel@tonic-gate 
5302*7c478bd9Sstevel@tonic-gate 	r = scf_scope_get_name(scope, tmp, sizeof (tmp));
5303*7c478bd9Sstevel@tonic-gate 
5304*7c478bd9Sstevel@tonic-gate 	if (r <= 0)
5305*7c478bd9Sstevel@tonic-gate 		return (r);
5306*7c478bd9Sstevel@tonic-gate 
5307*7c478bd9Sstevel@tonic-gate 	len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz);
5308*7c478bd9Sstevel@tonic-gate 	if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) {
5309*7c478bd9Sstevel@tonic-gate 		if (len >= sz)
5310*7c478bd9Sstevel@tonic-gate 			return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5311*7c478bd9Sstevel@tonic-gate 
5312*7c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
5313*7c478bd9Sstevel@tonic-gate 		if (len >= sz)
5314*7c478bd9Sstevel@tonic-gate 			return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5315*7c478bd9Sstevel@tonic-gate 		len = strlcat(out,
5316*7c478bd9Sstevel@tonic-gate 		    SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz);
5317*7c478bd9Sstevel@tonic-gate 	}
5318*7c478bd9Sstevel@tonic-gate 
5319*7c478bd9Sstevel@tonic-gate 	return (len);
5320*7c478bd9Sstevel@tonic-gate }
5321*7c478bd9Sstevel@tonic-gate 
5322*7c478bd9Sstevel@tonic-gate /*
5323*7c478bd9Sstevel@tonic-gate  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5324*7c478bd9Sstevel@tonic-gate  * big, bad element id, bad ids, bad types, scope has no parent, request not
5325*7c478bd9Sstevel@tonic-gate  * applicable to entity, name too long), _NOT_SET, _DELETED,
5326*7c478bd9Sstevel@tonic-gate  */
5327*7c478bd9Sstevel@tonic-gate ssize_t
5328*7c478bd9Sstevel@tonic-gate scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz)
5329*7c478bd9Sstevel@tonic-gate {
5330*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = svc->rd_d.rd_handle;
5331*7c478bd9Sstevel@tonic-gate 	scf_scope_t *scope = HANDLE_HOLD_SCOPE(h);
5332*7c478bd9Sstevel@tonic-gate 	ssize_t r, len;
5333*7c478bd9Sstevel@tonic-gate 
5334*7c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
5335*7c478bd9Sstevel@tonic-gate 
5336*7c478bd9Sstevel@tonic-gate 	r = datael_get_parent(&svc->rd_d, &scope->rd_d);
5337*7c478bd9Sstevel@tonic-gate 	if (r != SCF_SUCCESS) {
5338*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SCOPE(h);
5339*7c478bd9Sstevel@tonic-gate 
5340*7c478bd9Sstevel@tonic-gate 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
5341*7c478bd9Sstevel@tonic-gate 		return (-1);
5342*7c478bd9Sstevel@tonic-gate 	}
5343*7c478bd9Sstevel@tonic-gate 	if (out != NULL && sz > 0)
5344*7c478bd9Sstevel@tonic-gate 		len = scf_scope_to_fmri(scope, out, sz);
5345*7c478bd9Sstevel@tonic-gate 	else
5346*7c478bd9Sstevel@tonic-gate 		len = scf_scope_to_fmri(scope, tmp, 2);
5347*7c478bd9Sstevel@tonic-gate 
5348*7c478bd9Sstevel@tonic-gate 	HANDLE_RELE_SCOPE(h);
5349*7c478bd9Sstevel@tonic-gate 
5350*7c478bd9Sstevel@tonic-gate 	if (len < 0)
5351*7c478bd9Sstevel@tonic-gate 		return (-1);
5352*7c478bd9Sstevel@tonic-gate 
5353*7c478bd9Sstevel@tonic-gate 	if (out == NULL || len >= sz)
5354*7c478bd9Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5355*7c478bd9Sstevel@tonic-gate 	else
5356*7c478bd9Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz);
5357*7c478bd9Sstevel@tonic-gate 
5358*7c478bd9Sstevel@tonic-gate 	r = scf_service_get_name(svc, tmp, sizeof (tmp));
5359*7c478bd9Sstevel@tonic-gate 	if (r < 0)
5360*7c478bd9Sstevel@tonic-gate 		return (r);
5361*7c478bd9Sstevel@tonic-gate 
5362*7c478bd9Sstevel@tonic-gate 	if (out == NULL || len >= sz)
5363*7c478bd9Sstevel@tonic-gate 		len += r;
5364*7c478bd9Sstevel@tonic-gate 	else
5365*7c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
5366*7c478bd9Sstevel@tonic-gate 
5367*7c478bd9Sstevel@tonic-gate 	return (len);
5368*7c478bd9Sstevel@tonic-gate }
5369*7c478bd9Sstevel@tonic-gate 
5370*7c478bd9Sstevel@tonic-gate ssize_t
5371*7c478bd9Sstevel@tonic-gate scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz)
5372*7c478bd9Sstevel@tonic-gate {
5373*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = inst->rd_d.rd_handle;
5374*7c478bd9Sstevel@tonic-gate 	scf_service_t *svc = HANDLE_HOLD_SERVICE(h);
5375*7c478bd9Sstevel@tonic-gate 	ssize_t r, len;
5376*7c478bd9Sstevel@tonic-gate 
5377*7c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
5378*7c478bd9Sstevel@tonic-gate 
5379*7c478bd9Sstevel@tonic-gate 	r = datael_get_parent(&inst->rd_d, &svc->rd_d);
5380*7c478bd9Sstevel@tonic-gate 	if (r != SCF_SUCCESS) {
5381*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SERVICE(h);
5382*7c478bd9Sstevel@tonic-gate 		return (-1);
5383*7c478bd9Sstevel@tonic-gate 	}
5384*7c478bd9Sstevel@tonic-gate 
5385*7c478bd9Sstevel@tonic-gate 	len = scf_service_to_fmri(svc, out, sz);
5386*7c478bd9Sstevel@tonic-gate 
5387*7c478bd9Sstevel@tonic-gate 	HANDLE_RELE_SERVICE(h);
5388*7c478bd9Sstevel@tonic-gate 
5389*7c478bd9Sstevel@tonic-gate 	if (len < 0)
5390*7c478bd9Sstevel@tonic-gate 		return (len);
5391*7c478bd9Sstevel@tonic-gate 
5392*7c478bd9Sstevel@tonic-gate 	if (len >= sz)
5393*7c478bd9Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
5394*7c478bd9Sstevel@tonic-gate 	else
5395*7c478bd9Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz);
5396*7c478bd9Sstevel@tonic-gate 
5397*7c478bd9Sstevel@tonic-gate 	r = scf_instance_get_name(inst, tmp, sizeof (tmp));
5398*7c478bd9Sstevel@tonic-gate 	if (r < 0)
5399*7c478bd9Sstevel@tonic-gate 		return (r);
5400*7c478bd9Sstevel@tonic-gate 
5401*7c478bd9Sstevel@tonic-gate 	if (len >= sz)
5402*7c478bd9Sstevel@tonic-gate 		len += r;
5403*7c478bd9Sstevel@tonic-gate 	else
5404*7c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
5405*7c478bd9Sstevel@tonic-gate 
5406*7c478bd9Sstevel@tonic-gate 	return (len);
5407*7c478bd9Sstevel@tonic-gate }
5408*7c478bd9Sstevel@tonic-gate 
5409*7c478bd9Sstevel@tonic-gate ssize_t
5410*7c478bd9Sstevel@tonic-gate scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz)
5411*7c478bd9Sstevel@tonic-gate {
5412*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
5413*7c478bd9Sstevel@tonic-gate 
5414*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_parent_type request;
5415*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_integer_response response;
5416*7c478bd9Sstevel@tonic-gate 
5417*7c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
5418*7c478bd9Sstevel@tonic-gate 	ssize_t len, r;
5419*7c478bd9Sstevel@tonic-gate 
5420*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
5421*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE;
5422*7c478bd9Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
5423*7c478bd9Sstevel@tonic-gate 
5424*7c478bd9Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
5425*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
5426*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
5427*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
5428*7c478bd9Sstevel@tonic-gate 
5429*7c478bd9Sstevel@tonic-gate 	if (r < 0)
5430*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
5431*7c478bd9Sstevel@tonic-gate 
5432*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
5433*7c478bd9Sstevel@tonic-gate 	    r < sizeof (response)) {
5434*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
5435*7c478bd9Sstevel@tonic-gate 	}
5436*7c478bd9Sstevel@tonic-gate 
5437*7c478bd9Sstevel@tonic-gate 	switch (response.rpr_value) {
5438*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SERVICE: {
5439*7c478bd9Sstevel@tonic-gate 		scf_service_t *svc;
5440*7c478bd9Sstevel@tonic-gate 
5441*7c478bd9Sstevel@tonic-gate 		svc = HANDLE_HOLD_SERVICE(h);
5442*7c478bd9Sstevel@tonic-gate 
5443*7c478bd9Sstevel@tonic-gate 		r = datael_get_parent(&pg->rd_d, &svc->rd_d);
5444*7c478bd9Sstevel@tonic-gate 
5445*7c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
5446*7c478bd9Sstevel@tonic-gate 			len = scf_service_to_fmri(svc, out, sz);
5447*7c478bd9Sstevel@tonic-gate 
5448*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SERVICE(h);
5449*7c478bd9Sstevel@tonic-gate 		break;
5450*7c478bd9Sstevel@tonic-gate 	}
5451*7c478bd9Sstevel@tonic-gate 
5452*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE: {
5453*7c478bd9Sstevel@tonic-gate 		scf_instance_t *inst;
5454*7c478bd9Sstevel@tonic-gate 
5455*7c478bd9Sstevel@tonic-gate 		inst = HANDLE_HOLD_INSTANCE(h);
5456*7c478bd9Sstevel@tonic-gate 
5457*7c478bd9Sstevel@tonic-gate 		r = datael_get_parent(&pg->rd_d, &inst->rd_d);
5458*7c478bd9Sstevel@tonic-gate 
5459*7c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
5460*7c478bd9Sstevel@tonic-gate 			len = scf_instance_to_fmri(inst, out, sz);
5461*7c478bd9Sstevel@tonic-gate 
5462*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_INSTANCE(h);
5463*7c478bd9Sstevel@tonic-gate 		break;
5464*7c478bd9Sstevel@tonic-gate 	}
5465*7c478bd9Sstevel@tonic-gate 
5466*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPLEVEL: {
5467*7c478bd9Sstevel@tonic-gate 		scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h);
5468*7c478bd9Sstevel@tonic-gate 		scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h);
5469*7c478bd9Sstevel@tonic-gate 		scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h);
5470*7c478bd9Sstevel@tonic-gate 
5471*7c478bd9Sstevel@tonic-gate 		r = datael_get_parent(&pg->rd_d, &level->rd_d);
5472*7c478bd9Sstevel@tonic-gate 
5473*7c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
5474*7c478bd9Sstevel@tonic-gate 			r = datael_get_parent(&level->rd_d, &snap->rd_d);
5475*7c478bd9Sstevel@tonic-gate 
5476*7c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
5477*7c478bd9Sstevel@tonic-gate 			r = datael_get_parent(&snap->rd_d, &inst->rd_d);
5478*7c478bd9Sstevel@tonic-gate 
5479*7c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
5480*7c478bd9Sstevel@tonic-gate 			len = scf_instance_to_fmri(inst, out, sz);
5481*7c478bd9Sstevel@tonic-gate 
5482*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_INSTANCE(h);
5483*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SNAPSHOT(h);
5484*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SNAPLVL(h);
5485*7c478bd9Sstevel@tonic-gate 		break;
5486*7c478bd9Sstevel@tonic-gate 	}
5487*7c478bd9Sstevel@tonic-gate 
5488*7c478bd9Sstevel@tonic-gate 	default:
5489*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
5490*7c478bd9Sstevel@tonic-gate 	}
5491*7c478bd9Sstevel@tonic-gate 
5492*7c478bd9Sstevel@tonic-gate 	if (r != SCF_SUCCESS)
5493*7c478bd9Sstevel@tonic-gate 		return (r);
5494*7c478bd9Sstevel@tonic-gate 
5495*7c478bd9Sstevel@tonic-gate 	if (len >= sz)
5496*7c478bd9Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
5497*7c478bd9Sstevel@tonic-gate 	else
5498*7c478bd9Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz);
5499*7c478bd9Sstevel@tonic-gate 
5500*7c478bd9Sstevel@tonic-gate 	r = scf_pg_get_name(pg, tmp, sizeof (tmp));
5501*7c478bd9Sstevel@tonic-gate 
5502*7c478bd9Sstevel@tonic-gate 	if (r < 0)
5503*7c478bd9Sstevel@tonic-gate 		return (r);
5504*7c478bd9Sstevel@tonic-gate 
5505*7c478bd9Sstevel@tonic-gate 	if (len >= sz)
5506*7c478bd9Sstevel@tonic-gate 		len += r;
5507*7c478bd9Sstevel@tonic-gate 	else
5508*7c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
5509*7c478bd9Sstevel@tonic-gate 
5510*7c478bd9Sstevel@tonic-gate 	return (len);
5511*7c478bd9Sstevel@tonic-gate }
5512*7c478bd9Sstevel@tonic-gate 
5513*7c478bd9Sstevel@tonic-gate ssize_t
5514*7c478bd9Sstevel@tonic-gate scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz)
5515*7c478bd9Sstevel@tonic-gate {
5516*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
5517*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = HANDLE_HOLD_PG(h);
5518*7c478bd9Sstevel@tonic-gate 
5519*7c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
5520*7c478bd9Sstevel@tonic-gate 	ssize_t len;
5521*7c478bd9Sstevel@tonic-gate 	int r;
5522*7c478bd9Sstevel@tonic-gate 
5523*7c478bd9Sstevel@tonic-gate 	r = datael_get_parent(&prop->rd_d, &pg->rd_d);
5524*7c478bd9Sstevel@tonic-gate 	if (r != SCF_SUCCESS) {
5525*7c478bd9Sstevel@tonic-gate 		HANDLE_RELE_PG(h);
5526*7c478bd9Sstevel@tonic-gate 		return (-1);
5527*7c478bd9Sstevel@tonic-gate 	}
5528*7c478bd9Sstevel@tonic-gate 
5529*7c478bd9Sstevel@tonic-gate 	len = scf_pg_to_fmri(pg, out, sz);
5530*7c478bd9Sstevel@tonic-gate 
5531*7c478bd9Sstevel@tonic-gate 	HANDLE_RELE_PG(h);
5532*7c478bd9Sstevel@tonic-gate 
5533*7c478bd9Sstevel@tonic-gate 	if (len >= sz)
5534*7c478bd9Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
5535*7c478bd9Sstevel@tonic-gate 	else
5536*7c478bd9Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz);
5537*7c478bd9Sstevel@tonic-gate 
5538*7c478bd9Sstevel@tonic-gate 	r = scf_property_get_name(prop, tmp, sizeof (tmp));
5539*7c478bd9Sstevel@tonic-gate 
5540*7c478bd9Sstevel@tonic-gate 	if (r < 0)
5541*7c478bd9Sstevel@tonic-gate 		return (r);
5542*7c478bd9Sstevel@tonic-gate 
5543*7c478bd9Sstevel@tonic-gate 	if (len >= sz)
5544*7c478bd9Sstevel@tonic-gate 		len += r;
5545*7c478bd9Sstevel@tonic-gate 	else
5546*7c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
5547*7c478bd9Sstevel@tonic-gate 
5548*7c478bd9Sstevel@tonic-gate 	return (len);
5549*7c478bd9Sstevel@tonic-gate }
5550*7c478bd9Sstevel@tonic-gate 
5551*7c478bd9Sstevel@tonic-gate int
5552*7c478bd9Sstevel@tonic-gate scf_pg_get_underlying_pg(const scf_propertygroup_t *pg,
5553*7c478bd9Sstevel@tonic-gate     scf_propertygroup_t *out)
5554*7c478bd9Sstevel@tonic-gate {
5555*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
5556*7c478bd9Sstevel@tonic-gate 	scf_service_t *svc;
5557*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
5558*7c478bd9Sstevel@tonic-gate 
5559*7c478bd9Sstevel@tonic-gate 	char me[REP_PROTOCOL_NAME_LEN];
5560*7c478bd9Sstevel@tonic-gate 	int r;
5561*7c478bd9Sstevel@tonic-gate 
5562*7c478bd9Sstevel@tonic-gate 	if (h != out->rd_d.rd_handle)
5563*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5564*7c478bd9Sstevel@tonic-gate 
5565*7c478bd9Sstevel@tonic-gate 	r = scf_pg_get_name(pg, me, sizeof (me));
5566*7c478bd9Sstevel@tonic-gate 
5567*7c478bd9Sstevel@tonic-gate 	if (r < 0)
5568*7c478bd9Sstevel@tonic-gate 		return (r);
5569*7c478bd9Sstevel@tonic-gate 
5570*7c478bd9Sstevel@tonic-gate 	svc = HANDLE_HOLD_SERVICE(h);
5571*7c478bd9Sstevel@tonic-gate 	inst = HANDLE_HOLD_INSTANCE(h);
5572*7c478bd9Sstevel@tonic-gate 
5573*7c478bd9Sstevel@tonic-gate 	r = datael_get_parent(&pg->rd_d, &inst->rd_d);
5574*7c478bd9Sstevel@tonic-gate 
5575*7c478bd9Sstevel@tonic-gate 	if (r == SCF_SUCCESS) {
5576*7c478bd9Sstevel@tonic-gate 		r = datael_get_parent(&inst->rd_d, &svc->rd_d);
5577*7c478bd9Sstevel@tonic-gate 		if (r != SCF_SUCCESS) {
5578*7c478bd9Sstevel@tonic-gate 			goto out;
5579*7c478bd9Sstevel@tonic-gate 		}
5580*7c478bd9Sstevel@tonic-gate 		r = scf_service_get_pg(svc, me, out);
5581*7c478bd9Sstevel@tonic-gate 	} else {
5582*7c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_NOT_FOUND);
5583*7c478bd9Sstevel@tonic-gate 	}
5584*7c478bd9Sstevel@tonic-gate 
5585*7c478bd9Sstevel@tonic-gate out:
5586*7c478bd9Sstevel@tonic-gate 	HANDLE_RELE_SERVICE(h);
5587*7c478bd9Sstevel@tonic-gate 	HANDLE_RELE_INSTANCE(h);
5588*7c478bd9Sstevel@tonic-gate 	return (r);
5589*7c478bd9Sstevel@tonic-gate }
5590*7c478bd9Sstevel@tonic-gate 
5591*7c478bd9Sstevel@tonic-gate #define	LEGACY_SCHEME	"lrc:"
5592*7c478bd9Sstevel@tonic-gate #define	LEGACY_UNKNOWN	"unknown"
5593*7c478bd9Sstevel@tonic-gate 
5594*7c478bd9Sstevel@tonic-gate /*
5595*7c478bd9Sstevel@tonic-gate  * Implementation of scf_walk_fmri()
5596*7c478bd9Sstevel@tonic-gate  *
5597*7c478bd9Sstevel@tonic-gate  * This is a little tricky due to the many-to-many relationship between patterns
5598*7c478bd9Sstevel@tonic-gate  * and matches.  We need to be able to satisfy the following requirements:
5599*7c478bd9Sstevel@tonic-gate  *
5600*7c478bd9Sstevel@tonic-gate  * 	1) Detect patterns which match more than one FMRI, and be able to
5601*7c478bd9Sstevel@tonic-gate  *         report which FMRIs have been matched.
5602*7c478bd9Sstevel@tonic-gate  * 	2) Detect patterns which have not matched any FMRIs
5603*7c478bd9Sstevel@tonic-gate  * 	3) Visit each matching FMRI exactly once across all patterns
5604*7c478bd9Sstevel@tonic-gate  * 	4) Ignore FMRIs which have only been matched due to multiply-matching
5605*7c478bd9Sstevel@tonic-gate  *         patterns.
5606*7c478bd9Sstevel@tonic-gate  *
5607*7c478bd9Sstevel@tonic-gate  * We maintain an array of scf_pattern_t structures, one for each argument, and
5608*7c478bd9Sstevel@tonic-gate  * maintain a linked list of scf_match_t structures for each one.  We first
5609*7c478bd9Sstevel@tonic-gate  * qualify each pattern's type:
5610*7c478bd9Sstevel@tonic-gate  *
5611*7c478bd9Sstevel@tonic-gate  *	PATTERN_INVALID		The argument is invalid (too long).
5612*7c478bd9Sstevel@tonic-gate  *
5613*7c478bd9Sstevel@tonic-gate  *	PATTERN_EXACT		The pattern is a complete FMRI.  The list of
5614*7c478bd9Sstevel@tonic-gate  *				matches contains only a single entry.
5615*7c478bd9Sstevel@tonic-gate  *
5616*7c478bd9Sstevel@tonic-gate  * 	PATTERN_GLOB		The pattern will be matched against all
5617*7c478bd9Sstevel@tonic-gate  * 				FMRIs via fnmatch() in the second phase.
5618*7c478bd9Sstevel@tonic-gate  * 				Matches will be added to the pattern's list
5619*7c478bd9Sstevel@tonic-gate  * 				as they are found.
5620*7c478bd9Sstevel@tonic-gate  *
5621*7c478bd9Sstevel@tonic-gate  * 	PATTERN_PARTIAL		Everything else.  We will assume that this is
5622*7c478bd9Sstevel@tonic-gate  * 				an abbreviated FMRI, and match according to
5623*7c478bd9Sstevel@tonic-gate  * 				our abbreviated FMRI rules.  Matches will be
5624*7c478bd9Sstevel@tonic-gate  * 				added to the pattern's list as they are found.
5625*7c478bd9Sstevel@tonic-gate  *
5626*7c478bd9Sstevel@tonic-gate  * The first pass searches for arguments that are complete FMRIs.  These are
5627*7c478bd9Sstevel@tonic-gate  * classified as EXACT patterns and do not necessitate searching the entire
5628*7c478bd9Sstevel@tonic-gate  * tree.
5629*7c478bd9Sstevel@tonic-gate  *
5630*7c478bd9Sstevel@tonic-gate  * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
5631*7c478bd9Sstevel@tonic-gate  * arguments were given), we iterate over all services and instances in the
5632*7c478bd9Sstevel@tonic-gate  * repository, looking for matches.
5633*7c478bd9Sstevel@tonic-gate  *
5634*7c478bd9Sstevel@tonic-gate  * When a match is found, we add the match to the pattern's list.  We also enter
5635*7c478bd9Sstevel@tonic-gate  * the match into a hash table, resulting in something like this:
5636*7c478bd9Sstevel@tonic-gate  *
5637*7c478bd9Sstevel@tonic-gate  *       scf_pattern_t       scf_match_t
5638*7c478bd9Sstevel@tonic-gate  *     +---------------+      +-------+     +-------+
5639*7c478bd9Sstevel@tonic-gate  *     | pattern 'foo' |----->| match |---->| match |
5640*7c478bd9Sstevel@tonic-gate  *     +---------------+      +-------+     +-------+
5641*7c478bd9Sstevel@tonic-gate  *                                |             |
5642*7c478bd9Sstevel@tonic-gate  *           scf_match_key_t      |             |
5643*7c478bd9Sstevel@tonic-gate  *           +--------------+     |             |
5644*7c478bd9Sstevel@tonic-gate  *           | FMRI bar/foo |<----+             |
5645*7c478bd9Sstevel@tonic-gate  *           +--------------+                   |
5646*7c478bd9Sstevel@tonic-gate  *           | FMRI baz/foo |<------------------+
5647*7c478bd9Sstevel@tonic-gate  *           +--------------+
5648*7c478bd9Sstevel@tonic-gate  *
5649*7c478bd9Sstevel@tonic-gate  * Once we have all of this set up, we do one pass to report patterns matching
5650*7c478bd9Sstevel@tonic-gate  * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
5651*7c478bd9Sstevel@tonic-gate  * match was found.
5652*7c478bd9Sstevel@tonic-gate  *
5653*7c478bd9Sstevel@tonic-gate  * Finally, we walk through all valid patterns, and for each match, if we
5654*7c478bd9Sstevel@tonic-gate  * haven't already seen the match (as recorded in the hash table), then we
5655*7c478bd9Sstevel@tonic-gate  * execute the callback.
5656*7c478bd9Sstevel@tonic-gate  */
5657*7c478bd9Sstevel@tonic-gate 
5658*7c478bd9Sstevel@tonic-gate struct scf_matchkey;
5659*7c478bd9Sstevel@tonic-gate struct scf_match;
5660*7c478bd9Sstevel@tonic-gate 
5661*7c478bd9Sstevel@tonic-gate /*
5662*7c478bd9Sstevel@tonic-gate  * scf_pattern_t
5663*7c478bd9Sstevel@tonic-gate  */
5664*7c478bd9Sstevel@tonic-gate typedef struct scf_pattern {
5665*7c478bd9Sstevel@tonic-gate 	enum	{
5666*7c478bd9Sstevel@tonic-gate 		PATTERN_INVALID,	/* Uninitialized state */
5667*7c478bd9Sstevel@tonic-gate 		PATTERN_EXACT,
5668*7c478bd9Sstevel@tonic-gate 		PATTERN_GLOB,
5669*7c478bd9Sstevel@tonic-gate 		PATTERN_PARTIAL
5670*7c478bd9Sstevel@tonic-gate 	} sp_type;
5671*7c478bd9Sstevel@tonic-gate 	char			*sp_arg;	/* Original argument */
5672*7c478bd9Sstevel@tonic-gate 	struct scf_match	*sp_matches;	/* List of matches */
5673*7c478bd9Sstevel@tonic-gate 	int			sp_matchcount;	/* # of matches */
5674*7c478bd9Sstevel@tonic-gate } scf_pattern_t;
5675*7c478bd9Sstevel@tonic-gate 
5676*7c478bd9Sstevel@tonic-gate /*
5677*7c478bd9Sstevel@tonic-gate  * scf_matchkey_t
5678*7c478bd9Sstevel@tonic-gate  */
5679*7c478bd9Sstevel@tonic-gate typedef struct scf_matchkey {
5680*7c478bd9Sstevel@tonic-gate 	char			*sk_fmri;	/* Matching FMRI */
5681*7c478bd9Sstevel@tonic-gate 	char			*sk_legacy;	/* Legacy name */
5682*7c478bd9Sstevel@tonic-gate 	int			sk_seen;	/* If we've been seen */
5683*7c478bd9Sstevel@tonic-gate 	struct scf_matchkey	*sk_next;	/* Next in hash chain */
5684*7c478bd9Sstevel@tonic-gate } scf_matchkey_t;
5685*7c478bd9Sstevel@tonic-gate 
5686*7c478bd9Sstevel@tonic-gate /*
5687*7c478bd9Sstevel@tonic-gate  * scf_match_t
5688*7c478bd9Sstevel@tonic-gate  */
5689*7c478bd9Sstevel@tonic-gate typedef struct scf_match {
5690*7c478bd9Sstevel@tonic-gate 	scf_matchkey_t		*sm_key;
5691*7c478bd9Sstevel@tonic-gate 	struct scf_match	*sm_next;
5692*7c478bd9Sstevel@tonic-gate } scf_match_t;
5693*7c478bd9Sstevel@tonic-gate 
5694*7c478bd9Sstevel@tonic-gate #define	WALK_HTABLE_SIZE	123
5695*7c478bd9Sstevel@tonic-gate 
5696*7c478bd9Sstevel@tonic-gate /*
5697*7c478bd9Sstevel@tonic-gate  * scf_get_key()
5698*7c478bd9Sstevel@tonic-gate  *
5699*7c478bd9Sstevel@tonic-gate  * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
5700*7c478bd9Sstevel@tonic-gate  * this FMRI.  If the FMRI does not exist, it is added to the hash table.  If a
5701*7c478bd9Sstevel@tonic-gate  * new entry cannot be allocated due to lack of memory, NULL is returned.
5702*7c478bd9Sstevel@tonic-gate  */
5703*7c478bd9Sstevel@tonic-gate static scf_matchkey_t *
5704*7c478bd9Sstevel@tonic-gate scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy)
5705*7c478bd9Sstevel@tonic-gate {
5706*7c478bd9Sstevel@tonic-gate 	uint_t h = 0, g;
5707*7c478bd9Sstevel@tonic-gate 	const char *p, *k;
5708*7c478bd9Sstevel@tonic-gate 	scf_matchkey_t *key;
5709*7c478bd9Sstevel@tonic-gate 
5710*7c478bd9Sstevel@tonic-gate 	k = strstr(fmri, ":/");
5711*7c478bd9Sstevel@tonic-gate 	assert(k != NULL);
5712*7c478bd9Sstevel@tonic-gate 	k += 2;
5713*7c478bd9Sstevel@tonic-gate 
5714*7c478bd9Sstevel@tonic-gate 	/*
5715*7c478bd9Sstevel@tonic-gate 	 * Generic hash function from uts/common/os/modhash.c.
5716*7c478bd9Sstevel@tonic-gate 	 */
5717*7c478bd9Sstevel@tonic-gate 	for (p = k; *p != '\0'; ++p) {
5718*7c478bd9Sstevel@tonic-gate 		h = (h << 4) + *p;
5719*7c478bd9Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
5720*7c478bd9Sstevel@tonic-gate 			h ^= (g >> 24);
5721*7c478bd9Sstevel@tonic-gate 			h ^= g;
5722*7c478bd9Sstevel@tonic-gate 		}
5723*7c478bd9Sstevel@tonic-gate 	}
5724*7c478bd9Sstevel@tonic-gate 
5725*7c478bd9Sstevel@tonic-gate 	h %= WALK_HTABLE_SIZE;
5726*7c478bd9Sstevel@tonic-gate 
5727*7c478bd9Sstevel@tonic-gate 	/*
5728*7c478bd9Sstevel@tonic-gate 	 * Search for an existing key
5729*7c478bd9Sstevel@tonic-gate 	 */
5730*7c478bd9Sstevel@tonic-gate 	for (key = htable[h]; key != NULL; key = key->sk_next) {
5731*7c478bd9Sstevel@tonic-gate 		if (strcmp(key->sk_fmri, fmri) == 0)
5732*7c478bd9Sstevel@tonic-gate 			return (key);
5733*7c478bd9Sstevel@tonic-gate 	}
5734*7c478bd9Sstevel@tonic-gate 
5735*7c478bd9Sstevel@tonic-gate 	if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL)
5736*7c478bd9Sstevel@tonic-gate 		return (NULL);
5737*7c478bd9Sstevel@tonic-gate 
5738*7c478bd9Sstevel@tonic-gate 	/*
5739*7c478bd9Sstevel@tonic-gate 	 * Add new key to hash table.
5740*7c478bd9Sstevel@tonic-gate 	 */
5741*7c478bd9Sstevel@tonic-gate 	if ((key->sk_fmri = strdup(fmri)) == NULL) {
5742*7c478bd9Sstevel@tonic-gate 		free(key);
5743*7c478bd9Sstevel@tonic-gate 		return (NULL);
5744*7c478bd9Sstevel@tonic-gate 	}
5745*7c478bd9Sstevel@tonic-gate 
5746*7c478bd9Sstevel@tonic-gate 	if (legacy == NULL) {
5747*7c478bd9Sstevel@tonic-gate 		key->sk_legacy = NULL;
5748*7c478bd9Sstevel@tonic-gate 	} else if ((key->sk_legacy = strdup(legacy)) == NULL) {
5749*7c478bd9Sstevel@tonic-gate 		free(key->sk_fmri);
5750*7c478bd9Sstevel@tonic-gate 		free(key);
5751*7c478bd9Sstevel@tonic-gate 		return (NULL);
5752*7c478bd9Sstevel@tonic-gate 	}
5753*7c478bd9Sstevel@tonic-gate 
5754*7c478bd9Sstevel@tonic-gate 	key->sk_next = htable[h];
5755*7c478bd9Sstevel@tonic-gate 	htable[h] = key;
5756*7c478bd9Sstevel@tonic-gate 
5757*7c478bd9Sstevel@tonic-gate 	return (key);
5758*7c478bd9Sstevel@tonic-gate }
5759*7c478bd9Sstevel@tonic-gate 
5760*7c478bd9Sstevel@tonic-gate /*
5761*7c478bd9Sstevel@tonic-gate  * Given an FMRI, insert it into the pattern's list appropriately.
5762*7c478bd9Sstevel@tonic-gate  * svc_explicit indicates whether matching services should take
5763*7c478bd9Sstevel@tonic-gate  * precedence over matching instances.
5764*7c478bd9Sstevel@tonic-gate  */
5765*7c478bd9Sstevel@tonic-gate static scf_error_t
5766*7c478bd9Sstevel@tonic-gate scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy,
5767*7c478bd9Sstevel@tonic-gate     scf_pattern_t *pattern, int svc_explicit)
5768*7c478bd9Sstevel@tonic-gate {
5769*7c478bd9Sstevel@tonic-gate 	scf_match_t *match;
5770*7c478bd9Sstevel@tonic-gate 
5771*7c478bd9Sstevel@tonic-gate 	/*
5772*7c478bd9Sstevel@tonic-gate 	 * If svc_explicit is set, enforce the constaint that matching
5773*7c478bd9Sstevel@tonic-gate 	 * instances take precedence over matching services. Otherwise,
5774*7c478bd9Sstevel@tonic-gate 	 * matching services take precedence over matching instances.
5775*7c478bd9Sstevel@tonic-gate 	 */
5776*7c478bd9Sstevel@tonic-gate 	if (svc_explicit) {
5777*7c478bd9Sstevel@tonic-gate 		scf_match_t *next, *prev;
5778*7c478bd9Sstevel@tonic-gate 		/*
5779*7c478bd9Sstevel@tonic-gate 		 * If we match an instance, check to see if we must remove
5780*7c478bd9Sstevel@tonic-gate 		 * any matching services (for SCF_WALK_EXPLICIT).
5781*7c478bd9Sstevel@tonic-gate 		 */
5782*7c478bd9Sstevel@tonic-gate 		for (prev = match = pattern->sp_matches; match != NULL;
5783*7c478bd9Sstevel@tonic-gate 		    match = next) {
5784*7c478bd9Sstevel@tonic-gate 			size_t len = strlen(match->sm_key->sk_fmri);
5785*7c478bd9Sstevel@tonic-gate 			next = match->sm_next;
5786*7c478bd9Sstevel@tonic-gate 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
5787*7c478bd9Sstevel@tonic-gate 			    fmri[len] == ':') {
5788*7c478bd9Sstevel@tonic-gate 				if (prev == match)
5789*7c478bd9Sstevel@tonic-gate 					pattern->sp_matches = match->sm_next;
5790*7c478bd9Sstevel@tonic-gate 				else
5791*7c478bd9Sstevel@tonic-gate 					prev->sm_next = match->sm_next;
5792*7c478bd9Sstevel@tonic-gate 				pattern->sp_matchcount--;
5793*7c478bd9Sstevel@tonic-gate 				free(match);
5794*7c478bd9Sstevel@tonic-gate 			} else
5795*7c478bd9Sstevel@tonic-gate 				prev = match;
5796*7c478bd9Sstevel@tonic-gate 		}
5797*7c478bd9Sstevel@tonic-gate 	} else {
5798*7c478bd9Sstevel@tonic-gate 		/*
5799*7c478bd9Sstevel@tonic-gate 		 * If we've matched a service don't add any instances (for
5800*7c478bd9Sstevel@tonic-gate 		 * SCF_WALK_SERVICE).
5801*7c478bd9Sstevel@tonic-gate 		 */
5802*7c478bd9Sstevel@tonic-gate 		for (match = pattern->sp_matches; match != NULL;
5803*7c478bd9Sstevel@tonic-gate 		    match = match->sm_next) {
5804*7c478bd9Sstevel@tonic-gate 			size_t len = strlen(match->sm_key->sk_fmri);
5805*7c478bd9Sstevel@tonic-gate 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
5806*7c478bd9Sstevel@tonic-gate 			    fmri[len] == ':')
5807*7c478bd9Sstevel@tonic-gate 				return (0);
5808*7c478bd9Sstevel@tonic-gate 		}
5809*7c478bd9Sstevel@tonic-gate 	}
5810*7c478bd9Sstevel@tonic-gate 
5811*7c478bd9Sstevel@tonic-gate 	if ((match = malloc(sizeof (scf_match_t))) == NULL)
5812*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NO_MEMORY);
5813*7c478bd9Sstevel@tonic-gate 
5814*7c478bd9Sstevel@tonic-gate 	if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) {
5815*7c478bd9Sstevel@tonic-gate 		free(match);
5816*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NO_MEMORY);
5817*7c478bd9Sstevel@tonic-gate 	}
5818*7c478bd9Sstevel@tonic-gate 
5819*7c478bd9Sstevel@tonic-gate 	match->sm_next = pattern->sp_matches;
5820*7c478bd9Sstevel@tonic-gate 	pattern->sp_matches = match;
5821*7c478bd9Sstevel@tonic-gate 	pattern->sp_matchcount++;
5822*7c478bd9Sstevel@tonic-gate 
5823*7c478bd9Sstevel@tonic-gate 	return (0);
5824*7c478bd9Sstevel@tonic-gate }
5825*7c478bd9Sstevel@tonic-gate 
5826*7c478bd9Sstevel@tonic-gate /*
5827*7c478bd9Sstevel@tonic-gate  * Returns 1 if the fmri matches the given pattern, 0 otherwise.
5828*7c478bd9Sstevel@tonic-gate  */
5829*7c478bd9Sstevel@tonic-gate static int
5830*7c478bd9Sstevel@tonic-gate scf_cmp_pattern(char *fmri, scf_pattern_t *pattern)
5831*7c478bd9Sstevel@tonic-gate {
5832*7c478bd9Sstevel@tonic-gate 	char *tmp;
5833*7c478bd9Sstevel@tonic-gate 
5834*7c478bd9Sstevel@tonic-gate 	if (pattern->sp_type == PATTERN_GLOB) {
5835*7c478bd9Sstevel@tonic-gate 		if (fnmatch(pattern->sp_arg, fmri, 0) == 0)
5836*7c478bd9Sstevel@tonic-gate 			return (1);
5837*7c478bd9Sstevel@tonic-gate 	} else if (pattern->sp_type == PATTERN_PARTIAL &&
5838*7c478bd9Sstevel@tonic-gate 	    (tmp = strstr(fmri, pattern->sp_arg)) != NULL) {
5839*7c478bd9Sstevel@tonic-gate 		/*
5840*7c478bd9Sstevel@tonic-gate 		 * We only allow partial matches anchored on the end of
5841*7c478bd9Sstevel@tonic-gate 		 * a service or instance, and beginning on an element
5842*7c478bd9Sstevel@tonic-gate 		 * boundary.
5843*7c478bd9Sstevel@tonic-gate 		 */
5844*7c478bd9Sstevel@tonic-gate 		if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' &&
5845*7c478bd9Sstevel@tonic-gate 		    tmp[0] != ':')
5846*7c478bd9Sstevel@tonic-gate 			return (0);
5847*7c478bd9Sstevel@tonic-gate 		tmp += strlen(pattern->sp_arg);
5848*7c478bd9Sstevel@tonic-gate 		if (tmp != fmri + strlen(fmri) && tmp[0] != ':' &&
5849*7c478bd9Sstevel@tonic-gate 		    tmp[-1] != ':')
5850*7c478bd9Sstevel@tonic-gate 			return (0);
5851*7c478bd9Sstevel@tonic-gate 
5852*7c478bd9Sstevel@tonic-gate 		/*
5853*7c478bd9Sstevel@tonic-gate 		 * If the user has supplied a short pattern that matches
5854*7c478bd9Sstevel@tonic-gate 		 * 'svc:/' or 'lrc:/', ignore it.
5855*7c478bd9Sstevel@tonic-gate 		 */
5856*7c478bd9Sstevel@tonic-gate 		if (tmp <= fmri + 4)
5857*7c478bd9Sstevel@tonic-gate 			return (0);
5858*7c478bd9Sstevel@tonic-gate 
5859*7c478bd9Sstevel@tonic-gate 		return (1);
5860*7c478bd9Sstevel@tonic-gate 	}
5861*7c478bd9Sstevel@tonic-gate 
5862*7c478bd9Sstevel@tonic-gate 	return (0);
5863*7c478bd9Sstevel@tonic-gate }
5864*7c478bd9Sstevel@tonic-gate 
5865*7c478bd9Sstevel@tonic-gate /*
5866*7c478bd9Sstevel@tonic-gate  * Attempts to match the given FMRI against a set of patterns, keeping track of
5867*7c478bd9Sstevel@tonic-gate  * the results.
5868*7c478bd9Sstevel@tonic-gate  */
5869*7c478bd9Sstevel@tonic-gate static scf_error_t
5870*7c478bd9Sstevel@tonic-gate scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy,
5871*7c478bd9Sstevel@tonic-gate     int npattern, scf_pattern_t *pattern, int svc_explicit)
5872*7c478bd9Sstevel@tonic-gate {
5873*7c478bd9Sstevel@tonic-gate 	int i;
5874*7c478bd9Sstevel@tonic-gate 	int ret = 0;
5875*7c478bd9Sstevel@tonic-gate 
5876*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < npattern; i++) {
5877*7c478bd9Sstevel@tonic-gate 		if (scf_cmp_pattern(fmri, &pattern[i]) &&
5878*7c478bd9Sstevel@tonic-gate 		    (ret = scf_add_match(htable, fmri,
5879*7c478bd9Sstevel@tonic-gate 		    legacy, &pattern[i], svc_explicit)) != 0)
5880*7c478bd9Sstevel@tonic-gate 			return (ret);
5881*7c478bd9Sstevel@tonic-gate 	}
5882*7c478bd9Sstevel@tonic-gate 
5883*7c478bd9Sstevel@tonic-gate 	return (0);
5884*7c478bd9Sstevel@tonic-gate }
5885*7c478bd9Sstevel@tonic-gate 
5886*7c478bd9Sstevel@tonic-gate scf_error_t
5887*7c478bd9Sstevel@tonic-gate scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags,
5888*7c478bd9Sstevel@tonic-gate     scf_walk_callback callback, void *data, int *err,
5889*7c478bd9Sstevel@tonic-gate     void (*errfunc)(const char *, ...))
5890*7c478bd9Sstevel@tonic-gate {
5891*7c478bd9Sstevel@tonic-gate 	scf_pattern_t *pattern = NULL;
5892*7c478bd9Sstevel@tonic-gate 	int i;
5893*7c478bd9Sstevel@tonic-gate 	char *fmri = NULL;
5894*7c478bd9Sstevel@tonic-gate 	ssize_t max_fmri_length;
5895*7c478bd9Sstevel@tonic-gate 	scf_service_t *svc = NULL;
5896*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst = NULL;
5897*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL;
5898*7c478bd9Sstevel@tonic-gate 	scf_scope_t *scope = NULL;
5899*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
5900*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
5901*7c478bd9Sstevel@tonic-gate 	scf_value_t *value = NULL;
5902*7c478bd9Sstevel@tonic-gate 	int ret = 0;
5903*7c478bd9Sstevel@tonic-gate 	scf_matchkey_t **htable = NULL;
5904*7c478bd9Sstevel@tonic-gate 	int pattern_search = 0;
5905*7c478bd9Sstevel@tonic-gate 	ssize_t max_name_length;
5906*7c478bd9Sstevel@tonic-gate 	char *pgname = NULL;
5907*7c478bd9Sstevel@tonic-gate 	scf_walkinfo_t info;
5908*7c478bd9Sstevel@tonic-gate 
5909*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
5910*7c478bd9Sstevel@tonic-gate 	if (flags & SCF_WALK_EXPLICIT)
5911*7c478bd9Sstevel@tonic-gate 		assert(flags & SCF_WALK_SERVICE);
5912*7c478bd9Sstevel@tonic-gate 	if (flags & SCF_WALK_NOINSTANCE)
5913*7c478bd9Sstevel@tonic-gate 		assert(flags & SCF_WALK_SERVICE);
5914*7c478bd9Sstevel@tonic-gate 	if (flags & SCF_WALK_PROPERTY)
5915*7c478bd9Sstevel@tonic-gate 		assert(!(flags & SCF_WALK_LEGACY));
5916*7c478bd9Sstevel@tonic-gate #endif
5917*7c478bd9Sstevel@tonic-gate 
5918*7c478bd9Sstevel@tonic-gate 	/*
5919*7c478bd9Sstevel@tonic-gate 	 * Setup initial variables
5920*7c478bd9Sstevel@tonic-gate 	 */
5921*7c478bd9Sstevel@tonic-gate 	if ((max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1 ||
5922*7c478bd9Sstevel@tonic-gate 	    (max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1)
5923*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INTERNAL);
5924*7c478bd9Sstevel@tonic-gate 
5925*7c478bd9Sstevel@tonic-gate 	if ((fmri = malloc(max_fmri_length + 1)) == NULL ||
5926*7c478bd9Sstevel@tonic-gate 	    (pgname = malloc(max_name_length + 1)) == NULL) {
5927*7c478bd9Sstevel@tonic-gate 		ret = SCF_ERROR_NO_MEMORY;
5928*7c478bd9Sstevel@tonic-gate 		goto error;
5929*7c478bd9Sstevel@tonic-gate 	}
5930*7c478bd9Sstevel@tonic-gate 
5931*7c478bd9Sstevel@tonic-gate 	if (argc == 0) {
5932*7c478bd9Sstevel@tonic-gate 		pattern = NULL;
5933*7c478bd9Sstevel@tonic-gate 	} else if ((pattern = calloc(argc, sizeof (scf_pattern_t)))
5934*7c478bd9Sstevel@tonic-gate 	    == NULL) {
5935*7c478bd9Sstevel@tonic-gate 		ret = SCF_ERROR_NO_MEMORY;
5936*7c478bd9Sstevel@tonic-gate 		goto error;
5937*7c478bd9Sstevel@tonic-gate 	}
5938*7c478bd9Sstevel@tonic-gate 
5939*7c478bd9Sstevel@tonic-gate 	if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) {
5940*7c478bd9Sstevel@tonic-gate 		ret = SCF_ERROR_NO_MEMORY;
5941*7c478bd9Sstevel@tonic-gate 		goto error;
5942*7c478bd9Sstevel@tonic-gate 	}
5943*7c478bd9Sstevel@tonic-gate 
5944*7c478bd9Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
5945*7c478bd9Sstevel@tonic-gate 	    (svc = scf_service_create(h)) == NULL ||
5946*7c478bd9Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL ||
5947*7c478bd9Sstevel@tonic-gate 	    (sciter = scf_iter_create(h)) == NULL ||
5948*7c478bd9Sstevel@tonic-gate 	    (siter = scf_iter_create(h)) == NULL ||
5949*7c478bd9Sstevel@tonic-gate 	    (scope = scf_scope_create(h)) == NULL ||
5950*7c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
5951*7c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
5952*7c478bd9Sstevel@tonic-gate 	    (value = scf_value_create(h)) == NULL) {
5953*7c478bd9Sstevel@tonic-gate 		ret = scf_error();
5954*7c478bd9Sstevel@tonic-gate 		goto error;
5955*7c478bd9Sstevel@tonic-gate 	}
5956*7c478bd9Sstevel@tonic-gate 
5957*7c478bd9Sstevel@tonic-gate 	/*
5958*7c478bd9Sstevel@tonic-gate 	 * For each fmri given, we first check to see if it's a full service,
5959*7c478bd9Sstevel@tonic-gate 	 * instance, property group, or property FMRI.  This avoids having to do
5960*7c478bd9Sstevel@tonic-gate 	 * the (rather expensive) walk of all instances.  Any element which does
5961*7c478bd9Sstevel@tonic-gate 	 * not match a full fmri is identified as a globbed pattern or a partial
5962*7c478bd9Sstevel@tonic-gate 	 * fmri and stored in a private array when walking instances.
5963*7c478bd9Sstevel@tonic-gate 	 */
5964*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
5965*7c478bd9Sstevel@tonic-gate 		const char *scope_name, *svc_name, *inst_name, *pg_name;
5966*7c478bd9Sstevel@tonic-gate 		const char *prop_name;
5967*7c478bd9Sstevel@tonic-gate 
5968*7c478bd9Sstevel@tonic-gate 		if (strlen(argv[i]) > max_fmri_length) {
5969*7c478bd9Sstevel@tonic-gate 			errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]);
5970*7c478bd9Sstevel@tonic-gate 			if (err != NULL)
5971*7c478bd9Sstevel@tonic-gate 				*err = UU_EXIT_FATAL;
5972*7c478bd9Sstevel@tonic-gate 			continue;
5973*7c478bd9Sstevel@tonic-gate 		}
5974*7c478bd9Sstevel@tonic-gate 
5975*7c478bd9Sstevel@tonic-gate 		(void) strcpy(fmri, argv[i]);
5976*7c478bd9Sstevel@tonic-gate 		if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name,
5977*7c478bd9Sstevel@tonic-gate 		    &pg_name, &prop_name) != SCF_SUCCESS)
5978*7c478bd9Sstevel@tonic-gate 			goto badfmri;
5979*7c478bd9Sstevel@tonic-gate 
5980*7c478bd9Sstevel@tonic-gate 		/*
5981*7c478bd9Sstevel@tonic-gate 		 * If the user has specified SCF_WALK_PROPERTY, allow property
5982*7c478bd9Sstevel@tonic-gate 		 * groups and properties.
5983*7c478bd9Sstevel@tonic-gate 		 */
5984*7c478bd9Sstevel@tonic-gate 		if (pg_name != NULL || prop_name != NULL) {
5985*7c478bd9Sstevel@tonic-gate 			if (!(flags & SCF_WALK_PROPERTY))
5986*7c478bd9Sstevel@tonic-gate 				goto badfmri;
5987*7c478bd9Sstevel@tonic-gate 
5988*7c478bd9Sstevel@tonic-gate 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
5989*7c478bd9Sstevel@tonic-gate 			    NULL, pg, prop, 0) != 0)
5990*7c478bd9Sstevel@tonic-gate 				goto badfmri;
5991*7c478bd9Sstevel@tonic-gate 
5992*7c478bd9Sstevel@tonic-gate 			if (scf_pg_get_name(pg, NULL, 0) < 0 &&
5993*7c478bd9Sstevel@tonic-gate 			    scf_property_get_name(prop, NULL, 0) < 0)
5994*7c478bd9Sstevel@tonic-gate 				goto badfmri;
5995*7c478bd9Sstevel@tonic-gate 
5996*7c478bd9Sstevel@tonic-gate 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
5997*7c478bd9Sstevel@tonic-gate 			    <= 0) {
5998*7c478bd9Sstevel@tonic-gate 				/*
5999*7c478bd9Sstevel@tonic-gate 				 * scf_parse_fmri() should have caught this.
6000*7c478bd9Sstevel@tonic-gate 				 */
6001*7c478bd9Sstevel@tonic-gate 				abort();
6002*7c478bd9Sstevel@tonic-gate 			}
6003*7c478bd9Sstevel@tonic-gate 
6004*7c478bd9Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
6005*7c478bd9Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6006*7c478bd9Sstevel@tonic-gate 				goto error;
6007*7c478bd9Sstevel@tonic-gate 
6008*7c478bd9Sstevel@tonic-gate 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6009*7c478bd9Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
6010*7c478bd9Sstevel@tonic-gate 				goto error;
6011*7c478bd9Sstevel@tonic-gate 			}
6012*7c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_EXACT;
6013*7c478bd9Sstevel@tonic-gate 		}
6014*7c478bd9Sstevel@tonic-gate 
6015*7c478bd9Sstevel@tonic-gate 		/*
6016*7c478bd9Sstevel@tonic-gate 		 * We need at least a service name
6017*7c478bd9Sstevel@tonic-gate 		 */
6018*7c478bd9Sstevel@tonic-gate 		if (scope_name == NULL || svc_name == NULL)
6019*7c478bd9Sstevel@tonic-gate 			goto badfmri;
6020*7c478bd9Sstevel@tonic-gate 
6021*7c478bd9Sstevel@tonic-gate 		/*
6022*7c478bd9Sstevel@tonic-gate 		 * If we have a fully qualified instance, add it to our list of
6023*7c478bd9Sstevel@tonic-gate 		 * fmris to watch.
6024*7c478bd9Sstevel@tonic-gate 		 */
6025*7c478bd9Sstevel@tonic-gate 		if (inst_name != NULL) {
6026*7c478bd9Sstevel@tonic-gate 			if (flags & SCF_WALK_NOINSTANCE)
6027*7c478bd9Sstevel@tonic-gate 				goto badfmri;
6028*7c478bd9Sstevel@tonic-gate 
6029*7c478bd9Sstevel@tonic-gate 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
6030*7c478bd9Sstevel@tonic-gate 			    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
6031*7c478bd9Sstevel@tonic-gate 				goto badfmri;
6032*7c478bd9Sstevel@tonic-gate 
6033*7c478bd9Sstevel@tonic-gate 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
6034*7c478bd9Sstevel@tonic-gate 			    <= 0)
6035*7c478bd9Sstevel@tonic-gate 				goto badfmri;
6036*7c478bd9Sstevel@tonic-gate 
6037*7c478bd9Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
6038*7c478bd9Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6039*7c478bd9Sstevel@tonic-gate 				goto error;
6040*7c478bd9Sstevel@tonic-gate 
6041*7c478bd9Sstevel@tonic-gate 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6042*7c478bd9Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
6043*7c478bd9Sstevel@tonic-gate 				goto error;
6044*7c478bd9Sstevel@tonic-gate 			}
6045*7c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_EXACT;
6046*7c478bd9Sstevel@tonic-gate 
6047*7c478bd9Sstevel@tonic-gate 			continue;
6048*7c478bd9Sstevel@tonic-gate 		}
6049*7c478bd9Sstevel@tonic-gate 
6050*7c478bd9Sstevel@tonic-gate 		if (scf_handle_decode_fmri(h, argv[i], NULL, svc,
6051*7c478bd9Sstevel@tonic-gate 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) !=
6052*7c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS)
6053*7c478bd9Sstevel@tonic-gate 			goto badfmri;
6054*7c478bd9Sstevel@tonic-gate 
6055*7c478bd9Sstevel@tonic-gate 		/*
6056*7c478bd9Sstevel@tonic-gate 		 * If the user allows for bare services, then simply
6057*7c478bd9Sstevel@tonic-gate 		 * pass this service on.
6058*7c478bd9Sstevel@tonic-gate 		 */
6059*7c478bd9Sstevel@tonic-gate 		if (flags & SCF_WALK_SERVICE) {
6060*7c478bd9Sstevel@tonic-gate 			if (scf_service_to_fmri(svc, fmri,
6061*7c478bd9Sstevel@tonic-gate 			    max_fmri_length + 1) <= 0) {
6062*7c478bd9Sstevel@tonic-gate 				ret = scf_error();
6063*7c478bd9Sstevel@tonic-gate 				goto error;
6064*7c478bd9Sstevel@tonic-gate 			}
6065*7c478bd9Sstevel@tonic-gate 
6066*7c478bd9Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
6067*7c478bd9Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6068*7c478bd9Sstevel@tonic-gate 				goto error;
6069*7c478bd9Sstevel@tonic-gate 
6070*7c478bd9Sstevel@tonic-gate 			if ((pattern[i].sp_arg = strdup(argv[i]))
6071*7c478bd9Sstevel@tonic-gate 			    == NULL) {
6072*7c478bd9Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
6073*7c478bd9Sstevel@tonic-gate 				goto error;
6074*7c478bd9Sstevel@tonic-gate 			}
6075*7c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_EXACT;
6076*7c478bd9Sstevel@tonic-gate 			continue;
6077*7c478bd9Sstevel@tonic-gate 		}
6078*7c478bd9Sstevel@tonic-gate 
6079*7c478bd9Sstevel@tonic-gate 		if (flags & SCF_WALK_NOINSTANCE)
6080*7c478bd9Sstevel@tonic-gate 			goto badfmri;
6081*7c478bd9Sstevel@tonic-gate 
6082*7c478bd9Sstevel@tonic-gate 		/*
6083*7c478bd9Sstevel@tonic-gate 		 * Otherwise, iterate over all instances in the service.
6084*7c478bd9Sstevel@tonic-gate 		 */
6085*7c478bd9Sstevel@tonic-gate 		if (scf_iter_service_instances(iter, svc) !=
6086*7c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
6087*7c478bd9Sstevel@tonic-gate 			ret = scf_error();
6088*7c478bd9Sstevel@tonic-gate 			goto error;
6089*7c478bd9Sstevel@tonic-gate 		}
6090*7c478bd9Sstevel@tonic-gate 
6091*7c478bd9Sstevel@tonic-gate 		for (;;) {
6092*7c478bd9Sstevel@tonic-gate 			ret = scf_iter_next_instance(iter, inst);
6093*7c478bd9Sstevel@tonic-gate 			if (ret == 0)
6094*7c478bd9Sstevel@tonic-gate 				break;
6095*7c478bd9Sstevel@tonic-gate 			if (ret != 1) {
6096*7c478bd9Sstevel@tonic-gate 				ret = scf_error();
6097*7c478bd9Sstevel@tonic-gate 				goto error;
6098*7c478bd9Sstevel@tonic-gate 			}
6099*7c478bd9Sstevel@tonic-gate 
6100*7c478bd9Sstevel@tonic-gate 			if (scf_instance_to_fmri(inst, fmri,
6101*7c478bd9Sstevel@tonic-gate 			    max_fmri_length + 1) == -1)
6102*7c478bd9Sstevel@tonic-gate 				goto badfmri;
6103*7c478bd9Sstevel@tonic-gate 
6104*7c478bd9Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
6105*7c478bd9Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6106*7c478bd9Sstevel@tonic-gate 				goto error;
6107*7c478bd9Sstevel@tonic-gate 		}
6108*7c478bd9Sstevel@tonic-gate 
6109*7c478bd9Sstevel@tonic-gate 		if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6110*7c478bd9Sstevel@tonic-gate 			ret = SCF_ERROR_NO_MEMORY;
6111*7c478bd9Sstevel@tonic-gate 			goto error;
6112*7c478bd9Sstevel@tonic-gate 		}
6113*7c478bd9Sstevel@tonic-gate 		pattern[i].sp_type = PATTERN_EXACT;
6114*7c478bd9Sstevel@tonic-gate 
6115*7c478bd9Sstevel@tonic-gate 		continue;
6116*7c478bd9Sstevel@tonic-gate 
6117*7c478bd9Sstevel@tonic-gate badfmri:
6118*7c478bd9Sstevel@tonic-gate 
6119*7c478bd9Sstevel@tonic-gate 		/*
6120*7c478bd9Sstevel@tonic-gate 		 * If we got here because of a fatal error, bail out
6121*7c478bd9Sstevel@tonic-gate 		 * immediately.
6122*7c478bd9Sstevel@tonic-gate 		 */
6123*7c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
6124*7c478bd9Sstevel@tonic-gate 			ret = scf_error();
6125*7c478bd9Sstevel@tonic-gate 			goto error;
6126*7c478bd9Sstevel@tonic-gate 		}
6127*7c478bd9Sstevel@tonic-gate 
6128*7c478bd9Sstevel@tonic-gate 		/*
6129*7c478bd9Sstevel@tonic-gate 		 * At this point we failed to interpret the argument as a
6130*7c478bd9Sstevel@tonic-gate 		 * complete fmri, so mark it as a partial or globbed FMRI for
6131*7c478bd9Sstevel@tonic-gate 		 * later processing.
6132*7c478bd9Sstevel@tonic-gate 		 */
6133*7c478bd9Sstevel@tonic-gate 		if (strpbrk(argv[i], "*?[") != NULL) {
6134*7c478bd9Sstevel@tonic-gate 			/*
6135*7c478bd9Sstevel@tonic-gate 			 * Prepend svc:/ to patterns which don't begin with * or
6136*7c478bd9Sstevel@tonic-gate 			 * svc: or lrc:.
6137*7c478bd9Sstevel@tonic-gate 			 */
6138*7c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_GLOB;
6139*7c478bd9Sstevel@tonic-gate 			if (argv[i][0] == '*' ||
6140*7c478bd9Sstevel@tonic-gate 			    (strlen(argv[i]) >= 4 && argv[i][3] == ':'))
6141*7c478bd9Sstevel@tonic-gate 				pattern[i].sp_arg = strdup(argv[i]);
6142*7c478bd9Sstevel@tonic-gate 			else {
6143*7c478bd9Sstevel@tonic-gate 				pattern[i].sp_arg = malloc(strlen(argv[i]) + 6);
6144*7c478bd9Sstevel@tonic-gate 				if (pattern[i].sp_arg != NULL)
6145*7c478bd9Sstevel@tonic-gate 					(void) snprintf(pattern[i].sp_arg,
6146*7c478bd9Sstevel@tonic-gate 					    strlen(argv[i]) + 6, "svc:/%s",
6147*7c478bd9Sstevel@tonic-gate 					    argv[i]);
6148*7c478bd9Sstevel@tonic-gate 			}
6149*7c478bd9Sstevel@tonic-gate 		} else {
6150*7c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_PARTIAL;
6151*7c478bd9Sstevel@tonic-gate 			pattern[i].sp_arg = strdup(argv[i]);
6152*7c478bd9Sstevel@tonic-gate 		}
6153*7c478bd9Sstevel@tonic-gate 		pattern_search = 1;
6154*7c478bd9Sstevel@tonic-gate 		if (pattern[i].sp_arg == NULL) {
6155*7c478bd9Sstevel@tonic-gate 			ret = SCF_ERROR_NO_MEMORY;
6156*7c478bd9Sstevel@tonic-gate 			goto error;
6157*7c478bd9Sstevel@tonic-gate 		}
6158*7c478bd9Sstevel@tonic-gate 	}
6159*7c478bd9Sstevel@tonic-gate 
6160*7c478bd9Sstevel@tonic-gate 	if (pattern_search || argc == 0) {
6161*7c478bd9Sstevel@tonic-gate 		/*
6162*7c478bd9Sstevel@tonic-gate 		 * We have a set of patterns to search for.  Iterate over all
6163*7c478bd9Sstevel@tonic-gate 		 * instances and legacy services searching for matches.
6164*7c478bd9Sstevel@tonic-gate 		 */
6165*7c478bd9Sstevel@tonic-gate 		if (scf_handle_get_local_scope(h, scope) != 0) {
6166*7c478bd9Sstevel@tonic-gate 			ret = scf_error();
6167*7c478bd9Sstevel@tonic-gate 			goto error;
6168*7c478bd9Sstevel@tonic-gate 		}
6169*7c478bd9Sstevel@tonic-gate 
6170*7c478bd9Sstevel@tonic-gate 		if (scf_iter_scope_services(sciter, scope) != 0) {
6171*7c478bd9Sstevel@tonic-gate 			ret = scf_error();
6172*7c478bd9Sstevel@tonic-gate 			goto error;
6173*7c478bd9Sstevel@tonic-gate 		}
6174*7c478bd9Sstevel@tonic-gate 
6175*7c478bd9Sstevel@tonic-gate 		for (;;) {
6176*7c478bd9Sstevel@tonic-gate 			ret = scf_iter_next_service(sciter, svc);
6177*7c478bd9Sstevel@tonic-gate 			if (ret == 0)
6178*7c478bd9Sstevel@tonic-gate 				break;
6179*7c478bd9Sstevel@tonic-gate 			if (ret != 1) {
6180*7c478bd9Sstevel@tonic-gate 				ret = scf_error();
6181*7c478bd9Sstevel@tonic-gate 				goto error;
6182*7c478bd9Sstevel@tonic-gate 			}
6183*7c478bd9Sstevel@tonic-gate 
6184*7c478bd9Sstevel@tonic-gate 			if (flags & SCF_WALK_SERVICE) {
6185*7c478bd9Sstevel@tonic-gate 				/*
6186*7c478bd9Sstevel@tonic-gate 				 * If the user is requesting bare services, try
6187*7c478bd9Sstevel@tonic-gate 				 * to match the service first.
6188*7c478bd9Sstevel@tonic-gate 				 */
6189*7c478bd9Sstevel@tonic-gate 				if (scf_service_to_fmri(svc, fmri,
6190*7c478bd9Sstevel@tonic-gate 				    max_fmri_length + 1) < 0) {
6191*7c478bd9Sstevel@tonic-gate 					ret = scf_error();
6192*7c478bd9Sstevel@tonic-gate 					goto error;
6193*7c478bd9Sstevel@tonic-gate 				}
6194*7c478bd9Sstevel@tonic-gate 
6195*7c478bd9Sstevel@tonic-gate 				if (argc == 0) {
6196*7c478bd9Sstevel@tonic-gate 					info.fmri = fmri;
6197*7c478bd9Sstevel@tonic-gate 					info.scope = scope;
6198*7c478bd9Sstevel@tonic-gate 					info.svc = svc;
6199*7c478bd9Sstevel@tonic-gate 					info.inst = NULL;
6200*7c478bd9Sstevel@tonic-gate 					info.pg = NULL;
6201*7c478bd9Sstevel@tonic-gate 					info.prop = NULL;
6202*7c478bd9Sstevel@tonic-gate 					if ((ret = callback(data, &info)) != 0)
6203*7c478bd9Sstevel@tonic-gate 						goto error;
6204*7c478bd9Sstevel@tonic-gate 					continue;
6205*7c478bd9Sstevel@tonic-gate 				} else if ((ret = scf_pattern_match(htable,
6206*7c478bd9Sstevel@tonic-gate 				    fmri, NULL, argc, pattern,
6207*7c478bd9Sstevel@tonic-gate 				    flags & SCF_WALK_EXPLICIT)) != 0) {
6208*7c478bd9Sstevel@tonic-gate 					goto error;
6209*7c478bd9Sstevel@tonic-gate 				}
6210*7c478bd9Sstevel@tonic-gate 			}
6211*7c478bd9Sstevel@tonic-gate 
6212*7c478bd9Sstevel@tonic-gate 			if (flags & SCF_WALK_NOINSTANCE)
6213*7c478bd9Sstevel@tonic-gate 				continue;
6214*7c478bd9Sstevel@tonic-gate 
6215*7c478bd9Sstevel@tonic-gate 			/*
6216*7c478bd9Sstevel@tonic-gate 			 * Iterate over all instances in the service.
6217*7c478bd9Sstevel@tonic-gate 			 */
6218*7c478bd9Sstevel@tonic-gate 			if (scf_iter_service_instances(siter, svc) != 0) {
6219*7c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_DELETED) {
6220*7c478bd9Sstevel@tonic-gate 					ret = scf_error();
6221*7c478bd9Sstevel@tonic-gate 					goto error;
6222*7c478bd9Sstevel@tonic-gate 				}
6223*7c478bd9Sstevel@tonic-gate 				continue;
6224*7c478bd9Sstevel@tonic-gate 			}
6225*7c478bd9Sstevel@tonic-gate 
6226*7c478bd9Sstevel@tonic-gate 			for (;;) {
6227*7c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_instance(siter, inst);
6228*7c478bd9Sstevel@tonic-gate 				if (ret == 0)
6229*7c478bd9Sstevel@tonic-gate 					break;
6230*7c478bd9Sstevel@tonic-gate 				if (ret != 1) {
6231*7c478bd9Sstevel@tonic-gate 					if (scf_error() != SCF_ERROR_DELETED) {
6232*7c478bd9Sstevel@tonic-gate 						ret = scf_error();
6233*7c478bd9Sstevel@tonic-gate 						goto error;
6234*7c478bd9Sstevel@tonic-gate 					}
6235*7c478bd9Sstevel@tonic-gate 					break;
6236*7c478bd9Sstevel@tonic-gate 				}
6237*7c478bd9Sstevel@tonic-gate 
6238*7c478bd9Sstevel@tonic-gate 				if (scf_instance_to_fmri(inst, fmri,
6239*7c478bd9Sstevel@tonic-gate 				    max_fmri_length + 1) < 0) {
6240*7c478bd9Sstevel@tonic-gate 					ret = scf_error();
6241*7c478bd9Sstevel@tonic-gate 					goto error;
6242*7c478bd9Sstevel@tonic-gate 				}
6243*7c478bd9Sstevel@tonic-gate 
6244*7c478bd9Sstevel@tonic-gate 				/*
6245*7c478bd9Sstevel@tonic-gate 				 * Without arguments, execute the callback
6246*7c478bd9Sstevel@tonic-gate 				 * immediately.
6247*7c478bd9Sstevel@tonic-gate 				 */
6248*7c478bd9Sstevel@tonic-gate 				if (argc == 0) {
6249*7c478bd9Sstevel@tonic-gate 					info.fmri = fmri;
6250*7c478bd9Sstevel@tonic-gate 					info.scope = scope;
6251*7c478bd9Sstevel@tonic-gate 					info.svc = svc;
6252*7c478bd9Sstevel@tonic-gate 					info.inst = inst;
6253*7c478bd9Sstevel@tonic-gate 					info.pg = NULL;
6254*7c478bd9Sstevel@tonic-gate 					info.prop = NULL;
6255*7c478bd9Sstevel@tonic-gate 					if ((ret = callback(data, &info)) != 0)
6256*7c478bd9Sstevel@tonic-gate 						goto error;
6257*7c478bd9Sstevel@tonic-gate 				} else if ((ret = scf_pattern_match(htable,
6258*7c478bd9Sstevel@tonic-gate 				    fmri, NULL, argc, pattern,
6259*7c478bd9Sstevel@tonic-gate 				    flags & SCF_WALK_EXPLICIT)) != 0) {
6260*7c478bd9Sstevel@tonic-gate 					goto error;
6261*7c478bd9Sstevel@tonic-gate 				}
6262*7c478bd9Sstevel@tonic-gate 			}
6263*7c478bd9Sstevel@tonic-gate 		}
6264*7c478bd9Sstevel@tonic-gate 
6265*7c478bd9Sstevel@tonic-gate 		/*
6266*7c478bd9Sstevel@tonic-gate 		 * Search legacy services
6267*7c478bd9Sstevel@tonic-gate 		 */
6268*7c478bd9Sstevel@tonic-gate 		if ((flags & SCF_WALK_LEGACY)) {
6269*7c478bd9Sstevel@tonic-gate 			if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE,
6270*7c478bd9Sstevel@tonic-gate 			    svc) != 0) {
6271*7c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_NOT_FOUND) {
6272*7c478bd9Sstevel@tonic-gate 					ret = scf_error();
6273*7c478bd9Sstevel@tonic-gate 					goto error;
6274*7c478bd9Sstevel@tonic-gate 				}
6275*7c478bd9Sstevel@tonic-gate 
6276*7c478bd9Sstevel@tonic-gate 				goto nolegacy;
6277*7c478bd9Sstevel@tonic-gate 			}
6278*7c478bd9Sstevel@tonic-gate 
6279*7c478bd9Sstevel@tonic-gate 			if (scf_iter_service_pgs_typed(iter, svc,
6280*7c478bd9Sstevel@tonic-gate 			    SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
6281*7c478bd9Sstevel@tonic-gate 				ret = scf_error();
6282*7c478bd9Sstevel@tonic-gate 				goto error;
6283*7c478bd9Sstevel@tonic-gate 			}
6284*7c478bd9Sstevel@tonic-gate 
6285*7c478bd9Sstevel@tonic-gate 			(void) strcpy(fmri, LEGACY_SCHEME);
6286*7c478bd9Sstevel@tonic-gate 
6287*7c478bd9Sstevel@tonic-gate 			for (;;) {
6288*7c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_pg(iter, pg);
6289*7c478bd9Sstevel@tonic-gate 				if (ret == -1) {
6290*7c478bd9Sstevel@tonic-gate 					ret = scf_error();
6291*7c478bd9Sstevel@tonic-gate 					goto error;
6292*7c478bd9Sstevel@tonic-gate 				}
6293*7c478bd9Sstevel@tonic-gate 				if (ret == 0)
6294*7c478bd9Sstevel@tonic-gate 					break;
6295*7c478bd9Sstevel@tonic-gate 
6296*7c478bd9Sstevel@tonic-gate 				if (scf_pg_get_property(pg,
6297*7c478bd9Sstevel@tonic-gate 				    SCF_LEGACY_PROPERTY_NAME, prop) == -1) {
6298*7c478bd9Sstevel@tonic-gate 					ret = scf_error();
6299*7c478bd9Sstevel@tonic-gate 					if (ret == SCF_ERROR_DELETED ||
6300*7c478bd9Sstevel@tonic-gate 					    ret == SCF_ERROR_NOT_FOUND) {
6301*7c478bd9Sstevel@tonic-gate 						ret = 0;
6302*7c478bd9Sstevel@tonic-gate 						continue;
6303*7c478bd9Sstevel@tonic-gate 					}
6304*7c478bd9Sstevel@tonic-gate 					goto error;
6305*7c478bd9Sstevel@tonic-gate 				}
6306*7c478bd9Sstevel@tonic-gate 
6307*7c478bd9Sstevel@tonic-gate 				if (scf_property_is_type(prop, SCF_TYPE_ASTRING)
6308*7c478bd9Sstevel@tonic-gate 				    != SCF_SUCCESS) {
6309*7c478bd9Sstevel@tonic-gate 					if (scf_error() == SCF_ERROR_DELETED)
6310*7c478bd9Sstevel@tonic-gate 						continue;
6311*7c478bd9Sstevel@tonic-gate 					ret = scf_error();
6312*7c478bd9Sstevel@tonic-gate 					goto error;
6313*7c478bd9Sstevel@tonic-gate 				}
6314*7c478bd9Sstevel@tonic-gate 
6315*7c478bd9Sstevel@tonic-gate 				if (scf_property_get_value(prop, value) !=
6316*7c478bd9Sstevel@tonic-gate 				    SCF_SUCCESS)
6317*7c478bd9Sstevel@tonic-gate 					continue;
6318*7c478bd9Sstevel@tonic-gate 
6319*7c478bd9Sstevel@tonic-gate 				if (scf_value_get_astring(value,
6320*7c478bd9Sstevel@tonic-gate 				    fmri + sizeof (LEGACY_SCHEME) - 1,
6321*7c478bd9Sstevel@tonic-gate 				    max_fmri_length + 2 -
6322*7c478bd9Sstevel@tonic-gate 				    sizeof (LEGACY_SCHEME)) <= 0)
6323*7c478bd9Sstevel@tonic-gate 					continue;
6324*7c478bd9Sstevel@tonic-gate 
6325*7c478bd9Sstevel@tonic-gate 				if (scf_pg_get_name(pg, pgname,
6326*7c478bd9Sstevel@tonic-gate 				    max_name_length + 1) <= 0) {
6327*7c478bd9Sstevel@tonic-gate 					if (scf_error() == SCF_ERROR_DELETED)
6328*7c478bd9Sstevel@tonic-gate 						continue;
6329*7c478bd9Sstevel@tonic-gate 					ret = scf_error();
6330*7c478bd9Sstevel@tonic-gate 					goto error;
6331*7c478bd9Sstevel@tonic-gate 				}
6332*7c478bd9Sstevel@tonic-gate 
6333*7c478bd9Sstevel@tonic-gate 				if (argc == 0) {
6334*7c478bd9Sstevel@tonic-gate 					info.fmri = fmri;
6335*7c478bd9Sstevel@tonic-gate 					info.scope = scope;
6336*7c478bd9Sstevel@tonic-gate 					info.svc = NULL;
6337*7c478bd9Sstevel@tonic-gate 					info.inst = NULL;
6338*7c478bd9Sstevel@tonic-gate 					info.pg = pg;
6339*7c478bd9Sstevel@tonic-gate 					info.prop = NULL;
6340*7c478bd9Sstevel@tonic-gate 					if ((ret = callback(data, &info)) != 0)
6341*7c478bd9Sstevel@tonic-gate 						goto error;
6342*7c478bd9Sstevel@tonic-gate 				} else if ((ret = scf_pattern_match(htable,
6343*7c478bd9Sstevel@tonic-gate 				    fmri, pgname, argc, pattern,
6344*7c478bd9Sstevel@tonic-gate 				    flags & SCF_WALK_EXPLICIT)) != 0)
6345*7c478bd9Sstevel@tonic-gate 					goto error;
6346*7c478bd9Sstevel@tonic-gate 			}
6347*7c478bd9Sstevel@tonic-gate 
6348*7c478bd9Sstevel@tonic-gate 		}
6349*7c478bd9Sstevel@tonic-gate 	}
6350*7c478bd9Sstevel@tonic-gate nolegacy:
6351*7c478bd9Sstevel@tonic-gate 	ret = 0;
6352*7c478bd9Sstevel@tonic-gate 
6353*7c478bd9Sstevel@tonic-gate 	if (argc == 0)
6354*7c478bd9Sstevel@tonic-gate 		goto error;
6355*7c478bd9Sstevel@tonic-gate 
6356*7c478bd9Sstevel@tonic-gate 	/*
6357*7c478bd9Sstevel@tonic-gate 	 * Check all patterns, and see if we have that any that didn't match
6358*7c478bd9Sstevel@tonic-gate 	 * or any that matched multiple instances.  For svcprop, add up the
6359*7c478bd9Sstevel@tonic-gate 	 * total number of matching keys.
6360*7c478bd9Sstevel@tonic-gate 	 */
6361*7c478bd9Sstevel@tonic-gate 	info.count = 0;
6362*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
6363*7c478bd9Sstevel@tonic-gate 		scf_match_t *match;
6364*7c478bd9Sstevel@tonic-gate 
6365*7c478bd9Sstevel@tonic-gate 		if (pattern[i].sp_type == PATTERN_INVALID)
6366*7c478bd9Sstevel@tonic-gate 			continue;
6367*7c478bd9Sstevel@tonic-gate 		if (pattern[i].sp_matchcount == 0) {
6368*7c478bd9Sstevel@tonic-gate 			scf_msg_t msgid;
6369*7c478bd9Sstevel@tonic-gate 			/*
6370*7c478bd9Sstevel@tonic-gate 			 * Provide a useful error message based on the argument
6371*7c478bd9Sstevel@tonic-gate 			 * and the type of entity requested.
6372*7c478bd9Sstevel@tonic-gate 			 */
6373*7c478bd9Sstevel@tonic-gate 			if (!(flags & SCF_WALK_LEGACY) &&
6374*7c478bd9Sstevel@tonic-gate 			    strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0)
6375*7c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_LEGACY;
6376*7c478bd9Sstevel@tonic-gate 			else if (flags & SCF_WALK_PROPERTY)
6377*7c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOENTITY;
6378*7c478bd9Sstevel@tonic-gate 			else if (flags & SCF_WALK_NOINSTANCE)
6379*7c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOSERVICE;
6380*7c478bd9Sstevel@tonic-gate 			else if (flags & SCF_WALK_SERVICE)
6381*7c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOINSTSVC;
6382*7c478bd9Sstevel@tonic-gate 			else
6383*7c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOINSTANCE;
6384*7c478bd9Sstevel@tonic-gate 
6385*7c478bd9Sstevel@tonic-gate 			errfunc(scf_get_msg(msgid), pattern[i].sp_arg);
6386*7c478bd9Sstevel@tonic-gate 			if (err)
6387*7c478bd9Sstevel@tonic-gate 				*err = UU_EXIT_FATAL;
6388*7c478bd9Sstevel@tonic-gate 		} else if (!(flags & SCF_WALK_MULTIPLE) &&
6389*7c478bd9Sstevel@tonic-gate 		    pattern[i].sp_matchcount > 1) {
6390*7c478bd9Sstevel@tonic-gate 			size_t len, off;
6391*7c478bd9Sstevel@tonic-gate 			char *msg;
6392*7c478bd9Sstevel@tonic-gate 
6393*7c478bd9Sstevel@tonic-gate 			/*
6394*7c478bd9Sstevel@tonic-gate 			 * Construct a message with all possible FMRIs before
6395*7c478bd9Sstevel@tonic-gate 			 * passing off to error handling function.
6396*7c478bd9Sstevel@tonic-gate 			 *
6397*7c478bd9Sstevel@tonic-gate 			 * Note that strlen(scf_get_msg(...)) includes the
6398*7c478bd9Sstevel@tonic-gate 			 * length of '%s', which accounts for the terminating
6399*7c478bd9Sstevel@tonic-gate 			 * null byte.
6400*7c478bd9Sstevel@tonic-gate 			 */
6401*7c478bd9Sstevel@tonic-gate 			len = strlen(scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH)) +
6402*7c478bd9Sstevel@tonic-gate 			    strlen(pattern[i].sp_arg);
6403*7c478bd9Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
6404*7c478bd9Sstevel@tonic-gate 			    match = match->sm_next) {
6405*7c478bd9Sstevel@tonic-gate 				len += strlen(match->sm_key->sk_fmri) + 2;
6406*7c478bd9Sstevel@tonic-gate 			}
6407*7c478bd9Sstevel@tonic-gate 			if ((msg = malloc(len)) == NULL) {
6408*7c478bd9Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
6409*7c478bd9Sstevel@tonic-gate 				goto error;
6410*7c478bd9Sstevel@tonic-gate 			}
6411*7c478bd9Sstevel@tonic-gate 
6412*7c478bd9Sstevel@tonic-gate 			/* LINTED - format argument */
6413*7c478bd9Sstevel@tonic-gate 			(void) snprintf(msg, len,
6414*7c478bd9Sstevel@tonic-gate 			    scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH),
6415*7c478bd9Sstevel@tonic-gate 			    pattern[i].sp_arg);
6416*7c478bd9Sstevel@tonic-gate 			off = strlen(msg);
6417*7c478bd9Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
6418*7c478bd9Sstevel@tonic-gate 			    match = match->sm_next) {
6419*7c478bd9Sstevel@tonic-gate 				off += snprintf(msg + off, len - off, "\t%s\n",
6420*7c478bd9Sstevel@tonic-gate 				    match->sm_key->sk_fmri);
6421*7c478bd9Sstevel@tonic-gate 			}
6422*7c478bd9Sstevel@tonic-gate 
6423*7c478bd9Sstevel@tonic-gate 			errfunc(msg);
6424*7c478bd9Sstevel@tonic-gate 			if (err != NULL)
6425*7c478bd9Sstevel@tonic-gate 				*err = UU_EXIT_FATAL;
6426*7c478bd9Sstevel@tonic-gate 
6427*7c478bd9Sstevel@tonic-gate 			free(msg);
6428*7c478bd9Sstevel@tonic-gate 		} else {
6429*7c478bd9Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
6430*7c478bd9Sstevel@tonic-gate 			    match = match->sm_next) {
6431*7c478bd9Sstevel@tonic-gate 				if (!match->sm_key->sk_seen)
6432*7c478bd9Sstevel@tonic-gate 					info.count++;
6433*7c478bd9Sstevel@tonic-gate 				match->sm_key->sk_seen = 1;
6434*7c478bd9Sstevel@tonic-gate 			}
6435*7c478bd9Sstevel@tonic-gate 		}
6436*7c478bd9Sstevel@tonic-gate 	}
6437*7c478bd9Sstevel@tonic-gate 
6438*7c478bd9Sstevel@tonic-gate 	/*
6439*7c478bd9Sstevel@tonic-gate 	 * Clear 'sk_seen' for all keys.
6440*7c478bd9Sstevel@tonic-gate 	 */
6441*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < WALK_HTABLE_SIZE; i++) {
6442*7c478bd9Sstevel@tonic-gate 		scf_matchkey_t *key;
6443*7c478bd9Sstevel@tonic-gate 		for (key = htable[i]; key != NULL; key = key->sk_next)
6444*7c478bd9Sstevel@tonic-gate 			key->sk_seen = 0;
6445*7c478bd9Sstevel@tonic-gate 	}
6446*7c478bd9Sstevel@tonic-gate 
6447*7c478bd9Sstevel@tonic-gate 	/*
6448*7c478bd9Sstevel@tonic-gate 	 * Iterate over all the FMRIs in our hash table and execute the
6449*7c478bd9Sstevel@tonic-gate 	 * callback.
6450*7c478bd9Sstevel@tonic-gate 	 */
6451*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
6452*7c478bd9Sstevel@tonic-gate 		scf_match_t *match;
6453*7c478bd9Sstevel@tonic-gate 		scf_matchkey_t *key;
6454*7c478bd9Sstevel@tonic-gate 
6455*7c478bd9Sstevel@tonic-gate 		/*
6456*7c478bd9Sstevel@tonic-gate 		 * Ignore patterns which didn't match anything or matched too
6457*7c478bd9Sstevel@tonic-gate 		 * many FMRIs.
6458*7c478bd9Sstevel@tonic-gate 		 */
6459*7c478bd9Sstevel@tonic-gate 		if (pattern[i].sp_matchcount == 0 ||
6460*7c478bd9Sstevel@tonic-gate 		    (!(flags & SCF_WALK_MULTIPLE) &&
6461*7c478bd9Sstevel@tonic-gate 		    pattern[i].sp_matchcount > 1))
6462*7c478bd9Sstevel@tonic-gate 			continue;
6463*7c478bd9Sstevel@tonic-gate 
6464*7c478bd9Sstevel@tonic-gate 		for (match = pattern[i].sp_matches; match != NULL;
6465*7c478bd9Sstevel@tonic-gate 		    match = match->sm_next) {
6466*7c478bd9Sstevel@tonic-gate 
6467*7c478bd9Sstevel@tonic-gate 			key = match->sm_key;
6468*7c478bd9Sstevel@tonic-gate 			if (key->sk_seen)
6469*7c478bd9Sstevel@tonic-gate 				continue;
6470*7c478bd9Sstevel@tonic-gate 
6471*7c478bd9Sstevel@tonic-gate 			key->sk_seen = 1;
6472*7c478bd9Sstevel@tonic-gate 
6473*7c478bd9Sstevel@tonic-gate 			if (key->sk_legacy != NULL) {
6474*7c478bd9Sstevel@tonic-gate 				if (scf_scope_get_service(scope,
6475*7c478bd9Sstevel@tonic-gate 				    "smf/legacy_run", svc) != 0) {
6476*7c478bd9Sstevel@tonic-gate 					ret = scf_error();
6477*7c478bd9Sstevel@tonic-gate 					goto error;
6478*7c478bd9Sstevel@tonic-gate 				}
6479*7c478bd9Sstevel@tonic-gate 
6480*7c478bd9Sstevel@tonic-gate 				if (scf_service_get_pg(svc, key->sk_legacy,
6481*7c478bd9Sstevel@tonic-gate 				    pg) != 0)
6482*7c478bd9Sstevel@tonic-gate 					continue;
6483*7c478bd9Sstevel@tonic-gate 
6484*7c478bd9Sstevel@tonic-gate 				info.fmri = key->sk_fmri;
6485*7c478bd9Sstevel@tonic-gate 				info.scope = scope;
6486*7c478bd9Sstevel@tonic-gate 				info.svc = NULL;
6487*7c478bd9Sstevel@tonic-gate 				info.inst = NULL;
6488*7c478bd9Sstevel@tonic-gate 				info.pg = pg;
6489*7c478bd9Sstevel@tonic-gate 				info.prop = NULL;
6490*7c478bd9Sstevel@tonic-gate 				if ((ret = callback(data, &info)) != 0)
6491*7c478bd9Sstevel@tonic-gate 					goto error;
6492*7c478bd9Sstevel@tonic-gate 			} else {
6493*7c478bd9Sstevel@tonic-gate 				if (scf_handle_decode_fmri(h, key->sk_fmri,
6494*7c478bd9Sstevel@tonic-gate 				    scope, svc, inst, pg, prop, 0) !=
6495*7c478bd9Sstevel@tonic-gate 				    SCF_SUCCESS)
6496*7c478bd9Sstevel@tonic-gate 					continue;
6497*7c478bd9Sstevel@tonic-gate 
6498*7c478bd9Sstevel@tonic-gate 				info.fmri = key->sk_fmri;
6499*7c478bd9Sstevel@tonic-gate 				info.scope = scope;
6500*7c478bd9Sstevel@tonic-gate 				info.svc = svc;
6501*7c478bd9Sstevel@tonic-gate 				if (scf_instance_get_name(inst, NULL, 0) < 0) {
6502*7c478bd9Sstevel@tonic-gate 					if (scf_error() ==
6503*7c478bd9Sstevel@tonic-gate 					    SCF_ERROR_CONNECTION_BROKEN) {
6504*7c478bd9Sstevel@tonic-gate 						ret = scf_error();
6505*7c478bd9Sstevel@tonic-gate 						goto error;
6506*7c478bd9Sstevel@tonic-gate 					}
6507*7c478bd9Sstevel@tonic-gate 					info.inst = NULL;
6508*7c478bd9Sstevel@tonic-gate 				} else {
6509*7c478bd9Sstevel@tonic-gate 					info.inst = inst;
6510*7c478bd9Sstevel@tonic-gate 				}
6511*7c478bd9Sstevel@tonic-gate 				if (scf_pg_get_name(pg, NULL, 0) < 0) {
6512*7c478bd9Sstevel@tonic-gate 					if (scf_error() ==
6513*7c478bd9Sstevel@tonic-gate 					    SCF_ERROR_CONNECTION_BROKEN) {
6514*7c478bd9Sstevel@tonic-gate 						ret = scf_error();
6515*7c478bd9Sstevel@tonic-gate 						goto error;
6516*7c478bd9Sstevel@tonic-gate 					}
6517*7c478bd9Sstevel@tonic-gate 					info.pg = NULL;
6518*7c478bd9Sstevel@tonic-gate 				} else {
6519*7c478bd9Sstevel@tonic-gate 					info.pg = pg;
6520*7c478bd9Sstevel@tonic-gate 				}
6521*7c478bd9Sstevel@tonic-gate 				if (scf_property_get_name(prop, NULL, 0) < 0) {
6522*7c478bd9Sstevel@tonic-gate 					if (scf_error() ==
6523*7c478bd9Sstevel@tonic-gate 					    SCF_ERROR_CONNECTION_BROKEN) {
6524*7c478bd9Sstevel@tonic-gate 						ret = scf_error();
6525*7c478bd9Sstevel@tonic-gate 						goto error;
6526*7c478bd9Sstevel@tonic-gate 					}
6527*7c478bd9Sstevel@tonic-gate 					info.prop = NULL;
6528*7c478bd9Sstevel@tonic-gate 				} else {
6529*7c478bd9Sstevel@tonic-gate 					info.prop = prop;
6530*7c478bd9Sstevel@tonic-gate 				}
6531*7c478bd9Sstevel@tonic-gate 
6532*7c478bd9Sstevel@tonic-gate 				if ((ret = callback(data, &info)) != 0)
6533*7c478bd9Sstevel@tonic-gate 					goto error;
6534*7c478bd9Sstevel@tonic-gate 			}
6535*7c478bd9Sstevel@tonic-gate 		}
6536*7c478bd9Sstevel@tonic-gate 	}
6537*7c478bd9Sstevel@tonic-gate 
6538*7c478bd9Sstevel@tonic-gate error:
6539*7c478bd9Sstevel@tonic-gate 	if (htable) {
6540*7c478bd9Sstevel@tonic-gate 		scf_matchkey_t *key, *next;
6541*7c478bd9Sstevel@tonic-gate 
6542*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < WALK_HTABLE_SIZE; i++) {
6543*7c478bd9Sstevel@tonic-gate 
6544*7c478bd9Sstevel@tonic-gate 			for (key = htable[i]; key != NULL;
6545*7c478bd9Sstevel@tonic-gate 			    key = next) {
6546*7c478bd9Sstevel@tonic-gate 
6547*7c478bd9Sstevel@tonic-gate 				next = key->sk_next;
6548*7c478bd9Sstevel@tonic-gate 
6549*7c478bd9Sstevel@tonic-gate 				if (key->sk_fmri != NULL)
6550*7c478bd9Sstevel@tonic-gate 					free(key->sk_fmri);
6551*7c478bd9Sstevel@tonic-gate 				if (key->sk_legacy != NULL)
6552*7c478bd9Sstevel@tonic-gate 					free(key->sk_legacy);
6553*7c478bd9Sstevel@tonic-gate 				free(key);
6554*7c478bd9Sstevel@tonic-gate 			}
6555*7c478bd9Sstevel@tonic-gate 		}
6556*7c478bd9Sstevel@tonic-gate 		free(htable);
6557*7c478bd9Sstevel@tonic-gate 	}
6558*7c478bd9Sstevel@tonic-gate 	if (pattern != NULL) {
6559*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < argc; i++) {
6560*7c478bd9Sstevel@tonic-gate 			scf_match_t *match, *next;
6561*7c478bd9Sstevel@tonic-gate 
6562*7c478bd9Sstevel@tonic-gate 			if (pattern[i].sp_arg != NULL)
6563*7c478bd9Sstevel@tonic-gate 				free(pattern[i].sp_arg);
6564*7c478bd9Sstevel@tonic-gate 
6565*7c478bd9Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
6566*7c478bd9Sstevel@tonic-gate 			    match = next) {
6567*7c478bd9Sstevel@tonic-gate 
6568*7c478bd9Sstevel@tonic-gate 				next = match->sm_next;
6569*7c478bd9Sstevel@tonic-gate 
6570*7c478bd9Sstevel@tonic-gate 				free(match);
6571*7c478bd9Sstevel@tonic-gate 			}
6572*7c478bd9Sstevel@tonic-gate 		}
6573*7c478bd9Sstevel@tonic-gate 		free(pattern);
6574*7c478bd9Sstevel@tonic-gate 	}
6575*7c478bd9Sstevel@tonic-gate 
6576*7c478bd9Sstevel@tonic-gate 	free(fmri);
6577*7c478bd9Sstevel@tonic-gate 	free(pgname);
6578*7c478bd9Sstevel@tonic-gate 
6579*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(value);
6580*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
6581*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
6582*7c478bd9Sstevel@tonic-gate 	scf_scope_destroy(scope);
6583*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(siter);
6584*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(sciter);
6585*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
6586*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
6587*7c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
6588*7c478bd9Sstevel@tonic-gate 
6589*7c478bd9Sstevel@tonic-gate 	return (ret);
6590*7c478bd9Sstevel@tonic-gate }
6591*7c478bd9Sstevel@tonic-gate 
6592*7c478bd9Sstevel@tonic-gate /*
6593*7c478bd9Sstevel@tonic-gate  * _scf_request_backup:  a simple wrapper routine
6594*7c478bd9Sstevel@tonic-gate  */
6595*7c478bd9Sstevel@tonic-gate int
6596*7c478bd9Sstevel@tonic-gate _scf_request_backup(scf_handle_t *h, const char *name)
6597*7c478bd9Sstevel@tonic-gate {
6598*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_backup_request request;
6599*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
6600*7c478bd9Sstevel@tonic-gate 
6601*7c478bd9Sstevel@tonic-gate 	int r;
6602*7c478bd9Sstevel@tonic-gate 
6603*7c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
6604*7c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name))
6605*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
6606*7c478bd9Sstevel@tonic-gate 
6607*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
6608*7c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_BACKUP;
6609*7c478bd9Sstevel@tonic-gate 	request.rpr_changeid = handle_alloc_changeid(h);
6610*7c478bd9Sstevel@tonic-gate 
6611*7c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
6612*7c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
6613*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
6614*7c478bd9Sstevel@tonic-gate 
6615*7c478bd9Sstevel@tonic-gate 	if (r < 0) {
6616*7c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
6617*7c478bd9Sstevel@tonic-gate 	}
6618*7c478bd9Sstevel@tonic-gate 
6619*7c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
6620*7c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
6621*7c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
6622*7c478bd9Sstevel@tonic-gate }
6623