10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * This is the client layer for svc.configd.  All direct protocol interactions
310Sstevel@tonic-gate  * are handled here.
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * Essentially, the job of this layer is to turn the idempotent protocol
340Sstevel@tonic-gate  * into a series of non-idempotent calls into the object layer, while
350Sstevel@tonic-gate  * also handling the necessary locking.
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <alloca.h>
390Sstevel@tonic-gate #include <assert.h>
400Sstevel@tonic-gate #include <door.h>
410Sstevel@tonic-gate #include <errno.h>
420Sstevel@tonic-gate #include <limits.h>
430Sstevel@tonic-gate #include <pthread.h>
440Sstevel@tonic-gate #include <stdio.h>
450Sstevel@tonic-gate #include <stdlib.h>
460Sstevel@tonic-gate #include <string.h>
470Sstevel@tonic-gate #include <unistd.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #include <libuutil.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #include "configd.h"
520Sstevel@tonic-gate #include "repcache_protocol.h"
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #define	INVALID_CHANGEID	(0)
550Sstevel@tonic-gate #define	INVALID_DOORID		((door_id_t)-1)
560Sstevel@tonic-gate #define	INVALID_RESULT		((rep_protocol_responseid_t)INT_MIN)
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * lint doesn't like constant assertions
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate #ifdef lint
620Sstevel@tonic-gate #define	assert_nolint(x) (void)0
630Sstevel@tonic-gate #else
640Sstevel@tonic-gate #define	assert_nolint(x) assert(x)
650Sstevel@tonic-gate #endif
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * Protects client linkage and the freelist
690Sstevel@tonic-gate  */
700Sstevel@tonic-gate #define	CLIENT_HASH_SIZE	64
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #pragma align 64(client_hash)
730Sstevel@tonic-gate static client_bucket_t client_hash[CLIENT_HASH_SIZE];
740Sstevel@tonic-gate 
75*407Sjwadams static uu_avl_pool_t *entity_pool;
76*407Sjwadams static uu_avl_pool_t *iter_pool;
770Sstevel@tonic-gate static uu_list_pool_t *client_pool;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate #define	CLIENT_HASH(id)		(&client_hash[((id) & (CLIENT_HASH_SIZE - 1))])
800Sstevel@tonic-gate 
810Sstevel@tonic-gate uint_t request_log_size = 1024;		/* tunable, before we start */
820Sstevel@tonic-gate 
830Sstevel@tonic-gate static pthread_mutex_t request_log_lock = PTHREAD_MUTEX_INITIALIZER;
840Sstevel@tonic-gate static uint_t request_log_cur;
850Sstevel@tonic-gate request_log_entry_t	*request_log;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate static uint32_t		client_maxid;
880Sstevel@tonic-gate static pthread_mutex_t	client_lock;	/* protects client_maxid */
890Sstevel@tonic-gate 
900Sstevel@tonic-gate static request_log_entry_t *
910Sstevel@tonic-gate get_log(void)
920Sstevel@tonic-gate {
930Sstevel@tonic-gate 	thread_info_t *ti = thread_self();
940Sstevel@tonic-gate 	return (&ti->ti_log);
950Sstevel@tonic-gate }
960Sstevel@tonic-gate 
970Sstevel@tonic-gate void
980Sstevel@tonic-gate log_enter(request_log_entry_t *rlp)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	if (rlp->rl_start != 0 && request_log != NULL) {
1010Sstevel@tonic-gate 		request_log_entry_t *logrlp;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 		(void) pthread_mutex_lock(&request_log_lock);
1040Sstevel@tonic-gate 		assert(request_log_cur < request_log_size);
1050Sstevel@tonic-gate 		logrlp = &request_log[request_log_cur++];
1060Sstevel@tonic-gate 		if (request_log_cur == request_log_size)
1070Sstevel@tonic-gate 			request_log_cur = 0;
1080Sstevel@tonic-gate 		(void) memcpy(logrlp, rlp, sizeof (*rlp));
1090Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&request_log_lock);
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * Note that the svc.configd dmod will join all of the per-thread log entries
1150Sstevel@tonic-gate  * with the main log, so that even if the log is disabled, there is some
1160Sstevel@tonic-gate  * information available.
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate static request_log_entry_t *
1190Sstevel@tonic-gate start_log(uint32_t clientid)
1200Sstevel@tonic-gate {
1210Sstevel@tonic-gate 	request_log_entry_t *rlp = get_log();
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	log_enter(rlp);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	(void) memset(rlp, 0, sizeof (*rlp));
1260Sstevel@tonic-gate 	rlp->rl_start = gethrtime();
1270Sstevel@tonic-gate 	rlp->rl_tid = pthread_self();
1280Sstevel@tonic-gate 	rlp->rl_clientid = clientid;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	return (rlp);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate void
1340Sstevel@tonic-gate end_log(void)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	request_log_entry_t *rlp = get_log();
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	rlp->rl_end = gethrtime();
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate static void
1420Sstevel@tonic-gate add_log_ptr(request_log_entry_t *rlp, enum rc_ptr_type type, uint32_t id,
1430Sstevel@tonic-gate     void *ptr)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate 	request_log_ptr_t *rpp;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	if (rlp == NULL)
1480Sstevel@tonic-gate 		return;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	if (rlp->rl_num_ptrs >= MAX_PTRS)
1510Sstevel@tonic-gate 		return;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	rpp = &rlp->rl_ptrs[rlp->rl_num_ptrs++];
1540Sstevel@tonic-gate 	rpp->rlp_type = type;
1550Sstevel@tonic-gate 	rpp->rlp_id = id;
1560Sstevel@tonic-gate 	rpp->rlp_ptr = ptr;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	/*
1590Sstevel@tonic-gate 	 * For entities, it's useful to have the node pointer at the start
1600Sstevel@tonic-gate 	 * of the request.
1610Sstevel@tonic-gate 	 */
1620Sstevel@tonic-gate 	if (type == RC_PTR_TYPE_ENTITY && ptr != NULL)
1630Sstevel@tonic-gate 		rpp->rlp_data = ((repcache_entity_t *)ptr)->re_node.rnp_node;
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate int
1670Sstevel@tonic-gate client_is_privileged(void)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate 	thread_info_t *ti = thread_self();
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	ucred_t *uc;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	if (ti->ti_active_client != NULL &&
1740Sstevel@tonic-gate 	    ti->ti_active_client->rc_all_auths)
1750Sstevel@tonic-gate 		return (1);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	if ((uc = get_ucred()) == NULL)
1780Sstevel@tonic-gate 		return (0);
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	return (ucred_is_privileged(uc));
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate /*ARGSUSED*/
1840Sstevel@tonic-gate static int
1850Sstevel@tonic-gate client_compare(const void *lc_arg, const void *rc_arg, void *private)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	uint32_t l_id = ((const repcache_client_t *)lc_arg)->rc_id;
1880Sstevel@tonic-gate 	uint32_t r_id = ((const repcache_client_t *)rc_arg)->rc_id;
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	if (l_id > r_id)
1910Sstevel@tonic-gate 		return (1);
1920Sstevel@tonic-gate 	if (l_id < r_id)
1930Sstevel@tonic-gate 		return (-1);
1940Sstevel@tonic-gate 	return (0);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /*ARGSUSED*/
1980Sstevel@tonic-gate static int
1990Sstevel@tonic-gate entity_compare(const void *lc_arg, const void *rc_arg, void *private)
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate 	uint32_t l_id = ((const repcache_entity_t *)lc_arg)->re_id;
2020Sstevel@tonic-gate 	uint32_t r_id = ((const repcache_entity_t *)rc_arg)->re_id;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if (l_id > r_id)
2050Sstevel@tonic-gate 		return (1);
2060Sstevel@tonic-gate 	if (l_id < r_id)
2070Sstevel@tonic-gate 		return (-1);
2080Sstevel@tonic-gate 	return (0);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate /*ARGSUSED*/
2120Sstevel@tonic-gate static int
2130Sstevel@tonic-gate iter_compare(const void *lc_arg, const void *rc_arg, void *private)
2140Sstevel@tonic-gate {
2150Sstevel@tonic-gate 	uint32_t l_id = ((const repcache_iter_t *)lc_arg)->ri_id;
2160Sstevel@tonic-gate 	uint32_t r_id = ((const repcache_iter_t *)rc_arg)->ri_id;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	if (l_id > r_id)
2190Sstevel@tonic-gate 		return (1);
2200Sstevel@tonic-gate 	if (l_id < r_id)
2210Sstevel@tonic-gate 		return (-1);
2220Sstevel@tonic-gate 	return (0);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate static int
2260Sstevel@tonic-gate client_hash_init(void)
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate 	int x;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	assert_nolint(offsetof(repcache_entity_t, re_id) == 0);
231*407Sjwadams 	entity_pool = uu_avl_pool_create("repcache_entitys",
2320Sstevel@tonic-gate 	    sizeof (repcache_entity_t), offsetof(repcache_entity_t, re_link),
233*407Sjwadams 	    entity_compare, UU_AVL_POOL_DEBUG);
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	assert_nolint(offsetof(repcache_iter_t, ri_id) == 0);
236*407Sjwadams 	iter_pool = uu_avl_pool_create("repcache_iters",
2370Sstevel@tonic-gate 	    sizeof (repcache_iter_t), offsetof(repcache_iter_t, ri_link),
238*407Sjwadams 	    iter_compare, UU_AVL_POOL_DEBUG);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	assert_nolint(offsetof(repcache_client_t, rc_id) == 0);
2410Sstevel@tonic-gate 	client_pool = uu_list_pool_create("repcache_clients",
2420Sstevel@tonic-gate 	    sizeof (repcache_client_t), offsetof(repcache_client_t, rc_link),
2430Sstevel@tonic-gate 	    client_compare, UU_LIST_POOL_DEBUG);
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if (entity_pool == NULL || iter_pool == NULL || client_pool == NULL)
2460Sstevel@tonic-gate 		return (0);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	for (x = 0; x < CLIENT_HASH_SIZE; x++) {
2490Sstevel@tonic-gate 		uu_list_t *lp = uu_list_create(client_pool, &client_hash[x],
2500Sstevel@tonic-gate 		    UU_LIST_SORTED);
2510Sstevel@tonic-gate 		if (lp == NULL)
2520Sstevel@tonic-gate 			return (0);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		(void) pthread_mutex_init(&client_hash[x].cb_lock, NULL);
2550Sstevel@tonic-gate 		client_hash[x].cb_list = lp;
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	return (1);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate static repcache_client_t *
2620Sstevel@tonic-gate client_alloc(void)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate 	repcache_client_t *cp;
2650Sstevel@tonic-gate 	cp = uu_zalloc(sizeof (*cp));
2660Sstevel@tonic-gate 	if (cp == NULL)
2670Sstevel@tonic-gate 		return (NULL);
2680Sstevel@tonic-gate 
269*407Sjwadams 	cp->rc_entities = uu_avl_create(entity_pool, cp, 0);
270*407Sjwadams 	if (cp->rc_entities == NULL)
2710Sstevel@tonic-gate 		goto fail;
2720Sstevel@tonic-gate 
273*407Sjwadams 	cp->rc_iters = uu_avl_create(iter_pool, cp, 0);
274*407Sjwadams 	if (cp->rc_iters == NULL)
2750Sstevel@tonic-gate 		goto fail;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	uu_list_node_init(cp, &cp->rc_link, client_pool);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	cp->rc_doorfd = -1;
2800Sstevel@tonic-gate 	cp->rc_doorid = INVALID_DOORID;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	(void) pthread_mutex_init(&cp->rc_lock, NULL);
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	rc_node_ptr_init(&cp->rc_notify_ptr);
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	return (cp);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate fail:
289*407Sjwadams 	if (cp->rc_iters != NULL)
290*407Sjwadams 		uu_avl_destroy(cp->rc_iters);
291*407Sjwadams 	if (cp->rc_entities != NULL)
292*407Sjwadams 		uu_avl_destroy(cp->rc_entities);
2930Sstevel@tonic-gate 	uu_free(cp);
2940Sstevel@tonic-gate 	return (NULL);
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate static void
2980Sstevel@tonic-gate client_free(repcache_client_t *cp)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	assert(cp->rc_insert_thr == 0);
3010Sstevel@tonic-gate 	assert(cp->rc_refcnt == 0);
3020Sstevel@tonic-gate 	assert(cp->rc_doorfd == -1);
3030Sstevel@tonic-gate 	assert(cp->rc_doorid == INVALID_DOORID);
304*407Sjwadams 	assert(uu_avl_first(cp->rc_entities) == NULL);
305*407Sjwadams 	assert(uu_avl_first(cp->rc_iters) == NULL);
306*407Sjwadams 	uu_avl_destroy(cp->rc_entities);
307*407Sjwadams 	uu_avl_destroy(cp->rc_iters);
3080Sstevel@tonic-gate 	uu_list_node_fini(cp, &cp->rc_link, client_pool);
3090Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&cp->rc_lock);
3100Sstevel@tonic-gate 	uu_free(cp);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate static void
3140Sstevel@tonic-gate client_insert(repcache_client_t *cp)
3150Sstevel@tonic-gate {
3160Sstevel@tonic-gate 	client_bucket_t *bp = CLIENT_HASH(cp->rc_id);
3170Sstevel@tonic-gate 	uu_list_index_t idx;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	assert(cp->rc_id > 0);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	(void) pthread_mutex_lock(&bp->cb_lock);
3220Sstevel@tonic-gate 	/*
3230Sstevel@tonic-gate 	 * We assume it does not already exist
3240Sstevel@tonic-gate 	 */
3250Sstevel@tonic-gate 	(void) uu_list_find(bp->cb_list, cp, NULL, &idx);
3260Sstevel@tonic-gate 	uu_list_insert(bp->cb_list, cp, idx);
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&bp->cb_lock);
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate static repcache_client_t *
3320Sstevel@tonic-gate client_lookup(uint32_t id)
3330Sstevel@tonic-gate {
3340Sstevel@tonic-gate 	client_bucket_t *bp = CLIENT_HASH(id);
3350Sstevel@tonic-gate 	repcache_client_t *cp;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	(void) pthread_mutex_lock(&bp->cb_lock);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	cp = uu_list_find(bp->cb_list, &id, NULL, NULL);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	/*
3420Sstevel@tonic-gate 	 * Bump the reference count
3430Sstevel@tonic-gate 	 */
3440Sstevel@tonic-gate 	if (cp != NULL) {
3450Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cp->rc_lock);
3460Sstevel@tonic-gate 		assert(!(cp->rc_flags & RC_CLIENT_DEAD));
3470Sstevel@tonic-gate 		cp->rc_refcnt++;
3480Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&bp->cb_lock);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	return (cp);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate static void
3560Sstevel@tonic-gate client_release(repcache_client_t *cp)
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
3590Sstevel@tonic-gate 	assert(cp->rc_refcnt > 0);
3600Sstevel@tonic-gate 	assert(cp->rc_insert_thr != pthread_self());
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	--cp->rc_refcnt;
3630Sstevel@tonic-gate 	(void) pthread_cond_broadcast(&cp->rc_cv);
3640Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate /*
3680Sstevel@tonic-gate  * We only allow one thread to be inserting at a time, to prevent
3690Sstevel@tonic-gate  * insert/insert races.
3700Sstevel@tonic-gate  */
3710Sstevel@tonic-gate static void
3720Sstevel@tonic-gate client_start_insert(repcache_client_t *cp)
3730Sstevel@tonic-gate {
3740Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
3750Sstevel@tonic-gate 	assert(cp->rc_refcnt > 0);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	while (cp->rc_insert_thr != 0) {
3780Sstevel@tonic-gate 		assert(cp->rc_insert_thr != pthread_self());
3790Sstevel@tonic-gate 		(void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock);
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 	cp->rc_insert_thr = pthread_self();
3820Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate static void
3860Sstevel@tonic-gate client_end_insert(repcache_client_t *cp)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
3890Sstevel@tonic-gate 	assert(cp->rc_insert_thr == pthread_self());
3900Sstevel@tonic-gate 	cp->rc_insert_thr = 0;
3910Sstevel@tonic-gate 	(void) pthread_cond_broadcast(&cp->rc_cv);
3920Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate /*ARGSUSED*/
3960Sstevel@tonic-gate static repcache_entity_t *
3970Sstevel@tonic-gate entity_alloc(repcache_client_t *cp)
3980Sstevel@tonic-gate {
3990Sstevel@tonic-gate 	repcache_entity_t *ep = uu_zalloc(sizeof (repcache_entity_t));
4000Sstevel@tonic-gate 	if (ep != NULL) {
401*407Sjwadams 		uu_avl_node_init(ep, &ep->re_link, entity_pool);
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 	return (ep);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate static void
4070Sstevel@tonic-gate entity_add(repcache_client_t *cp, repcache_entity_t *ep)
4080Sstevel@tonic-gate {
409*407Sjwadams 	uu_avl_index_t idx;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
4120Sstevel@tonic-gate 	assert(cp->rc_insert_thr == pthread_self());
4130Sstevel@tonic-gate 
414*407Sjwadams 	(void) uu_avl_find(cp->rc_entities, ep, NULL, &idx);
415*407Sjwadams 	uu_avl_insert(cp->rc_entities, ep, idx);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate static repcache_entity_t *
4210Sstevel@tonic-gate entity_find(repcache_client_t *cp, uint32_t id)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate 	repcache_entity_t *ep;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
426*407Sjwadams 	ep = uu_avl_find(cp->rc_entities, &id, NULL, NULL);
4270Sstevel@tonic-gate 	if (ep != NULL) {
4280Sstevel@tonic-gate 		add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, ep);
4290Sstevel@tonic-gate 		(void) pthread_mutex_lock(&ep->re_lock);
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	return (ep);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate /*
4370Sstevel@tonic-gate  * Fails with
4380Sstevel@tonic-gate  *   _DUPLICATE_ID - the ids are equal
4390Sstevel@tonic-gate  *   _UNKNOWN_ID - an id does not designate an active register
4400Sstevel@tonic-gate  */
4410Sstevel@tonic-gate static int
4420Sstevel@tonic-gate entity_find2(repcache_client_t *cp, uint32_t id1, repcache_entity_t **out1,
4430Sstevel@tonic-gate     uint32_t id2, repcache_entity_t **out2)
4440Sstevel@tonic-gate {
4450Sstevel@tonic-gate 	repcache_entity_t *e1, *e2;
4460Sstevel@tonic-gate 	request_log_entry_t *rlp;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	if (id1 == id2)
4490Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_DUPLICATE_ID);
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
452*407Sjwadams 	e1 = uu_avl_find(cp->rc_entities, &id1, NULL, NULL);
453*407Sjwadams 	e2 = uu_avl_find(cp->rc_entities, &id2, NULL, NULL);
4540Sstevel@tonic-gate 	if (e1 == NULL || e2 == NULL) {
4550Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
4560Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
4570Sstevel@tonic-gate 	}
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	assert(e1 != e2);
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	/*
4620Sstevel@tonic-gate 	 * locks are ordered by id number
4630Sstevel@tonic-gate 	 */
4640Sstevel@tonic-gate 	if (id1 < id2) {
4650Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e1->re_lock);
4660Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e2->re_lock);
4670Sstevel@tonic-gate 	} else {
4680Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e2->re_lock);
4690Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e1->re_lock);
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate 	*out1 = e1;
4720Sstevel@tonic-gate 	*out2 = e2;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	if ((rlp = get_log()) != NULL) {
4770Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id1, e1);
4780Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id2, e2);
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate static void
4850Sstevel@tonic-gate entity_release(repcache_entity_t *ep)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate 	assert(ep->re_node.rnp_node == NULL ||
4880Sstevel@tonic-gate 	    !MUTEX_HELD(&ep->re_node.rnp_node->rn_lock));
4890Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ep->re_lock);
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate static void
4930Sstevel@tonic-gate entity_destroy(repcache_entity_t *entity)
4940Sstevel@tonic-gate {
4950Sstevel@tonic-gate 	(void) pthread_mutex_lock(&entity->re_lock);
4960Sstevel@tonic-gate 	rc_node_clear(&entity->re_node, 0);
4970Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&entity->re_lock);
4980Sstevel@tonic-gate 
499*407Sjwadams 	uu_avl_node_fini(entity, &entity->re_link, entity_pool);
5000Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&entity->re_lock);
5010Sstevel@tonic-gate 	uu_free(entity);
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate static void
5050Sstevel@tonic-gate entity_remove(repcache_client_t *cp, uint32_t id)
5060Sstevel@tonic-gate {
5070Sstevel@tonic-gate 	repcache_entity_t *entity;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
510*407Sjwadams 	entity = uu_avl_find(cp->rc_entities, &id, NULL, NULL);
5110Sstevel@tonic-gate 	if (entity != NULL)
512*407Sjwadams 		uu_avl_remove(cp->rc_entities, entity);
5130Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	if (entity != NULL)
5160Sstevel@tonic-gate 		entity_destroy(entity);
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate static void
5200Sstevel@tonic-gate entity_cleanup(repcache_client_t *cp)
5210Sstevel@tonic-gate {
5220Sstevel@tonic-gate 	repcache_entity_t *ep;
5230Sstevel@tonic-gate 	void *cookie = NULL;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
526*407Sjwadams 	while ((ep = uu_avl_teardown(cp->rc_entities, &cookie)) != NULL) {
5270Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
5280Sstevel@tonic-gate 		entity_destroy(ep);
5290Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cp->rc_lock);
5300Sstevel@tonic-gate 	}
5310Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate /*ARGSUSED*/
5350Sstevel@tonic-gate static repcache_iter_t *
5360Sstevel@tonic-gate iter_alloc(repcache_client_t *cp)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate 	repcache_iter_t *iter;
5390Sstevel@tonic-gate 	iter = uu_zalloc(sizeof (repcache_iter_t));
5400Sstevel@tonic-gate 	if (iter != NULL)
541*407Sjwadams 		uu_avl_node_init(iter, &iter->ri_link, iter_pool);
5420Sstevel@tonic-gate 	return (iter);
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate static void
5460Sstevel@tonic-gate iter_add(repcache_client_t *cp, repcache_iter_t *iter)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate 	uu_list_index_t idx;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
5510Sstevel@tonic-gate 	assert(cp->rc_insert_thr == pthread_self());
5520Sstevel@tonic-gate 
553*407Sjwadams 	(void) uu_avl_find(cp->rc_iters, iter, NULL, &idx);
554*407Sjwadams 	uu_avl_insert(cp->rc_iters, iter, idx);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate static repcache_iter_t *
5600Sstevel@tonic-gate iter_find(repcache_client_t *cp, uint32_t id)
5610Sstevel@tonic-gate {
5620Sstevel@tonic-gate 	repcache_iter_t *iter;
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
5650Sstevel@tonic-gate 
566*407Sjwadams 	iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL);
5670Sstevel@tonic-gate 	if (iter != NULL) {
5680Sstevel@tonic-gate 		add_log_ptr(get_log(), RC_PTR_TYPE_ITER, id, iter);
5690Sstevel@tonic-gate 		(void) pthread_mutex_lock(&iter->ri_lock);
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	return (iter);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate /*
5770Sstevel@tonic-gate  * Fails with
5780Sstevel@tonic-gate  *   _UNKNOWN_ID - iter_id or entity_id does not designate an active register
5790Sstevel@tonic-gate  */
5800Sstevel@tonic-gate static int
5810Sstevel@tonic-gate iter_find_w_entity(repcache_client_t *cp, uint32_t iter_id,
5820Sstevel@tonic-gate     repcache_iter_t **iterp, uint32_t entity_id, repcache_entity_t **epp)
5830Sstevel@tonic-gate {
5840Sstevel@tonic-gate 	repcache_iter_t *iter;
5850Sstevel@tonic-gate 	repcache_entity_t *ep;
5860Sstevel@tonic-gate 	request_log_entry_t *rlp;
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
589*407Sjwadams 	iter = uu_avl_find(cp->rc_iters, &iter_id, NULL, NULL);
590*407Sjwadams 	ep = uu_avl_find(cp->rc_entities, &entity_id, NULL, NULL);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	assert(iter == NULL || !MUTEX_HELD(&iter->ri_lock));
5930Sstevel@tonic-gate 	assert(ep == NULL || !MUTEX_HELD(&ep->re_lock));
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	if (iter == NULL || ep == NULL) {
5960Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
5970Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	(void) pthread_mutex_lock(&iter->ri_lock);
6010Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ep->re_lock);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	*iterp = iter;
6060Sstevel@tonic-gate 	*epp = ep;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if ((rlp = get_log()) != NULL) {
6090Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, entity_id, ep);
6100Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ITER, iter_id, iter);
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
6140Sstevel@tonic-gate }
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate static void
6170Sstevel@tonic-gate iter_release(repcache_iter_t *iter)
6180Sstevel@tonic-gate {
6190Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&iter->ri_lock);
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate static void
6230Sstevel@tonic-gate iter_destroy(repcache_iter_t *iter)
6240Sstevel@tonic-gate {
6250Sstevel@tonic-gate 	(void) pthread_mutex_lock(&iter->ri_lock);
6260Sstevel@tonic-gate 	rc_iter_destroy(&iter->ri_iter);
6270Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&iter->ri_lock);
6280Sstevel@tonic-gate 
629*407Sjwadams 	uu_avl_node_fini(iter, &iter->ri_link, iter_pool);
6300Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&iter->ri_lock);
6310Sstevel@tonic-gate 	uu_free(iter);
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate static void
6350Sstevel@tonic-gate iter_remove(repcache_client_t *cp, uint32_t id)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate 	repcache_iter_t *iter;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
640*407Sjwadams 	iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL);
6410Sstevel@tonic-gate 	if (iter != NULL)
642*407Sjwadams 		uu_avl_remove(cp->rc_iters, iter);
6430Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	if (iter != NULL)
6460Sstevel@tonic-gate 		iter_destroy(iter);
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate static void
6500Sstevel@tonic-gate iter_cleanup(repcache_client_t *cp)
6510Sstevel@tonic-gate {
6520Sstevel@tonic-gate 	repcache_iter_t *iter;
6530Sstevel@tonic-gate 	void *cookie = NULL;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
656*407Sjwadams 	while ((iter = uu_avl_teardown(cp->rc_iters, &cookie)) != NULL) {
6570Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
6580Sstevel@tonic-gate 		iter_destroy(iter);
6590Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cp->rc_lock);
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate /*
6650Sstevel@tonic-gate  * Ensure that the passed client id is no longer usable, wait for any
6660Sstevel@tonic-gate  * outstanding invocations to complete, then destroy the client
6670Sstevel@tonic-gate  * structure.
6680Sstevel@tonic-gate  */
6690Sstevel@tonic-gate static void
6700Sstevel@tonic-gate client_destroy(uint32_t id)
6710Sstevel@tonic-gate {
6720Sstevel@tonic-gate 	client_bucket_t *bp = CLIENT_HASH(id);
6730Sstevel@tonic-gate 	repcache_client_t *cp;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	(void) pthread_mutex_lock(&bp->cb_lock);
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	cp = uu_list_find(bp->cb_list, &id, NULL, NULL);
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	if (cp == NULL) {
6800Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&bp->cb_lock);
6810Sstevel@tonic-gate 		return;
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	uu_list_remove(bp->cb_list, cp);
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&bp->cb_lock);
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/* kick the waiters out */
6890Sstevel@tonic-gate 	rc_notify_info_fini(&cp->rc_notify_info);
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
6920Sstevel@tonic-gate 	assert(!(cp->rc_flags & RC_CLIENT_DEAD));
6930Sstevel@tonic-gate 	cp->rc_flags |= RC_CLIENT_DEAD;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	if (cp->rc_doorfd != -1) {
6960Sstevel@tonic-gate 		if (door_revoke(cp->rc_doorfd) < 0)
6970Sstevel@tonic-gate 			perror("door_revoke");
6980Sstevel@tonic-gate 		cp->rc_doorfd = -1;
6990Sstevel@tonic-gate 		cp->rc_doorid = INVALID_DOORID;
7000Sstevel@tonic-gate 	}
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	while (cp->rc_refcnt > 0)
7030Sstevel@tonic-gate 		(void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock);
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	assert(cp->rc_insert_thr == 0 && cp->rc_notify_thr == 0);
7060Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	/*
7090Sstevel@tonic-gate 	 * destroy outstanding objects
7100Sstevel@tonic-gate 	 */
7110Sstevel@tonic-gate 	entity_cleanup(cp);
7120Sstevel@tonic-gate 	iter_cleanup(cp);
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	/*
7150Sstevel@tonic-gate 	 * clean up notifications
7160Sstevel@tonic-gate 	 */
7170Sstevel@tonic-gate 	rc_pg_notify_fini(&cp->rc_pg_notify);
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	client_free(cp);
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate /*
7230Sstevel@tonic-gate  * Fails with
7240Sstevel@tonic-gate  *   _TYPE_MISMATCH - the entity is already set up with a different type
7250Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
7260Sstevel@tonic-gate  */
7270Sstevel@tonic-gate static int
7280Sstevel@tonic-gate entity_setup(repcache_client_t *cp, struct rep_protocol_entity_setup *rpr)
7290Sstevel@tonic-gate {
7300Sstevel@tonic-gate 	repcache_entity_t *ep;
7310Sstevel@tonic-gate 	uint32_t type;
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	client_start_insert(cp);
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) {
7360Sstevel@tonic-gate 		type = ep->re_type;
7370Sstevel@tonic-gate 		entity_release(ep);
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 		client_end_insert(cp);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 		if (type != rpr->rpr_entitytype)
7420Sstevel@tonic-gate 			return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
7430Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	switch (type = rpr->rpr_entitytype) {
7470Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SCOPE:
7480Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SERVICE:
7490Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE:
7500Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
7510Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPLEVEL:
7520Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
7530Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTY:
7540Sstevel@tonic-gate 		break;
7550Sstevel@tonic-gate 	default:
7560Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
7570Sstevel@tonic-gate 	}
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	ep = entity_alloc(cp);
7600Sstevel@tonic-gate 	if (ep == NULL) {
7610Sstevel@tonic-gate 		client_end_insert(cp);
7620Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
7630Sstevel@tonic-gate 	}
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	ep->re_id = rpr->rpr_entityid;
7660Sstevel@tonic-gate 	ep->re_changeid = INVALID_CHANGEID;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	ep->re_type = type;
7690Sstevel@tonic-gate 	rc_node_ptr_init(&ep->re_node);
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	entity_add(cp, ep);
7720Sstevel@tonic-gate 	client_end_insert(cp);
7730Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
7740Sstevel@tonic-gate }
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate /*ARGSUSED*/
7770Sstevel@tonic-gate static void
7780Sstevel@tonic-gate entity_name(repcache_client_t *cp, const void *in, size_t insz, void *out_arg,
7790Sstevel@tonic-gate     size_t *outsz, void *arg)
7800Sstevel@tonic-gate {
7810Sstevel@tonic-gate 	const struct rep_protocol_entity_name *rpr = in;
7820Sstevel@tonic-gate 	struct rep_protocol_name_response *out = out_arg;
7830Sstevel@tonic-gate 	repcache_entity_t *ep;
7840Sstevel@tonic-gate 	size_t sz = sizeof (out->rpr_name);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	if (ep == NULL) {
7910Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
7920Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
7930Sstevel@tonic-gate 		return;
7940Sstevel@tonic-gate 	}
7950Sstevel@tonic-gate 	out->rpr_response = rc_node_name(&ep->re_node, out->rpr_name,
7960Sstevel@tonic-gate 	    sz, rpr->rpr_answertype, &sz);
7970Sstevel@tonic-gate 	entity_release(ep);
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	/*
8000Sstevel@tonic-gate 	 * If we fail, we only return the response code.
8010Sstevel@tonic-gate 	 * If we succeed, we don't return anything after the '\0' in rpr_name.
8020Sstevel@tonic-gate 	 */
8030Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS)
8040Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
8050Sstevel@tonic-gate 	else
8060Sstevel@tonic-gate 		*outsz = offsetof(struct rep_protocol_name_response,
8070Sstevel@tonic-gate 		    rpr_name[sz + 1]);
8080Sstevel@tonic-gate }
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate /*ARGSUSED*/
8110Sstevel@tonic-gate static void
8120Sstevel@tonic-gate entity_parent_type(repcache_client_t *cp, const void *in, size_t insz,
8130Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
8140Sstevel@tonic-gate {
8150Sstevel@tonic-gate 	const struct rep_protocol_entity_name *rpr = in;
8160Sstevel@tonic-gate 	struct rep_protocol_integer_response *out = out_arg;
8170Sstevel@tonic-gate 	repcache_entity_t *ep;
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	if (ep == NULL) {
8240Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
8250Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
8260Sstevel@tonic-gate 		return;
8270Sstevel@tonic-gate 	}
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	out->rpr_response = rc_node_parent_type(&ep->re_node, &out->rpr_value);
8300Sstevel@tonic-gate 	entity_release(ep);
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS)
8330Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate /*
8370Sstevel@tonic-gate  * Fails with
8380Sstevel@tonic-gate  *   _DUPLICATE_ID - the ids are equal
8390Sstevel@tonic-gate  *   _UNKNOWN_ID - an id does not designate an active register
8400Sstevel@tonic-gate  *   _INVALID_TYPE - type is invalid
8410Sstevel@tonic-gate  *   _TYPE_MISMATCH - np doesn't carry children of type type
8420Sstevel@tonic-gate  *   _DELETED - np has been deleted
8430Sstevel@tonic-gate  *   _NOT_FOUND - no child with that name/type combo found
8440Sstevel@tonic-gate  *   _NO_RESOURCES
8450Sstevel@tonic-gate  *   _BACKEND_ACCESS
8460Sstevel@tonic-gate  */
8470Sstevel@tonic-gate static int
8480Sstevel@tonic-gate entity_get_child(repcache_client_t *cp,
8490Sstevel@tonic-gate     struct rep_protocol_entity_get_child *rpr)
8500Sstevel@tonic-gate {
8510Sstevel@tonic-gate 	repcache_entity_t *parent, *child;
8520Sstevel@tonic-gate 	int result;
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	uint32_t parentid = rpr->rpr_entityid;
8550Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_childid;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	result = entity_find2(cp, childid, &child, parentid, &parent);
8580Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
8590Sstevel@tonic-gate 		return (result);
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	result = rc_node_get_child(&parent->re_node, rpr->rpr_name,
8640Sstevel@tonic-gate 	    child->re_type, &child->re_node);
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	entity_release(child);
8670Sstevel@tonic-gate 	entity_release(parent);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	return (result);
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate /*
8730Sstevel@tonic-gate  * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED,
8740Sstevel@tonic-gate  * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS.
8750Sstevel@tonic-gate  * Fails with
8760Sstevel@tonic-gate  *   _DUPLICATE_ID - the ids are equal
8770Sstevel@tonic-gate  *   _UNKNOWN_ID - an id does not designate an active register
8780Sstevel@tonic-gate  *   _NOT_SET - child is not set
8790Sstevel@tonic-gate  *   _DELETED - child has been deleted
8800Sstevel@tonic-gate  *   _TYPE_MISMATCH - child's parent does not match that of the parent register
8810Sstevel@tonic-gate  *   _NOT_FOUND - child has no parent (and is a scope)
8820Sstevel@tonic-gate  */
8830Sstevel@tonic-gate static int
8840Sstevel@tonic-gate entity_get_parent(repcache_client_t *cp, struct rep_protocol_entity_parent *rpr)
8850Sstevel@tonic-gate {
8860Sstevel@tonic-gate 	repcache_entity_t *child, *parent;
8870Sstevel@tonic-gate 	int result;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_entityid;
8900Sstevel@tonic-gate 	uint32_t outid = rpr->rpr_outid;
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	result = entity_find2(cp, childid, &child, outid, &parent);
8930Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
8940Sstevel@tonic-gate 		return (result);
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	result = rc_node_get_parent(&child->re_node, parent->re_type,
8970Sstevel@tonic-gate 	    &parent->re_node);
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	entity_release(child);
9000Sstevel@tonic-gate 	entity_release(parent);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	return (result);
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate static int
9060Sstevel@tonic-gate entity_get(repcache_client_t *cp, struct rep_protocol_entity_get *rpr)
9070Sstevel@tonic-gate {
9080Sstevel@tonic-gate 	repcache_entity_t *ep;
9090Sstevel@tonic-gate 	int result;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	if (ep == NULL)
9140Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	switch (rpr->rpr_object) {
9170Sstevel@tonic-gate 	case RP_ENTITY_GET_INVALIDATE:
9180Sstevel@tonic-gate 		rc_node_clear(&ep->re_node, 0);
9190Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
9200Sstevel@tonic-gate 		break;
9210Sstevel@tonic-gate 	case RP_ENTITY_GET_MOST_LOCAL_SCOPE:
9220Sstevel@tonic-gate 		result = rc_local_scope(ep->re_type, &ep->re_node);
9230Sstevel@tonic-gate 		break;
9240Sstevel@tonic-gate 	default:
9250Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
9260Sstevel@tonic-gate 		break;
9270Sstevel@tonic-gate 	}
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	entity_release(ep);
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	return (result);
9320Sstevel@tonic-gate }
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate static int
9350Sstevel@tonic-gate entity_update(repcache_client_t *cp, struct rep_protocol_entity_update *rpr)
9360Sstevel@tonic-gate {
9370Sstevel@tonic-gate 	repcache_entity_t *ep;
9380Sstevel@tonic-gate 	int result;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
9410Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	if (ep == NULL)
9460Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	if (ep->re_changeid == rpr->rpr_changeid) {
9490Sstevel@tonic-gate 		result = REP_PROTOCOL_DONE;
9500Sstevel@tonic-gate 	} else {
9510Sstevel@tonic-gate 		result = rc_node_update(&ep->re_node);
9520Sstevel@tonic-gate 		if (result == REP_PROTOCOL_DONE)
9530Sstevel@tonic-gate 			ep->re_changeid = rpr->rpr_changeid;
9540Sstevel@tonic-gate 	}
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	entity_release(ep);
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	return (result);
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate static int
9620Sstevel@tonic-gate entity_reset(repcache_client_t *cp, struct rep_protocol_entity_reset *rpr)
9630Sstevel@tonic-gate {
9640Sstevel@tonic-gate 	repcache_entity_t *ep;
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
9670Sstevel@tonic-gate 	if (ep == NULL)
9680Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	rc_node_clear(&ep->re_node, 0);
9710Sstevel@tonic-gate 	ep->re_txstate = REPCACHE_TX_INIT;
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	entity_release(ep);
9740Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
9750Sstevel@tonic-gate }
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate /*
9780Sstevel@tonic-gate  * Fails with
9790Sstevel@tonic-gate  *   _BAD_REQUEST - request has invalid changeid
9800Sstevel@tonic-gate  *		    rpr_name is invalid
9810Sstevel@tonic-gate  *		    cannot create children for parent's type of node
9820Sstevel@tonic-gate  *   _DUPLICATE_ID - request has duplicate ids
9830Sstevel@tonic-gate  *   _UNKNOWN_ID - request has unknown id
9840Sstevel@tonic-gate  *   _DELETED - parent has been deleted
9850Sstevel@tonic-gate  *   _NOT_SET - parent is reset
9860Sstevel@tonic-gate  *   _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP
9870Sstevel@tonic-gate  *   _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid
9880Sstevel@tonic-gate  *   _TYPE_MISMATCH - parent cannot have children of type rpr_childtype
9890Sstevel@tonic-gate  *   _NO_RESOURCES
9900Sstevel@tonic-gate  *   _PERMISSION_DENIED
9910Sstevel@tonic-gate  *   _BACKEND_ACCESS
9920Sstevel@tonic-gate  *   _BACKEND_READONLY
9930Sstevel@tonic-gate  *   _EXISTS - child already exists
9940Sstevel@tonic-gate  *   _NOT_FOUND - could not allocate new id
9950Sstevel@tonic-gate  */
9960Sstevel@tonic-gate static int
9970Sstevel@tonic-gate entity_create_child(repcache_client_t *cp,
9980Sstevel@tonic-gate     struct rep_protocol_entity_create_child *rpr)
9990Sstevel@tonic-gate {
10000Sstevel@tonic-gate 	repcache_entity_t *parent;
10010Sstevel@tonic-gate 	repcache_entity_t *child;
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	uint32_t parentid = rpr->rpr_entityid;
10040Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_childid;
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	int result;
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
10090Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	result = entity_find2(cp, parentid, &parent, childid, &child);
10120Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
10130Sstevel@tonic-gate 		return (result);
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	if (child->re_changeid == rpr->rpr_changeid) {
10180Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
10190Sstevel@tonic-gate 	} else {
10200Sstevel@tonic-gate 		result = rc_node_create_child(&parent->re_node,
10210Sstevel@tonic-gate 		    rpr->rpr_childtype, rpr->rpr_name, &child->re_node);
10220Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
10230Sstevel@tonic-gate 			child->re_changeid = rpr->rpr_changeid;
10240Sstevel@tonic-gate 	}
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	entity_release(parent);
10270Sstevel@tonic-gate 	entity_release(child);
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	return (result);
10300Sstevel@tonic-gate }
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate static int
10330Sstevel@tonic-gate entity_create_pg(repcache_client_t *cp,
10340Sstevel@tonic-gate     struct rep_protocol_entity_create_pg *rpr)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate 	repcache_entity_t *parent;
10370Sstevel@tonic-gate 	repcache_entity_t *child;
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	uint32_t parentid = rpr->rpr_entityid;
10400Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_childid;
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	int result;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
10450Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	result = entity_find2(cp, parentid, &parent, childid, &child);
10480Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
10490Sstevel@tonic-gate 		return (result);
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
10520Sstevel@tonic-gate 	rpr->rpr_type[sizeof (rpr->rpr_type) - 1] = 0;
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	if (child->re_changeid == rpr->rpr_changeid) {
10550Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
10560Sstevel@tonic-gate 	} else {
10570Sstevel@tonic-gate 		result = rc_node_create_child_pg(&parent->re_node,
10580Sstevel@tonic-gate 		    child->re_type, rpr->rpr_name, rpr->rpr_type,
10590Sstevel@tonic-gate 		    rpr->rpr_flags, &child->re_node);
10600Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
10610Sstevel@tonic-gate 			child->re_changeid = rpr->rpr_changeid;
10620Sstevel@tonic-gate 	}
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	entity_release(parent);
10650Sstevel@tonic-gate 	entity_release(child);
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	return (result);
10680Sstevel@tonic-gate }
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate static int
10710Sstevel@tonic-gate entity_delete(repcache_client_t *cp,
10720Sstevel@tonic-gate     struct rep_protocol_entity_delete *rpr)
10730Sstevel@tonic-gate {
10740Sstevel@tonic-gate 	repcache_entity_t *entity;
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	uint32_t entityid = rpr->rpr_entityid;
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	int result;
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
10810Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	entity = entity_find(cp, entityid);
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	if (entity == NULL)
10860Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	if (entity->re_changeid == rpr->rpr_changeid) {
10890Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
10900Sstevel@tonic-gate 	} else {
10910Sstevel@tonic-gate 		result = rc_node_delete(&entity->re_node);
10920Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
10930Sstevel@tonic-gate 			entity->re_changeid = rpr->rpr_changeid;
10940Sstevel@tonic-gate 	}
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	entity_release(entity);
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	return (result);
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate static rep_protocol_responseid_t
11020Sstevel@tonic-gate entity_teardown(repcache_client_t *cp, struct rep_protocol_entity_teardown *rpr)
11030Sstevel@tonic-gate {
11040Sstevel@tonic-gate 	entity_remove(cp, rpr->rpr_entityid);
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
11070Sstevel@tonic-gate }
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate /*
11100Sstevel@tonic-gate  * Fails with
11110Sstevel@tonic-gate  *   _MISORDERED - the iterator exists and is not reset
11120Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
11130Sstevel@tonic-gate  */
11140Sstevel@tonic-gate static int
11150Sstevel@tonic-gate iter_setup(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
11160Sstevel@tonic-gate {
11170Sstevel@tonic-gate 	repcache_iter_t *iter;
11180Sstevel@tonic-gate 	uint32_t sequence;
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	client_start_insert(cp);
11210Sstevel@tonic-gate 	/*
11220Sstevel@tonic-gate 	 * If the iter already exists, and hasn't been read from,
11230Sstevel@tonic-gate 	 * we assume the previous call succeeded.
11240Sstevel@tonic-gate 	 */
11250Sstevel@tonic-gate 	if ((iter = iter_find(cp, rpr->rpr_iterid)) != NULL) {
11260Sstevel@tonic-gate 		sequence = iter->ri_sequence;
11270Sstevel@tonic-gate 		iter_release(iter);
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 		client_end_insert(cp);
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 		if (sequence != 0)
11320Sstevel@tonic-gate 			return (REP_PROTOCOL_FAIL_MISORDERED);
11330Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);
11340Sstevel@tonic-gate 	}
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	iter = iter_alloc(cp);
11370Sstevel@tonic-gate 	if (iter == NULL) {
11380Sstevel@tonic-gate 		client_end_insert(cp);
11390Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
11400Sstevel@tonic-gate 	}
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	iter->ri_id = rpr->rpr_iterid;
11430Sstevel@tonic-gate 	iter->ri_type = REP_PROTOCOL_TYPE_INVALID;
11440Sstevel@tonic-gate 	iter->ri_sequence = 0;
11450Sstevel@tonic-gate 	iter_add(cp, iter);
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 	client_end_insert(cp);
11480Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate /*
11520Sstevel@tonic-gate  * Fails with
11530Sstevel@tonic-gate  *   _UNKNOWN_ID
11540Sstevel@tonic-gate  *   _MISORDERED - iterator has already been started
11550Sstevel@tonic-gate  *   _NOT_SET
11560Sstevel@tonic-gate  *   _DELETED
11570Sstevel@tonic-gate  *   _TYPE_MISMATCH - entity cannot have type children
11580Sstevel@tonic-gate  *   _BAD_REQUEST - rpr_flags is invalid
11590Sstevel@tonic-gate  *		    rpr_pattern is invalid
11600Sstevel@tonic-gate  *   _NO_RESOURCES
11610Sstevel@tonic-gate  *   _INVALID_TYPE
11620Sstevel@tonic-gate  *   _BACKEND_ACCESS
11630Sstevel@tonic-gate  */
11640Sstevel@tonic-gate static int
11650Sstevel@tonic-gate iter_start(repcache_client_t *cp, struct rep_protocol_iter_start *rpr)
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate 	int result;
11680Sstevel@tonic-gate 	repcache_iter_t *iter;
11690Sstevel@tonic-gate 	repcache_entity_t *ep;
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 	result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter,
11720Sstevel@tonic-gate 	    rpr->rpr_entity, &ep);
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
11750Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 	if (iter->ri_sequence > 1) {
11780Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_MISORDERED;
11790Sstevel@tonic-gate 		goto end;
11800Sstevel@tonic-gate 	}
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	if (iter->ri_sequence == 1) {
11830Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
11840Sstevel@tonic-gate 		goto end;
11850Sstevel@tonic-gate 	}
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0;
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 	result = rc_node_setup_iter(&ep->re_node, &iter->ri_iter,
11900Sstevel@tonic-gate 	    rpr->rpr_itertype, rpr->rpr_flags, rpr->rpr_pattern);
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS)
11930Sstevel@tonic-gate 		iter->ri_sequence++;
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate end:
11960Sstevel@tonic-gate 	iter_release(iter);
11970Sstevel@tonic-gate 	entity_release(ep);
11980Sstevel@tonic-gate 	return (result);
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate /*
12020Sstevel@tonic-gate  * Returns
12030Sstevel@tonic-gate  *   _UNKNOWN_ID
12040Sstevel@tonic-gate  *   _NOT_SET - iter has not been started
12050Sstevel@tonic-gate  *   _MISORDERED
12060Sstevel@tonic-gate  *   _BAD_REQUEST - iter walks values
12070Sstevel@tonic-gate  *   _TYPE_MISMATCH - iter does not walk type entities
12080Sstevel@tonic-gate  *   _DELETED - parent was deleted
12090Sstevel@tonic-gate  *   _NO_RESOURCES
12100Sstevel@tonic-gate  *   _INVALID_TYPE - type is invalid
12110Sstevel@tonic-gate  *   _DONE
12120Sstevel@tonic-gate  *   _SUCCESS
12130Sstevel@tonic-gate  *
12140Sstevel@tonic-gate  * For composed property group iterators, can also return
12150Sstevel@tonic-gate  *   _TYPE_MISMATCH - parent cannot have type children
12160Sstevel@tonic-gate  *   _BACKEND_ACCESS
12170Sstevel@tonic-gate  */
12180Sstevel@tonic-gate static rep_protocol_responseid_t
12190Sstevel@tonic-gate iter_read(repcache_client_t *cp, struct rep_protocol_iter_read *rpr)
12200Sstevel@tonic-gate {
12210Sstevel@tonic-gate 	rep_protocol_responseid_t result;
12220Sstevel@tonic-gate 	repcache_iter_t *iter;
12230Sstevel@tonic-gate 	repcache_entity_t *ep;
12240Sstevel@tonic-gate 	uint32_t sequence;
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter,
12270Sstevel@tonic-gate 	    rpr->rpr_entityid, &ep);
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
12300Sstevel@tonic-gate 		return (result);
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	sequence = rpr->rpr_sequence;
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	if (iter->ri_sequence == 0) {
12350Sstevel@tonic-gate 		iter_release(iter);
12360Sstevel@tonic-gate 		entity_release(ep);
12370Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NOT_SET);
12380Sstevel@tonic-gate 	}
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	if (sequence == 1) {
12410Sstevel@tonic-gate 		iter_release(iter);
12420Sstevel@tonic-gate 		entity_release(ep);
12430Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_MISORDERED);
12440Sstevel@tonic-gate 	}
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	if (sequence == iter->ri_sequence) {
12470Sstevel@tonic-gate 		iter_release(iter);
12480Sstevel@tonic-gate 		entity_release(ep);
12490Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);
12500Sstevel@tonic-gate 	}
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	if (sequence == iter->ri_sequence + 1) {
12530Sstevel@tonic-gate 		result = rc_iter_next(iter->ri_iter, &ep->re_node,
12540Sstevel@tonic-gate 		    ep->re_type);
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
12570Sstevel@tonic-gate 			iter->ri_sequence++;
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 		iter_release(iter);
12600Sstevel@tonic-gate 		entity_release(ep);
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 		return (result);
12630Sstevel@tonic-gate 	}
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	iter_release(iter);
12660Sstevel@tonic-gate 	entity_release(ep);
12670Sstevel@tonic-gate 	return (REP_PROTOCOL_FAIL_MISORDERED);
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate /*ARGSUSED*/
12710Sstevel@tonic-gate static void
12720Sstevel@tonic-gate iter_read_value(repcache_client_t *cp, const void *in, size_t insz,
12730Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
12740Sstevel@tonic-gate {
12750Sstevel@tonic-gate 	const struct rep_protocol_iter_read_value *rpr = in;
12760Sstevel@tonic-gate 	struct rep_protocol_value_response *out = out_arg;
12770Sstevel@tonic-gate 	rep_protocol_responseid_t result;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	repcache_iter_t *iter;
12800Sstevel@tonic-gate 	uint32_t sequence;
12810Sstevel@tonic-gate 	int repeat;
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	iter = iter_find(cp, rpr->rpr_iterid);
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	if (iter == NULL) {
12880Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
12890Sstevel@tonic-gate 		goto out;
12900Sstevel@tonic-gate 	}
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	sequence = rpr->rpr_sequence;
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	if (iter->ri_sequence == 0) {
12950Sstevel@tonic-gate 		iter_release(iter);
12960Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_NOT_SET;
12970Sstevel@tonic-gate 		goto out;
12980Sstevel@tonic-gate 	}
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	repeat = (sequence == iter->ri_sequence);
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	if (sequence == 1 || (!repeat && sequence != iter->ri_sequence + 1)) {
13030Sstevel@tonic-gate 		iter_release(iter);
13040Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_MISORDERED;
13050Sstevel@tonic-gate 		goto out;
13060Sstevel@tonic-gate 	}
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	result = rc_iter_next_value(iter->ri_iter, out, outsz, repeat);
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	if (!repeat && result == REP_PROTOCOL_SUCCESS)
13110Sstevel@tonic-gate 		iter->ri_sequence++;
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	iter_release(iter);
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate out:
13160Sstevel@tonic-gate 	/*
13170Sstevel@tonic-gate 	 * If we fail, we only return the response code.
13180Sstevel@tonic-gate 	 * If we succeed, rc_iter_next_value has shortened *outsz
13190Sstevel@tonic-gate 	 * to only include the value bytes needed.
13200Sstevel@tonic-gate 	 */
13210Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS && result != REP_PROTOCOL_DONE)
13220Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	out->rpr_response = result;
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate static int
13280Sstevel@tonic-gate iter_reset(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
13290Sstevel@tonic-gate {
13300Sstevel@tonic-gate 	repcache_iter_t *iter = iter_find(cp, rpr->rpr_iterid);
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	if (iter == NULL)
13330Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	if (iter->ri_sequence != 0) {
13360Sstevel@tonic-gate 		iter->ri_sequence = 0;
13370Sstevel@tonic-gate 		rc_iter_destroy(&iter->ri_iter);
13380Sstevel@tonic-gate 	}
13390Sstevel@tonic-gate 	iter_release(iter);
13400Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate static rep_protocol_responseid_t
13440Sstevel@tonic-gate iter_teardown(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
13450Sstevel@tonic-gate {
13460Sstevel@tonic-gate 	iter_remove(cp, rpr->rpr_iterid);
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate static rep_protocol_responseid_t
13520Sstevel@tonic-gate tx_start(repcache_client_t *cp, struct rep_protocol_transaction_start *rpr)
13530Sstevel@tonic-gate {
13540Sstevel@tonic-gate 	repcache_entity_t *tx;
13550Sstevel@tonic-gate 	repcache_entity_t *ep;
13560Sstevel@tonic-gate 	rep_protocol_responseid_t result;
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	uint32_t txid = rpr->rpr_entityid_tx;
13590Sstevel@tonic-gate 	uint32_t epid = rpr->rpr_entityid;
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	result = entity_find2(cp, txid, &tx, epid, &ep);
13620Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
13630Sstevel@tonic-gate 		return (result);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	if (tx->re_txstate == REPCACHE_TX_SETUP) {
13660Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
13670Sstevel@tonic-gate 		goto end;
13680Sstevel@tonic-gate 	}
13690Sstevel@tonic-gate 	if (tx->re_txstate != REPCACHE_TX_INIT) {
13700Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_MISORDERED;
13710Sstevel@tonic-gate 		goto end;
13720Sstevel@tonic-gate 	}
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 	result = rc_node_setup_tx(&ep->re_node, &tx->re_node);
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate end:
13770Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS)
13780Sstevel@tonic-gate 		tx->re_txstate = REPCACHE_TX_SETUP;
13790Sstevel@tonic-gate 	else
13800Sstevel@tonic-gate 		rc_node_clear(&tx->re_node, 0);
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	entity_release(ep);
13830Sstevel@tonic-gate 	entity_release(tx);
13840Sstevel@tonic-gate 	return (result);
13850Sstevel@tonic-gate }
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate /*ARGSUSED*/
13880Sstevel@tonic-gate static void
13890Sstevel@tonic-gate tx_commit(repcache_client_t *cp, const void *in, size_t insz,
13900Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
13910Sstevel@tonic-gate {
13920Sstevel@tonic-gate 	struct rep_protocol_response *out = out_arg;
13930Sstevel@tonic-gate 	const struct rep_protocol_transaction_commit *rpr = in;
13940Sstevel@tonic-gate 	repcache_entity_t *tx;
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
13970Sstevel@tonic-gate 	assert(insz >= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE);
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	if (rpr->rpr_size != insz) {
14000Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_BAD_REQUEST;
14010Sstevel@tonic-gate 		return;
14020Sstevel@tonic-gate 	}
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 	tx = entity_find(cp, rpr->rpr_entityid);
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	if (tx == NULL) {
14070Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
14080Sstevel@tonic-gate 		return;
14090Sstevel@tonic-gate 	}
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	switch (tx->re_txstate) {
14120Sstevel@tonic-gate 	case REPCACHE_TX_INIT:
14130Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_MISORDERED;
14140Sstevel@tonic-gate 		break;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	case REPCACHE_TX_SETUP:
14170Sstevel@tonic-gate 		out->rpr_response = rc_tx_commit(&tx->re_node, rpr->rpr_cmd,
14180Sstevel@tonic-gate 		    insz - REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE);
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 		if (out->rpr_response == REP_PROTOCOL_SUCCESS) {
14210Sstevel@tonic-gate 			tx->re_txstate = REPCACHE_TX_COMMITTED;
14220Sstevel@tonic-gate 			rc_node_clear(&tx->re_node, 0);
14230Sstevel@tonic-gate 		}
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 		break;
14260Sstevel@tonic-gate 	case REPCACHE_TX_COMMITTED:
14270Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_SUCCESS;
14280Sstevel@tonic-gate 		break;
14290Sstevel@tonic-gate 	default:
14300Sstevel@tonic-gate 		assert(0);	/* CAN'T HAPPEN */
14310Sstevel@tonic-gate 		break;
14320Sstevel@tonic-gate 	}
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	entity_release(tx);
14350Sstevel@tonic-gate }
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate static rep_protocol_responseid_t
14380Sstevel@tonic-gate next_snaplevel(repcache_client_t *cp, struct rep_protocol_entity_pair *rpr)
14390Sstevel@tonic-gate {
14400Sstevel@tonic-gate 	repcache_entity_t *src;
14410Sstevel@tonic-gate 	repcache_entity_t *dest;
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entity_src;
14440Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entity_dst;
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	int result;
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
14490Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
14500Sstevel@tonic-gate 		return (result);
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate 	result = rc_node_next_snaplevel(&src->re_node, &dest->re_node);
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	entity_release(src);
14550Sstevel@tonic-gate 	entity_release(dest);
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate 	return (result);
14580Sstevel@tonic-gate }
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate static rep_protocol_responseid_t
14610Sstevel@tonic-gate snapshot_take(repcache_client_t *cp, struct rep_protocol_snapshot_take *rpr)
14620Sstevel@tonic-gate {
14630Sstevel@tonic-gate 	repcache_entity_t *src;
14640Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entityid_src;
14650Sstevel@tonic-gate 	repcache_entity_t *dest;
14660Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entityid_dest;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	int result;
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
14710Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
14720Sstevel@tonic-gate 		return (result);
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
14750Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
14760Sstevel@tonic-gate 	} else {
14770Sstevel@tonic-gate 		rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 		if (rpr->rpr_flags == REP_SNAPSHOT_NEW)
14800Sstevel@tonic-gate 			result = rc_snapshot_take_new(&src->re_node, NULL,
14810Sstevel@tonic-gate 			    NULL, rpr->rpr_name, &dest->re_node);
14820Sstevel@tonic-gate 		else if (rpr->rpr_flags == REP_SNAPSHOT_ATTACH &&
14830Sstevel@tonic-gate 		    rpr->rpr_name[0] == 0)
14840Sstevel@tonic-gate 			result = rc_snapshot_take_attach(&src->re_node,
14850Sstevel@tonic-gate 			    &dest->re_node);
14860Sstevel@tonic-gate 		else
14870Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_BAD_REQUEST;
14880Sstevel@tonic-gate 	}
14890Sstevel@tonic-gate 	entity_release(src);
14900Sstevel@tonic-gate 	entity_release(dest);
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	return (result);
14930Sstevel@tonic-gate }
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate static rep_protocol_responseid_t
14960Sstevel@tonic-gate snapshot_take_named(repcache_client_t *cp,
14970Sstevel@tonic-gate     struct rep_protocol_snapshot_take_named *rpr)
14980Sstevel@tonic-gate {
14990Sstevel@tonic-gate 	repcache_entity_t *src;
15000Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entityid_src;
15010Sstevel@tonic-gate 	repcache_entity_t *dest;
15020Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entityid_dest;
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	int result;
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
15070Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
15080Sstevel@tonic-gate 		return (result);
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
15110Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
15120Sstevel@tonic-gate 	} else {
15130Sstevel@tonic-gate 		rpr->rpr_svcname[sizeof (rpr->rpr_svcname) - 1] = 0;
15140Sstevel@tonic-gate 		rpr->rpr_instname[sizeof (rpr->rpr_instname) - 1] = 0;
15150Sstevel@tonic-gate 		rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 		result = rc_snapshot_take_new(&src->re_node, rpr->rpr_svcname,
15180Sstevel@tonic-gate 		    rpr->rpr_instname, rpr->rpr_name, &dest->re_node);
15190Sstevel@tonic-gate 	}
15200Sstevel@tonic-gate 	entity_release(src);
15210Sstevel@tonic-gate 	entity_release(dest);
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	return (result);
15240Sstevel@tonic-gate }
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate static rep_protocol_responseid_t
15270Sstevel@tonic-gate snapshot_attach(repcache_client_t *cp, struct rep_protocol_snapshot_attach *rpr)
15280Sstevel@tonic-gate {
15290Sstevel@tonic-gate 	repcache_entity_t *src;
15300Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entityid_src;
15310Sstevel@tonic-gate 	repcache_entity_t *dest;
15320Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entityid_dest;
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	int result;
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
15370Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
15380Sstevel@tonic-gate 		return (result);
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 	result = rc_snapshot_attach(&src->re_node, &dest->re_node);
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	entity_release(src);
15430Sstevel@tonic-gate 	entity_release(dest);
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	return (result);
15460Sstevel@tonic-gate }
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate /*ARGSUSED*/
15490Sstevel@tonic-gate static void
15500Sstevel@tonic-gate property_get_type(repcache_client_t *cp, const void *in, size_t insz,
15510Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
15520Sstevel@tonic-gate {
15530Sstevel@tonic-gate 	const struct rep_protocol_property_request *rpr = in;
15540Sstevel@tonic-gate 	struct rep_protocol_integer_response *out = out_arg;
15550Sstevel@tonic-gate 	repcache_entity_t *ep;
15560Sstevel@tonic-gate 	rep_protocol_value_type_t t = 0;
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	if (ep == NULL) {
15630Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
15640Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
15650Sstevel@tonic-gate 		return;
15660Sstevel@tonic-gate 	}
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 	out->rpr_response = rc_node_get_property_type(&ep->re_node, &t);
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	entity_release(ep);
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS)
15730Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
15740Sstevel@tonic-gate 	else
15750Sstevel@tonic-gate 		out->rpr_value = t;
15760Sstevel@tonic-gate }
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate /*
15790Sstevel@tonic-gate  * Fails with:
15800Sstevel@tonic-gate  *	_UNKNOWN_ID - an id does not designate an active register
15810Sstevel@tonic-gate  *	_NOT_SET - The property is not set
15820Sstevel@tonic-gate  *	_DELETED - The property has been deleted
15830Sstevel@tonic-gate  *	_TYPE_MISMATCH - The object is not a property
15840Sstevel@tonic-gate  *	_NOT_FOUND - The property has no values.
15850Sstevel@tonic-gate  *
15860Sstevel@tonic-gate  * Succeeds with:
15870Sstevel@tonic-gate  *	_SUCCESS - The property has 1 value.
15880Sstevel@tonic-gate  *	_TRUNCATED - The property has >1 value.
15890Sstevel@tonic-gate  */
15900Sstevel@tonic-gate /*ARGSUSED*/
15910Sstevel@tonic-gate static void
15920Sstevel@tonic-gate property_get_value(repcache_client_t *cp, const void *in, size_t insz,
15930Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
15940Sstevel@tonic-gate {
15950Sstevel@tonic-gate 	const struct rep_protocol_property_request *rpr = in;
15960Sstevel@tonic-gate 	struct rep_protocol_value_response *out = out_arg;
15970Sstevel@tonic-gate 	repcache_entity_t *ep;
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
16020Sstevel@tonic-gate 	if (ep == NULL) {
16030Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
16040Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
16050Sstevel@tonic-gate 		return;
16060Sstevel@tonic-gate 	}
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	out->rpr_response = rc_node_get_property_value(&ep->re_node, out,
16090Sstevel@tonic-gate 	    outsz);
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	entity_release(ep);
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	/*
16140Sstevel@tonic-gate 	 * If we fail, we only return the response code.
16150Sstevel@tonic-gate 	 * If we succeed, rc_node_get_property_value has shortened *outsz
16160Sstevel@tonic-gate 	 * to only include the value bytes needed.
16170Sstevel@tonic-gate 	 */
16180Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS &&
16190Sstevel@tonic-gate 	    out->rpr_response != REP_PROTOCOL_FAIL_TRUNCATED)
16200Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
16210Sstevel@tonic-gate }
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate static rep_protocol_responseid_t
16240Sstevel@tonic-gate propertygrp_notify(repcache_client_t *cp,
16250Sstevel@tonic-gate     struct rep_protocol_propertygrp_request *rpr, int *out_fd)
16260Sstevel@tonic-gate {
16270Sstevel@tonic-gate 	int fds[2];
16280Sstevel@tonic-gate 	int ours, theirs;
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 	rep_protocol_responseid_t result;
16310Sstevel@tonic-gate 	repcache_entity_t *ep;
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	if (pipe(fds) < 0)
16340Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	ours = fds[0];
16370Sstevel@tonic-gate 	theirs = fds[1];
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	if ((ep = entity_find(cp, rpr->rpr_entityid)) == NULL) {
16400Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
16410Sstevel@tonic-gate 		goto fail;
16420Sstevel@tonic-gate 	}
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	/*
16450Sstevel@tonic-gate 	 * While the following can race with other threads setting up a
16460Sstevel@tonic-gate 	 * notification, the worst that can happen is that our fd has
16470Sstevel@tonic-gate 	 * already been closed before we return.
16480Sstevel@tonic-gate 	 */
16490Sstevel@tonic-gate 	result = rc_pg_notify_setup(&cp->rc_pg_notify, &ep->re_node,
16500Sstevel@tonic-gate 	    ours);
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 	entity_release(ep);
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
16550Sstevel@tonic-gate 		goto fail;
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 	*out_fd = theirs;
16580Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate fail:
16610Sstevel@tonic-gate 	(void) close(ours);
16620Sstevel@tonic-gate 	(void) close(theirs);
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 	return (result);
16650Sstevel@tonic-gate }
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate static rep_protocol_responseid_t
16680Sstevel@tonic-gate client_add_notify(repcache_client_t *cp,
16690Sstevel@tonic-gate     struct rep_protocol_notify_request *rpr)
16700Sstevel@tonic-gate {
16710Sstevel@tonic-gate 	rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0;
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 	switch (rpr->rpr_type) {
16740Sstevel@tonic-gate 	case REP_PROTOCOL_NOTIFY_PGNAME:
16750Sstevel@tonic-gate 		return (rc_notify_info_add_name(&cp->rc_notify_info,
16760Sstevel@tonic-gate 		    rpr->rpr_pattern));
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 	case REP_PROTOCOL_NOTIFY_PGTYPE:
16790Sstevel@tonic-gate 		return (rc_notify_info_add_type(&cp->rc_notify_info,
16800Sstevel@tonic-gate 		    rpr->rpr_pattern));
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	default:
16830Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
16840Sstevel@tonic-gate 	}
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate /*ARGSUSED*/
16880Sstevel@tonic-gate static void
16890Sstevel@tonic-gate client_wait(repcache_client_t *cp, const void *in, size_t insz,
16900Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
16910Sstevel@tonic-gate {
16920Sstevel@tonic-gate 	int result;
16930Sstevel@tonic-gate 	repcache_entity_t *ep;
16940Sstevel@tonic-gate 	const struct rep_protocol_wait_request *rpr = in;
16950Sstevel@tonic-gate 	struct rep_protocol_fmri_response *out = out_arg;
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
17000Sstevel@tonic-gate 	if (cp->rc_notify_thr != 0) {
17010Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
17020Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_EXISTS;
17030Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
17040Sstevel@tonic-gate 		return;
17050Sstevel@tonic-gate 	}
17060Sstevel@tonic-gate 	cp->rc_notify_thr = pthread_self();
17070Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 	result = rc_notify_info_wait(&cp->rc_notify_info, &cp->rc_notify_ptr,
17100Sstevel@tonic-gate 	    out->rpr_fmri, sizeof (out->rpr_fmri));
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS) {
17130Sstevel@tonic-gate 		if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) {
17140Sstevel@tonic-gate 			if (ep->re_type == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
17150Sstevel@tonic-gate 				rc_node_ptr_assign(&ep->re_node,
17160Sstevel@tonic-gate 				    &cp->rc_notify_ptr);
17170Sstevel@tonic-gate 			} else {
17180Sstevel@tonic-gate 				result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
17190Sstevel@tonic-gate 			}
17200Sstevel@tonic-gate 			entity_release(ep);
17210Sstevel@tonic-gate 		} else {
17220Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
17230Sstevel@tonic-gate 		}
17240Sstevel@tonic-gate 		rc_node_clear(&cp->rc_notify_ptr, 0);
17250Sstevel@tonic-gate 	}
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
17280Sstevel@tonic-gate 	assert(cp->rc_notify_thr == pthread_self());
17290Sstevel@tonic-gate 	cp->rc_notify_thr = 0;
17300Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	out->rpr_response = result;
17330Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
17340Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate /*
17380Sstevel@tonic-gate  * Can return:
17390Sstevel@tonic-gate  *	_PERMISSION_DENIED	not enough privileges to do request.
17400Sstevel@tonic-gate  *	_BAD_REQUEST		name is not valid or reserved
17410Sstevel@tonic-gate  *	_TRUNCATED		name is too long for current repository path
17420Sstevel@tonic-gate  *	_UNKNOWN		failed for unknown reason (details written to
17430Sstevel@tonic-gate  *				console)
17440Sstevel@tonic-gate  *	_BACKEND_READONLY	backend is not writable
17450Sstevel@tonic-gate  *
17460Sstevel@tonic-gate  *	_SUCCESS		Backup completed successfully.
17470Sstevel@tonic-gate  */
17480Sstevel@tonic-gate static rep_protocol_responseid_t
17490Sstevel@tonic-gate backup_repository(repcache_client_t *cp,
17500Sstevel@tonic-gate     struct rep_protocol_backup_request *rpr)
17510Sstevel@tonic-gate {
17520Sstevel@tonic-gate 	rep_protocol_responseid_t result;
17530Sstevel@tonic-gate 	ucred_t *uc = get_ucred();
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	if (!client_is_privileged() && (uc == NULL || ucred_geteuid(uc) != 0))
17560Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 	rpr->rpr_name[REP_PROTOCOL_NAME_LEN - 1] = 0;
17590Sstevel@tonic-gate 	if (strcmp(rpr->rpr_name, REPOSITORY_BOOT_BACKUP) == 0)
17600Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
17630Sstevel@tonic-gate 	if (rpr->rpr_changeid != cp->rc_changeid) {
17640Sstevel@tonic-gate 		result = backend_create_backup(rpr->rpr_name);
17650Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
17660Sstevel@tonic-gate 			cp->rc_changeid = rpr->rpr_changeid;
17670Sstevel@tonic-gate 	} else {
17680Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
17690Sstevel@tonic-gate 	}
17700Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 	return (result);
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 
17760Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_f(repcache_client_t *cp,
17770Sstevel@tonic-gate     const void *rpr);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate /*ARGSUSED*/
17800Sstevel@tonic-gate static void
17810Sstevel@tonic-gate simple_handler(repcache_client_t *cp, const void *in, size_t insz,
17820Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
17830Sstevel@tonic-gate {
17840Sstevel@tonic-gate 	protocol_simple_f *f = (protocol_simple_f *)arg;
17850Sstevel@tonic-gate 	rep_protocol_response_t *out = out_arg;
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
17880Sstevel@tonic-gate 	assert(f != NULL);
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 	out->rpr_response = (*f)(cp, in);
17910Sstevel@tonic-gate }
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_fd_f(repcache_client_t *cp,
17940Sstevel@tonic-gate     const void *rpr, int *out_fd);
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate /*ARGSUSED*/
17970Sstevel@tonic-gate static void
17980Sstevel@tonic-gate simple_fd_handler(repcache_client_t *cp, const void *in, size_t insz,
17990Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg, int *out_fd)
18000Sstevel@tonic-gate {
18010Sstevel@tonic-gate 	protocol_simple_fd_f *f = (protocol_simple_fd_f *)arg;
18020Sstevel@tonic-gate 	rep_protocol_response_t *out = out_arg;
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
18050Sstevel@tonic-gate 	assert(f != NULL);
18060Sstevel@tonic-gate 
18070Sstevel@tonic-gate 	out->rpr_response = (*f)(cp, in, out_fd);
18080Sstevel@tonic-gate }
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate typedef void protocol_handler_f(repcache_client_t *, const void *in,
18110Sstevel@tonic-gate     size_t insz, void *out, size_t *outsz, void *arg);
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate typedef void protocol_handler_fdret_f(repcache_client_t *, const void *in,
18140Sstevel@tonic-gate     size_t insz, void *out, size_t *outsz, void *arg, int *fd_out);
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate #define	PROTO(p, f, in) {						\
18170Sstevel@tonic-gate 		p, #p, simple_handler, (void *)(&f), NULL,		\
18180Sstevel@tonic-gate 		    sizeof (in), sizeof (rep_protocol_response_t), 0	\
18190Sstevel@tonic-gate 	}
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate #define	PROTO_FD_OUT(p, f, in) {					\
18220Sstevel@tonic-gate 		p, #p, NULL, (void *)(&f), simple_fd_handler,		\
18230Sstevel@tonic-gate 		    sizeof (in),					\
18240Sstevel@tonic-gate 		    sizeof (rep_protocol_response_t),			\
18250Sstevel@tonic-gate 		    PROTO_FLAG_RETFD					\
18260Sstevel@tonic-gate 	}
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate #define	PROTO_VARIN(p, f, insz) {					\
18290Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
18300Sstevel@tonic-gate 		    insz, sizeof (rep_protocol_response_t),		\
18310Sstevel@tonic-gate 		    PROTO_FLAG_VARINPUT					\
18320Sstevel@tonic-gate 	}
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate #define	PROTO_UINT_OUT(p, f, in) {					\
18350Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
18360Sstevel@tonic-gate 		    sizeof (in),					\
18370Sstevel@tonic-gate 		    sizeof (struct rep_protocol_integer_response), 0	\
18380Sstevel@tonic-gate 	}
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate #define	PROTO_NAME_OUT(p, f, in) {					\
18410Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
18420Sstevel@tonic-gate 		    sizeof (in),					\
18430Sstevel@tonic-gate 		    sizeof (struct rep_protocol_name_response), 0	\
18440Sstevel@tonic-gate 	}
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate #define	PROTO_FMRI_OUT(p, f, in) {					\
18470Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
18480Sstevel@tonic-gate 		    sizeof (in),					\
18490Sstevel@tonic-gate 		    sizeof (struct rep_protocol_fmri_response), 0	\
18500Sstevel@tonic-gate 	}
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate #define	PROTO_VALUE_OUT(p, f, in) {					\
18530Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
18540Sstevel@tonic-gate 		    sizeof (in),					\
18550Sstevel@tonic-gate 		    sizeof (struct rep_protocol_value_response), 0	\
18560Sstevel@tonic-gate 	}
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate #define	PROTO_PANIC(p)	{ p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
18590Sstevel@tonic-gate #define	PROTO_END()	{ 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate #define	PROTO_FLAG_PANIC	0x00000001	/* should never be called */
18620Sstevel@tonic-gate #define	PROTO_FLAG_VARINPUT	0x00000004	/* in_size is minimum size */
18630Sstevel@tonic-gate #define	PROTO_FLAG_RETFD	0x00000008	/* can also return an FD */
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate #define	PROTO_ALL_FLAGS		0x0000000f	/* all flags */
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate static struct protocol_entry {
18680Sstevel@tonic-gate 	enum rep_protocol_requestid	pt_request;
18690Sstevel@tonic-gate 	const char			*pt_name;
18700Sstevel@tonic-gate 	protocol_handler_f		*pt_handler;
18710Sstevel@tonic-gate 	void				*pt_arg;
18720Sstevel@tonic-gate 	protocol_handler_fdret_f	*pt_fd_handler;
18730Sstevel@tonic-gate 	size_t				pt_in_size;
18740Sstevel@tonic-gate 	size_t				pt_out_max;
18750Sstevel@tonic-gate 	uint32_t			pt_flags;
18760Sstevel@tonic-gate } protocol_table[] = {
18770Sstevel@tonic-gate 	PROTO_PANIC(REP_PROTOCOL_CLOSE),		/* special case */
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_SETUP,		entity_setup,
18800Sstevel@tonic-gate 	    struct rep_protocol_entity_setup),
18810Sstevel@tonic-gate 	PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME,	entity_name,
18820Sstevel@tonic-gate 	    struct rep_protocol_entity_name),
18830Sstevel@tonic-gate 	PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE,	entity_parent_type,
18840Sstevel@tonic-gate 	    struct rep_protocol_entity_parent_type),
18850Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_GET_CHILD,		entity_get_child,
18860Sstevel@tonic-gate 	    struct rep_protocol_entity_get_child),
18870Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_GET_PARENT,		entity_get_parent,
18880Sstevel@tonic-gate 	    struct rep_protocol_entity_parent),
18890Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_GET,			entity_get,
18900Sstevel@tonic-gate 	    struct rep_protocol_entity_get),
18910Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_UPDATE,		entity_update,
18920Sstevel@tonic-gate 	    struct rep_protocol_entity_update),
18930Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD,		entity_create_child,
18940Sstevel@tonic-gate 	    struct rep_protocol_entity_create_child),
18950Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_CREATE_PG,		entity_create_pg,
18960Sstevel@tonic-gate 	    struct rep_protocol_entity_create_pg),
18970Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_DELETE,		entity_delete,
18980Sstevel@tonic-gate 	    struct rep_protocol_entity_delete),
18990Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_RESET,		entity_reset,
19000Sstevel@tonic-gate 	    struct rep_protocol_entity_reset),
19010Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_TEARDOWN,		entity_teardown,
19020Sstevel@tonic-gate 	    struct rep_protocol_entity_teardown),
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_SETUP,			iter_setup,
19050Sstevel@tonic-gate 	    struct rep_protocol_iter_request),
19060Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_START,			iter_start,
19070Sstevel@tonic-gate 	    struct rep_protocol_iter_start),
19080Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_READ,			iter_read,
19090Sstevel@tonic-gate 	    struct rep_protocol_iter_read),
19100Sstevel@tonic-gate 	PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE,	iter_read_value,
19110Sstevel@tonic-gate 	    struct rep_protocol_iter_read_value),
19120Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_RESET,			iter_reset,
19130Sstevel@tonic-gate 	    struct rep_protocol_iter_request),
19140Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_TEARDOWN,		iter_teardown,
19150Sstevel@tonic-gate 	    struct rep_protocol_iter_request),
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL,		next_snaplevel,
19180Sstevel@tonic-gate 	    struct rep_protocol_entity_pair),
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_SNAPSHOT_TAKE,		snapshot_take,
19210Sstevel@tonic-gate 	    struct rep_protocol_snapshot_take),
19220Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED,		snapshot_take_named,
19230Sstevel@tonic-gate 	    struct rep_protocol_snapshot_take_named),
19240Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH,		snapshot_attach,
19250Sstevel@tonic-gate 	    struct rep_protocol_snapshot_attach),
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate 	PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE,	property_get_type,
19280Sstevel@tonic-gate 	    struct rep_protocol_property_request),
19290Sstevel@tonic-gate 	PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE, property_get_value,
19300Sstevel@tonic-gate 	    struct rep_protocol_property_request),
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate 	PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT, propertygrp_notify,
19330Sstevel@tonic-gate 	    struct rep_protocol_propertygrp_request),
19340Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START,	tx_start,
19350Sstevel@tonic-gate 	    struct rep_protocol_transaction_start),
19360Sstevel@tonic-gate 	PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT,	tx_commit,
19370Sstevel@tonic-gate 	    REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE),
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY,		client_add_notify,
19400Sstevel@tonic-gate 	    struct rep_protocol_notify_request),
19410Sstevel@tonic-gate 	PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT,	client_wait,
19420Sstevel@tonic-gate 	    struct rep_protocol_wait_request),
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_BACKUP,			backup_repository,
19450Sstevel@tonic-gate 	    struct rep_protocol_backup_request),
19460Sstevel@tonic-gate 
19470Sstevel@tonic-gate 	PROTO_END()
19480Sstevel@tonic-gate };
19490Sstevel@tonic-gate #undef PROTO
19500Sstevel@tonic-gate #undef PROTO_FMRI_OUT
19510Sstevel@tonic-gate #undef PROTO_NAME_OUT
19520Sstevel@tonic-gate #undef PROTO_UINT_OUT
19530Sstevel@tonic-gate #undef PROTO_PANIC
19540Sstevel@tonic-gate #undef PROTO_END
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate /*
19570Sstevel@tonic-gate  * The number of entries, sans PROTO_END()
19580Sstevel@tonic-gate  */
19590Sstevel@tonic-gate #define	PROTOCOL_ENTRIES \
19600Sstevel@tonic-gate 	    (sizeof (protocol_table) / sizeof (*protocol_table) - 1)
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate #define	PROTOCOL_PREFIX "REP_PROTOCOL_"
19630Sstevel@tonic-gate 
19640Sstevel@tonic-gate int
19650Sstevel@tonic-gate client_init(void)
19660Sstevel@tonic-gate {
19670Sstevel@tonic-gate 	int i;
19680Sstevel@tonic-gate 	struct protocol_entry *e;
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 	if (!client_hash_init())
19710Sstevel@tonic-gate 		return (0);
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 	if (request_log_size > 0) {
19740Sstevel@tonic-gate 		request_log = uu_zalloc(request_log_size *
19750Sstevel@tonic-gate 		    sizeof (request_log_entry_t));
19760Sstevel@tonic-gate 	}
19770Sstevel@tonic-gate 
19780Sstevel@tonic-gate 	/*
19790Sstevel@tonic-gate 	 * update the names to not include REP_PROTOCOL_
19800Sstevel@tonic-gate 	 */
19810Sstevel@tonic-gate 	for (i = 0; i < PROTOCOL_ENTRIES; i++) {
19820Sstevel@tonic-gate 		e = &protocol_table[i];
19830Sstevel@tonic-gate 		assert(strncmp(e->pt_name, PROTOCOL_PREFIX,
19840Sstevel@tonic-gate 		    strlen(PROTOCOL_PREFIX)) == 0);
19850Sstevel@tonic-gate 		e->pt_name += strlen(PROTOCOL_PREFIX);
19860Sstevel@tonic-gate 	}
19870Sstevel@tonic-gate 	/*
19880Sstevel@tonic-gate 	 * verify the protocol table is consistent
19890Sstevel@tonic-gate 	 */
19900Sstevel@tonic-gate 	for (i = 0; i < PROTOCOL_ENTRIES; i++) {
19910Sstevel@tonic-gate 		e = &protocol_table[i];
19920Sstevel@tonic-gate 		assert(e->pt_request == (REP_PROTOCOL_BASE + i));
19930Sstevel@tonic-gate 
19940Sstevel@tonic-gate 		assert((e->pt_flags & ~PROTO_ALL_FLAGS) == 0);
19950Sstevel@tonic-gate 
19960Sstevel@tonic-gate 		if (e->pt_flags & PROTO_FLAG_PANIC)
19970Sstevel@tonic-gate 			assert(e->pt_in_size == 0 && e->pt_out_max == 0 &&
19980Sstevel@tonic-gate 			    e->pt_handler == NULL);
19990Sstevel@tonic-gate 		else
20000Sstevel@tonic-gate 			assert(e->pt_in_size != 0 && e->pt_out_max != 0 &&
20010Sstevel@tonic-gate 			    (e->pt_handler != NULL ||
20020Sstevel@tonic-gate 			    e->pt_fd_handler != NULL));
20030Sstevel@tonic-gate 	}
20040Sstevel@tonic-gate 	assert((REP_PROTOCOL_BASE + i) == REP_PROTOCOL_MAX_REQUEST);
20050Sstevel@tonic-gate 
20060Sstevel@tonic-gate 	assert(protocol_table[i].pt_request == 0);
20070Sstevel@tonic-gate 
20080Sstevel@tonic-gate 	return (1);
20090Sstevel@tonic-gate }
20100Sstevel@tonic-gate 
20110Sstevel@tonic-gate static void
20120Sstevel@tonic-gate client_switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *desc_in,
20130Sstevel@tonic-gate     uint_t n_desc)
20140Sstevel@tonic-gate {
20150Sstevel@tonic-gate 	thread_info_t *ti = thread_self();
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	repcache_client_t *cp;
20180Sstevel@tonic-gate 	uint32_t id = (uint32_t)cookie;
20190Sstevel@tonic-gate 	enum rep_protocol_requestid request_code;
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 	rep_protocol_responseid_t result = INVALID_RESULT;
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate 	struct protocol_entry *e;
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate 	char *retval = NULL;
20260Sstevel@tonic-gate 	size_t retsize = 0;
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 	int retfd = -1;
20290Sstevel@tonic-gate 	door_desc_t desc;
20300Sstevel@tonic-gate 	request_log_entry_t *rlp;
20310Sstevel@tonic-gate 
20320Sstevel@tonic-gate 	rlp = start_log(id);
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 	if (n_desc != 0)
20350Sstevel@tonic-gate 		uu_die("can't happen: %d descriptors @%p (cookie %p)",
20360Sstevel@tonic-gate 		    n_desc, desc_in, cookie);
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 	if (argp == DOOR_UNREF_DATA) {
20390Sstevel@tonic-gate 		client_destroy(id);
20400Sstevel@tonic-gate 		goto bad_end;
20410Sstevel@tonic-gate 	}
20420Sstevel@tonic-gate 
20430Sstevel@tonic-gate 	thread_newstate(ti, TI_CLIENT_CALL);
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate 	/*
20460Sstevel@tonic-gate 	 * To simplify returning just a result code, we set up for
20470Sstevel@tonic-gate 	 * that case here.
20480Sstevel@tonic-gate 	 */
20490Sstevel@tonic-gate 	retval = (char *)&result;
20500Sstevel@tonic-gate 	retsize = sizeof (result);
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 	if (arg_size < sizeof (request_code)) {
20530Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
20540Sstevel@tonic-gate 		goto end_unheld;
20550Sstevel@tonic-gate 	}
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	ti->ti_client_request = (void *)argp;
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate 	/* LINTED alignment */
20600Sstevel@tonic-gate 	request_code = *(uint32_t *)argp;
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	if (rlp != NULL) {
20630Sstevel@tonic-gate 		rlp->rl_request = request_code;
20640Sstevel@tonic-gate 	}
20650Sstevel@tonic-gate 	/*
20660Sstevel@tonic-gate 	 * In order to avoid locking problems on removal, we handle the
20670Sstevel@tonic-gate 	 * "close" case before doing a lookup.
20680Sstevel@tonic-gate 	 */
20690Sstevel@tonic-gate 	if (request_code == REP_PROTOCOL_CLOSE) {
20700Sstevel@tonic-gate 		client_destroy(id);
20710Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
20720Sstevel@tonic-gate 		goto end_unheld;
20730Sstevel@tonic-gate 	}
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate 	cp = client_lookup(id);
20760Sstevel@tonic-gate 	/*
20770Sstevel@tonic-gate 	 * cp is held
20780Sstevel@tonic-gate 	 */
20790Sstevel@tonic-gate 
20800Sstevel@tonic-gate 	if (cp == NULL)
20810Sstevel@tonic-gate 		goto bad_end;
20820Sstevel@tonic-gate 
20830Sstevel@tonic-gate 	if (rlp != NULL)
20840Sstevel@tonic-gate 		rlp->rl_client = cp;
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 	ti->ti_active_client = cp;
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 	if (request_code < REP_PROTOCOL_BASE ||
20890Sstevel@tonic-gate 	    request_code >= REP_PROTOCOL_BASE + PROTOCOL_ENTRIES) {
20900Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
20910Sstevel@tonic-gate 		goto end;
20920Sstevel@tonic-gate 	}
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	e = &protocol_table[request_code - REP_PROTOCOL_BASE];
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 	assert(!(e->pt_flags & PROTO_FLAG_PANIC));
20970Sstevel@tonic-gate 
20980Sstevel@tonic-gate 	if (e->pt_flags & PROTO_FLAG_VARINPUT) {
20990Sstevel@tonic-gate 		if (arg_size < e->pt_in_size) {
21000Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_BAD_REQUEST;
21010Sstevel@tonic-gate 			goto end;
21020Sstevel@tonic-gate 		}
21030Sstevel@tonic-gate 	} else if (arg_size != e->pt_in_size) {
21040Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
21050Sstevel@tonic-gate 		goto end;
21060Sstevel@tonic-gate 	}
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 	if (retsize != e->pt_out_max) {
21090Sstevel@tonic-gate 		retsize = e->pt_out_max;
21100Sstevel@tonic-gate 		retval = alloca(retsize);
21110Sstevel@tonic-gate 	}
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate 	if (e->pt_flags & PROTO_FLAG_RETFD)
21140Sstevel@tonic-gate 		e->pt_fd_handler(cp, argp, arg_size, retval, &retsize,
21150Sstevel@tonic-gate 		    e->pt_arg, &retfd);
21160Sstevel@tonic-gate 	else
21170Sstevel@tonic-gate 		e->pt_handler(cp, argp, arg_size, retval, &retsize, e->pt_arg);
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate end:
21200Sstevel@tonic-gate 	ti->ti_active_client = NULL;
21210Sstevel@tonic-gate 	client_release(cp);
21220Sstevel@tonic-gate 
21230Sstevel@tonic-gate end_unheld:
21240Sstevel@tonic-gate 	if (rlp != NULL) {
21250Sstevel@tonic-gate 		/* LINTED alignment */
21260Sstevel@tonic-gate 		rlp->rl_response = *(uint32_t *)retval;
21270Sstevel@tonic-gate 		end_log();
21280Sstevel@tonic-gate 		rlp = NULL;
21290Sstevel@tonic-gate 	}
21300Sstevel@tonic-gate 	ti->ti_client_request = NULL;
21310Sstevel@tonic-gate 	thread_newstate(ti, TI_DOOR_RETURN);
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate 	if (retval == (char *)&result) {
21340Sstevel@tonic-gate 		assert(result != INVALID_RESULT && retsize == sizeof (result));
21350Sstevel@tonic-gate 	} else {
21360Sstevel@tonic-gate 		/* LINTED alignment */
21370Sstevel@tonic-gate 		result = *(uint32_t *)retval;
21380Sstevel@tonic-gate 	}
21390Sstevel@tonic-gate 	if (retfd != -1) {
21400Sstevel@tonic-gate 		desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
21410Sstevel@tonic-gate 		desc.d_data.d_desc.d_descriptor = retfd;
21420Sstevel@tonic-gate 		(void) door_return(retval, retsize, &desc, 1);
21430Sstevel@tonic-gate 	} else {
21440Sstevel@tonic-gate 		(void) door_return(retval, retsize, NULL, 0);
21450Sstevel@tonic-gate 	}
21460Sstevel@tonic-gate bad_end:
21470Sstevel@tonic-gate 	if (rlp != NULL) {
21480Sstevel@tonic-gate 		rlp->rl_response = -1;
21490Sstevel@tonic-gate 		end_log();
21500Sstevel@tonic-gate 		rlp = NULL;
21510Sstevel@tonic-gate 	}
21520Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
21530Sstevel@tonic-gate }
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate int
21560Sstevel@tonic-gate create_client(pid_t pid, uint32_t debugflags, int privileged, int *out_fd)
21570Sstevel@tonic-gate {
21580Sstevel@tonic-gate 	int fd;
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate 	repcache_client_t *cp;
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 	struct door_info info;
21630Sstevel@tonic-gate 
21640Sstevel@tonic-gate 	int door_flags = DOOR_UNREF | DOOR_REFUSE_DESC;
21650Sstevel@tonic-gate #ifdef DOOR_NO_CANCEL
21660Sstevel@tonic-gate 	door_flags |= DOOR_NO_CANCEL;
21670Sstevel@tonic-gate #endif
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 	cp = client_alloc();
21700Sstevel@tonic-gate 	if (cp == NULL)
21710Sstevel@tonic-gate 		return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate 	(void) pthread_mutex_lock(&client_lock);
21740Sstevel@tonic-gate 	cp->rc_id = ++client_maxid;
21750Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&client_lock);
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate 	cp->rc_all_auths = privileged;
21780Sstevel@tonic-gate 	cp->rc_pid = pid;
21790Sstevel@tonic-gate 	cp->rc_debug = debugflags;
21800Sstevel@tonic-gate 
21810Sstevel@tonic-gate 	cp->rc_doorfd = door_create(client_switcher, (void *)cp->rc_id,
21820Sstevel@tonic-gate 	    door_flags);
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 	if (cp->rc_doorfd < 0) {
21850Sstevel@tonic-gate 		client_free(cp);
21860Sstevel@tonic-gate 		return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
21870Sstevel@tonic-gate 	}
21880Sstevel@tonic-gate #ifdef DOOR_PARAM_DATA_MIN
21890Sstevel@tonic-gate 	(void) door_setparam(cp->rc_doorfd, DOOR_PARAM_DATA_MIN,
21900Sstevel@tonic-gate 	    sizeof (enum rep_protocol_requestid));
21910Sstevel@tonic-gate #endif
21920Sstevel@tonic-gate 
21930Sstevel@tonic-gate 	if ((fd = dup(cp->rc_doorfd)) < 0 ||
21940Sstevel@tonic-gate 	    door_info(cp->rc_doorfd, &info) < 0) {
21950Sstevel@tonic-gate 		if (fd >= 0)
21960Sstevel@tonic-gate 			(void) close(fd);
21970Sstevel@tonic-gate 		(void) door_revoke(cp->rc_doorfd);
21980Sstevel@tonic-gate 		cp->rc_doorfd = -1;
21990Sstevel@tonic-gate 		client_free(cp);
22000Sstevel@tonic-gate 		return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
22010Sstevel@tonic-gate 	}
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 	rc_pg_notify_init(&cp->rc_pg_notify);
22040Sstevel@tonic-gate 	rc_notify_info_init(&cp->rc_notify_info);
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate 	client_insert(cp);
22070Sstevel@tonic-gate 
22080Sstevel@tonic-gate 	cp->rc_doorid = info.di_uniquifier;
22090Sstevel@tonic-gate 	*out_fd = fd;
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 	return (REPOSITORY_DOOR_SUCCESS);
22120Sstevel@tonic-gate }
2213