xref: /titanic_53/usr/src/cmd/svc/configd/client.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2005 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 client layer for svc.configd.  All direct protocol interactions
31*7c478bd9Sstevel@tonic-gate  * are handled here.
32*7c478bd9Sstevel@tonic-gate  *
33*7c478bd9Sstevel@tonic-gate  * Essentially, the job of this layer is to turn the idempotent protocol
34*7c478bd9Sstevel@tonic-gate  * into a series of non-idempotent calls into the object layer, while
35*7c478bd9Sstevel@tonic-gate  * also handling the necessary locking.
36*7c478bd9Sstevel@tonic-gate  */
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include <alloca.h>
39*7c478bd9Sstevel@tonic-gate #include <assert.h>
40*7c478bd9Sstevel@tonic-gate #include <door.h>
41*7c478bd9Sstevel@tonic-gate #include <errno.h>
42*7c478bd9Sstevel@tonic-gate #include <limits.h>
43*7c478bd9Sstevel@tonic-gate #include <pthread.h>
44*7c478bd9Sstevel@tonic-gate #include <stdio.h>
45*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
46*7c478bd9Sstevel@tonic-gate #include <string.h>
47*7c478bd9Sstevel@tonic-gate #include <unistd.h>
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #include <libuutil.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include "configd.h"
52*7c478bd9Sstevel@tonic-gate #include "repcache_protocol.h"
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #define	INVALID_CHANGEID	(0)
55*7c478bd9Sstevel@tonic-gate #define	INVALID_DOORID		((door_id_t)-1)
56*7c478bd9Sstevel@tonic-gate #define	INVALID_RESULT		((rep_protocol_responseid_t)INT_MIN)
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /*
59*7c478bd9Sstevel@tonic-gate  * lint doesn't like constant assertions
60*7c478bd9Sstevel@tonic-gate  */
61*7c478bd9Sstevel@tonic-gate #ifdef lint
62*7c478bd9Sstevel@tonic-gate #define	assert_nolint(x) (void)0
63*7c478bd9Sstevel@tonic-gate #else
64*7c478bd9Sstevel@tonic-gate #define	assert_nolint(x) assert(x)
65*7c478bd9Sstevel@tonic-gate #endif
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate /*
68*7c478bd9Sstevel@tonic-gate  * Protects client linkage and the freelist
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate #define	CLIENT_HASH_SIZE	64
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate #pragma align 64(client_hash)
73*7c478bd9Sstevel@tonic-gate static client_bucket_t client_hash[CLIENT_HASH_SIZE];
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate static uu_list_pool_t *entity_pool;
76*7c478bd9Sstevel@tonic-gate static uu_list_pool_t *iter_pool;
77*7c478bd9Sstevel@tonic-gate static uu_list_pool_t *client_pool;
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate #define	CLIENT_HASH(id)		(&client_hash[((id) & (CLIENT_HASH_SIZE - 1))])
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate uint_t request_log_size = 1024;		/* tunable, before we start */
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate static pthread_mutex_t request_log_lock = PTHREAD_MUTEX_INITIALIZER;
84*7c478bd9Sstevel@tonic-gate static uint_t request_log_cur;
85*7c478bd9Sstevel@tonic-gate request_log_entry_t	*request_log;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate static uint32_t		client_maxid;
88*7c478bd9Sstevel@tonic-gate static pthread_mutex_t	client_lock;	/* protects client_maxid */
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate static request_log_entry_t *
91*7c478bd9Sstevel@tonic-gate get_log(void)
92*7c478bd9Sstevel@tonic-gate {
93*7c478bd9Sstevel@tonic-gate 	thread_info_t *ti = thread_self();
94*7c478bd9Sstevel@tonic-gate 	return (&ti->ti_log);
95*7c478bd9Sstevel@tonic-gate }
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate void
98*7c478bd9Sstevel@tonic-gate log_enter(request_log_entry_t *rlp)
99*7c478bd9Sstevel@tonic-gate {
100*7c478bd9Sstevel@tonic-gate 	if (rlp->rl_start != 0 && request_log != NULL) {
101*7c478bd9Sstevel@tonic-gate 		request_log_entry_t *logrlp;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&request_log_lock);
104*7c478bd9Sstevel@tonic-gate 		assert(request_log_cur < request_log_size);
105*7c478bd9Sstevel@tonic-gate 		logrlp = &request_log[request_log_cur++];
106*7c478bd9Sstevel@tonic-gate 		if (request_log_cur == request_log_size)
107*7c478bd9Sstevel@tonic-gate 			request_log_cur = 0;
108*7c478bd9Sstevel@tonic-gate 		(void) memcpy(logrlp, rlp, sizeof (*rlp));
109*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&request_log_lock);
110*7c478bd9Sstevel@tonic-gate 	}
111*7c478bd9Sstevel@tonic-gate }
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate /*
114*7c478bd9Sstevel@tonic-gate  * Note that the svc.configd dmod will join all of the per-thread log entries
115*7c478bd9Sstevel@tonic-gate  * with the main log, so that even if the log is disabled, there is some
116*7c478bd9Sstevel@tonic-gate  * information available.
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate static request_log_entry_t *
119*7c478bd9Sstevel@tonic-gate start_log(uint32_t clientid)
120*7c478bd9Sstevel@tonic-gate {
121*7c478bd9Sstevel@tonic-gate 	request_log_entry_t *rlp = get_log();
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	log_enter(rlp);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	(void) memset(rlp, 0, sizeof (*rlp));
126*7c478bd9Sstevel@tonic-gate 	rlp->rl_start = gethrtime();
127*7c478bd9Sstevel@tonic-gate 	rlp->rl_tid = pthread_self();
128*7c478bd9Sstevel@tonic-gate 	rlp->rl_clientid = clientid;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	return (rlp);
131*7c478bd9Sstevel@tonic-gate }
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate void
134*7c478bd9Sstevel@tonic-gate end_log(void)
135*7c478bd9Sstevel@tonic-gate {
136*7c478bd9Sstevel@tonic-gate 	request_log_entry_t *rlp = get_log();
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	rlp->rl_end = gethrtime();
139*7c478bd9Sstevel@tonic-gate }
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate static void
142*7c478bd9Sstevel@tonic-gate add_log_ptr(request_log_entry_t *rlp, enum rc_ptr_type type, uint32_t id,
143*7c478bd9Sstevel@tonic-gate     void *ptr)
144*7c478bd9Sstevel@tonic-gate {
145*7c478bd9Sstevel@tonic-gate 	request_log_ptr_t *rpp;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	if (rlp == NULL)
148*7c478bd9Sstevel@tonic-gate 		return;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	if (rlp->rl_num_ptrs >= MAX_PTRS)
151*7c478bd9Sstevel@tonic-gate 		return;
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	rpp = &rlp->rl_ptrs[rlp->rl_num_ptrs++];
154*7c478bd9Sstevel@tonic-gate 	rpp->rlp_type = type;
155*7c478bd9Sstevel@tonic-gate 	rpp->rlp_id = id;
156*7c478bd9Sstevel@tonic-gate 	rpp->rlp_ptr = ptr;
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	/*
159*7c478bd9Sstevel@tonic-gate 	 * For entities, it's useful to have the node pointer at the start
160*7c478bd9Sstevel@tonic-gate 	 * of the request.
161*7c478bd9Sstevel@tonic-gate 	 */
162*7c478bd9Sstevel@tonic-gate 	if (type == RC_PTR_TYPE_ENTITY && ptr != NULL)
163*7c478bd9Sstevel@tonic-gate 		rpp->rlp_data = ((repcache_entity_t *)ptr)->re_node.rnp_node;
164*7c478bd9Sstevel@tonic-gate }
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate int
167*7c478bd9Sstevel@tonic-gate client_is_privileged(void)
168*7c478bd9Sstevel@tonic-gate {
169*7c478bd9Sstevel@tonic-gate 	thread_info_t *ti = thread_self();
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	ucred_t *uc;
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 	if (ti->ti_active_client != NULL &&
174*7c478bd9Sstevel@tonic-gate 	    ti->ti_active_client->rc_all_auths)
175*7c478bd9Sstevel@tonic-gate 		return (1);
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	if ((uc = get_ucred()) == NULL)
178*7c478bd9Sstevel@tonic-gate 		return (0);
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	return (ucred_is_privileged(uc));
181*7c478bd9Sstevel@tonic-gate }
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
184*7c478bd9Sstevel@tonic-gate static int
185*7c478bd9Sstevel@tonic-gate client_compare(const void *lc_arg, const void *rc_arg, void *private)
186*7c478bd9Sstevel@tonic-gate {
187*7c478bd9Sstevel@tonic-gate 	uint32_t l_id = ((const repcache_client_t *)lc_arg)->rc_id;
188*7c478bd9Sstevel@tonic-gate 	uint32_t r_id = ((const repcache_client_t *)rc_arg)->rc_id;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	if (l_id > r_id)
191*7c478bd9Sstevel@tonic-gate 		return (1);
192*7c478bd9Sstevel@tonic-gate 	if (l_id < r_id)
193*7c478bd9Sstevel@tonic-gate 		return (-1);
194*7c478bd9Sstevel@tonic-gate 	return (0);
195*7c478bd9Sstevel@tonic-gate }
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
198*7c478bd9Sstevel@tonic-gate static int
199*7c478bd9Sstevel@tonic-gate entity_compare(const void *lc_arg, const void *rc_arg, void *private)
200*7c478bd9Sstevel@tonic-gate {
201*7c478bd9Sstevel@tonic-gate 	uint32_t l_id = ((const repcache_entity_t *)lc_arg)->re_id;
202*7c478bd9Sstevel@tonic-gate 	uint32_t r_id = ((const repcache_entity_t *)rc_arg)->re_id;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if (l_id > r_id)
205*7c478bd9Sstevel@tonic-gate 		return (1);
206*7c478bd9Sstevel@tonic-gate 	if (l_id < r_id)
207*7c478bd9Sstevel@tonic-gate 		return (-1);
208*7c478bd9Sstevel@tonic-gate 	return (0);
209*7c478bd9Sstevel@tonic-gate }
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
212*7c478bd9Sstevel@tonic-gate static int
213*7c478bd9Sstevel@tonic-gate iter_compare(const void *lc_arg, const void *rc_arg, void *private)
214*7c478bd9Sstevel@tonic-gate {
215*7c478bd9Sstevel@tonic-gate 	uint32_t l_id = ((const repcache_iter_t *)lc_arg)->ri_id;
216*7c478bd9Sstevel@tonic-gate 	uint32_t r_id = ((const repcache_iter_t *)rc_arg)->ri_id;
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	if (l_id > r_id)
219*7c478bd9Sstevel@tonic-gate 		return (1);
220*7c478bd9Sstevel@tonic-gate 	if (l_id < r_id)
221*7c478bd9Sstevel@tonic-gate 		return (-1);
222*7c478bd9Sstevel@tonic-gate 	return (0);
223*7c478bd9Sstevel@tonic-gate }
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate static int
226*7c478bd9Sstevel@tonic-gate client_hash_init(void)
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate 	int x;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	assert_nolint(offsetof(repcache_entity_t, re_id) == 0);
231*7c478bd9Sstevel@tonic-gate 	entity_pool = uu_list_pool_create("repcache_entitys",
232*7c478bd9Sstevel@tonic-gate 	    sizeof (repcache_entity_t), offsetof(repcache_entity_t, re_link),
233*7c478bd9Sstevel@tonic-gate 	    entity_compare, UU_LIST_POOL_DEBUG);
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	assert_nolint(offsetof(repcache_iter_t, ri_id) == 0);
236*7c478bd9Sstevel@tonic-gate 	iter_pool = uu_list_pool_create("repcache_iters",
237*7c478bd9Sstevel@tonic-gate 	    sizeof (repcache_iter_t), offsetof(repcache_iter_t, ri_link),
238*7c478bd9Sstevel@tonic-gate 	    iter_compare, UU_LIST_POOL_DEBUG);
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	assert_nolint(offsetof(repcache_client_t, rc_id) == 0);
241*7c478bd9Sstevel@tonic-gate 	client_pool = uu_list_pool_create("repcache_clients",
242*7c478bd9Sstevel@tonic-gate 	    sizeof (repcache_client_t), offsetof(repcache_client_t, rc_link),
243*7c478bd9Sstevel@tonic-gate 	    client_compare, UU_LIST_POOL_DEBUG);
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	if (entity_pool == NULL || iter_pool == NULL || client_pool == NULL)
246*7c478bd9Sstevel@tonic-gate 		return (0);
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	for (x = 0; x < CLIENT_HASH_SIZE; x++) {
249*7c478bd9Sstevel@tonic-gate 		uu_list_t *lp = uu_list_create(client_pool, &client_hash[x],
250*7c478bd9Sstevel@tonic-gate 		    UU_LIST_SORTED);
251*7c478bd9Sstevel@tonic-gate 		if (lp == NULL)
252*7c478bd9Sstevel@tonic-gate 			return (0);
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_init(&client_hash[x].cb_lock, NULL);
255*7c478bd9Sstevel@tonic-gate 		client_hash[x].cb_list = lp;
256*7c478bd9Sstevel@tonic-gate 	}
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	return (1);
259*7c478bd9Sstevel@tonic-gate }
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate static repcache_client_t *
262*7c478bd9Sstevel@tonic-gate client_alloc(void)
263*7c478bd9Sstevel@tonic-gate {
264*7c478bd9Sstevel@tonic-gate 	repcache_client_t *cp;
265*7c478bd9Sstevel@tonic-gate 	cp = uu_zalloc(sizeof (*cp));
266*7c478bd9Sstevel@tonic-gate 	if (cp == NULL)
267*7c478bd9Sstevel@tonic-gate 		return (NULL);
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	cp->rc_entity_list = uu_list_create(entity_pool, cp, UU_LIST_SORTED);
270*7c478bd9Sstevel@tonic-gate 	if (cp->rc_entity_list == NULL)
271*7c478bd9Sstevel@tonic-gate 		goto fail;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	cp->rc_iter_list = uu_list_create(iter_pool, cp, UU_LIST_SORTED);
274*7c478bd9Sstevel@tonic-gate 	if (cp->rc_iter_list == NULL)
275*7c478bd9Sstevel@tonic-gate 		goto fail;
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	uu_list_node_init(cp, &cp->rc_link, client_pool);
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	cp->rc_doorfd = -1;
280*7c478bd9Sstevel@tonic-gate 	cp->rc_doorid = INVALID_DOORID;
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&cp->rc_lock, NULL);
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	rc_node_ptr_init(&cp->rc_notify_ptr);
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	return (cp);
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate fail:
289*7c478bd9Sstevel@tonic-gate 	if (cp->rc_iter_list != NULL)
290*7c478bd9Sstevel@tonic-gate 		uu_list_destroy(cp->rc_iter_list);
291*7c478bd9Sstevel@tonic-gate 	if (cp->rc_entity_list != NULL)
292*7c478bd9Sstevel@tonic-gate 		uu_list_destroy(cp->rc_entity_list);
293*7c478bd9Sstevel@tonic-gate 	uu_free(cp);
294*7c478bd9Sstevel@tonic-gate 	return (NULL);
295*7c478bd9Sstevel@tonic-gate }
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate static void
298*7c478bd9Sstevel@tonic-gate client_free(repcache_client_t *cp)
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_insert_thr == 0);
301*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_refcnt == 0);
302*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_doorfd == -1);
303*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_doorid == INVALID_DOORID);
304*7c478bd9Sstevel@tonic-gate 	assert(uu_list_first(cp->rc_entity_list) == NULL);
305*7c478bd9Sstevel@tonic-gate 	assert(uu_list_first(cp->rc_iter_list) == NULL);
306*7c478bd9Sstevel@tonic-gate 	uu_list_destroy(cp->rc_entity_list);
307*7c478bd9Sstevel@tonic-gate 	uu_list_destroy(cp->rc_iter_list);
308*7c478bd9Sstevel@tonic-gate 	uu_list_node_fini(cp, &cp->rc_link, client_pool);
309*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&cp->rc_lock);
310*7c478bd9Sstevel@tonic-gate 	uu_free(cp);
311*7c478bd9Sstevel@tonic-gate }
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate static void
314*7c478bd9Sstevel@tonic-gate client_insert(repcache_client_t *cp)
315*7c478bd9Sstevel@tonic-gate {
316*7c478bd9Sstevel@tonic-gate 	client_bucket_t *bp = CLIENT_HASH(cp->rc_id);
317*7c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_id > 0);
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&bp->cb_lock);
322*7c478bd9Sstevel@tonic-gate 	/*
323*7c478bd9Sstevel@tonic-gate 	 * We assume it does not already exist
324*7c478bd9Sstevel@tonic-gate 	 */
325*7c478bd9Sstevel@tonic-gate 	(void) uu_list_find(bp->cb_list, cp, NULL, &idx);
326*7c478bd9Sstevel@tonic-gate 	uu_list_insert(bp->cb_list, cp, idx);
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&bp->cb_lock);
329*7c478bd9Sstevel@tonic-gate }
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate static repcache_client_t *
332*7c478bd9Sstevel@tonic-gate client_lookup(uint32_t id)
333*7c478bd9Sstevel@tonic-gate {
334*7c478bd9Sstevel@tonic-gate 	client_bucket_t *bp = CLIENT_HASH(id);
335*7c478bd9Sstevel@tonic-gate 	repcache_client_t *cp;
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&bp->cb_lock);
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	cp = uu_list_find(bp->cb_list, &id, NULL, NULL);
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	/*
342*7c478bd9Sstevel@tonic-gate 	 * Bump the reference count
343*7c478bd9Sstevel@tonic-gate 	 */
344*7c478bd9Sstevel@tonic-gate 	if (cp != NULL) {
345*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cp->rc_lock);
346*7c478bd9Sstevel@tonic-gate 		assert(!(cp->rc_flags & RC_CLIENT_DEAD));
347*7c478bd9Sstevel@tonic-gate 		cp->rc_refcnt++;
348*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&bp->cb_lock);
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	return (cp);
353*7c478bd9Sstevel@tonic-gate }
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate static void
356*7c478bd9Sstevel@tonic-gate client_release(repcache_client_t *cp)
357*7c478bd9Sstevel@tonic-gate {
358*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
359*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_refcnt > 0);
360*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_insert_thr != pthread_self());
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	--cp->rc_refcnt;
363*7c478bd9Sstevel@tonic-gate 	(void) pthread_cond_broadcast(&cp->rc_cv);
364*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate /*
368*7c478bd9Sstevel@tonic-gate  * We only allow one thread to be inserting at a time, to prevent
369*7c478bd9Sstevel@tonic-gate  * insert/insert races.
370*7c478bd9Sstevel@tonic-gate  */
371*7c478bd9Sstevel@tonic-gate static void
372*7c478bd9Sstevel@tonic-gate client_start_insert(repcache_client_t *cp)
373*7c478bd9Sstevel@tonic-gate {
374*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
375*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_refcnt > 0);
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	while (cp->rc_insert_thr != 0) {
378*7c478bd9Sstevel@tonic-gate 		assert(cp->rc_insert_thr != pthread_self());
379*7c478bd9Sstevel@tonic-gate 		(void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock);
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate 	cp->rc_insert_thr = pthread_self();
382*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
383*7c478bd9Sstevel@tonic-gate }
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate static void
386*7c478bd9Sstevel@tonic-gate client_end_insert(repcache_client_t *cp)
387*7c478bd9Sstevel@tonic-gate {
388*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
389*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_insert_thr == pthread_self());
390*7c478bd9Sstevel@tonic-gate 	cp->rc_insert_thr = 0;
391*7c478bd9Sstevel@tonic-gate 	(void) pthread_cond_broadcast(&cp->rc_cv);
392*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
393*7c478bd9Sstevel@tonic-gate }
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
396*7c478bd9Sstevel@tonic-gate static repcache_entity_t *
397*7c478bd9Sstevel@tonic-gate entity_alloc(repcache_client_t *cp)
398*7c478bd9Sstevel@tonic-gate {
399*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep = uu_zalloc(sizeof (repcache_entity_t));
400*7c478bd9Sstevel@tonic-gate 	if (ep != NULL) {
401*7c478bd9Sstevel@tonic-gate 		uu_list_node_init(ep, &ep->re_link, entity_pool);
402*7c478bd9Sstevel@tonic-gate 	}
403*7c478bd9Sstevel@tonic-gate 	return (ep);
404*7c478bd9Sstevel@tonic-gate }
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate static void
407*7c478bd9Sstevel@tonic-gate entity_add(repcache_client_t *cp, repcache_entity_t *ep)
408*7c478bd9Sstevel@tonic-gate {
409*7c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
412*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_insert_thr == pthread_self());
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	(void) uu_list_find(cp->rc_entity_list, ep, NULL, &idx);
415*7c478bd9Sstevel@tonic-gate 	uu_list_insert(cp->rc_entity_list, ep, idx);
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
418*7c478bd9Sstevel@tonic-gate }
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate static repcache_entity_t *
421*7c478bd9Sstevel@tonic-gate entity_find(repcache_client_t *cp, uint32_t id)
422*7c478bd9Sstevel@tonic-gate {
423*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
426*7c478bd9Sstevel@tonic-gate 	ep = uu_list_find(cp->rc_entity_list, &id, NULL, NULL);
427*7c478bd9Sstevel@tonic-gate 	if (ep != NULL) {
428*7c478bd9Sstevel@tonic-gate 		add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, ep);
429*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&ep->re_lock);
430*7c478bd9Sstevel@tonic-gate 	}
431*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	return (ep);
434*7c478bd9Sstevel@tonic-gate }
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate /*
437*7c478bd9Sstevel@tonic-gate  * Fails with
438*7c478bd9Sstevel@tonic-gate  *   _DUPLICATE_ID - the ids are equal
439*7c478bd9Sstevel@tonic-gate  *   _UNKNOWN_ID - an id does not designate an active register
440*7c478bd9Sstevel@tonic-gate  */
441*7c478bd9Sstevel@tonic-gate static int
442*7c478bd9Sstevel@tonic-gate entity_find2(repcache_client_t *cp, uint32_t id1, repcache_entity_t **out1,
443*7c478bd9Sstevel@tonic-gate     uint32_t id2, repcache_entity_t **out2)
444*7c478bd9Sstevel@tonic-gate {
445*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *e1, *e2;
446*7c478bd9Sstevel@tonic-gate 	request_log_entry_t *rlp;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	if (id1 == id2)
449*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_DUPLICATE_ID);
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
452*7c478bd9Sstevel@tonic-gate 	e1 = uu_list_find(cp->rc_entity_list, &id1, NULL, NULL);
453*7c478bd9Sstevel@tonic-gate 	e2 = uu_list_find(cp->rc_entity_list, &id2, NULL, NULL);
454*7c478bd9Sstevel@tonic-gate 	if (e1 == NULL || e2 == NULL) {
455*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
456*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	assert(e1 != e2);
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	/*
462*7c478bd9Sstevel@tonic-gate 	 * locks are ordered by id number
463*7c478bd9Sstevel@tonic-gate 	 */
464*7c478bd9Sstevel@tonic-gate 	if (id1 < id2) {
465*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e1->re_lock);
466*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e2->re_lock);
467*7c478bd9Sstevel@tonic-gate 	} else {
468*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e2->re_lock);
469*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e1->re_lock);
470*7c478bd9Sstevel@tonic-gate 	}
471*7c478bd9Sstevel@tonic-gate 	*out1 = e1;
472*7c478bd9Sstevel@tonic-gate 	*out2 = e2;
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	if ((rlp = get_log()) != NULL) {
477*7c478bd9Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id1, e1);
478*7c478bd9Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id2, e2);
479*7c478bd9Sstevel@tonic-gate 	}
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
482*7c478bd9Sstevel@tonic-gate }
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate static void
485*7c478bd9Sstevel@tonic-gate entity_release(repcache_entity_t *ep)
486*7c478bd9Sstevel@tonic-gate {
487*7c478bd9Sstevel@tonic-gate 	assert(ep->re_node.rnp_node == NULL ||
488*7c478bd9Sstevel@tonic-gate 	    !MUTEX_HELD(&ep->re_node.rnp_node->rn_lock));
489*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ep->re_lock);
490*7c478bd9Sstevel@tonic-gate }
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate static void
493*7c478bd9Sstevel@tonic-gate entity_destroy(repcache_entity_t *entity)
494*7c478bd9Sstevel@tonic-gate {
495*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&entity->re_lock);
496*7c478bd9Sstevel@tonic-gate 	rc_node_clear(&entity->re_node, 0);
497*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&entity->re_lock);
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	uu_list_node_fini(entity, &entity->re_link, entity_pool);
500*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&entity->re_lock);
501*7c478bd9Sstevel@tonic-gate 	uu_free(entity);
502*7c478bd9Sstevel@tonic-gate }
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate static void
505*7c478bd9Sstevel@tonic-gate entity_remove(repcache_client_t *cp, uint32_t id)
506*7c478bd9Sstevel@tonic-gate {
507*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *entity;
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
510*7c478bd9Sstevel@tonic-gate 	entity = uu_list_find(cp->rc_entity_list, &id, NULL, NULL);
511*7c478bd9Sstevel@tonic-gate 	if (entity != NULL)
512*7c478bd9Sstevel@tonic-gate 		uu_list_remove(cp->rc_entity_list, entity);
513*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	if (entity != NULL)
516*7c478bd9Sstevel@tonic-gate 		entity_destroy(entity);
517*7c478bd9Sstevel@tonic-gate }
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate static void
520*7c478bd9Sstevel@tonic-gate entity_cleanup(repcache_client_t *cp)
521*7c478bd9Sstevel@tonic-gate {
522*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
523*7c478bd9Sstevel@tonic-gate 	void *cookie = NULL;
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
526*7c478bd9Sstevel@tonic-gate 	while ((ep = uu_list_teardown(cp->rc_entity_list, &cookie)) != NULL) {
527*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
528*7c478bd9Sstevel@tonic-gate 		entity_destroy(ep);
529*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cp->rc_lock);
530*7c478bd9Sstevel@tonic-gate 	}
531*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
532*7c478bd9Sstevel@tonic-gate }
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
535*7c478bd9Sstevel@tonic-gate static repcache_iter_t *
536*7c478bd9Sstevel@tonic-gate iter_alloc(repcache_client_t *cp)
537*7c478bd9Sstevel@tonic-gate {
538*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter;
539*7c478bd9Sstevel@tonic-gate 	iter = uu_zalloc(sizeof (repcache_iter_t));
540*7c478bd9Sstevel@tonic-gate 	if (iter != NULL)
541*7c478bd9Sstevel@tonic-gate 		uu_list_node_init(iter, &iter->ri_link, iter_pool);
542*7c478bd9Sstevel@tonic-gate 	return (iter);
543*7c478bd9Sstevel@tonic-gate }
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate static void
546*7c478bd9Sstevel@tonic-gate iter_add(repcache_client_t *cp, repcache_iter_t *iter)
547*7c478bd9Sstevel@tonic-gate {
548*7c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
551*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_insert_thr == pthread_self());
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	(void) uu_list_find(cp->rc_iter_list, iter, NULL, &idx);
554*7c478bd9Sstevel@tonic-gate 	uu_list_insert(cp->rc_iter_list, iter, idx);
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
557*7c478bd9Sstevel@tonic-gate }
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate static repcache_iter_t *
560*7c478bd9Sstevel@tonic-gate iter_find(repcache_client_t *cp, uint32_t id)
561*7c478bd9Sstevel@tonic-gate {
562*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	iter = uu_list_find(cp->rc_iter_list, &id, NULL, NULL);
567*7c478bd9Sstevel@tonic-gate 	if (iter != NULL) {
568*7c478bd9Sstevel@tonic-gate 		add_log_ptr(get_log(), RC_PTR_TYPE_ITER, id, iter);
569*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&iter->ri_lock);
570*7c478bd9Sstevel@tonic-gate 	}
571*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	return (iter);
574*7c478bd9Sstevel@tonic-gate }
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate /*
577*7c478bd9Sstevel@tonic-gate  * Fails with
578*7c478bd9Sstevel@tonic-gate  *   _UNKNOWN_ID - iter_id or entity_id does not designate an active register
579*7c478bd9Sstevel@tonic-gate  */
580*7c478bd9Sstevel@tonic-gate static int
581*7c478bd9Sstevel@tonic-gate iter_find_w_entity(repcache_client_t *cp, uint32_t iter_id,
582*7c478bd9Sstevel@tonic-gate     repcache_iter_t **iterp, uint32_t entity_id, repcache_entity_t **epp)
583*7c478bd9Sstevel@tonic-gate {
584*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter;
585*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
586*7c478bd9Sstevel@tonic-gate 	request_log_entry_t *rlp;
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
589*7c478bd9Sstevel@tonic-gate 	iter = uu_list_find(cp->rc_iter_list, &iter_id, NULL, NULL);
590*7c478bd9Sstevel@tonic-gate 	ep = uu_list_find(cp->rc_entity_list, &entity_id, NULL, NULL);
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	assert(iter == NULL || !MUTEX_HELD(&iter->ri_lock));
593*7c478bd9Sstevel@tonic-gate 	assert(ep == NULL || !MUTEX_HELD(&ep->re_lock));
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	if (iter == NULL || ep == NULL) {
596*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
597*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
598*7c478bd9Sstevel@tonic-gate 	}
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&iter->ri_lock);
601*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ep->re_lock);
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	*iterp = iter;
606*7c478bd9Sstevel@tonic-gate 	*epp = ep;
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	if ((rlp = get_log()) != NULL) {
609*7c478bd9Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, entity_id, ep);
610*7c478bd9Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ITER, iter_id, iter);
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
614*7c478bd9Sstevel@tonic-gate }
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate static void
617*7c478bd9Sstevel@tonic-gate iter_release(repcache_iter_t *iter)
618*7c478bd9Sstevel@tonic-gate {
619*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&iter->ri_lock);
620*7c478bd9Sstevel@tonic-gate }
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate static void
623*7c478bd9Sstevel@tonic-gate iter_destroy(repcache_iter_t *iter)
624*7c478bd9Sstevel@tonic-gate {
625*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&iter->ri_lock);
626*7c478bd9Sstevel@tonic-gate 	rc_iter_destroy(&iter->ri_iter);
627*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&iter->ri_lock);
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	uu_list_node_fini(iter, &iter->ri_link, iter_pool);
630*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&iter->ri_lock);
631*7c478bd9Sstevel@tonic-gate 	uu_free(iter);
632*7c478bd9Sstevel@tonic-gate }
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate static void
635*7c478bd9Sstevel@tonic-gate iter_remove(repcache_client_t *cp, uint32_t id)
636*7c478bd9Sstevel@tonic-gate {
637*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter;
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
640*7c478bd9Sstevel@tonic-gate 	iter = uu_list_find(cp->rc_iter_list, &id, NULL, NULL);
641*7c478bd9Sstevel@tonic-gate 	if (iter != NULL)
642*7c478bd9Sstevel@tonic-gate 		uu_list_remove(cp->rc_iter_list, iter);
643*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 	if (iter != NULL)
646*7c478bd9Sstevel@tonic-gate 		iter_destroy(iter);
647*7c478bd9Sstevel@tonic-gate }
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate static void
650*7c478bd9Sstevel@tonic-gate iter_cleanup(repcache_client_t *cp)
651*7c478bd9Sstevel@tonic-gate {
652*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter;
653*7c478bd9Sstevel@tonic-gate 	void *cookie = NULL;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
656*7c478bd9Sstevel@tonic-gate 	while ((iter = uu_list_teardown(cp->rc_iter_list, &cookie)) != NULL) {
657*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
658*7c478bd9Sstevel@tonic-gate 		iter_destroy(iter);
659*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cp->rc_lock);
660*7c478bd9Sstevel@tonic-gate 	}
661*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
662*7c478bd9Sstevel@tonic-gate }
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate /*
665*7c478bd9Sstevel@tonic-gate  * Ensure that the passed client id is no longer usable, wait for any
666*7c478bd9Sstevel@tonic-gate  * outstanding invocations to complete, then destroy the client
667*7c478bd9Sstevel@tonic-gate  * structure.
668*7c478bd9Sstevel@tonic-gate  */
669*7c478bd9Sstevel@tonic-gate static void
670*7c478bd9Sstevel@tonic-gate client_destroy(uint32_t id)
671*7c478bd9Sstevel@tonic-gate {
672*7c478bd9Sstevel@tonic-gate 	client_bucket_t *bp = CLIENT_HASH(id);
673*7c478bd9Sstevel@tonic-gate 	repcache_client_t *cp;
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&bp->cb_lock);
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	cp = uu_list_find(bp->cb_list, &id, NULL, NULL);
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
680*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&bp->cb_lock);
681*7c478bd9Sstevel@tonic-gate 		return;
682*7c478bd9Sstevel@tonic-gate 	}
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 	uu_list_remove(bp->cb_list, cp);
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&bp->cb_lock);
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	/* kick the waiters out */
689*7c478bd9Sstevel@tonic-gate 	rc_notify_info_fini(&cp->rc_notify_info);
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
692*7c478bd9Sstevel@tonic-gate 	assert(!(cp->rc_flags & RC_CLIENT_DEAD));
693*7c478bd9Sstevel@tonic-gate 	cp->rc_flags |= RC_CLIENT_DEAD;
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 	if (cp->rc_doorfd != -1) {
696*7c478bd9Sstevel@tonic-gate 		if (door_revoke(cp->rc_doorfd) < 0)
697*7c478bd9Sstevel@tonic-gate 			perror("door_revoke");
698*7c478bd9Sstevel@tonic-gate 		cp->rc_doorfd = -1;
699*7c478bd9Sstevel@tonic-gate 		cp->rc_doorid = INVALID_DOORID;
700*7c478bd9Sstevel@tonic-gate 	}
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 	while (cp->rc_refcnt > 0)
703*7c478bd9Sstevel@tonic-gate 		(void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock);
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_insert_thr == 0 && cp->rc_notify_thr == 0);
706*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	/*
709*7c478bd9Sstevel@tonic-gate 	 * destroy outstanding objects
710*7c478bd9Sstevel@tonic-gate 	 */
711*7c478bd9Sstevel@tonic-gate 	entity_cleanup(cp);
712*7c478bd9Sstevel@tonic-gate 	iter_cleanup(cp);
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	/*
715*7c478bd9Sstevel@tonic-gate 	 * clean up notifications
716*7c478bd9Sstevel@tonic-gate 	 */
717*7c478bd9Sstevel@tonic-gate 	rc_pg_notify_fini(&cp->rc_pg_notify);
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 	client_free(cp);
720*7c478bd9Sstevel@tonic-gate }
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate /*
723*7c478bd9Sstevel@tonic-gate  * Fails with
724*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - the entity is already set up with a different type
725*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
726*7c478bd9Sstevel@tonic-gate  */
727*7c478bd9Sstevel@tonic-gate static int
728*7c478bd9Sstevel@tonic-gate entity_setup(repcache_client_t *cp, struct rep_protocol_entity_setup *rpr)
729*7c478bd9Sstevel@tonic-gate {
730*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
731*7c478bd9Sstevel@tonic-gate 	uint32_t type;
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	client_start_insert(cp);
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) {
736*7c478bd9Sstevel@tonic-gate 		type = ep->re_type;
737*7c478bd9Sstevel@tonic-gate 		entity_release(ep);
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 		client_end_insert(cp);
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 		if (type != rpr->rpr_entitytype)
742*7c478bd9Sstevel@tonic-gate 			return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
743*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);
744*7c478bd9Sstevel@tonic-gate 	}
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 	switch (type = rpr->rpr_entitytype) {
747*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SCOPE:
748*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SERVICE:
749*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE:
750*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
751*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPLEVEL:
752*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
753*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTY:
754*7c478bd9Sstevel@tonic-gate 		break;
755*7c478bd9Sstevel@tonic-gate 	default:
756*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
757*7c478bd9Sstevel@tonic-gate 	}
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	ep = entity_alloc(cp);
760*7c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
761*7c478bd9Sstevel@tonic-gate 		client_end_insert(cp);
762*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
763*7c478bd9Sstevel@tonic-gate 	}
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 	ep->re_id = rpr->rpr_entityid;
766*7c478bd9Sstevel@tonic-gate 	ep->re_changeid = INVALID_CHANGEID;
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	ep->re_type = type;
769*7c478bd9Sstevel@tonic-gate 	rc_node_ptr_init(&ep->re_node);
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	entity_add(cp, ep);
772*7c478bd9Sstevel@tonic-gate 	client_end_insert(cp);
773*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
774*7c478bd9Sstevel@tonic-gate }
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
777*7c478bd9Sstevel@tonic-gate static void
778*7c478bd9Sstevel@tonic-gate entity_name(repcache_client_t *cp, const void *in, size_t insz, void *out_arg,
779*7c478bd9Sstevel@tonic-gate     size_t *outsz, void *arg)
780*7c478bd9Sstevel@tonic-gate {
781*7c478bd9Sstevel@tonic-gate 	const struct rep_protocol_entity_name *rpr = in;
782*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_name_response *out = out_arg;
783*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
784*7c478bd9Sstevel@tonic-gate 	size_t sz = sizeof (out->rpr_name);
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
791*7c478bd9Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
792*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
793*7c478bd9Sstevel@tonic-gate 		return;
794*7c478bd9Sstevel@tonic-gate 	}
795*7c478bd9Sstevel@tonic-gate 	out->rpr_response = rc_node_name(&ep->re_node, out->rpr_name,
796*7c478bd9Sstevel@tonic-gate 	    sz, rpr->rpr_answertype, &sz);
797*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 	/*
800*7c478bd9Sstevel@tonic-gate 	 * If we fail, we only return the response code.
801*7c478bd9Sstevel@tonic-gate 	 * If we succeed, we don't return anything after the '\0' in rpr_name.
802*7c478bd9Sstevel@tonic-gate 	 */
803*7c478bd9Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS)
804*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
805*7c478bd9Sstevel@tonic-gate 	else
806*7c478bd9Sstevel@tonic-gate 		*outsz = offsetof(struct rep_protocol_name_response,
807*7c478bd9Sstevel@tonic-gate 		    rpr_name[sz + 1]);
808*7c478bd9Sstevel@tonic-gate }
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
811*7c478bd9Sstevel@tonic-gate static void
812*7c478bd9Sstevel@tonic-gate entity_parent_type(repcache_client_t *cp, const void *in, size_t insz,
813*7c478bd9Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
814*7c478bd9Sstevel@tonic-gate {
815*7c478bd9Sstevel@tonic-gate 	const struct rep_protocol_entity_name *rpr = in;
816*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_integer_response *out = out_arg;
817*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
824*7c478bd9Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
825*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
826*7c478bd9Sstevel@tonic-gate 		return;
827*7c478bd9Sstevel@tonic-gate 	}
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	out->rpr_response = rc_node_parent_type(&ep->re_node, &out->rpr_value);
830*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS)
833*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
834*7c478bd9Sstevel@tonic-gate }
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate /*
837*7c478bd9Sstevel@tonic-gate  * Fails with
838*7c478bd9Sstevel@tonic-gate  *   _DUPLICATE_ID - the ids are equal
839*7c478bd9Sstevel@tonic-gate  *   _UNKNOWN_ID - an id does not designate an active register
840*7c478bd9Sstevel@tonic-gate  *   _INVALID_TYPE - type is invalid
841*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - np doesn't carry children of type type
842*7c478bd9Sstevel@tonic-gate  *   _DELETED - np has been deleted
843*7c478bd9Sstevel@tonic-gate  *   _NOT_FOUND - no child with that name/type combo found
844*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
845*7c478bd9Sstevel@tonic-gate  *   _BACKEND_ACCESS
846*7c478bd9Sstevel@tonic-gate  */
847*7c478bd9Sstevel@tonic-gate static int
848*7c478bd9Sstevel@tonic-gate entity_get_child(repcache_client_t *cp,
849*7c478bd9Sstevel@tonic-gate     struct rep_protocol_entity_get_child *rpr)
850*7c478bd9Sstevel@tonic-gate {
851*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *parent, *child;
852*7c478bd9Sstevel@tonic-gate 	int result;
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	uint32_t parentid = rpr->rpr_entityid;
855*7c478bd9Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_childid;
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	result = entity_find2(cp, childid, &child, parentid, &parent);
858*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
859*7c478bd9Sstevel@tonic-gate 		return (result);
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	result = rc_node_get_child(&parent->re_node, rpr->rpr_name,
864*7c478bd9Sstevel@tonic-gate 	    child->re_type, &child->re_node);
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	entity_release(child);
867*7c478bd9Sstevel@tonic-gate 	entity_release(parent);
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	return (result);
870*7c478bd9Sstevel@tonic-gate }
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate /*
873*7c478bd9Sstevel@tonic-gate  * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED,
874*7c478bd9Sstevel@tonic-gate  * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS.
875*7c478bd9Sstevel@tonic-gate  * Fails with
876*7c478bd9Sstevel@tonic-gate  *   _DUPLICATE_ID - the ids are equal
877*7c478bd9Sstevel@tonic-gate  *   _UNKNOWN_ID - an id does not designate an active register
878*7c478bd9Sstevel@tonic-gate  *   _NOT_SET - child is not set
879*7c478bd9Sstevel@tonic-gate  *   _DELETED - child has been deleted
880*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - child's parent does not match that of the parent register
881*7c478bd9Sstevel@tonic-gate  *   _NOT_FOUND - child has no parent (and is a scope)
882*7c478bd9Sstevel@tonic-gate  */
883*7c478bd9Sstevel@tonic-gate static int
884*7c478bd9Sstevel@tonic-gate entity_get_parent(repcache_client_t *cp, struct rep_protocol_entity_parent *rpr)
885*7c478bd9Sstevel@tonic-gate {
886*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *child, *parent;
887*7c478bd9Sstevel@tonic-gate 	int result;
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_entityid;
890*7c478bd9Sstevel@tonic-gate 	uint32_t outid = rpr->rpr_outid;
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	result = entity_find2(cp, childid, &child, outid, &parent);
893*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
894*7c478bd9Sstevel@tonic-gate 		return (result);
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate 	result = rc_node_get_parent(&child->re_node, parent->re_type,
897*7c478bd9Sstevel@tonic-gate 	    &parent->re_node);
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	entity_release(child);
900*7c478bd9Sstevel@tonic-gate 	entity_release(parent);
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	return (result);
903*7c478bd9Sstevel@tonic-gate }
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate static int
906*7c478bd9Sstevel@tonic-gate entity_get(repcache_client_t *cp, struct rep_protocol_entity_get *rpr)
907*7c478bd9Sstevel@tonic-gate {
908*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
909*7c478bd9Sstevel@tonic-gate 	int result;
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 	if (ep == NULL)
914*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	switch (rpr->rpr_object) {
917*7c478bd9Sstevel@tonic-gate 	case RP_ENTITY_GET_INVALIDATE:
918*7c478bd9Sstevel@tonic-gate 		rc_node_clear(&ep->re_node, 0);
919*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
920*7c478bd9Sstevel@tonic-gate 		break;
921*7c478bd9Sstevel@tonic-gate 	case RP_ENTITY_GET_MOST_LOCAL_SCOPE:
922*7c478bd9Sstevel@tonic-gate 		result = rc_local_scope(ep->re_type, &ep->re_node);
923*7c478bd9Sstevel@tonic-gate 		break;
924*7c478bd9Sstevel@tonic-gate 	default:
925*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
926*7c478bd9Sstevel@tonic-gate 		break;
927*7c478bd9Sstevel@tonic-gate 	}
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 	return (result);
932*7c478bd9Sstevel@tonic-gate }
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate static int
935*7c478bd9Sstevel@tonic-gate entity_update(repcache_client_t *cp, struct rep_protocol_entity_update *rpr)
936*7c478bd9Sstevel@tonic-gate {
937*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
938*7c478bd9Sstevel@tonic-gate 	int result;
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
941*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 	if (ep == NULL)
946*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 	if (ep->re_changeid == rpr->rpr_changeid) {
949*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_DONE;
950*7c478bd9Sstevel@tonic-gate 	} else {
951*7c478bd9Sstevel@tonic-gate 		result = rc_node_update(&ep->re_node);
952*7c478bd9Sstevel@tonic-gate 		if (result == REP_PROTOCOL_DONE)
953*7c478bd9Sstevel@tonic-gate 			ep->re_changeid = rpr->rpr_changeid;
954*7c478bd9Sstevel@tonic-gate 	}
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	return (result);
959*7c478bd9Sstevel@tonic-gate }
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate static int
962*7c478bd9Sstevel@tonic-gate entity_reset(repcache_client_t *cp, struct rep_protocol_entity_reset *rpr)
963*7c478bd9Sstevel@tonic-gate {
964*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
967*7c478bd9Sstevel@tonic-gate 	if (ep == NULL)
968*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	rc_node_clear(&ep->re_node, 0);
971*7c478bd9Sstevel@tonic-gate 	ep->re_txstate = REPCACHE_TX_INIT;
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
974*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
975*7c478bd9Sstevel@tonic-gate }
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate /*
978*7c478bd9Sstevel@tonic-gate  * Fails with
979*7c478bd9Sstevel@tonic-gate  *   _BAD_REQUEST - request has invalid changeid
980*7c478bd9Sstevel@tonic-gate  *		    rpr_name is invalid
981*7c478bd9Sstevel@tonic-gate  *		    cannot create children for parent's type of node
982*7c478bd9Sstevel@tonic-gate  *   _DUPLICATE_ID - request has duplicate ids
983*7c478bd9Sstevel@tonic-gate  *   _UNKNOWN_ID - request has unknown id
984*7c478bd9Sstevel@tonic-gate  *   _DELETED - parent has been deleted
985*7c478bd9Sstevel@tonic-gate  *   _NOT_SET - parent is reset
986*7c478bd9Sstevel@tonic-gate  *   _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP
987*7c478bd9Sstevel@tonic-gate  *   _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid
988*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - parent cannot have children of type rpr_childtype
989*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
990*7c478bd9Sstevel@tonic-gate  *   _PERMISSION_DENIED
991*7c478bd9Sstevel@tonic-gate  *   _BACKEND_ACCESS
992*7c478bd9Sstevel@tonic-gate  *   _BACKEND_READONLY
993*7c478bd9Sstevel@tonic-gate  *   _EXISTS - child already exists
994*7c478bd9Sstevel@tonic-gate  *   _NOT_FOUND - could not allocate new id
995*7c478bd9Sstevel@tonic-gate  */
996*7c478bd9Sstevel@tonic-gate static int
997*7c478bd9Sstevel@tonic-gate entity_create_child(repcache_client_t *cp,
998*7c478bd9Sstevel@tonic-gate     struct rep_protocol_entity_create_child *rpr)
999*7c478bd9Sstevel@tonic-gate {
1000*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *parent;
1001*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *child;
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 	uint32_t parentid = rpr->rpr_entityid;
1004*7c478bd9Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_childid;
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate 	int result;
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
1009*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 	result = entity_find2(cp, parentid, &parent, childid, &child);
1012*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1013*7c478bd9Sstevel@tonic-gate 		return (result);
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 	if (child->re_changeid == rpr->rpr_changeid) {
1018*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
1019*7c478bd9Sstevel@tonic-gate 	} else {
1020*7c478bd9Sstevel@tonic-gate 		result = rc_node_create_child(&parent->re_node,
1021*7c478bd9Sstevel@tonic-gate 		    rpr->rpr_childtype, rpr->rpr_name, &child->re_node);
1022*7c478bd9Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
1023*7c478bd9Sstevel@tonic-gate 			child->re_changeid = rpr->rpr_changeid;
1024*7c478bd9Sstevel@tonic-gate 	}
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 	entity_release(parent);
1027*7c478bd9Sstevel@tonic-gate 	entity_release(child);
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	return (result);
1030*7c478bd9Sstevel@tonic-gate }
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate static int
1033*7c478bd9Sstevel@tonic-gate entity_create_pg(repcache_client_t *cp,
1034*7c478bd9Sstevel@tonic-gate     struct rep_protocol_entity_create_pg *rpr)
1035*7c478bd9Sstevel@tonic-gate {
1036*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *parent;
1037*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *child;
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate 	uint32_t parentid = rpr->rpr_entityid;
1040*7c478bd9Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_childid;
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 	int result;
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
1045*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate 	result = entity_find2(cp, parentid, &parent, childid, &child);
1048*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1049*7c478bd9Sstevel@tonic-gate 		return (result);
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 	rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
1052*7c478bd9Sstevel@tonic-gate 	rpr->rpr_type[sizeof (rpr->rpr_type) - 1] = 0;
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 	if (child->re_changeid == rpr->rpr_changeid) {
1055*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
1056*7c478bd9Sstevel@tonic-gate 	} else {
1057*7c478bd9Sstevel@tonic-gate 		result = rc_node_create_child_pg(&parent->re_node,
1058*7c478bd9Sstevel@tonic-gate 		    child->re_type, rpr->rpr_name, rpr->rpr_type,
1059*7c478bd9Sstevel@tonic-gate 		    rpr->rpr_flags, &child->re_node);
1060*7c478bd9Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
1061*7c478bd9Sstevel@tonic-gate 			child->re_changeid = rpr->rpr_changeid;
1062*7c478bd9Sstevel@tonic-gate 	}
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 	entity_release(parent);
1065*7c478bd9Sstevel@tonic-gate 	entity_release(child);
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	return (result);
1068*7c478bd9Sstevel@tonic-gate }
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate static int
1071*7c478bd9Sstevel@tonic-gate entity_delete(repcache_client_t *cp,
1072*7c478bd9Sstevel@tonic-gate     struct rep_protocol_entity_delete *rpr)
1073*7c478bd9Sstevel@tonic-gate {
1074*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *entity;
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate 	uint32_t entityid = rpr->rpr_entityid;
1077*7c478bd9Sstevel@tonic-gate 
1078*7c478bd9Sstevel@tonic-gate 	int result;
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
1081*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate 	entity = entity_find(cp, entityid);
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	if (entity == NULL)
1086*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate 	if (entity->re_changeid == rpr->rpr_changeid) {
1089*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
1090*7c478bd9Sstevel@tonic-gate 	} else {
1091*7c478bd9Sstevel@tonic-gate 		result = rc_node_delete(&entity->re_node);
1092*7c478bd9Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
1093*7c478bd9Sstevel@tonic-gate 			entity->re_changeid = rpr->rpr_changeid;
1094*7c478bd9Sstevel@tonic-gate 	}
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 	entity_release(entity);
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 	return (result);
1099*7c478bd9Sstevel@tonic-gate }
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1102*7c478bd9Sstevel@tonic-gate entity_teardown(repcache_client_t *cp, struct rep_protocol_entity_teardown *rpr)
1103*7c478bd9Sstevel@tonic-gate {
1104*7c478bd9Sstevel@tonic-gate 	entity_remove(cp, rpr->rpr_entityid);
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1107*7c478bd9Sstevel@tonic-gate }
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate /*
1110*7c478bd9Sstevel@tonic-gate  * Fails with
1111*7c478bd9Sstevel@tonic-gate  *   _MISORDERED - the iterator exists and is not reset
1112*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
1113*7c478bd9Sstevel@tonic-gate  */
1114*7c478bd9Sstevel@tonic-gate static int
1115*7c478bd9Sstevel@tonic-gate iter_setup(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
1116*7c478bd9Sstevel@tonic-gate {
1117*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter;
1118*7c478bd9Sstevel@tonic-gate 	uint32_t sequence;
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 	client_start_insert(cp);
1121*7c478bd9Sstevel@tonic-gate 	/*
1122*7c478bd9Sstevel@tonic-gate 	 * If the iter already exists, and hasn't been read from,
1123*7c478bd9Sstevel@tonic-gate 	 * we assume the previous call succeeded.
1124*7c478bd9Sstevel@tonic-gate 	 */
1125*7c478bd9Sstevel@tonic-gate 	if ((iter = iter_find(cp, rpr->rpr_iterid)) != NULL) {
1126*7c478bd9Sstevel@tonic-gate 		sequence = iter->ri_sequence;
1127*7c478bd9Sstevel@tonic-gate 		iter_release(iter);
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 		client_end_insert(cp);
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 		if (sequence != 0)
1132*7c478bd9Sstevel@tonic-gate 			return (REP_PROTOCOL_FAIL_MISORDERED);
1133*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);
1134*7c478bd9Sstevel@tonic-gate 	}
1135*7c478bd9Sstevel@tonic-gate 
1136*7c478bd9Sstevel@tonic-gate 	iter = iter_alloc(cp);
1137*7c478bd9Sstevel@tonic-gate 	if (iter == NULL) {
1138*7c478bd9Sstevel@tonic-gate 		client_end_insert(cp);
1139*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1140*7c478bd9Sstevel@tonic-gate 	}
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 	iter->ri_id = rpr->rpr_iterid;
1143*7c478bd9Sstevel@tonic-gate 	iter->ri_type = REP_PROTOCOL_TYPE_INVALID;
1144*7c478bd9Sstevel@tonic-gate 	iter->ri_sequence = 0;
1145*7c478bd9Sstevel@tonic-gate 	iter_add(cp, iter);
1146*7c478bd9Sstevel@tonic-gate 
1147*7c478bd9Sstevel@tonic-gate 	client_end_insert(cp);
1148*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1149*7c478bd9Sstevel@tonic-gate }
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate /*
1152*7c478bd9Sstevel@tonic-gate  * Fails with
1153*7c478bd9Sstevel@tonic-gate  *   _UNKNOWN_ID
1154*7c478bd9Sstevel@tonic-gate  *   _MISORDERED - iterator has already been started
1155*7c478bd9Sstevel@tonic-gate  *   _NOT_SET
1156*7c478bd9Sstevel@tonic-gate  *   _DELETED
1157*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - entity cannot have type children
1158*7c478bd9Sstevel@tonic-gate  *   _BAD_REQUEST - rpr_flags is invalid
1159*7c478bd9Sstevel@tonic-gate  *		    rpr_pattern is invalid
1160*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
1161*7c478bd9Sstevel@tonic-gate  *   _INVALID_TYPE
1162*7c478bd9Sstevel@tonic-gate  *   _BACKEND_ACCESS
1163*7c478bd9Sstevel@tonic-gate  */
1164*7c478bd9Sstevel@tonic-gate static int
1165*7c478bd9Sstevel@tonic-gate iter_start(repcache_client_t *cp, struct rep_protocol_iter_start *rpr)
1166*7c478bd9Sstevel@tonic-gate {
1167*7c478bd9Sstevel@tonic-gate 	int result;
1168*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter;
1169*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 	result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter,
1172*7c478bd9Sstevel@tonic-gate 	    rpr->rpr_entity, &ep);
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1175*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate 	if (iter->ri_sequence > 1) {
1178*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_MISORDERED;
1179*7c478bd9Sstevel@tonic-gate 		goto end;
1180*7c478bd9Sstevel@tonic-gate 	}
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate 	if (iter->ri_sequence == 1) {
1183*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
1184*7c478bd9Sstevel@tonic-gate 		goto end;
1185*7c478bd9Sstevel@tonic-gate 	}
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate 	rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0;
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate 	result = rc_node_setup_iter(&ep->re_node, &iter->ri_iter,
1190*7c478bd9Sstevel@tonic-gate 	    rpr->rpr_itertype, rpr->rpr_flags, rpr->rpr_pattern);
1191*7c478bd9Sstevel@tonic-gate 
1192*7c478bd9Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS)
1193*7c478bd9Sstevel@tonic-gate 		iter->ri_sequence++;
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate end:
1196*7c478bd9Sstevel@tonic-gate 	iter_release(iter);
1197*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
1198*7c478bd9Sstevel@tonic-gate 	return (result);
1199*7c478bd9Sstevel@tonic-gate }
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate /*
1202*7c478bd9Sstevel@tonic-gate  * Returns
1203*7c478bd9Sstevel@tonic-gate  *   _UNKNOWN_ID
1204*7c478bd9Sstevel@tonic-gate  *   _NOT_SET - iter has not been started
1205*7c478bd9Sstevel@tonic-gate  *   _MISORDERED
1206*7c478bd9Sstevel@tonic-gate  *   _BAD_REQUEST - iter walks values
1207*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - iter does not walk type entities
1208*7c478bd9Sstevel@tonic-gate  *   _DELETED - parent was deleted
1209*7c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
1210*7c478bd9Sstevel@tonic-gate  *   _INVALID_TYPE - type is invalid
1211*7c478bd9Sstevel@tonic-gate  *   _DONE
1212*7c478bd9Sstevel@tonic-gate  *   _SUCCESS
1213*7c478bd9Sstevel@tonic-gate  *
1214*7c478bd9Sstevel@tonic-gate  * For composed property group iterators, can also return
1215*7c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - parent cannot have type children
1216*7c478bd9Sstevel@tonic-gate  *   _BACKEND_ACCESS
1217*7c478bd9Sstevel@tonic-gate  */
1218*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1219*7c478bd9Sstevel@tonic-gate iter_read(repcache_client_t *cp, struct rep_protocol_iter_read *rpr)
1220*7c478bd9Sstevel@tonic-gate {
1221*7c478bd9Sstevel@tonic-gate 	rep_protocol_responseid_t result;
1222*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter;
1223*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
1224*7c478bd9Sstevel@tonic-gate 	uint32_t sequence;
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter,
1227*7c478bd9Sstevel@tonic-gate 	    rpr->rpr_entityid, &ep);
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1230*7c478bd9Sstevel@tonic-gate 		return (result);
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 	sequence = rpr->rpr_sequence;
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate 	if (iter->ri_sequence == 0) {
1235*7c478bd9Sstevel@tonic-gate 		iter_release(iter);
1236*7c478bd9Sstevel@tonic-gate 		entity_release(ep);
1237*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NOT_SET);
1238*7c478bd9Sstevel@tonic-gate 	}
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 	if (sequence == 1) {
1241*7c478bd9Sstevel@tonic-gate 		iter_release(iter);
1242*7c478bd9Sstevel@tonic-gate 		entity_release(ep);
1243*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_MISORDERED);
1244*7c478bd9Sstevel@tonic-gate 	}
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	if (sequence == iter->ri_sequence) {
1247*7c478bd9Sstevel@tonic-gate 		iter_release(iter);
1248*7c478bd9Sstevel@tonic-gate 		entity_release(ep);
1249*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);
1250*7c478bd9Sstevel@tonic-gate 	}
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	if (sequence == iter->ri_sequence + 1) {
1253*7c478bd9Sstevel@tonic-gate 		result = rc_iter_next(iter->ri_iter, &ep->re_node,
1254*7c478bd9Sstevel@tonic-gate 		    ep->re_type);
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
1257*7c478bd9Sstevel@tonic-gate 			iter->ri_sequence++;
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate 		iter_release(iter);
1260*7c478bd9Sstevel@tonic-gate 		entity_release(ep);
1261*7c478bd9Sstevel@tonic-gate 
1262*7c478bd9Sstevel@tonic-gate 		return (result);
1263*7c478bd9Sstevel@tonic-gate 	}
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate 	iter_release(iter);
1266*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
1267*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_FAIL_MISORDERED);
1268*7c478bd9Sstevel@tonic-gate }
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1271*7c478bd9Sstevel@tonic-gate static void
1272*7c478bd9Sstevel@tonic-gate iter_read_value(repcache_client_t *cp, const void *in, size_t insz,
1273*7c478bd9Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
1274*7c478bd9Sstevel@tonic-gate {
1275*7c478bd9Sstevel@tonic-gate 	const struct rep_protocol_iter_read_value *rpr = in;
1276*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_value_response *out = out_arg;
1277*7c478bd9Sstevel@tonic-gate 	rep_protocol_responseid_t result;
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter;
1280*7c478bd9Sstevel@tonic-gate 	uint32_t sequence;
1281*7c478bd9Sstevel@tonic-gate 	int repeat;
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate 	iter = iter_find(cp, rpr->rpr_iterid);
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 	if (iter == NULL) {
1288*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1289*7c478bd9Sstevel@tonic-gate 		goto out;
1290*7c478bd9Sstevel@tonic-gate 	}
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	sequence = rpr->rpr_sequence;
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	if (iter->ri_sequence == 0) {
1295*7c478bd9Sstevel@tonic-gate 		iter_release(iter);
1296*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_NOT_SET;
1297*7c478bd9Sstevel@tonic-gate 		goto out;
1298*7c478bd9Sstevel@tonic-gate 	}
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 	repeat = (sequence == iter->ri_sequence);
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate 	if (sequence == 1 || (!repeat && sequence != iter->ri_sequence + 1)) {
1303*7c478bd9Sstevel@tonic-gate 		iter_release(iter);
1304*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_MISORDERED;
1305*7c478bd9Sstevel@tonic-gate 		goto out;
1306*7c478bd9Sstevel@tonic-gate 	}
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 	result = rc_iter_next_value(iter->ri_iter, out, outsz, repeat);
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate 	if (!repeat && result == REP_PROTOCOL_SUCCESS)
1311*7c478bd9Sstevel@tonic-gate 		iter->ri_sequence++;
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate 	iter_release(iter);
1314*7c478bd9Sstevel@tonic-gate 
1315*7c478bd9Sstevel@tonic-gate out:
1316*7c478bd9Sstevel@tonic-gate 	/*
1317*7c478bd9Sstevel@tonic-gate 	 * If we fail, we only return the response code.
1318*7c478bd9Sstevel@tonic-gate 	 * If we succeed, rc_iter_next_value has shortened *outsz
1319*7c478bd9Sstevel@tonic-gate 	 * to only include the value bytes needed.
1320*7c478bd9Sstevel@tonic-gate 	 */
1321*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS && result != REP_PROTOCOL_DONE)
1322*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	out->rpr_response = result;
1325*7c478bd9Sstevel@tonic-gate }
1326*7c478bd9Sstevel@tonic-gate 
1327*7c478bd9Sstevel@tonic-gate static int
1328*7c478bd9Sstevel@tonic-gate iter_reset(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
1329*7c478bd9Sstevel@tonic-gate {
1330*7c478bd9Sstevel@tonic-gate 	repcache_iter_t *iter = iter_find(cp, rpr->rpr_iterid);
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 	if (iter == NULL)
1333*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate 	if (iter->ri_sequence != 0) {
1336*7c478bd9Sstevel@tonic-gate 		iter->ri_sequence = 0;
1337*7c478bd9Sstevel@tonic-gate 		rc_iter_destroy(&iter->ri_iter);
1338*7c478bd9Sstevel@tonic-gate 	}
1339*7c478bd9Sstevel@tonic-gate 	iter_release(iter);
1340*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1341*7c478bd9Sstevel@tonic-gate }
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1344*7c478bd9Sstevel@tonic-gate iter_teardown(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
1345*7c478bd9Sstevel@tonic-gate {
1346*7c478bd9Sstevel@tonic-gate 	iter_remove(cp, rpr->rpr_iterid);
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1349*7c478bd9Sstevel@tonic-gate }
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1352*7c478bd9Sstevel@tonic-gate tx_start(repcache_client_t *cp, struct rep_protocol_transaction_start *rpr)
1353*7c478bd9Sstevel@tonic-gate {
1354*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *tx;
1355*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
1356*7c478bd9Sstevel@tonic-gate 	rep_protocol_responseid_t result;
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate 	uint32_t txid = rpr->rpr_entityid_tx;
1359*7c478bd9Sstevel@tonic-gate 	uint32_t epid = rpr->rpr_entityid;
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate 	result = entity_find2(cp, txid, &tx, epid, &ep);
1362*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1363*7c478bd9Sstevel@tonic-gate 		return (result);
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate 	if (tx->re_txstate == REPCACHE_TX_SETUP) {
1366*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
1367*7c478bd9Sstevel@tonic-gate 		goto end;
1368*7c478bd9Sstevel@tonic-gate 	}
1369*7c478bd9Sstevel@tonic-gate 	if (tx->re_txstate != REPCACHE_TX_INIT) {
1370*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_MISORDERED;
1371*7c478bd9Sstevel@tonic-gate 		goto end;
1372*7c478bd9Sstevel@tonic-gate 	}
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 	result = rc_node_setup_tx(&ep->re_node, &tx->re_node);
1375*7c478bd9Sstevel@tonic-gate 
1376*7c478bd9Sstevel@tonic-gate end:
1377*7c478bd9Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS)
1378*7c478bd9Sstevel@tonic-gate 		tx->re_txstate = REPCACHE_TX_SETUP;
1379*7c478bd9Sstevel@tonic-gate 	else
1380*7c478bd9Sstevel@tonic-gate 		rc_node_clear(&tx->re_node, 0);
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
1383*7c478bd9Sstevel@tonic-gate 	entity_release(tx);
1384*7c478bd9Sstevel@tonic-gate 	return (result);
1385*7c478bd9Sstevel@tonic-gate }
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1388*7c478bd9Sstevel@tonic-gate static void
1389*7c478bd9Sstevel@tonic-gate tx_commit(repcache_client_t *cp, const void *in, size_t insz,
1390*7c478bd9Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
1391*7c478bd9Sstevel@tonic-gate {
1392*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_response *out = out_arg;
1393*7c478bd9Sstevel@tonic-gate 	const struct rep_protocol_transaction_commit *rpr = in;
1394*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *tx;
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
1397*7c478bd9Sstevel@tonic-gate 	assert(insz >= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE);
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate 	if (rpr->rpr_size != insz) {
1400*7c478bd9Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_BAD_REQUEST;
1401*7c478bd9Sstevel@tonic-gate 		return;
1402*7c478bd9Sstevel@tonic-gate 	}
1403*7c478bd9Sstevel@tonic-gate 
1404*7c478bd9Sstevel@tonic-gate 	tx = entity_find(cp, rpr->rpr_entityid);
1405*7c478bd9Sstevel@tonic-gate 
1406*7c478bd9Sstevel@tonic-gate 	if (tx == NULL) {
1407*7c478bd9Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1408*7c478bd9Sstevel@tonic-gate 		return;
1409*7c478bd9Sstevel@tonic-gate 	}
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate 	switch (tx->re_txstate) {
1412*7c478bd9Sstevel@tonic-gate 	case REPCACHE_TX_INIT:
1413*7c478bd9Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_MISORDERED;
1414*7c478bd9Sstevel@tonic-gate 		break;
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 	case REPCACHE_TX_SETUP:
1417*7c478bd9Sstevel@tonic-gate 		out->rpr_response = rc_tx_commit(&tx->re_node, rpr->rpr_cmd,
1418*7c478bd9Sstevel@tonic-gate 		    insz - REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE);
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate 		if (out->rpr_response == REP_PROTOCOL_SUCCESS) {
1421*7c478bd9Sstevel@tonic-gate 			tx->re_txstate = REPCACHE_TX_COMMITTED;
1422*7c478bd9Sstevel@tonic-gate 			rc_node_clear(&tx->re_node, 0);
1423*7c478bd9Sstevel@tonic-gate 		}
1424*7c478bd9Sstevel@tonic-gate 
1425*7c478bd9Sstevel@tonic-gate 		break;
1426*7c478bd9Sstevel@tonic-gate 	case REPCACHE_TX_COMMITTED:
1427*7c478bd9Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_SUCCESS;
1428*7c478bd9Sstevel@tonic-gate 		break;
1429*7c478bd9Sstevel@tonic-gate 	default:
1430*7c478bd9Sstevel@tonic-gate 		assert(0);	/* CAN'T HAPPEN */
1431*7c478bd9Sstevel@tonic-gate 		break;
1432*7c478bd9Sstevel@tonic-gate 	}
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 	entity_release(tx);
1435*7c478bd9Sstevel@tonic-gate }
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1438*7c478bd9Sstevel@tonic-gate next_snaplevel(repcache_client_t *cp, struct rep_protocol_entity_pair *rpr)
1439*7c478bd9Sstevel@tonic-gate {
1440*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *src;
1441*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *dest;
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entity_src;
1444*7c478bd9Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entity_dst;
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate 	int result;
1447*7c478bd9Sstevel@tonic-gate 
1448*7c478bd9Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
1449*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1450*7c478bd9Sstevel@tonic-gate 		return (result);
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 	result = rc_node_next_snaplevel(&src->re_node, &dest->re_node);
1453*7c478bd9Sstevel@tonic-gate 
1454*7c478bd9Sstevel@tonic-gate 	entity_release(src);
1455*7c478bd9Sstevel@tonic-gate 	entity_release(dest);
1456*7c478bd9Sstevel@tonic-gate 
1457*7c478bd9Sstevel@tonic-gate 	return (result);
1458*7c478bd9Sstevel@tonic-gate }
1459*7c478bd9Sstevel@tonic-gate 
1460*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1461*7c478bd9Sstevel@tonic-gate snapshot_take(repcache_client_t *cp, struct rep_protocol_snapshot_take *rpr)
1462*7c478bd9Sstevel@tonic-gate {
1463*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *src;
1464*7c478bd9Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entityid_src;
1465*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *dest;
1466*7c478bd9Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entityid_dest;
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 	int result;
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
1471*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1472*7c478bd9Sstevel@tonic-gate 		return (result);
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate 	if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
1475*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
1476*7c478bd9Sstevel@tonic-gate 	} else {
1477*7c478bd9Sstevel@tonic-gate 		rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate 		if (rpr->rpr_flags == REP_SNAPSHOT_NEW)
1480*7c478bd9Sstevel@tonic-gate 			result = rc_snapshot_take_new(&src->re_node, NULL,
1481*7c478bd9Sstevel@tonic-gate 			    NULL, rpr->rpr_name, &dest->re_node);
1482*7c478bd9Sstevel@tonic-gate 		else if (rpr->rpr_flags == REP_SNAPSHOT_ATTACH &&
1483*7c478bd9Sstevel@tonic-gate 		    rpr->rpr_name[0] == 0)
1484*7c478bd9Sstevel@tonic-gate 			result = rc_snapshot_take_attach(&src->re_node,
1485*7c478bd9Sstevel@tonic-gate 			    &dest->re_node);
1486*7c478bd9Sstevel@tonic-gate 		else
1487*7c478bd9Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_BAD_REQUEST;
1488*7c478bd9Sstevel@tonic-gate 	}
1489*7c478bd9Sstevel@tonic-gate 	entity_release(src);
1490*7c478bd9Sstevel@tonic-gate 	entity_release(dest);
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate 	return (result);
1493*7c478bd9Sstevel@tonic-gate }
1494*7c478bd9Sstevel@tonic-gate 
1495*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1496*7c478bd9Sstevel@tonic-gate snapshot_take_named(repcache_client_t *cp,
1497*7c478bd9Sstevel@tonic-gate     struct rep_protocol_snapshot_take_named *rpr)
1498*7c478bd9Sstevel@tonic-gate {
1499*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *src;
1500*7c478bd9Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entityid_src;
1501*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *dest;
1502*7c478bd9Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entityid_dest;
1503*7c478bd9Sstevel@tonic-gate 
1504*7c478bd9Sstevel@tonic-gate 	int result;
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
1507*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1508*7c478bd9Sstevel@tonic-gate 		return (result);
1509*7c478bd9Sstevel@tonic-gate 
1510*7c478bd9Sstevel@tonic-gate 	if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
1511*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
1512*7c478bd9Sstevel@tonic-gate 	} else {
1513*7c478bd9Sstevel@tonic-gate 		rpr->rpr_svcname[sizeof (rpr->rpr_svcname) - 1] = 0;
1514*7c478bd9Sstevel@tonic-gate 		rpr->rpr_instname[sizeof (rpr->rpr_instname) - 1] = 0;
1515*7c478bd9Sstevel@tonic-gate 		rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
1516*7c478bd9Sstevel@tonic-gate 
1517*7c478bd9Sstevel@tonic-gate 		result = rc_snapshot_take_new(&src->re_node, rpr->rpr_svcname,
1518*7c478bd9Sstevel@tonic-gate 		    rpr->rpr_instname, rpr->rpr_name, &dest->re_node);
1519*7c478bd9Sstevel@tonic-gate 	}
1520*7c478bd9Sstevel@tonic-gate 	entity_release(src);
1521*7c478bd9Sstevel@tonic-gate 	entity_release(dest);
1522*7c478bd9Sstevel@tonic-gate 
1523*7c478bd9Sstevel@tonic-gate 	return (result);
1524*7c478bd9Sstevel@tonic-gate }
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1527*7c478bd9Sstevel@tonic-gate snapshot_attach(repcache_client_t *cp, struct rep_protocol_snapshot_attach *rpr)
1528*7c478bd9Sstevel@tonic-gate {
1529*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *src;
1530*7c478bd9Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entityid_src;
1531*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *dest;
1532*7c478bd9Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entityid_dest;
1533*7c478bd9Sstevel@tonic-gate 
1534*7c478bd9Sstevel@tonic-gate 	int result;
1535*7c478bd9Sstevel@tonic-gate 
1536*7c478bd9Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
1537*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1538*7c478bd9Sstevel@tonic-gate 		return (result);
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate 	result = rc_snapshot_attach(&src->re_node, &dest->re_node);
1541*7c478bd9Sstevel@tonic-gate 
1542*7c478bd9Sstevel@tonic-gate 	entity_release(src);
1543*7c478bd9Sstevel@tonic-gate 	entity_release(dest);
1544*7c478bd9Sstevel@tonic-gate 
1545*7c478bd9Sstevel@tonic-gate 	return (result);
1546*7c478bd9Sstevel@tonic-gate }
1547*7c478bd9Sstevel@tonic-gate 
1548*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1549*7c478bd9Sstevel@tonic-gate static void
1550*7c478bd9Sstevel@tonic-gate property_get_type(repcache_client_t *cp, const void *in, size_t insz,
1551*7c478bd9Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
1552*7c478bd9Sstevel@tonic-gate {
1553*7c478bd9Sstevel@tonic-gate 	const struct rep_protocol_property_request *rpr = in;
1554*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_integer_response *out = out_arg;
1555*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
1556*7c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t = 0;
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
1559*7c478bd9Sstevel@tonic-gate 
1560*7c478bd9Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
1563*7c478bd9Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1564*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
1565*7c478bd9Sstevel@tonic-gate 		return;
1566*7c478bd9Sstevel@tonic-gate 	}
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate 	out->rpr_response = rc_node_get_property_type(&ep->re_node, &t);
1569*7c478bd9Sstevel@tonic-gate 
1570*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS)
1573*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
1574*7c478bd9Sstevel@tonic-gate 	else
1575*7c478bd9Sstevel@tonic-gate 		out->rpr_value = t;
1576*7c478bd9Sstevel@tonic-gate }
1577*7c478bd9Sstevel@tonic-gate 
1578*7c478bd9Sstevel@tonic-gate /*
1579*7c478bd9Sstevel@tonic-gate  * Fails with:
1580*7c478bd9Sstevel@tonic-gate  *	_UNKNOWN_ID - an id does not designate an active register
1581*7c478bd9Sstevel@tonic-gate  *	_NOT_SET - The property is not set
1582*7c478bd9Sstevel@tonic-gate  *	_DELETED - The property has been deleted
1583*7c478bd9Sstevel@tonic-gate  *	_TYPE_MISMATCH - The object is not a property
1584*7c478bd9Sstevel@tonic-gate  *	_NOT_FOUND - The property has no values.
1585*7c478bd9Sstevel@tonic-gate  *
1586*7c478bd9Sstevel@tonic-gate  * Succeeds with:
1587*7c478bd9Sstevel@tonic-gate  *	_SUCCESS - The property has 1 value.
1588*7c478bd9Sstevel@tonic-gate  *	_TRUNCATED - The property has >1 value.
1589*7c478bd9Sstevel@tonic-gate  */
1590*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1591*7c478bd9Sstevel@tonic-gate static void
1592*7c478bd9Sstevel@tonic-gate property_get_value(repcache_client_t *cp, const void *in, size_t insz,
1593*7c478bd9Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
1594*7c478bd9Sstevel@tonic-gate {
1595*7c478bd9Sstevel@tonic-gate 	const struct rep_protocol_property_request *rpr = in;
1596*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_value_response *out = out_arg;
1597*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
1598*7c478bd9Sstevel@tonic-gate 
1599*7c478bd9Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
1600*7c478bd9Sstevel@tonic-gate 
1601*7c478bd9Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
1602*7c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
1603*7c478bd9Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1604*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
1605*7c478bd9Sstevel@tonic-gate 		return;
1606*7c478bd9Sstevel@tonic-gate 	}
1607*7c478bd9Sstevel@tonic-gate 
1608*7c478bd9Sstevel@tonic-gate 	out->rpr_response = rc_node_get_property_value(&ep->re_node, out,
1609*7c478bd9Sstevel@tonic-gate 	    outsz);
1610*7c478bd9Sstevel@tonic-gate 
1611*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate 	/*
1614*7c478bd9Sstevel@tonic-gate 	 * If we fail, we only return the response code.
1615*7c478bd9Sstevel@tonic-gate 	 * If we succeed, rc_node_get_property_value has shortened *outsz
1616*7c478bd9Sstevel@tonic-gate 	 * to only include the value bytes needed.
1617*7c478bd9Sstevel@tonic-gate 	 */
1618*7c478bd9Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS &&
1619*7c478bd9Sstevel@tonic-gate 	    out->rpr_response != REP_PROTOCOL_FAIL_TRUNCATED)
1620*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
1621*7c478bd9Sstevel@tonic-gate }
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1624*7c478bd9Sstevel@tonic-gate propertygrp_notify(repcache_client_t *cp,
1625*7c478bd9Sstevel@tonic-gate     struct rep_protocol_propertygrp_request *rpr, int *out_fd)
1626*7c478bd9Sstevel@tonic-gate {
1627*7c478bd9Sstevel@tonic-gate 	int fds[2];
1628*7c478bd9Sstevel@tonic-gate 	int ours, theirs;
1629*7c478bd9Sstevel@tonic-gate 
1630*7c478bd9Sstevel@tonic-gate 	rep_protocol_responseid_t result;
1631*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
1632*7c478bd9Sstevel@tonic-gate 
1633*7c478bd9Sstevel@tonic-gate 	if (pipe(fds) < 0)
1634*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate 	ours = fds[0];
1637*7c478bd9Sstevel@tonic-gate 	theirs = fds[1];
1638*7c478bd9Sstevel@tonic-gate 
1639*7c478bd9Sstevel@tonic-gate 	if ((ep = entity_find(cp, rpr->rpr_entityid)) == NULL) {
1640*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1641*7c478bd9Sstevel@tonic-gate 		goto fail;
1642*7c478bd9Sstevel@tonic-gate 	}
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate 	/*
1645*7c478bd9Sstevel@tonic-gate 	 * While the following can race with other threads setting up a
1646*7c478bd9Sstevel@tonic-gate 	 * notification, the worst that can happen is that our fd has
1647*7c478bd9Sstevel@tonic-gate 	 * already been closed before we return.
1648*7c478bd9Sstevel@tonic-gate 	 */
1649*7c478bd9Sstevel@tonic-gate 	result = rc_pg_notify_setup(&cp->rc_pg_notify, &ep->re_node,
1650*7c478bd9Sstevel@tonic-gate 	    ours);
1651*7c478bd9Sstevel@tonic-gate 
1652*7c478bd9Sstevel@tonic-gate 	entity_release(ep);
1653*7c478bd9Sstevel@tonic-gate 
1654*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1655*7c478bd9Sstevel@tonic-gate 		goto fail;
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate 	*out_fd = theirs;
1658*7c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1659*7c478bd9Sstevel@tonic-gate 
1660*7c478bd9Sstevel@tonic-gate fail:
1661*7c478bd9Sstevel@tonic-gate 	(void) close(ours);
1662*7c478bd9Sstevel@tonic-gate 	(void) close(theirs);
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate 	return (result);
1665*7c478bd9Sstevel@tonic-gate }
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1668*7c478bd9Sstevel@tonic-gate client_add_notify(repcache_client_t *cp,
1669*7c478bd9Sstevel@tonic-gate     struct rep_protocol_notify_request *rpr)
1670*7c478bd9Sstevel@tonic-gate {
1671*7c478bd9Sstevel@tonic-gate 	rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0;
1672*7c478bd9Sstevel@tonic-gate 
1673*7c478bd9Sstevel@tonic-gate 	switch (rpr->rpr_type) {
1674*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_NOTIFY_PGNAME:
1675*7c478bd9Sstevel@tonic-gate 		return (rc_notify_info_add_name(&cp->rc_notify_info,
1676*7c478bd9Sstevel@tonic-gate 		    rpr->rpr_pattern));
1677*7c478bd9Sstevel@tonic-gate 
1678*7c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_NOTIFY_PGTYPE:
1679*7c478bd9Sstevel@tonic-gate 		return (rc_notify_info_add_type(&cp->rc_notify_info,
1680*7c478bd9Sstevel@tonic-gate 		    rpr->rpr_pattern));
1681*7c478bd9Sstevel@tonic-gate 
1682*7c478bd9Sstevel@tonic-gate 	default:
1683*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1684*7c478bd9Sstevel@tonic-gate 	}
1685*7c478bd9Sstevel@tonic-gate }
1686*7c478bd9Sstevel@tonic-gate 
1687*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1688*7c478bd9Sstevel@tonic-gate static void
1689*7c478bd9Sstevel@tonic-gate client_wait(repcache_client_t *cp, const void *in, size_t insz,
1690*7c478bd9Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
1691*7c478bd9Sstevel@tonic-gate {
1692*7c478bd9Sstevel@tonic-gate 	int result;
1693*7c478bd9Sstevel@tonic-gate 	repcache_entity_t *ep;
1694*7c478bd9Sstevel@tonic-gate 	const struct rep_protocol_wait_request *rpr = in;
1695*7c478bd9Sstevel@tonic-gate 	struct rep_protocol_fmri_response *out = out_arg;
1696*7c478bd9Sstevel@tonic-gate 
1697*7c478bd9Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
1698*7c478bd9Sstevel@tonic-gate 
1699*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
1700*7c478bd9Sstevel@tonic-gate 	if (cp->rc_notify_thr != 0) {
1701*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
1702*7c478bd9Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_EXISTS;
1703*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
1704*7c478bd9Sstevel@tonic-gate 		return;
1705*7c478bd9Sstevel@tonic-gate 	}
1706*7c478bd9Sstevel@tonic-gate 	cp->rc_notify_thr = pthread_self();
1707*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
1708*7c478bd9Sstevel@tonic-gate 
1709*7c478bd9Sstevel@tonic-gate 	result = rc_notify_info_wait(&cp->rc_notify_info, &cp->rc_notify_ptr,
1710*7c478bd9Sstevel@tonic-gate 	    out->rpr_fmri, sizeof (out->rpr_fmri));
1711*7c478bd9Sstevel@tonic-gate 
1712*7c478bd9Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS) {
1713*7c478bd9Sstevel@tonic-gate 		if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) {
1714*7c478bd9Sstevel@tonic-gate 			if (ep->re_type == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
1715*7c478bd9Sstevel@tonic-gate 				rc_node_ptr_assign(&ep->re_node,
1716*7c478bd9Sstevel@tonic-gate 				    &cp->rc_notify_ptr);
1717*7c478bd9Sstevel@tonic-gate 			} else {
1718*7c478bd9Sstevel@tonic-gate 				result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
1719*7c478bd9Sstevel@tonic-gate 			}
1720*7c478bd9Sstevel@tonic-gate 			entity_release(ep);
1721*7c478bd9Sstevel@tonic-gate 		} else {
1722*7c478bd9Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1723*7c478bd9Sstevel@tonic-gate 		}
1724*7c478bd9Sstevel@tonic-gate 		rc_node_clear(&cp->rc_notify_ptr, 0);
1725*7c478bd9Sstevel@tonic-gate 	}
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
1728*7c478bd9Sstevel@tonic-gate 	assert(cp->rc_notify_thr == pthread_self());
1729*7c478bd9Sstevel@tonic-gate 	cp->rc_notify_thr = 0;
1730*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
1731*7c478bd9Sstevel@tonic-gate 
1732*7c478bd9Sstevel@tonic-gate 	out->rpr_response = result;
1733*7c478bd9Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1734*7c478bd9Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
1735*7c478bd9Sstevel@tonic-gate }
1736*7c478bd9Sstevel@tonic-gate 
1737*7c478bd9Sstevel@tonic-gate /*
1738*7c478bd9Sstevel@tonic-gate  * Can return:
1739*7c478bd9Sstevel@tonic-gate  *	_PERMISSION_DENIED	not enough privileges to do request.
1740*7c478bd9Sstevel@tonic-gate  *	_BAD_REQUEST		name is not valid or reserved
1741*7c478bd9Sstevel@tonic-gate  *	_TRUNCATED		name is too long for current repository path
1742*7c478bd9Sstevel@tonic-gate  *	_UNKNOWN		failed for unknown reason (details written to
1743*7c478bd9Sstevel@tonic-gate  *				console)
1744*7c478bd9Sstevel@tonic-gate  *	_BACKEND_READONLY	backend is not writable
1745*7c478bd9Sstevel@tonic-gate  *
1746*7c478bd9Sstevel@tonic-gate  *	_SUCCESS		Backup completed successfully.
1747*7c478bd9Sstevel@tonic-gate  */
1748*7c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t
1749*7c478bd9Sstevel@tonic-gate backup_repository(repcache_client_t *cp,
1750*7c478bd9Sstevel@tonic-gate     struct rep_protocol_backup_request *rpr)
1751*7c478bd9Sstevel@tonic-gate {
1752*7c478bd9Sstevel@tonic-gate 	rep_protocol_responseid_t result;
1753*7c478bd9Sstevel@tonic-gate 	ucred_t *uc = get_ucred();
1754*7c478bd9Sstevel@tonic-gate 
1755*7c478bd9Sstevel@tonic-gate 	if (!client_is_privileged() && (uc == NULL || ucred_geteuid(uc) != 0))
1756*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
1757*7c478bd9Sstevel@tonic-gate 
1758*7c478bd9Sstevel@tonic-gate 	rpr->rpr_name[REP_PROTOCOL_NAME_LEN - 1] = 0;
1759*7c478bd9Sstevel@tonic-gate 	if (strcmp(rpr->rpr_name, REPOSITORY_BOOT_BACKUP) == 0)
1760*7c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1761*7c478bd9Sstevel@tonic-gate 
1762*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
1763*7c478bd9Sstevel@tonic-gate 	if (rpr->rpr_changeid != cp->rc_changeid) {
1764*7c478bd9Sstevel@tonic-gate 		result = backend_create_backup(rpr->rpr_name);
1765*7c478bd9Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
1766*7c478bd9Sstevel@tonic-gate 			cp->rc_changeid = rpr->rpr_changeid;
1767*7c478bd9Sstevel@tonic-gate 	} else {
1768*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
1769*7c478bd9Sstevel@tonic-gate 	}
1770*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
1771*7c478bd9Sstevel@tonic-gate 
1772*7c478bd9Sstevel@tonic-gate 	return (result);
1773*7c478bd9Sstevel@tonic-gate }
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate 
1776*7c478bd9Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_f(repcache_client_t *cp,
1777*7c478bd9Sstevel@tonic-gate     const void *rpr);
1778*7c478bd9Sstevel@tonic-gate 
1779*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1780*7c478bd9Sstevel@tonic-gate static void
1781*7c478bd9Sstevel@tonic-gate simple_handler(repcache_client_t *cp, const void *in, size_t insz,
1782*7c478bd9Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
1783*7c478bd9Sstevel@tonic-gate {
1784*7c478bd9Sstevel@tonic-gate 	protocol_simple_f *f = (protocol_simple_f *)arg;
1785*7c478bd9Sstevel@tonic-gate 	rep_protocol_response_t *out = out_arg;
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
1788*7c478bd9Sstevel@tonic-gate 	assert(f != NULL);
1789*7c478bd9Sstevel@tonic-gate 
1790*7c478bd9Sstevel@tonic-gate 	out->rpr_response = (*f)(cp, in);
1791*7c478bd9Sstevel@tonic-gate }
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_fd_f(repcache_client_t *cp,
1794*7c478bd9Sstevel@tonic-gate     const void *rpr, int *out_fd);
1795*7c478bd9Sstevel@tonic-gate 
1796*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1797*7c478bd9Sstevel@tonic-gate static void
1798*7c478bd9Sstevel@tonic-gate simple_fd_handler(repcache_client_t *cp, const void *in, size_t insz,
1799*7c478bd9Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg, int *out_fd)
1800*7c478bd9Sstevel@tonic-gate {
1801*7c478bd9Sstevel@tonic-gate 	protocol_simple_fd_f *f = (protocol_simple_fd_f *)arg;
1802*7c478bd9Sstevel@tonic-gate 	rep_protocol_response_t *out = out_arg;
1803*7c478bd9Sstevel@tonic-gate 
1804*7c478bd9Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
1805*7c478bd9Sstevel@tonic-gate 	assert(f != NULL);
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate 	out->rpr_response = (*f)(cp, in, out_fd);
1808*7c478bd9Sstevel@tonic-gate }
1809*7c478bd9Sstevel@tonic-gate 
1810*7c478bd9Sstevel@tonic-gate typedef void protocol_handler_f(repcache_client_t *, const void *in,
1811*7c478bd9Sstevel@tonic-gate     size_t insz, void *out, size_t *outsz, void *arg);
1812*7c478bd9Sstevel@tonic-gate 
1813*7c478bd9Sstevel@tonic-gate typedef void protocol_handler_fdret_f(repcache_client_t *, const void *in,
1814*7c478bd9Sstevel@tonic-gate     size_t insz, void *out, size_t *outsz, void *arg, int *fd_out);
1815*7c478bd9Sstevel@tonic-gate 
1816*7c478bd9Sstevel@tonic-gate #define	PROTO(p, f, in) {						\
1817*7c478bd9Sstevel@tonic-gate 		p, #p, simple_handler, (void *)(&f), NULL,		\
1818*7c478bd9Sstevel@tonic-gate 		    sizeof (in), sizeof (rep_protocol_response_t), 0	\
1819*7c478bd9Sstevel@tonic-gate 	}
1820*7c478bd9Sstevel@tonic-gate 
1821*7c478bd9Sstevel@tonic-gate #define	PROTO_FD_OUT(p, f, in) {					\
1822*7c478bd9Sstevel@tonic-gate 		p, #p, NULL, (void *)(&f), simple_fd_handler,		\
1823*7c478bd9Sstevel@tonic-gate 		    sizeof (in),					\
1824*7c478bd9Sstevel@tonic-gate 		    sizeof (rep_protocol_response_t),			\
1825*7c478bd9Sstevel@tonic-gate 		    PROTO_FLAG_RETFD					\
1826*7c478bd9Sstevel@tonic-gate 	}
1827*7c478bd9Sstevel@tonic-gate 
1828*7c478bd9Sstevel@tonic-gate #define	PROTO_VARIN(p, f, insz) {					\
1829*7c478bd9Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
1830*7c478bd9Sstevel@tonic-gate 		    insz, sizeof (rep_protocol_response_t),		\
1831*7c478bd9Sstevel@tonic-gate 		    PROTO_FLAG_VARINPUT					\
1832*7c478bd9Sstevel@tonic-gate 	}
1833*7c478bd9Sstevel@tonic-gate 
1834*7c478bd9Sstevel@tonic-gate #define	PROTO_UINT_OUT(p, f, in) {					\
1835*7c478bd9Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
1836*7c478bd9Sstevel@tonic-gate 		    sizeof (in),					\
1837*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rep_protocol_integer_response), 0	\
1838*7c478bd9Sstevel@tonic-gate 	}
1839*7c478bd9Sstevel@tonic-gate 
1840*7c478bd9Sstevel@tonic-gate #define	PROTO_NAME_OUT(p, f, in) {					\
1841*7c478bd9Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
1842*7c478bd9Sstevel@tonic-gate 		    sizeof (in),					\
1843*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rep_protocol_name_response), 0	\
1844*7c478bd9Sstevel@tonic-gate 	}
1845*7c478bd9Sstevel@tonic-gate 
1846*7c478bd9Sstevel@tonic-gate #define	PROTO_FMRI_OUT(p, f, in) {					\
1847*7c478bd9Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
1848*7c478bd9Sstevel@tonic-gate 		    sizeof (in),					\
1849*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rep_protocol_fmri_response), 0	\
1850*7c478bd9Sstevel@tonic-gate 	}
1851*7c478bd9Sstevel@tonic-gate 
1852*7c478bd9Sstevel@tonic-gate #define	PROTO_VALUE_OUT(p, f, in) {					\
1853*7c478bd9Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
1854*7c478bd9Sstevel@tonic-gate 		    sizeof (in),					\
1855*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rep_protocol_value_response), 0	\
1856*7c478bd9Sstevel@tonic-gate 	}
1857*7c478bd9Sstevel@tonic-gate 
1858*7c478bd9Sstevel@tonic-gate #define	PROTO_PANIC(p)	{ p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
1859*7c478bd9Sstevel@tonic-gate #define	PROTO_END()	{ 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
1860*7c478bd9Sstevel@tonic-gate 
1861*7c478bd9Sstevel@tonic-gate #define	PROTO_FLAG_PANIC	0x00000001	/* should never be called */
1862*7c478bd9Sstevel@tonic-gate #define	PROTO_FLAG_VARINPUT	0x00000004	/* in_size is minimum size */
1863*7c478bd9Sstevel@tonic-gate #define	PROTO_FLAG_RETFD	0x00000008	/* can also return an FD */
1864*7c478bd9Sstevel@tonic-gate 
1865*7c478bd9Sstevel@tonic-gate #define	PROTO_ALL_FLAGS		0x0000000f	/* all flags */
1866*7c478bd9Sstevel@tonic-gate 
1867*7c478bd9Sstevel@tonic-gate static struct protocol_entry {
1868*7c478bd9Sstevel@tonic-gate 	enum rep_protocol_requestid	pt_request;
1869*7c478bd9Sstevel@tonic-gate 	const char			*pt_name;
1870*7c478bd9Sstevel@tonic-gate 	protocol_handler_f		*pt_handler;
1871*7c478bd9Sstevel@tonic-gate 	void				*pt_arg;
1872*7c478bd9Sstevel@tonic-gate 	protocol_handler_fdret_f	*pt_fd_handler;
1873*7c478bd9Sstevel@tonic-gate 	size_t				pt_in_size;
1874*7c478bd9Sstevel@tonic-gate 	size_t				pt_out_max;
1875*7c478bd9Sstevel@tonic-gate 	uint32_t			pt_flags;
1876*7c478bd9Sstevel@tonic-gate } protocol_table[] = {
1877*7c478bd9Sstevel@tonic-gate 	PROTO_PANIC(REP_PROTOCOL_CLOSE),		/* special case */
1878*7c478bd9Sstevel@tonic-gate 
1879*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_SETUP,		entity_setup,
1880*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_setup),
1881*7c478bd9Sstevel@tonic-gate 	PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME,	entity_name,
1882*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_name),
1883*7c478bd9Sstevel@tonic-gate 	PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE,	entity_parent_type,
1884*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_parent_type),
1885*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_GET_CHILD,		entity_get_child,
1886*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_get_child),
1887*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_GET_PARENT,		entity_get_parent,
1888*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_parent),
1889*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_GET,			entity_get,
1890*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_get),
1891*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_UPDATE,		entity_update,
1892*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_update),
1893*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD,		entity_create_child,
1894*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_create_child),
1895*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_CREATE_PG,		entity_create_pg,
1896*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_create_pg),
1897*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_DELETE,		entity_delete,
1898*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_delete),
1899*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_RESET,		entity_reset,
1900*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_reset),
1901*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_TEARDOWN,		entity_teardown,
1902*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_teardown),
1903*7c478bd9Sstevel@tonic-gate 
1904*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_SETUP,			iter_setup,
1905*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_iter_request),
1906*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_START,			iter_start,
1907*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_iter_start),
1908*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_READ,			iter_read,
1909*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_iter_read),
1910*7c478bd9Sstevel@tonic-gate 	PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE,	iter_read_value,
1911*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_iter_read_value),
1912*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_RESET,			iter_reset,
1913*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_iter_request),
1914*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_TEARDOWN,		iter_teardown,
1915*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_iter_request),
1916*7c478bd9Sstevel@tonic-gate 
1917*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL,		next_snaplevel,
1918*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_entity_pair),
1919*7c478bd9Sstevel@tonic-gate 
1920*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_SNAPSHOT_TAKE,		snapshot_take,
1921*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_snapshot_take),
1922*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED,		snapshot_take_named,
1923*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_snapshot_take_named),
1924*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH,		snapshot_attach,
1925*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_snapshot_attach),
1926*7c478bd9Sstevel@tonic-gate 
1927*7c478bd9Sstevel@tonic-gate 	PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE,	property_get_type,
1928*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_property_request),
1929*7c478bd9Sstevel@tonic-gate 	PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE, property_get_value,
1930*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_property_request),
1931*7c478bd9Sstevel@tonic-gate 
1932*7c478bd9Sstevel@tonic-gate 	PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT, propertygrp_notify,
1933*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_propertygrp_request),
1934*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START,	tx_start,
1935*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_transaction_start),
1936*7c478bd9Sstevel@tonic-gate 	PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT,	tx_commit,
1937*7c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE),
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY,		client_add_notify,
1940*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_notify_request),
1941*7c478bd9Sstevel@tonic-gate 	PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT,	client_wait,
1942*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_wait_request),
1943*7c478bd9Sstevel@tonic-gate 
1944*7c478bd9Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_BACKUP,			backup_repository,
1945*7c478bd9Sstevel@tonic-gate 	    struct rep_protocol_backup_request),
1946*7c478bd9Sstevel@tonic-gate 
1947*7c478bd9Sstevel@tonic-gate 	PROTO_END()
1948*7c478bd9Sstevel@tonic-gate };
1949*7c478bd9Sstevel@tonic-gate #undef PROTO
1950*7c478bd9Sstevel@tonic-gate #undef PROTO_FMRI_OUT
1951*7c478bd9Sstevel@tonic-gate #undef PROTO_NAME_OUT
1952*7c478bd9Sstevel@tonic-gate #undef PROTO_UINT_OUT
1953*7c478bd9Sstevel@tonic-gate #undef PROTO_PANIC
1954*7c478bd9Sstevel@tonic-gate #undef PROTO_END
1955*7c478bd9Sstevel@tonic-gate 
1956*7c478bd9Sstevel@tonic-gate /*
1957*7c478bd9Sstevel@tonic-gate  * The number of entries, sans PROTO_END()
1958*7c478bd9Sstevel@tonic-gate  */
1959*7c478bd9Sstevel@tonic-gate #define	PROTOCOL_ENTRIES \
1960*7c478bd9Sstevel@tonic-gate 	    (sizeof (protocol_table) / sizeof (*protocol_table) - 1)
1961*7c478bd9Sstevel@tonic-gate 
1962*7c478bd9Sstevel@tonic-gate #define	PROTOCOL_PREFIX "REP_PROTOCOL_"
1963*7c478bd9Sstevel@tonic-gate 
1964*7c478bd9Sstevel@tonic-gate int
1965*7c478bd9Sstevel@tonic-gate client_init(void)
1966*7c478bd9Sstevel@tonic-gate {
1967*7c478bd9Sstevel@tonic-gate 	int i;
1968*7c478bd9Sstevel@tonic-gate 	struct protocol_entry *e;
1969*7c478bd9Sstevel@tonic-gate 
1970*7c478bd9Sstevel@tonic-gate 	if (!client_hash_init())
1971*7c478bd9Sstevel@tonic-gate 		return (0);
1972*7c478bd9Sstevel@tonic-gate 
1973*7c478bd9Sstevel@tonic-gate 	if (request_log_size > 0) {
1974*7c478bd9Sstevel@tonic-gate 		request_log = uu_zalloc(request_log_size *
1975*7c478bd9Sstevel@tonic-gate 		    sizeof (request_log_entry_t));
1976*7c478bd9Sstevel@tonic-gate 	}
1977*7c478bd9Sstevel@tonic-gate 
1978*7c478bd9Sstevel@tonic-gate 	/*
1979*7c478bd9Sstevel@tonic-gate 	 * update the names to not include REP_PROTOCOL_
1980*7c478bd9Sstevel@tonic-gate 	 */
1981*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < PROTOCOL_ENTRIES; i++) {
1982*7c478bd9Sstevel@tonic-gate 		e = &protocol_table[i];
1983*7c478bd9Sstevel@tonic-gate 		assert(strncmp(e->pt_name, PROTOCOL_PREFIX,
1984*7c478bd9Sstevel@tonic-gate 		    strlen(PROTOCOL_PREFIX)) == 0);
1985*7c478bd9Sstevel@tonic-gate 		e->pt_name += strlen(PROTOCOL_PREFIX);
1986*7c478bd9Sstevel@tonic-gate 	}
1987*7c478bd9Sstevel@tonic-gate 	/*
1988*7c478bd9Sstevel@tonic-gate 	 * verify the protocol table is consistent
1989*7c478bd9Sstevel@tonic-gate 	 */
1990*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < PROTOCOL_ENTRIES; i++) {
1991*7c478bd9Sstevel@tonic-gate 		e = &protocol_table[i];
1992*7c478bd9Sstevel@tonic-gate 		assert(e->pt_request == (REP_PROTOCOL_BASE + i));
1993*7c478bd9Sstevel@tonic-gate 
1994*7c478bd9Sstevel@tonic-gate 		assert((e->pt_flags & ~PROTO_ALL_FLAGS) == 0);
1995*7c478bd9Sstevel@tonic-gate 
1996*7c478bd9Sstevel@tonic-gate 		if (e->pt_flags & PROTO_FLAG_PANIC)
1997*7c478bd9Sstevel@tonic-gate 			assert(e->pt_in_size == 0 && e->pt_out_max == 0 &&
1998*7c478bd9Sstevel@tonic-gate 			    e->pt_handler == NULL);
1999*7c478bd9Sstevel@tonic-gate 		else
2000*7c478bd9Sstevel@tonic-gate 			assert(e->pt_in_size != 0 && e->pt_out_max != 0 &&
2001*7c478bd9Sstevel@tonic-gate 			    (e->pt_handler != NULL ||
2002*7c478bd9Sstevel@tonic-gate 			    e->pt_fd_handler != NULL));
2003*7c478bd9Sstevel@tonic-gate 	}
2004*7c478bd9Sstevel@tonic-gate 	assert((REP_PROTOCOL_BASE + i) == REP_PROTOCOL_MAX_REQUEST);
2005*7c478bd9Sstevel@tonic-gate 
2006*7c478bd9Sstevel@tonic-gate 	assert(protocol_table[i].pt_request == 0);
2007*7c478bd9Sstevel@tonic-gate 
2008*7c478bd9Sstevel@tonic-gate 	return (1);
2009*7c478bd9Sstevel@tonic-gate }
2010*7c478bd9Sstevel@tonic-gate 
2011*7c478bd9Sstevel@tonic-gate static void
2012*7c478bd9Sstevel@tonic-gate client_switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *desc_in,
2013*7c478bd9Sstevel@tonic-gate     uint_t n_desc)
2014*7c478bd9Sstevel@tonic-gate {
2015*7c478bd9Sstevel@tonic-gate 	thread_info_t *ti = thread_self();
2016*7c478bd9Sstevel@tonic-gate 
2017*7c478bd9Sstevel@tonic-gate 	repcache_client_t *cp;
2018*7c478bd9Sstevel@tonic-gate 	uint32_t id = (uint32_t)cookie;
2019*7c478bd9Sstevel@tonic-gate 	enum rep_protocol_requestid request_code;
2020*7c478bd9Sstevel@tonic-gate 
2021*7c478bd9Sstevel@tonic-gate 	rep_protocol_responseid_t result = INVALID_RESULT;
2022*7c478bd9Sstevel@tonic-gate 
2023*7c478bd9Sstevel@tonic-gate 	struct protocol_entry *e;
2024*7c478bd9Sstevel@tonic-gate 
2025*7c478bd9Sstevel@tonic-gate 	char *retval = NULL;
2026*7c478bd9Sstevel@tonic-gate 	size_t retsize = 0;
2027*7c478bd9Sstevel@tonic-gate 
2028*7c478bd9Sstevel@tonic-gate 	int retfd = -1;
2029*7c478bd9Sstevel@tonic-gate 	door_desc_t desc;
2030*7c478bd9Sstevel@tonic-gate 	request_log_entry_t *rlp;
2031*7c478bd9Sstevel@tonic-gate 
2032*7c478bd9Sstevel@tonic-gate 	rlp = start_log(id);
2033*7c478bd9Sstevel@tonic-gate 
2034*7c478bd9Sstevel@tonic-gate 	if (n_desc != 0)
2035*7c478bd9Sstevel@tonic-gate 		uu_die("can't happen: %d descriptors @%p (cookie %p)",
2036*7c478bd9Sstevel@tonic-gate 		    n_desc, desc_in, cookie);
2037*7c478bd9Sstevel@tonic-gate 
2038*7c478bd9Sstevel@tonic-gate 	if (argp == DOOR_UNREF_DATA) {
2039*7c478bd9Sstevel@tonic-gate 		client_destroy(id);
2040*7c478bd9Sstevel@tonic-gate 		goto bad_end;
2041*7c478bd9Sstevel@tonic-gate 	}
2042*7c478bd9Sstevel@tonic-gate 
2043*7c478bd9Sstevel@tonic-gate 	thread_newstate(ti, TI_CLIENT_CALL);
2044*7c478bd9Sstevel@tonic-gate 
2045*7c478bd9Sstevel@tonic-gate 	/*
2046*7c478bd9Sstevel@tonic-gate 	 * To simplify returning just a result code, we set up for
2047*7c478bd9Sstevel@tonic-gate 	 * that case here.
2048*7c478bd9Sstevel@tonic-gate 	 */
2049*7c478bd9Sstevel@tonic-gate 	retval = (char *)&result;
2050*7c478bd9Sstevel@tonic-gate 	retsize = sizeof (result);
2051*7c478bd9Sstevel@tonic-gate 
2052*7c478bd9Sstevel@tonic-gate 	if (arg_size < sizeof (request_code)) {
2053*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
2054*7c478bd9Sstevel@tonic-gate 		goto end_unheld;
2055*7c478bd9Sstevel@tonic-gate 	}
2056*7c478bd9Sstevel@tonic-gate 
2057*7c478bd9Sstevel@tonic-gate 	ti->ti_client_request = (void *)argp;
2058*7c478bd9Sstevel@tonic-gate 
2059*7c478bd9Sstevel@tonic-gate 	/* LINTED alignment */
2060*7c478bd9Sstevel@tonic-gate 	request_code = *(uint32_t *)argp;
2061*7c478bd9Sstevel@tonic-gate 
2062*7c478bd9Sstevel@tonic-gate 	if (rlp != NULL) {
2063*7c478bd9Sstevel@tonic-gate 		rlp->rl_request = request_code;
2064*7c478bd9Sstevel@tonic-gate 	}
2065*7c478bd9Sstevel@tonic-gate 	/*
2066*7c478bd9Sstevel@tonic-gate 	 * In order to avoid locking problems on removal, we handle the
2067*7c478bd9Sstevel@tonic-gate 	 * "close" case before doing a lookup.
2068*7c478bd9Sstevel@tonic-gate 	 */
2069*7c478bd9Sstevel@tonic-gate 	if (request_code == REP_PROTOCOL_CLOSE) {
2070*7c478bd9Sstevel@tonic-gate 		client_destroy(id);
2071*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
2072*7c478bd9Sstevel@tonic-gate 		goto end_unheld;
2073*7c478bd9Sstevel@tonic-gate 	}
2074*7c478bd9Sstevel@tonic-gate 
2075*7c478bd9Sstevel@tonic-gate 	cp = client_lookup(id);
2076*7c478bd9Sstevel@tonic-gate 	/*
2077*7c478bd9Sstevel@tonic-gate 	 * cp is held
2078*7c478bd9Sstevel@tonic-gate 	 */
2079*7c478bd9Sstevel@tonic-gate 
2080*7c478bd9Sstevel@tonic-gate 	if (cp == NULL)
2081*7c478bd9Sstevel@tonic-gate 		goto bad_end;
2082*7c478bd9Sstevel@tonic-gate 
2083*7c478bd9Sstevel@tonic-gate 	if (rlp != NULL)
2084*7c478bd9Sstevel@tonic-gate 		rlp->rl_client = cp;
2085*7c478bd9Sstevel@tonic-gate 
2086*7c478bd9Sstevel@tonic-gate 	ti->ti_active_client = cp;
2087*7c478bd9Sstevel@tonic-gate 
2088*7c478bd9Sstevel@tonic-gate 	if (request_code < REP_PROTOCOL_BASE ||
2089*7c478bd9Sstevel@tonic-gate 	    request_code >= REP_PROTOCOL_BASE + PROTOCOL_ENTRIES) {
2090*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
2091*7c478bd9Sstevel@tonic-gate 		goto end;
2092*7c478bd9Sstevel@tonic-gate 	}
2093*7c478bd9Sstevel@tonic-gate 
2094*7c478bd9Sstevel@tonic-gate 	e = &protocol_table[request_code - REP_PROTOCOL_BASE];
2095*7c478bd9Sstevel@tonic-gate 
2096*7c478bd9Sstevel@tonic-gate 	assert(!(e->pt_flags & PROTO_FLAG_PANIC));
2097*7c478bd9Sstevel@tonic-gate 
2098*7c478bd9Sstevel@tonic-gate 	if (e->pt_flags & PROTO_FLAG_VARINPUT) {
2099*7c478bd9Sstevel@tonic-gate 		if (arg_size < e->pt_in_size) {
2100*7c478bd9Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_BAD_REQUEST;
2101*7c478bd9Sstevel@tonic-gate 			goto end;
2102*7c478bd9Sstevel@tonic-gate 		}
2103*7c478bd9Sstevel@tonic-gate 	} else if (arg_size != e->pt_in_size) {
2104*7c478bd9Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
2105*7c478bd9Sstevel@tonic-gate 		goto end;
2106*7c478bd9Sstevel@tonic-gate 	}
2107*7c478bd9Sstevel@tonic-gate 
2108*7c478bd9Sstevel@tonic-gate 	if (retsize != e->pt_out_max) {
2109*7c478bd9Sstevel@tonic-gate 		retsize = e->pt_out_max;
2110*7c478bd9Sstevel@tonic-gate 		retval = alloca(retsize);
2111*7c478bd9Sstevel@tonic-gate 	}
2112*7c478bd9Sstevel@tonic-gate 
2113*7c478bd9Sstevel@tonic-gate 	if (e->pt_flags & PROTO_FLAG_RETFD)
2114*7c478bd9Sstevel@tonic-gate 		e->pt_fd_handler(cp, argp, arg_size, retval, &retsize,
2115*7c478bd9Sstevel@tonic-gate 		    e->pt_arg, &retfd);
2116*7c478bd9Sstevel@tonic-gate 	else
2117*7c478bd9Sstevel@tonic-gate 		e->pt_handler(cp, argp, arg_size, retval, &retsize, e->pt_arg);
2118*7c478bd9Sstevel@tonic-gate 
2119*7c478bd9Sstevel@tonic-gate end:
2120*7c478bd9Sstevel@tonic-gate 	ti->ti_active_client = NULL;
2121*7c478bd9Sstevel@tonic-gate 	client_release(cp);
2122*7c478bd9Sstevel@tonic-gate 
2123*7c478bd9Sstevel@tonic-gate end_unheld:
2124*7c478bd9Sstevel@tonic-gate 	if (rlp != NULL) {
2125*7c478bd9Sstevel@tonic-gate 		/* LINTED alignment */
2126*7c478bd9Sstevel@tonic-gate 		rlp->rl_response = *(uint32_t *)retval;
2127*7c478bd9Sstevel@tonic-gate 		end_log();
2128*7c478bd9Sstevel@tonic-gate 		rlp = NULL;
2129*7c478bd9Sstevel@tonic-gate 	}
2130*7c478bd9Sstevel@tonic-gate 	ti->ti_client_request = NULL;
2131*7c478bd9Sstevel@tonic-gate 	thread_newstate(ti, TI_DOOR_RETURN);
2132*7c478bd9Sstevel@tonic-gate 
2133*7c478bd9Sstevel@tonic-gate 	if (retval == (char *)&result) {
2134*7c478bd9Sstevel@tonic-gate 		assert(result != INVALID_RESULT && retsize == sizeof (result));
2135*7c478bd9Sstevel@tonic-gate 	} else {
2136*7c478bd9Sstevel@tonic-gate 		/* LINTED alignment */
2137*7c478bd9Sstevel@tonic-gate 		result = *(uint32_t *)retval;
2138*7c478bd9Sstevel@tonic-gate 	}
2139*7c478bd9Sstevel@tonic-gate 	if (retfd != -1) {
2140*7c478bd9Sstevel@tonic-gate 		desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
2141*7c478bd9Sstevel@tonic-gate 		desc.d_data.d_desc.d_descriptor = retfd;
2142*7c478bd9Sstevel@tonic-gate 		(void) door_return(retval, retsize, &desc, 1);
2143*7c478bd9Sstevel@tonic-gate 	} else {
2144*7c478bd9Sstevel@tonic-gate 		(void) door_return(retval, retsize, NULL, 0);
2145*7c478bd9Sstevel@tonic-gate 	}
2146*7c478bd9Sstevel@tonic-gate bad_end:
2147*7c478bd9Sstevel@tonic-gate 	if (rlp != NULL) {
2148*7c478bd9Sstevel@tonic-gate 		rlp->rl_response = -1;
2149*7c478bd9Sstevel@tonic-gate 		end_log();
2150*7c478bd9Sstevel@tonic-gate 		rlp = NULL;
2151*7c478bd9Sstevel@tonic-gate 	}
2152*7c478bd9Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
2153*7c478bd9Sstevel@tonic-gate }
2154*7c478bd9Sstevel@tonic-gate 
2155*7c478bd9Sstevel@tonic-gate int
2156*7c478bd9Sstevel@tonic-gate create_client(pid_t pid, uint32_t debugflags, int privileged, int *out_fd)
2157*7c478bd9Sstevel@tonic-gate {
2158*7c478bd9Sstevel@tonic-gate 	int fd;
2159*7c478bd9Sstevel@tonic-gate 
2160*7c478bd9Sstevel@tonic-gate 	repcache_client_t *cp;
2161*7c478bd9Sstevel@tonic-gate 
2162*7c478bd9Sstevel@tonic-gate 	struct door_info info;
2163*7c478bd9Sstevel@tonic-gate 
2164*7c478bd9Sstevel@tonic-gate 	int door_flags = DOOR_UNREF | DOOR_REFUSE_DESC;
2165*7c478bd9Sstevel@tonic-gate #ifdef DOOR_NO_CANCEL
2166*7c478bd9Sstevel@tonic-gate 	door_flags |= DOOR_NO_CANCEL;
2167*7c478bd9Sstevel@tonic-gate #endif
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate 	cp = client_alloc();
2170*7c478bd9Sstevel@tonic-gate 	if (cp == NULL)
2171*7c478bd9Sstevel@tonic-gate 		return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
2172*7c478bd9Sstevel@tonic-gate 
2173*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&client_lock);
2174*7c478bd9Sstevel@tonic-gate 	cp->rc_id = ++client_maxid;
2175*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&client_lock);
2176*7c478bd9Sstevel@tonic-gate 
2177*7c478bd9Sstevel@tonic-gate 	cp->rc_all_auths = privileged;
2178*7c478bd9Sstevel@tonic-gate 	cp->rc_pid = pid;
2179*7c478bd9Sstevel@tonic-gate 	cp->rc_debug = debugflags;
2180*7c478bd9Sstevel@tonic-gate 
2181*7c478bd9Sstevel@tonic-gate 	cp->rc_doorfd = door_create(client_switcher, (void *)cp->rc_id,
2182*7c478bd9Sstevel@tonic-gate 	    door_flags);
2183*7c478bd9Sstevel@tonic-gate 
2184*7c478bd9Sstevel@tonic-gate 	if (cp->rc_doorfd < 0) {
2185*7c478bd9Sstevel@tonic-gate 		client_free(cp);
2186*7c478bd9Sstevel@tonic-gate 		return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
2187*7c478bd9Sstevel@tonic-gate 	}
2188*7c478bd9Sstevel@tonic-gate #ifdef DOOR_PARAM_DATA_MIN
2189*7c478bd9Sstevel@tonic-gate 	(void) door_setparam(cp->rc_doorfd, DOOR_PARAM_DATA_MIN,
2190*7c478bd9Sstevel@tonic-gate 	    sizeof (enum rep_protocol_requestid));
2191*7c478bd9Sstevel@tonic-gate #endif
2192*7c478bd9Sstevel@tonic-gate 
2193*7c478bd9Sstevel@tonic-gate 	if ((fd = dup(cp->rc_doorfd)) < 0 ||
2194*7c478bd9Sstevel@tonic-gate 	    door_info(cp->rc_doorfd, &info) < 0) {
2195*7c478bd9Sstevel@tonic-gate 		if (fd >= 0)
2196*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
2197*7c478bd9Sstevel@tonic-gate 		(void) door_revoke(cp->rc_doorfd);
2198*7c478bd9Sstevel@tonic-gate 		cp->rc_doorfd = -1;
2199*7c478bd9Sstevel@tonic-gate 		client_free(cp);
2200*7c478bd9Sstevel@tonic-gate 		return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
2201*7c478bd9Sstevel@tonic-gate 	}
2202*7c478bd9Sstevel@tonic-gate 
2203*7c478bd9Sstevel@tonic-gate 	rc_pg_notify_init(&cp->rc_pg_notify);
2204*7c478bd9Sstevel@tonic-gate 	rc_notify_info_init(&cp->rc_notify_info);
2205*7c478bd9Sstevel@tonic-gate 
2206*7c478bd9Sstevel@tonic-gate 	client_insert(cp);
2207*7c478bd9Sstevel@tonic-gate 
2208*7c478bd9Sstevel@tonic-gate 	cp->rc_doorid = info.di_uniquifier;
2209*7c478bd9Sstevel@tonic-gate 	*out_fd = fd;
2210*7c478bd9Sstevel@tonic-gate 
2211*7c478bd9Sstevel@tonic-gate 	return (REPOSITORY_DOOR_SUCCESS);
2212*7c478bd9Sstevel@tonic-gate }
2213