xref: /onnv-gate/usr/src/cmd/svc/configd/client.c (revision 12130:2dd35fca1632)
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
52832Sjeanm  * Common Development and Distribution License (the "License").
62832Sjeanm  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
215777Stw21770 
220Sstevel@tonic-gate /*
23*12130SMarek.Pospisil@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * This is the client layer for svc.configd.  All direct protocol interactions
280Sstevel@tonic-gate  * are handled here.
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * Essentially, the job of this layer is to turn the idempotent protocol
310Sstevel@tonic-gate  * into a series of non-idempotent calls into the object layer, while
320Sstevel@tonic-gate  * also handling the necessary locking.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <alloca.h>
360Sstevel@tonic-gate #include <assert.h>
375777Stw21770 #include <bsm/adt_event.h>
380Sstevel@tonic-gate #include <door.h>
390Sstevel@tonic-gate #include <errno.h>
405777Stw21770 #include <libintl.h>
410Sstevel@tonic-gate #include <limits.h>
420Sstevel@tonic-gate #include <pthread.h>
430Sstevel@tonic-gate #include <stdio.h>
440Sstevel@tonic-gate #include <stdlib.h>
450Sstevel@tonic-gate #include <string.h>
465777Stw21770 #include <syslog.h>
475777Stw21770 #include <ucred.h>
480Sstevel@tonic-gate #include <unistd.h>
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include <libuutil.h>
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #include "configd.h"
530Sstevel@tonic-gate #include "repcache_protocol.h"
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #define	INVALID_CHANGEID	(0)
560Sstevel@tonic-gate #define	INVALID_DOORID		((door_id_t)-1)
570Sstevel@tonic-gate #define	INVALID_RESULT		((rep_protocol_responseid_t)INT_MIN)
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * lint doesn't like constant assertions
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate #ifdef lint
630Sstevel@tonic-gate #define	assert_nolint(x) (void)0
640Sstevel@tonic-gate #else
650Sstevel@tonic-gate #define	assert_nolint(x) assert(x)
660Sstevel@tonic-gate #endif
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * Protects client linkage and the freelist
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate #define	CLIENT_HASH_SIZE	64
720Sstevel@tonic-gate 
730Sstevel@tonic-gate #pragma align 64(client_hash)
740Sstevel@tonic-gate static client_bucket_t client_hash[CLIENT_HASH_SIZE];
750Sstevel@tonic-gate 
76407Sjwadams static uu_avl_pool_t *entity_pool;
77407Sjwadams static uu_avl_pool_t *iter_pool;
780Sstevel@tonic-gate static uu_list_pool_t *client_pool;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate #define	CLIENT_HASH(id)		(&client_hash[((id) & (CLIENT_HASH_SIZE - 1))])
810Sstevel@tonic-gate 
820Sstevel@tonic-gate uint_t request_log_size = 1024;		/* tunable, before we start */
830Sstevel@tonic-gate 
840Sstevel@tonic-gate static pthread_mutex_t request_log_lock = PTHREAD_MUTEX_INITIALIZER;
850Sstevel@tonic-gate static uint_t request_log_cur;
860Sstevel@tonic-gate request_log_entry_t	*request_log;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate static uint32_t		client_maxid;
890Sstevel@tonic-gate static pthread_mutex_t	client_lock;	/* protects client_maxid */
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static request_log_entry_t *
get_log(void)920Sstevel@tonic-gate get_log(void)
930Sstevel@tonic-gate {
940Sstevel@tonic-gate 	thread_info_t *ti = thread_self();
950Sstevel@tonic-gate 	return (&ti->ti_log);
960Sstevel@tonic-gate }
970Sstevel@tonic-gate 
980Sstevel@tonic-gate void
log_enter(request_log_entry_t * rlp)990Sstevel@tonic-gate log_enter(request_log_entry_t *rlp)
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate 	if (rlp->rl_start != 0 && request_log != NULL) {
1020Sstevel@tonic-gate 		request_log_entry_t *logrlp;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 		(void) pthread_mutex_lock(&request_log_lock);
1050Sstevel@tonic-gate 		assert(request_log_cur < request_log_size);
1060Sstevel@tonic-gate 		logrlp = &request_log[request_log_cur++];
1070Sstevel@tonic-gate 		if (request_log_cur == request_log_size)
1080Sstevel@tonic-gate 			request_log_cur = 0;
1090Sstevel@tonic-gate 		(void) memcpy(logrlp, rlp, sizeof (*rlp));
1100Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&request_log_lock);
1110Sstevel@tonic-gate 	}
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /*
1150Sstevel@tonic-gate  * Note that the svc.configd dmod will join all of the per-thread log entries
1160Sstevel@tonic-gate  * with the main log, so that even if the log is disabled, there is some
1170Sstevel@tonic-gate  * information available.
1180Sstevel@tonic-gate  */
1190Sstevel@tonic-gate static request_log_entry_t *
start_log(uint32_t clientid)1200Sstevel@tonic-gate start_log(uint32_t clientid)
1210Sstevel@tonic-gate {
1220Sstevel@tonic-gate 	request_log_entry_t *rlp = get_log();
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	log_enter(rlp);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	(void) memset(rlp, 0, sizeof (*rlp));
1270Sstevel@tonic-gate 	rlp->rl_start = gethrtime();
1280Sstevel@tonic-gate 	rlp->rl_tid = pthread_self();
1290Sstevel@tonic-gate 	rlp->rl_clientid = clientid;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	return (rlp);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate void
end_log(void)1350Sstevel@tonic-gate end_log(void)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	request_log_entry_t *rlp = get_log();
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	rlp->rl_end = gethrtime();
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate static void
add_log_ptr(request_log_entry_t * rlp,enum rc_ptr_type type,uint32_t id,void * ptr)1430Sstevel@tonic-gate add_log_ptr(request_log_entry_t *rlp, enum rc_ptr_type type, uint32_t id,
1440Sstevel@tonic-gate     void *ptr)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate 	request_log_ptr_t *rpp;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	if (rlp == NULL)
1490Sstevel@tonic-gate 		return;
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	if (rlp->rl_num_ptrs >= MAX_PTRS)
1520Sstevel@tonic-gate 		return;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	rpp = &rlp->rl_ptrs[rlp->rl_num_ptrs++];
1550Sstevel@tonic-gate 	rpp->rlp_type = type;
1560Sstevel@tonic-gate 	rpp->rlp_id = id;
1570Sstevel@tonic-gate 	rpp->rlp_ptr = ptr;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	/*
1600Sstevel@tonic-gate 	 * For entities, it's useful to have the node pointer at the start
1610Sstevel@tonic-gate 	 * of the request.
1620Sstevel@tonic-gate 	 */
1630Sstevel@tonic-gate 	if (type == RC_PTR_TYPE_ENTITY && ptr != NULL)
1640Sstevel@tonic-gate 		rpp->rlp_data = ((repcache_entity_t *)ptr)->re_node.rnp_node;
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate int
client_is_privileged(void)1680Sstevel@tonic-gate client_is_privileged(void)
1690Sstevel@tonic-gate {
1700Sstevel@tonic-gate 	thread_info_t *ti = thread_self();
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	ucred_t *uc;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	if (ti->ti_active_client != NULL &&
1750Sstevel@tonic-gate 	    ti->ti_active_client->rc_all_auths)
1760Sstevel@tonic-gate 		return (1);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if ((uc = get_ucred()) == NULL)
1790Sstevel@tonic-gate 		return (0);
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	return (ucred_is_privileged(uc));
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate /*ARGSUSED*/
1850Sstevel@tonic-gate static int
client_compare(const void * lc_arg,const void * rc_arg,void * private)1860Sstevel@tonic-gate client_compare(const void *lc_arg, const void *rc_arg, void *private)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	uint32_t l_id = ((const repcache_client_t *)lc_arg)->rc_id;
1890Sstevel@tonic-gate 	uint32_t r_id = ((const repcache_client_t *)rc_arg)->rc_id;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	if (l_id > r_id)
1920Sstevel@tonic-gate 		return (1);
1930Sstevel@tonic-gate 	if (l_id < r_id)
1940Sstevel@tonic-gate 		return (-1);
1950Sstevel@tonic-gate 	return (0);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*ARGSUSED*/
1990Sstevel@tonic-gate static int
entity_compare(const void * lc_arg,const void * rc_arg,void * private)2000Sstevel@tonic-gate entity_compare(const void *lc_arg, const void *rc_arg, void *private)
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	uint32_t l_id = ((const repcache_entity_t *)lc_arg)->re_id;
2030Sstevel@tonic-gate 	uint32_t r_id = ((const repcache_entity_t *)rc_arg)->re_id;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	if (l_id > r_id)
2060Sstevel@tonic-gate 		return (1);
2070Sstevel@tonic-gate 	if (l_id < r_id)
2080Sstevel@tonic-gate 		return (-1);
2090Sstevel@tonic-gate 	return (0);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate /*ARGSUSED*/
2130Sstevel@tonic-gate static int
iter_compare(const void * lc_arg,const void * rc_arg,void * private)2140Sstevel@tonic-gate iter_compare(const void *lc_arg, const void *rc_arg, void *private)
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate 	uint32_t l_id = ((const repcache_iter_t *)lc_arg)->ri_id;
2170Sstevel@tonic-gate 	uint32_t r_id = ((const repcache_iter_t *)rc_arg)->ri_id;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	if (l_id > r_id)
2200Sstevel@tonic-gate 		return (1);
2210Sstevel@tonic-gate 	if (l_id < r_id)
2220Sstevel@tonic-gate 		return (-1);
2230Sstevel@tonic-gate 	return (0);
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate static int
client_hash_init(void)2270Sstevel@tonic-gate client_hash_init(void)
2280Sstevel@tonic-gate {
2290Sstevel@tonic-gate 	int x;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	assert_nolint(offsetof(repcache_entity_t, re_id) == 0);
232407Sjwadams 	entity_pool = uu_avl_pool_create("repcache_entitys",
2330Sstevel@tonic-gate 	    sizeof (repcache_entity_t), offsetof(repcache_entity_t, re_link),
234407Sjwadams 	    entity_compare, UU_AVL_POOL_DEBUG);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	assert_nolint(offsetof(repcache_iter_t, ri_id) == 0);
237407Sjwadams 	iter_pool = uu_avl_pool_create("repcache_iters",
2380Sstevel@tonic-gate 	    sizeof (repcache_iter_t), offsetof(repcache_iter_t, ri_link),
239407Sjwadams 	    iter_compare, UU_AVL_POOL_DEBUG);
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	assert_nolint(offsetof(repcache_client_t, rc_id) == 0);
2420Sstevel@tonic-gate 	client_pool = uu_list_pool_create("repcache_clients",
2430Sstevel@tonic-gate 	    sizeof (repcache_client_t), offsetof(repcache_client_t, rc_link),
2440Sstevel@tonic-gate 	    client_compare, UU_LIST_POOL_DEBUG);
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if (entity_pool == NULL || iter_pool == NULL || client_pool == NULL)
2470Sstevel@tonic-gate 		return (0);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	for (x = 0; x < CLIENT_HASH_SIZE; x++) {
2500Sstevel@tonic-gate 		uu_list_t *lp = uu_list_create(client_pool, &client_hash[x],
2510Sstevel@tonic-gate 		    UU_LIST_SORTED);
2520Sstevel@tonic-gate 		if (lp == NULL)
2530Sstevel@tonic-gate 			return (0);
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 		(void) pthread_mutex_init(&client_hash[x].cb_lock, NULL);
2560Sstevel@tonic-gate 		client_hash[x].cb_list = lp;
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	return (1);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate static repcache_client_t *
client_alloc(void)2630Sstevel@tonic-gate client_alloc(void)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 	repcache_client_t *cp;
2660Sstevel@tonic-gate 	cp = uu_zalloc(sizeof (*cp));
2670Sstevel@tonic-gate 	if (cp == NULL)
2680Sstevel@tonic-gate 		return (NULL);
2690Sstevel@tonic-gate 
270407Sjwadams 	cp->rc_entities = uu_avl_create(entity_pool, cp, 0);
271407Sjwadams 	if (cp->rc_entities == NULL)
2720Sstevel@tonic-gate 		goto fail;
2730Sstevel@tonic-gate 
274407Sjwadams 	cp->rc_iters = uu_avl_create(iter_pool, cp, 0);
275407Sjwadams 	if (cp->rc_iters == NULL)
2760Sstevel@tonic-gate 		goto fail;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	uu_list_node_init(cp, &cp->rc_link, client_pool);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	cp->rc_doorfd = -1;
2810Sstevel@tonic-gate 	cp->rc_doorid = INVALID_DOORID;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	(void) pthread_mutex_init(&cp->rc_lock, NULL);
2845777Stw21770 	(void) pthread_mutex_init(&cp->rc_annotate_lock, NULL);
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	rc_node_ptr_init(&cp->rc_notify_ptr);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	return (cp);
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate fail:
291407Sjwadams 	if (cp->rc_iters != NULL)
292407Sjwadams 		uu_avl_destroy(cp->rc_iters);
293407Sjwadams 	if (cp->rc_entities != NULL)
294407Sjwadams 		uu_avl_destroy(cp->rc_entities);
2950Sstevel@tonic-gate 	uu_free(cp);
2960Sstevel@tonic-gate 	return (NULL);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate static void
client_free(repcache_client_t * cp)3000Sstevel@tonic-gate client_free(repcache_client_t *cp)
3010Sstevel@tonic-gate {
3020Sstevel@tonic-gate 	assert(cp->rc_insert_thr == 0);
3030Sstevel@tonic-gate 	assert(cp->rc_refcnt == 0);
3040Sstevel@tonic-gate 	assert(cp->rc_doorfd == -1);
3050Sstevel@tonic-gate 	assert(cp->rc_doorid == INVALID_DOORID);
306407Sjwadams 	assert(uu_avl_first(cp->rc_entities) == NULL);
307407Sjwadams 	assert(uu_avl_first(cp->rc_iters) == NULL);
308407Sjwadams 	uu_avl_destroy(cp->rc_entities);
309407Sjwadams 	uu_avl_destroy(cp->rc_iters);
3100Sstevel@tonic-gate 	uu_list_node_fini(cp, &cp->rc_link, client_pool);
3110Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&cp->rc_lock);
3125777Stw21770 	(void) pthread_mutex_destroy(&cp->rc_annotate_lock);
3135777Stw21770 	rc_node_ptr_free_mem(&cp->rc_notify_ptr);
3140Sstevel@tonic-gate 	uu_free(cp);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate static void
client_insert(repcache_client_t * cp)3180Sstevel@tonic-gate client_insert(repcache_client_t *cp)
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate 	client_bucket_t *bp = CLIENT_HASH(cp->rc_id);
3210Sstevel@tonic-gate 	uu_list_index_t idx;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	assert(cp->rc_id > 0);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	(void) pthread_mutex_lock(&bp->cb_lock);
3260Sstevel@tonic-gate 	/*
3270Sstevel@tonic-gate 	 * We assume it does not already exist
3280Sstevel@tonic-gate 	 */
3290Sstevel@tonic-gate 	(void) uu_list_find(bp->cb_list, cp, NULL, &idx);
3300Sstevel@tonic-gate 	uu_list_insert(bp->cb_list, cp, idx);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&bp->cb_lock);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate static repcache_client_t *
client_lookup(uint32_t id)3360Sstevel@tonic-gate client_lookup(uint32_t id)
3370Sstevel@tonic-gate {
3380Sstevel@tonic-gate 	client_bucket_t *bp = CLIENT_HASH(id);
3390Sstevel@tonic-gate 	repcache_client_t *cp;
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	(void) pthread_mutex_lock(&bp->cb_lock);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	cp = uu_list_find(bp->cb_list, &id, NULL, NULL);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	/*
3460Sstevel@tonic-gate 	 * Bump the reference count
3470Sstevel@tonic-gate 	 */
3480Sstevel@tonic-gate 	if (cp != NULL) {
3490Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cp->rc_lock);
3500Sstevel@tonic-gate 		assert(!(cp->rc_flags & RC_CLIENT_DEAD));
3510Sstevel@tonic-gate 		cp->rc_refcnt++;
3520Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&bp->cb_lock);
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	return (cp);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate static void
client_release(repcache_client_t * cp)3600Sstevel@tonic-gate client_release(repcache_client_t *cp)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
3630Sstevel@tonic-gate 	assert(cp->rc_refcnt > 0);
3640Sstevel@tonic-gate 	assert(cp->rc_insert_thr != pthread_self());
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	--cp->rc_refcnt;
3670Sstevel@tonic-gate 	(void) pthread_cond_broadcast(&cp->rc_cv);
3680Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate  * We only allow one thread to be inserting at a time, to prevent
3730Sstevel@tonic-gate  * insert/insert races.
3740Sstevel@tonic-gate  */
3750Sstevel@tonic-gate static void
client_start_insert(repcache_client_t * cp)3760Sstevel@tonic-gate client_start_insert(repcache_client_t *cp)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
3790Sstevel@tonic-gate 	assert(cp->rc_refcnt > 0);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	while (cp->rc_insert_thr != 0) {
3820Sstevel@tonic-gate 		assert(cp->rc_insert_thr != pthread_self());
3830Sstevel@tonic-gate 		(void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock);
3840Sstevel@tonic-gate 	}
3850Sstevel@tonic-gate 	cp->rc_insert_thr = pthread_self();
3860Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate static void
client_end_insert(repcache_client_t * cp)3900Sstevel@tonic-gate client_end_insert(repcache_client_t *cp)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
3930Sstevel@tonic-gate 	assert(cp->rc_insert_thr == pthread_self());
3940Sstevel@tonic-gate 	cp->rc_insert_thr = 0;
3950Sstevel@tonic-gate 	(void) pthread_cond_broadcast(&cp->rc_cv);
3960Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate /*ARGSUSED*/
4000Sstevel@tonic-gate static repcache_entity_t *
entity_alloc(repcache_client_t * cp)4010Sstevel@tonic-gate entity_alloc(repcache_client_t *cp)
4020Sstevel@tonic-gate {
4030Sstevel@tonic-gate 	repcache_entity_t *ep = uu_zalloc(sizeof (repcache_entity_t));
4040Sstevel@tonic-gate 	if (ep != NULL) {
405407Sjwadams 		uu_avl_node_init(ep, &ep->re_link, entity_pool);
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 	return (ep);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate static void
entity_add(repcache_client_t * cp,repcache_entity_t * ep)4110Sstevel@tonic-gate entity_add(repcache_client_t *cp, repcache_entity_t *ep)
4120Sstevel@tonic-gate {
413407Sjwadams 	uu_avl_index_t idx;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
4160Sstevel@tonic-gate 	assert(cp->rc_insert_thr == pthread_self());
4170Sstevel@tonic-gate 
418407Sjwadams 	(void) uu_avl_find(cp->rc_entities, ep, NULL, &idx);
419407Sjwadams 	uu_avl_insert(cp->rc_entities, ep, idx);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate static repcache_entity_t *
entity_find(repcache_client_t * cp,uint32_t id)4250Sstevel@tonic-gate entity_find(repcache_client_t *cp, uint32_t id)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	repcache_entity_t *ep;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
430407Sjwadams 	ep = uu_avl_find(cp->rc_entities, &id, NULL, NULL);
4310Sstevel@tonic-gate 	if (ep != NULL) {
4320Sstevel@tonic-gate 		add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, ep);
4330Sstevel@tonic-gate 		(void) pthread_mutex_lock(&ep->re_lock);
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	return (ep);
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate /*
4410Sstevel@tonic-gate  * Fails with
4420Sstevel@tonic-gate  *   _DUPLICATE_ID - the ids are equal
4430Sstevel@tonic-gate  *   _UNKNOWN_ID - an id does not designate an active register
4440Sstevel@tonic-gate  */
4450Sstevel@tonic-gate static int
entity_find2(repcache_client_t * cp,uint32_t id1,repcache_entity_t ** out1,uint32_t id2,repcache_entity_t ** out2)4460Sstevel@tonic-gate entity_find2(repcache_client_t *cp, uint32_t id1, repcache_entity_t **out1,
4470Sstevel@tonic-gate     uint32_t id2, repcache_entity_t **out2)
4480Sstevel@tonic-gate {
4490Sstevel@tonic-gate 	repcache_entity_t *e1, *e2;
4500Sstevel@tonic-gate 	request_log_entry_t *rlp;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	if (id1 == id2)
4530Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_DUPLICATE_ID);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
456407Sjwadams 	e1 = uu_avl_find(cp->rc_entities, &id1, NULL, NULL);
457407Sjwadams 	e2 = uu_avl_find(cp->rc_entities, &id2, NULL, NULL);
4580Sstevel@tonic-gate 	if (e1 == NULL || e2 == NULL) {
4590Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
4600Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	assert(e1 != e2);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	/*
4660Sstevel@tonic-gate 	 * locks are ordered by id number
4670Sstevel@tonic-gate 	 */
4680Sstevel@tonic-gate 	if (id1 < id2) {
4690Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e1->re_lock);
4700Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e2->re_lock);
4710Sstevel@tonic-gate 	} else {
4720Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e2->re_lock);
4730Sstevel@tonic-gate 		(void) pthread_mutex_lock(&e1->re_lock);
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 	*out1 = e1;
4760Sstevel@tonic-gate 	*out2 = e2;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	if ((rlp = get_log()) != NULL) {
4810Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id1, e1);
4820Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id2, e2);
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate static void
entity_release(repcache_entity_t * ep)4890Sstevel@tonic-gate entity_release(repcache_entity_t *ep)
4900Sstevel@tonic-gate {
4910Sstevel@tonic-gate 	assert(ep->re_node.rnp_node == NULL ||
4920Sstevel@tonic-gate 	    !MUTEX_HELD(&ep->re_node.rnp_node->rn_lock));
4930Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ep->re_lock);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate static void
entity_destroy(repcache_entity_t * entity)4970Sstevel@tonic-gate entity_destroy(repcache_entity_t *entity)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	(void) pthread_mutex_lock(&entity->re_lock);
5000Sstevel@tonic-gate 	rc_node_clear(&entity->re_node, 0);
5010Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&entity->re_lock);
5020Sstevel@tonic-gate 
503407Sjwadams 	uu_avl_node_fini(entity, &entity->re_link, entity_pool);
5040Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&entity->re_lock);
5055777Stw21770 	rc_node_ptr_free_mem(&entity->re_node);
5060Sstevel@tonic-gate 	uu_free(entity);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate static void
entity_remove(repcache_client_t * cp,uint32_t id)5100Sstevel@tonic-gate entity_remove(repcache_client_t *cp, uint32_t id)
5110Sstevel@tonic-gate {
5120Sstevel@tonic-gate 	repcache_entity_t *entity;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
515407Sjwadams 	entity = uu_avl_find(cp->rc_entities, &id, NULL, NULL);
5167266Sbustos 	if (entity != NULL) {
5177266Sbustos 		add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, entity);
5187266Sbustos 
519407Sjwadams 		uu_avl_remove(cp->rc_entities, entity);
5207266Sbustos 	}
5210Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	if (entity != NULL)
5240Sstevel@tonic-gate 		entity_destroy(entity);
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate static void
entity_cleanup(repcache_client_t * cp)5280Sstevel@tonic-gate entity_cleanup(repcache_client_t *cp)
5290Sstevel@tonic-gate {
5300Sstevel@tonic-gate 	repcache_entity_t *ep;
5310Sstevel@tonic-gate 	void *cookie = NULL;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
534407Sjwadams 	while ((ep = uu_avl_teardown(cp->rc_entities, &cookie)) != NULL) {
5350Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
5360Sstevel@tonic-gate 		entity_destroy(ep);
5370Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cp->rc_lock);
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate /*ARGSUSED*/
5430Sstevel@tonic-gate static repcache_iter_t *
iter_alloc(repcache_client_t * cp)5440Sstevel@tonic-gate iter_alloc(repcache_client_t *cp)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate 	repcache_iter_t *iter;
5470Sstevel@tonic-gate 	iter = uu_zalloc(sizeof (repcache_iter_t));
5480Sstevel@tonic-gate 	if (iter != NULL)
549407Sjwadams 		uu_avl_node_init(iter, &iter->ri_link, iter_pool);
5500Sstevel@tonic-gate 	return (iter);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate static void
iter_add(repcache_client_t * cp,repcache_iter_t * iter)5540Sstevel@tonic-gate iter_add(repcache_client_t *cp, repcache_iter_t *iter)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate 	uu_list_index_t idx;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
5590Sstevel@tonic-gate 	assert(cp->rc_insert_thr == pthread_self());
5600Sstevel@tonic-gate 
561407Sjwadams 	(void) uu_avl_find(cp->rc_iters, iter, NULL, &idx);
562407Sjwadams 	uu_avl_insert(cp->rc_iters, iter, idx);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate static repcache_iter_t *
iter_find(repcache_client_t * cp,uint32_t id)5680Sstevel@tonic-gate iter_find(repcache_client_t *cp, uint32_t id)
5690Sstevel@tonic-gate {
5700Sstevel@tonic-gate 	repcache_iter_t *iter;
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
5730Sstevel@tonic-gate 
574407Sjwadams 	iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL);
5750Sstevel@tonic-gate 	if (iter != NULL) {
5760Sstevel@tonic-gate 		add_log_ptr(get_log(), RC_PTR_TYPE_ITER, id, iter);
5770Sstevel@tonic-gate 		(void) pthread_mutex_lock(&iter->ri_lock);
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	return (iter);
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate /*
5850Sstevel@tonic-gate  * Fails with
5860Sstevel@tonic-gate  *   _UNKNOWN_ID - iter_id or entity_id does not designate an active register
5870Sstevel@tonic-gate  */
5880Sstevel@tonic-gate static int
iter_find_w_entity(repcache_client_t * cp,uint32_t iter_id,repcache_iter_t ** iterp,uint32_t entity_id,repcache_entity_t ** epp)5890Sstevel@tonic-gate iter_find_w_entity(repcache_client_t *cp, uint32_t iter_id,
5900Sstevel@tonic-gate     repcache_iter_t **iterp, uint32_t entity_id, repcache_entity_t **epp)
5910Sstevel@tonic-gate {
5920Sstevel@tonic-gate 	repcache_iter_t *iter;
5930Sstevel@tonic-gate 	repcache_entity_t *ep;
5940Sstevel@tonic-gate 	request_log_entry_t *rlp;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
597407Sjwadams 	iter = uu_avl_find(cp->rc_iters, &iter_id, NULL, NULL);
598407Sjwadams 	ep = uu_avl_find(cp->rc_entities, &entity_id, NULL, NULL);
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	assert(iter == NULL || !MUTEX_HELD(&iter->ri_lock));
6010Sstevel@tonic-gate 	assert(ep == NULL || !MUTEX_HELD(&ep->re_lock));
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if (iter == NULL || ep == NULL) {
6040Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
6050Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	(void) pthread_mutex_lock(&iter->ri_lock);
6090Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ep->re_lock);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	*iterp = iter;
6140Sstevel@tonic-gate 	*epp = ep;
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	if ((rlp = get_log()) != NULL) {
6170Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, entity_id, ep);
6180Sstevel@tonic-gate 		add_log_ptr(rlp, RC_PTR_TYPE_ITER, iter_id, iter);
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate static void
iter_release(repcache_iter_t * iter)6250Sstevel@tonic-gate iter_release(repcache_iter_t *iter)
6260Sstevel@tonic-gate {
6270Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&iter->ri_lock);
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate static void
iter_destroy(repcache_iter_t * iter)6310Sstevel@tonic-gate iter_destroy(repcache_iter_t *iter)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate 	(void) pthread_mutex_lock(&iter->ri_lock);
6340Sstevel@tonic-gate 	rc_iter_destroy(&iter->ri_iter);
6350Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&iter->ri_lock);
6360Sstevel@tonic-gate 
637407Sjwadams 	uu_avl_node_fini(iter, &iter->ri_link, iter_pool);
6380Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&iter->ri_lock);
6390Sstevel@tonic-gate 	uu_free(iter);
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate static void
iter_remove(repcache_client_t * cp,uint32_t id)6430Sstevel@tonic-gate iter_remove(repcache_client_t *cp, uint32_t id)
6440Sstevel@tonic-gate {
6450Sstevel@tonic-gate 	repcache_iter_t *iter;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
648407Sjwadams 	iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL);
6490Sstevel@tonic-gate 	if (iter != NULL)
650407Sjwadams 		uu_avl_remove(cp->rc_iters, iter);
6510Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	if (iter != NULL)
6540Sstevel@tonic-gate 		iter_destroy(iter);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate static void
iter_cleanup(repcache_client_t * cp)6580Sstevel@tonic-gate iter_cleanup(repcache_client_t *cp)
6590Sstevel@tonic-gate {
6600Sstevel@tonic-gate 	repcache_iter_t *iter;
6610Sstevel@tonic-gate 	void *cookie = NULL;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
664407Sjwadams 	while ((iter = uu_avl_teardown(cp->rc_iters, &cookie)) != NULL) {
6650Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
6660Sstevel@tonic-gate 		iter_destroy(iter);
6670Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cp->rc_lock);
6680Sstevel@tonic-gate 	}
6690Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate /*
6730Sstevel@tonic-gate  * Ensure that the passed client id is no longer usable, wait for any
6740Sstevel@tonic-gate  * outstanding invocations to complete, then destroy the client
6750Sstevel@tonic-gate  * structure.
6760Sstevel@tonic-gate  */
6770Sstevel@tonic-gate static void
client_destroy(uint32_t id)6780Sstevel@tonic-gate client_destroy(uint32_t id)
6790Sstevel@tonic-gate {
6800Sstevel@tonic-gate 	client_bucket_t *bp = CLIENT_HASH(id);
6810Sstevel@tonic-gate 	repcache_client_t *cp;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	(void) pthread_mutex_lock(&bp->cb_lock);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	cp = uu_list_find(bp->cb_list, &id, NULL, NULL);
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	if (cp == NULL) {
6880Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&bp->cb_lock);
6890Sstevel@tonic-gate 		return;
6900Sstevel@tonic-gate 	}
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	uu_list_remove(bp->cb_list, cp);
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&bp->cb_lock);
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	/* kick the waiters out */
6970Sstevel@tonic-gate 	rc_notify_info_fini(&cp->rc_notify_info);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
7000Sstevel@tonic-gate 	assert(!(cp->rc_flags & RC_CLIENT_DEAD));
7010Sstevel@tonic-gate 	cp->rc_flags |= RC_CLIENT_DEAD;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	if (cp->rc_doorfd != -1) {
7040Sstevel@tonic-gate 		if (door_revoke(cp->rc_doorfd) < 0)
7050Sstevel@tonic-gate 			perror("door_revoke");
7060Sstevel@tonic-gate 		cp->rc_doorfd = -1;
7070Sstevel@tonic-gate 		cp->rc_doorid = INVALID_DOORID;
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	while (cp->rc_refcnt > 0)
7110Sstevel@tonic-gate 		(void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	assert(cp->rc_insert_thr == 0 && cp->rc_notify_thr == 0);
7140Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	/*
7170Sstevel@tonic-gate 	 * destroy outstanding objects
7180Sstevel@tonic-gate 	 */
7190Sstevel@tonic-gate 	entity_cleanup(cp);
7200Sstevel@tonic-gate 	iter_cleanup(cp);
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	/*
7230Sstevel@tonic-gate 	 * clean up notifications
7240Sstevel@tonic-gate 	 */
7250Sstevel@tonic-gate 	rc_pg_notify_fini(&cp->rc_pg_notify);
7260Sstevel@tonic-gate 
7275777Stw21770 	/*
7285777Stw21770 	 * clean up annotations
7295777Stw21770 	 */
7305777Stw21770 	if (cp->rc_operation != NULL)
7315777Stw21770 		free((void *)cp->rc_operation);
7325777Stw21770 	if (cp->rc_file != NULL)
7335777Stw21770 		free((void *)cp->rc_file);
7345777Stw21770 
7355777Stw21770 	/*
7365777Stw21770 	 * End audit session.
7375777Stw21770 	 */
7385777Stw21770 	(void) adt_end_session(cp->rc_adt_session);
7395777Stw21770 
7400Sstevel@tonic-gate 	client_free(cp);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate /*
7440Sstevel@tonic-gate  * Fails with
7450Sstevel@tonic-gate  *   _TYPE_MISMATCH - the entity is already set up with a different type
7460Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
7470Sstevel@tonic-gate  */
7480Sstevel@tonic-gate static int
entity_setup(repcache_client_t * cp,struct rep_protocol_entity_setup * rpr)7490Sstevel@tonic-gate entity_setup(repcache_client_t *cp, struct rep_protocol_entity_setup *rpr)
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate 	repcache_entity_t *ep;
7520Sstevel@tonic-gate 	uint32_t type;
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	client_start_insert(cp);
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) {
7570Sstevel@tonic-gate 		type = ep->re_type;
7580Sstevel@tonic-gate 		entity_release(ep);
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 		client_end_insert(cp);
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		if (type != rpr->rpr_entitytype)
7630Sstevel@tonic-gate 			return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
7640Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	switch (type = rpr->rpr_entitytype) {
7680Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SCOPE:
7690Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SERVICE:
7700Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE:
7710Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
7720Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPLEVEL:
7730Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
7740Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTY:
7750Sstevel@tonic-gate 		break;
7760Sstevel@tonic-gate 	default:
7770Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	ep = entity_alloc(cp);
7810Sstevel@tonic-gate 	if (ep == NULL) {
7820Sstevel@tonic-gate 		client_end_insert(cp);
7830Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	ep->re_id = rpr->rpr_entityid;
7870Sstevel@tonic-gate 	ep->re_changeid = INVALID_CHANGEID;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	ep->re_type = type;
7900Sstevel@tonic-gate 	rc_node_ptr_init(&ep->re_node);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	entity_add(cp, ep);
7930Sstevel@tonic-gate 	client_end_insert(cp);
7940Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
7950Sstevel@tonic-gate }
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate /*ARGSUSED*/
7980Sstevel@tonic-gate static void
entity_name(repcache_client_t * cp,const void * in,size_t insz,void * out_arg,size_t * outsz,void * arg)7990Sstevel@tonic-gate entity_name(repcache_client_t *cp, const void *in, size_t insz, void *out_arg,
8000Sstevel@tonic-gate     size_t *outsz, void *arg)
8010Sstevel@tonic-gate {
8020Sstevel@tonic-gate 	const struct rep_protocol_entity_name *rpr = in;
8030Sstevel@tonic-gate 	struct rep_protocol_name_response *out = out_arg;
8040Sstevel@tonic-gate 	repcache_entity_t *ep;
8050Sstevel@tonic-gate 	size_t sz = sizeof (out->rpr_name);
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	if (ep == NULL) {
8120Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
8130Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
8140Sstevel@tonic-gate 		return;
8150Sstevel@tonic-gate 	}
8160Sstevel@tonic-gate 	out->rpr_response = rc_node_name(&ep->re_node, out->rpr_name,
8170Sstevel@tonic-gate 	    sz, rpr->rpr_answertype, &sz);
8180Sstevel@tonic-gate 	entity_release(ep);
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * If we fail, we only return the response code.
8220Sstevel@tonic-gate 	 * If we succeed, we don't return anything after the '\0' in rpr_name.
8230Sstevel@tonic-gate 	 */
8240Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS)
8250Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
8260Sstevel@tonic-gate 	else
8270Sstevel@tonic-gate 		*outsz = offsetof(struct rep_protocol_name_response,
8280Sstevel@tonic-gate 		    rpr_name[sz + 1]);
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate /*ARGSUSED*/
8320Sstevel@tonic-gate static void
entity_parent_type(repcache_client_t * cp,const void * in,size_t insz,void * out_arg,size_t * outsz,void * arg)8330Sstevel@tonic-gate entity_parent_type(repcache_client_t *cp, const void *in, size_t insz,
8340Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate 	const struct rep_protocol_entity_name *rpr = in;
8370Sstevel@tonic-gate 	struct rep_protocol_integer_response *out = out_arg;
8380Sstevel@tonic-gate 	repcache_entity_t *ep;
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	if (ep == NULL) {
8450Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
8460Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
8470Sstevel@tonic-gate 		return;
8480Sstevel@tonic-gate 	}
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	out->rpr_response = rc_node_parent_type(&ep->re_node, &out->rpr_value);
8510Sstevel@tonic-gate 	entity_release(ep);
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS)
8540Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate /*
8580Sstevel@tonic-gate  * Fails with
8590Sstevel@tonic-gate  *   _DUPLICATE_ID - the ids are equal
8600Sstevel@tonic-gate  *   _UNKNOWN_ID - an id does not designate an active register
8610Sstevel@tonic-gate  *   _INVALID_TYPE - type is invalid
8620Sstevel@tonic-gate  *   _TYPE_MISMATCH - np doesn't carry children of type type
8630Sstevel@tonic-gate  *   _DELETED - np has been deleted
8640Sstevel@tonic-gate  *   _NOT_FOUND - no child with that name/type combo found
8650Sstevel@tonic-gate  *   _NO_RESOURCES
8660Sstevel@tonic-gate  *   _BACKEND_ACCESS
8670Sstevel@tonic-gate  */
8680Sstevel@tonic-gate static int
entity_get_child(repcache_client_t * cp,struct rep_protocol_entity_get_child * rpr)8690Sstevel@tonic-gate entity_get_child(repcache_client_t *cp,
8700Sstevel@tonic-gate     struct rep_protocol_entity_get_child *rpr)
8710Sstevel@tonic-gate {
8720Sstevel@tonic-gate 	repcache_entity_t *parent, *child;
8730Sstevel@tonic-gate 	int result;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	uint32_t parentid = rpr->rpr_entityid;
8760Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_childid;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	result = entity_find2(cp, childid, &child, parentid, &parent);
8790Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
8800Sstevel@tonic-gate 		return (result);
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	result = rc_node_get_child(&parent->re_node, rpr->rpr_name,
8850Sstevel@tonic-gate 	    child->re_type, &child->re_node);
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	entity_release(child);
8880Sstevel@tonic-gate 	entity_release(parent);
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	return (result);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate /*
8940Sstevel@tonic-gate  * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED,
8950Sstevel@tonic-gate  * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS.
8960Sstevel@tonic-gate  * Fails with
8970Sstevel@tonic-gate  *   _DUPLICATE_ID - the ids are equal
8980Sstevel@tonic-gate  *   _UNKNOWN_ID - an id does not designate an active register
8990Sstevel@tonic-gate  *   _NOT_SET - child is not set
9000Sstevel@tonic-gate  *   _DELETED - child has been deleted
9010Sstevel@tonic-gate  *   _TYPE_MISMATCH - child's parent does not match that of the parent register
9020Sstevel@tonic-gate  *   _NOT_FOUND - child has no parent (and is a scope)
9030Sstevel@tonic-gate  */
9040Sstevel@tonic-gate static int
entity_get_parent(repcache_client_t * cp,struct rep_protocol_entity_parent * rpr)9050Sstevel@tonic-gate entity_get_parent(repcache_client_t *cp, struct rep_protocol_entity_parent *rpr)
9060Sstevel@tonic-gate {
9070Sstevel@tonic-gate 	repcache_entity_t *child, *parent;
9080Sstevel@tonic-gate 	int result;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_entityid;
9110Sstevel@tonic-gate 	uint32_t outid = rpr->rpr_outid;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	result = entity_find2(cp, childid, &child, outid, &parent);
9140Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
9150Sstevel@tonic-gate 		return (result);
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	result = rc_node_get_parent(&child->re_node, parent->re_type,
9180Sstevel@tonic-gate 	    &parent->re_node);
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	entity_release(child);
9210Sstevel@tonic-gate 	entity_release(parent);
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	return (result);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate static int
entity_get(repcache_client_t * cp,struct rep_protocol_entity_get * rpr)9270Sstevel@tonic-gate entity_get(repcache_client_t *cp, struct rep_protocol_entity_get *rpr)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate 	repcache_entity_t *ep;
9300Sstevel@tonic-gate 	int result;
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	if (ep == NULL)
9350Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	switch (rpr->rpr_object) {
9380Sstevel@tonic-gate 	case RP_ENTITY_GET_INVALIDATE:
9390Sstevel@tonic-gate 		rc_node_clear(&ep->re_node, 0);
9400Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
9410Sstevel@tonic-gate 		break;
9420Sstevel@tonic-gate 	case RP_ENTITY_GET_MOST_LOCAL_SCOPE:
9430Sstevel@tonic-gate 		result = rc_local_scope(ep->re_type, &ep->re_node);
9440Sstevel@tonic-gate 		break;
9450Sstevel@tonic-gate 	default:
9460Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
9470Sstevel@tonic-gate 		break;
9480Sstevel@tonic-gate 	}
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	entity_release(ep);
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	return (result);
9530Sstevel@tonic-gate }
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate static int
entity_update(repcache_client_t * cp,struct rep_protocol_entity_update * rpr)9560Sstevel@tonic-gate entity_update(repcache_client_t *cp, struct rep_protocol_entity_update *rpr)
9570Sstevel@tonic-gate {
9580Sstevel@tonic-gate 	repcache_entity_t *ep;
9590Sstevel@tonic-gate 	int result;
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
9620Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	if (ep == NULL)
9670Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	if (ep->re_changeid == rpr->rpr_changeid) {
9700Sstevel@tonic-gate 		result = REP_PROTOCOL_DONE;
9710Sstevel@tonic-gate 	} else {
9720Sstevel@tonic-gate 		result = rc_node_update(&ep->re_node);
9730Sstevel@tonic-gate 		if (result == REP_PROTOCOL_DONE)
9740Sstevel@tonic-gate 			ep->re_changeid = rpr->rpr_changeid;
9750Sstevel@tonic-gate 	}
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	entity_release(ep);
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	return (result);
9800Sstevel@tonic-gate }
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate static int
entity_reset(repcache_client_t * cp,struct rep_protocol_entity_reset * rpr)9830Sstevel@tonic-gate entity_reset(repcache_client_t *cp, struct rep_protocol_entity_reset *rpr)
9840Sstevel@tonic-gate {
9850Sstevel@tonic-gate 	repcache_entity_t *ep;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
9880Sstevel@tonic-gate 	if (ep == NULL)
9890Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	rc_node_clear(&ep->re_node, 0);
9920Sstevel@tonic-gate 	ep->re_txstate = REPCACHE_TX_INIT;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	entity_release(ep);
9950Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate /*
9990Sstevel@tonic-gate  * Fails with
10000Sstevel@tonic-gate  *   _BAD_REQUEST - request has invalid changeid
10010Sstevel@tonic-gate  *		    rpr_name is invalid
10020Sstevel@tonic-gate  *		    cannot create children for parent's type of node
10030Sstevel@tonic-gate  *   _DUPLICATE_ID - request has duplicate ids
10040Sstevel@tonic-gate  *   _UNKNOWN_ID - request has unknown id
10050Sstevel@tonic-gate  *   _DELETED - parent has been deleted
10060Sstevel@tonic-gate  *   _NOT_SET - parent is reset
10070Sstevel@tonic-gate  *   _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP
10080Sstevel@tonic-gate  *   _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid
10090Sstevel@tonic-gate  *   _TYPE_MISMATCH - parent cannot have children of type rpr_childtype
10100Sstevel@tonic-gate  *   _NO_RESOURCES
10110Sstevel@tonic-gate  *   _PERMISSION_DENIED
10120Sstevel@tonic-gate  *   _BACKEND_ACCESS
10130Sstevel@tonic-gate  *   _BACKEND_READONLY
10140Sstevel@tonic-gate  *   _EXISTS - child already exists
10150Sstevel@tonic-gate  */
10160Sstevel@tonic-gate static int
entity_create_child(repcache_client_t * cp,struct rep_protocol_entity_create_child * rpr)10170Sstevel@tonic-gate entity_create_child(repcache_client_t *cp,
10180Sstevel@tonic-gate     struct rep_protocol_entity_create_child *rpr)
10190Sstevel@tonic-gate {
10200Sstevel@tonic-gate 	repcache_entity_t *parent;
10210Sstevel@tonic-gate 	repcache_entity_t *child;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	uint32_t parentid = rpr->rpr_entityid;
10240Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_childid;
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	int result;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
10290Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	result = entity_find2(cp, parentid, &parent, childid, &child);
10320Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
10330Sstevel@tonic-gate 		return (result);
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	if (child->re_changeid == rpr->rpr_changeid) {
10380Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
10390Sstevel@tonic-gate 	} else {
10400Sstevel@tonic-gate 		result = rc_node_create_child(&parent->re_node,
10410Sstevel@tonic-gate 		    rpr->rpr_childtype, rpr->rpr_name, &child->re_node);
10420Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
10430Sstevel@tonic-gate 			child->re_changeid = rpr->rpr_changeid;
10440Sstevel@tonic-gate 	}
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	entity_release(parent);
10470Sstevel@tonic-gate 	entity_release(child);
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	return (result);
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate static int
entity_create_pg(repcache_client_t * cp,struct rep_protocol_entity_create_pg * rpr)10530Sstevel@tonic-gate entity_create_pg(repcache_client_t *cp,
10540Sstevel@tonic-gate     struct rep_protocol_entity_create_pg *rpr)
10550Sstevel@tonic-gate {
10560Sstevel@tonic-gate 	repcache_entity_t *parent;
10570Sstevel@tonic-gate 	repcache_entity_t *child;
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	uint32_t parentid = rpr->rpr_entityid;
10600Sstevel@tonic-gate 	uint32_t childid = rpr->rpr_childid;
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	int result;
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
10650Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	result = entity_find2(cp, parentid, &parent, childid, &child);
10680Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
10690Sstevel@tonic-gate 		return (result);
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
10720Sstevel@tonic-gate 	rpr->rpr_type[sizeof (rpr->rpr_type) - 1] = 0;
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	if (child->re_changeid == rpr->rpr_changeid) {
10750Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
10760Sstevel@tonic-gate 	} else {
10770Sstevel@tonic-gate 		result = rc_node_create_child_pg(&parent->re_node,
10780Sstevel@tonic-gate 		    child->re_type, rpr->rpr_name, rpr->rpr_type,
10790Sstevel@tonic-gate 		    rpr->rpr_flags, &child->re_node);
10800Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
10810Sstevel@tonic-gate 			child->re_changeid = rpr->rpr_changeid;
10820Sstevel@tonic-gate 	}
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	entity_release(parent);
10850Sstevel@tonic-gate 	entity_release(child);
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	return (result);
10880Sstevel@tonic-gate }
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate static int
entity_delete(repcache_client_t * cp,struct rep_protocol_entity_delete * rpr)10910Sstevel@tonic-gate entity_delete(repcache_client_t *cp,
10920Sstevel@tonic-gate     struct rep_protocol_entity_delete *rpr)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate 	repcache_entity_t *entity;
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	uint32_t entityid = rpr->rpr_entityid;
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	int result;
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	if (rpr->rpr_changeid == INVALID_CHANGEID)
11010Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	entity = entity_find(cp, entityid);
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	if (entity == NULL)
11060Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 	if (entity->re_changeid == rpr->rpr_changeid) {
11090Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
11100Sstevel@tonic-gate 	} else {
11110Sstevel@tonic-gate 		result = rc_node_delete(&entity->re_node);
11120Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
11130Sstevel@tonic-gate 			entity->re_changeid = rpr->rpr_changeid;
11140Sstevel@tonic-gate 	}
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	entity_release(entity);
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	return (result);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate static rep_protocol_responseid_t
entity_teardown(repcache_client_t * cp,struct rep_protocol_entity_teardown * rpr)11220Sstevel@tonic-gate entity_teardown(repcache_client_t *cp, struct rep_protocol_entity_teardown *rpr)
11230Sstevel@tonic-gate {
11240Sstevel@tonic-gate 	entity_remove(cp, rpr->rpr_entityid);
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate /*
11300Sstevel@tonic-gate  * Fails with
11310Sstevel@tonic-gate  *   _MISORDERED - the iterator exists and is not reset
11320Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
11330Sstevel@tonic-gate  */
11340Sstevel@tonic-gate static int
iter_setup(repcache_client_t * cp,struct rep_protocol_iter_request * rpr)11350Sstevel@tonic-gate iter_setup(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
11360Sstevel@tonic-gate {
11370Sstevel@tonic-gate 	repcache_iter_t *iter;
11380Sstevel@tonic-gate 	uint32_t sequence;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	client_start_insert(cp);
11410Sstevel@tonic-gate 	/*
11420Sstevel@tonic-gate 	 * If the iter already exists, and hasn't been read from,
11430Sstevel@tonic-gate 	 * we assume the previous call succeeded.
11440Sstevel@tonic-gate 	 */
11450Sstevel@tonic-gate 	if ((iter = iter_find(cp, rpr->rpr_iterid)) != NULL) {
11460Sstevel@tonic-gate 		sequence = iter->ri_sequence;
11470Sstevel@tonic-gate 		iter_release(iter);
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 		client_end_insert(cp);
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 		if (sequence != 0)
11520Sstevel@tonic-gate 			return (REP_PROTOCOL_FAIL_MISORDERED);
11530Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);
11540Sstevel@tonic-gate 	}
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	iter = iter_alloc(cp);
11570Sstevel@tonic-gate 	if (iter == NULL) {
11580Sstevel@tonic-gate 		client_end_insert(cp);
11590Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
11600Sstevel@tonic-gate 	}
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 	iter->ri_id = rpr->rpr_iterid;
11630Sstevel@tonic-gate 	iter->ri_type = REP_PROTOCOL_TYPE_INVALID;
11640Sstevel@tonic-gate 	iter->ri_sequence = 0;
11650Sstevel@tonic-gate 	iter_add(cp, iter);
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	client_end_insert(cp);
11680Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate /*
11720Sstevel@tonic-gate  * Fails with
11730Sstevel@tonic-gate  *   _UNKNOWN_ID
11740Sstevel@tonic-gate  *   _MISORDERED - iterator has already been started
11750Sstevel@tonic-gate  *   _NOT_SET
11760Sstevel@tonic-gate  *   _DELETED
11770Sstevel@tonic-gate  *   _TYPE_MISMATCH - entity cannot have type children
11780Sstevel@tonic-gate  *   _BAD_REQUEST - rpr_flags is invalid
11790Sstevel@tonic-gate  *		    rpr_pattern is invalid
11800Sstevel@tonic-gate  *   _NO_RESOURCES
11810Sstevel@tonic-gate  *   _INVALID_TYPE
11820Sstevel@tonic-gate  *   _BACKEND_ACCESS
11830Sstevel@tonic-gate  */
11840Sstevel@tonic-gate static int
iter_start(repcache_client_t * cp,struct rep_protocol_iter_start * rpr)11850Sstevel@tonic-gate iter_start(repcache_client_t *cp, struct rep_protocol_iter_start *rpr)
11860Sstevel@tonic-gate {
11870Sstevel@tonic-gate 	int result;
11880Sstevel@tonic-gate 	repcache_iter_t *iter;
11890Sstevel@tonic-gate 	repcache_entity_t *ep;
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter,
11920Sstevel@tonic-gate 	    rpr->rpr_entity, &ep);
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
11950Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	if (iter->ri_sequence > 1) {
11980Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_MISORDERED;
11990Sstevel@tonic-gate 		goto end;
12000Sstevel@tonic-gate 	}
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 	if (iter->ri_sequence == 1) {
12030Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
12040Sstevel@tonic-gate 		goto end;
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0;
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	result = rc_node_setup_iter(&ep->re_node, &iter->ri_iter,
12100Sstevel@tonic-gate 	    rpr->rpr_itertype, rpr->rpr_flags, rpr->rpr_pattern);
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS)
12130Sstevel@tonic-gate 		iter->ri_sequence++;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate end:
12160Sstevel@tonic-gate 	iter_release(iter);
12170Sstevel@tonic-gate 	entity_release(ep);
12180Sstevel@tonic-gate 	return (result);
12190Sstevel@tonic-gate }
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate /*
12220Sstevel@tonic-gate  * Returns
12230Sstevel@tonic-gate  *   _UNKNOWN_ID
12240Sstevel@tonic-gate  *   _NOT_SET - iter has not been started
12250Sstevel@tonic-gate  *   _MISORDERED
12260Sstevel@tonic-gate  *   _BAD_REQUEST - iter walks values
12270Sstevel@tonic-gate  *   _TYPE_MISMATCH - iter does not walk type entities
12280Sstevel@tonic-gate  *   _DELETED - parent was deleted
12290Sstevel@tonic-gate  *   _NO_RESOURCES
12300Sstevel@tonic-gate  *   _INVALID_TYPE - type is invalid
12310Sstevel@tonic-gate  *   _DONE
12320Sstevel@tonic-gate  *   _SUCCESS
12330Sstevel@tonic-gate  *
12340Sstevel@tonic-gate  * For composed property group iterators, can also return
12350Sstevel@tonic-gate  *   _TYPE_MISMATCH - parent cannot have type children
12360Sstevel@tonic-gate  *   _BACKEND_ACCESS
12370Sstevel@tonic-gate  */
12380Sstevel@tonic-gate static rep_protocol_responseid_t
iter_read(repcache_client_t * cp,struct rep_protocol_iter_read * rpr)12390Sstevel@tonic-gate iter_read(repcache_client_t *cp, struct rep_protocol_iter_read *rpr)
12400Sstevel@tonic-gate {
12410Sstevel@tonic-gate 	rep_protocol_responseid_t result;
12420Sstevel@tonic-gate 	repcache_iter_t *iter;
12430Sstevel@tonic-gate 	repcache_entity_t *ep;
12440Sstevel@tonic-gate 	uint32_t sequence;
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter,
12470Sstevel@tonic-gate 	    rpr->rpr_entityid, &ep);
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
12500Sstevel@tonic-gate 		return (result);
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	sequence = rpr->rpr_sequence;
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	if (iter->ri_sequence == 0) {
12550Sstevel@tonic-gate 		iter_release(iter);
12560Sstevel@tonic-gate 		entity_release(ep);
12570Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NOT_SET);
12580Sstevel@tonic-gate 	}
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 	if (sequence == 1) {
12610Sstevel@tonic-gate 		iter_release(iter);
12620Sstevel@tonic-gate 		entity_release(ep);
12630Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_MISORDERED);
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	if (sequence == iter->ri_sequence) {
12670Sstevel@tonic-gate 		iter_release(iter);
12680Sstevel@tonic-gate 		entity_release(ep);
12690Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);
12700Sstevel@tonic-gate 	}
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	if (sequence == iter->ri_sequence + 1) {
12730Sstevel@tonic-gate 		result = rc_iter_next(iter->ri_iter, &ep->re_node,
12740Sstevel@tonic-gate 		    ep->re_type);
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
12770Sstevel@tonic-gate 			iter->ri_sequence++;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 		iter_release(iter);
12800Sstevel@tonic-gate 		entity_release(ep);
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 		return (result);
12830Sstevel@tonic-gate 	}
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	iter_release(iter);
12860Sstevel@tonic-gate 	entity_release(ep);
12870Sstevel@tonic-gate 	return (REP_PROTOCOL_FAIL_MISORDERED);
12880Sstevel@tonic-gate }
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate /*ARGSUSED*/
12910Sstevel@tonic-gate static void
iter_read_value(repcache_client_t * cp,const void * in,size_t insz,void * out_arg,size_t * outsz,void * arg)12920Sstevel@tonic-gate iter_read_value(repcache_client_t *cp, const void *in, size_t insz,
12930Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
12940Sstevel@tonic-gate {
12950Sstevel@tonic-gate 	const struct rep_protocol_iter_read_value *rpr = in;
12960Sstevel@tonic-gate 	struct rep_protocol_value_response *out = out_arg;
12970Sstevel@tonic-gate 	rep_protocol_responseid_t result;
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	repcache_iter_t *iter;
13000Sstevel@tonic-gate 	uint32_t sequence;
13010Sstevel@tonic-gate 	int repeat;
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	iter = iter_find(cp, rpr->rpr_iterid);
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	if (iter == NULL) {
13080Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
13090Sstevel@tonic-gate 		goto out;
13100Sstevel@tonic-gate 	}
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	sequence = rpr->rpr_sequence;
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	if (iter->ri_sequence == 0) {
13150Sstevel@tonic-gate 		iter_release(iter);
13160Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_NOT_SET;
13170Sstevel@tonic-gate 		goto out;
13180Sstevel@tonic-gate 	}
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	repeat = (sequence == iter->ri_sequence);
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 	if (sequence == 1 || (!repeat && sequence != iter->ri_sequence + 1)) {
13230Sstevel@tonic-gate 		iter_release(iter);
13240Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_MISORDERED;
13250Sstevel@tonic-gate 		goto out;
13260Sstevel@tonic-gate 	}
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	result = rc_iter_next_value(iter->ri_iter, out, outsz, repeat);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	if (!repeat && result == REP_PROTOCOL_SUCCESS)
13310Sstevel@tonic-gate 		iter->ri_sequence++;
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	iter_release(iter);
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate out:
13360Sstevel@tonic-gate 	/*
13370Sstevel@tonic-gate 	 * If we fail, we only return the response code.
13380Sstevel@tonic-gate 	 * If we succeed, rc_iter_next_value has shortened *outsz
13390Sstevel@tonic-gate 	 * to only include the value bytes needed.
13400Sstevel@tonic-gate 	 */
13410Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS && result != REP_PROTOCOL_DONE)
13420Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	out->rpr_response = result;
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate static int
iter_reset(repcache_client_t * cp,struct rep_protocol_iter_request * rpr)13480Sstevel@tonic-gate iter_reset(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
13490Sstevel@tonic-gate {
13500Sstevel@tonic-gate 	repcache_iter_t *iter = iter_find(cp, rpr->rpr_iterid);
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 	if (iter == NULL)
13530Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	if (iter->ri_sequence != 0) {
13560Sstevel@tonic-gate 		iter->ri_sequence = 0;
13570Sstevel@tonic-gate 		rc_iter_destroy(&iter->ri_iter);
13580Sstevel@tonic-gate 	}
13590Sstevel@tonic-gate 	iter_release(iter);
13600Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate static rep_protocol_responseid_t
iter_teardown(repcache_client_t * cp,struct rep_protocol_iter_request * rpr)13640Sstevel@tonic-gate iter_teardown(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
13650Sstevel@tonic-gate {
13660Sstevel@tonic-gate 	iter_remove(cp, rpr->rpr_iterid);
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
13690Sstevel@tonic-gate }
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate static rep_protocol_responseid_t
tx_start(repcache_client_t * cp,struct rep_protocol_transaction_start * rpr)13720Sstevel@tonic-gate tx_start(repcache_client_t *cp, struct rep_protocol_transaction_start *rpr)
13730Sstevel@tonic-gate {
13740Sstevel@tonic-gate 	repcache_entity_t *tx;
13750Sstevel@tonic-gate 	repcache_entity_t *ep;
13760Sstevel@tonic-gate 	rep_protocol_responseid_t result;
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	uint32_t txid = rpr->rpr_entityid_tx;
13790Sstevel@tonic-gate 	uint32_t epid = rpr->rpr_entityid;
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	result = entity_find2(cp, txid, &tx, epid, &ep);
13820Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
13830Sstevel@tonic-gate 		return (result);
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	if (tx->re_txstate == REPCACHE_TX_SETUP) {
13860Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
13870Sstevel@tonic-gate 		goto end;
13880Sstevel@tonic-gate 	}
13890Sstevel@tonic-gate 	if (tx->re_txstate != REPCACHE_TX_INIT) {
13900Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_MISORDERED;
13910Sstevel@tonic-gate 		goto end;
13920Sstevel@tonic-gate 	}
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 	result = rc_node_setup_tx(&ep->re_node, &tx->re_node);
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate end:
13970Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS)
13980Sstevel@tonic-gate 		tx->re_txstate = REPCACHE_TX_SETUP;
13990Sstevel@tonic-gate 	else
14000Sstevel@tonic-gate 		rc_node_clear(&tx->re_node, 0);
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate 	entity_release(ep);
14030Sstevel@tonic-gate 	entity_release(tx);
14040Sstevel@tonic-gate 	return (result);
14050Sstevel@tonic-gate }
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate /*ARGSUSED*/
14080Sstevel@tonic-gate static void
tx_commit(repcache_client_t * cp,const void * in,size_t insz,void * out_arg,size_t * outsz,void * arg)14090Sstevel@tonic-gate tx_commit(repcache_client_t *cp, const void *in, size_t insz,
14100Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
14110Sstevel@tonic-gate {
14120Sstevel@tonic-gate 	struct rep_protocol_response *out = out_arg;
14130Sstevel@tonic-gate 	const struct rep_protocol_transaction_commit *rpr = in;
14140Sstevel@tonic-gate 	repcache_entity_t *tx;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
14170Sstevel@tonic-gate 	assert(insz >= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE);
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 	if (rpr->rpr_size != insz) {
14200Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_BAD_REQUEST;
14210Sstevel@tonic-gate 		return;
14220Sstevel@tonic-gate 	}
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	tx = entity_find(cp, rpr->rpr_entityid);
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	if (tx == NULL) {
14270Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
14280Sstevel@tonic-gate 		return;
14290Sstevel@tonic-gate 	}
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	switch (tx->re_txstate) {
14320Sstevel@tonic-gate 	case REPCACHE_TX_INIT:
14330Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_MISORDERED;
14340Sstevel@tonic-gate 		break;
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	case REPCACHE_TX_SETUP:
14370Sstevel@tonic-gate 		out->rpr_response = rc_tx_commit(&tx->re_node, rpr->rpr_cmd,
14380Sstevel@tonic-gate 		    insz - REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE);
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 		if (out->rpr_response == REP_PROTOCOL_SUCCESS) {
14410Sstevel@tonic-gate 			tx->re_txstate = REPCACHE_TX_COMMITTED;
14420Sstevel@tonic-gate 			rc_node_clear(&tx->re_node, 0);
14430Sstevel@tonic-gate 		}
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 		break;
14460Sstevel@tonic-gate 	case REPCACHE_TX_COMMITTED:
14470Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_SUCCESS;
14480Sstevel@tonic-gate 		break;
14490Sstevel@tonic-gate 	default:
14500Sstevel@tonic-gate 		assert(0);	/* CAN'T HAPPEN */
14510Sstevel@tonic-gate 		break;
14520Sstevel@tonic-gate 	}
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	entity_release(tx);
14550Sstevel@tonic-gate }
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate static rep_protocol_responseid_t
next_snaplevel(repcache_client_t * cp,struct rep_protocol_entity_pair * rpr)14580Sstevel@tonic-gate next_snaplevel(repcache_client_t *cp, struct rep_protocol_entity_pair *rpr)
14590Sstevel@tonic-gate {
14600Sstevel@tonic-gate 	repcache_entity_t *src;
14610Sstevel@tonic-gate 	repcache_entity_t *dest;
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entity_src;
14640Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entity_dst;
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 	int result;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
14690Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
14700Sstevel@tonic-gate 		return (result);
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	result = rc_node_next_snaplevel(&src->re_node, &dest->re_node);
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	entity_release(src);
14750Sstevel@tonic-gate 	entity_release(dest);
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	return (result);
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate static rep_protocol_responseid_t
snapshot_take(repcache_client_t * cp,struct rep_protocol_snapshot_take * rpr)14810Sstevel@tonic-gate snapshot_take(repcache_client_t *cp, struct rep_protocol_snapshot_take *rpr)
14820Sstevel@tonic-gate {
14830Sstevel@tonic-gate 	repcache_entity_t *src;
14840Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entityid_src;
14850Sstevel@tonic-gate 	repcache_entity_t *dest;
14860Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entityid_dest;
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	int result;
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
14910Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
14920Sstevel@tonic-gate 		return (result);
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
14950Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
14960Sstevel@tonic-gate 	} else {
14970Sstevel@tonic-gate 		rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 		if (rpr->rpr_flags == REP_SNAPSHOT_NEW)
15000Sstevel@tonic-gate 			result = rc_snapshot_take_new(&src->re_node, NULL,
15010Sstevel@tonic-gate 			    NULL, rpr->rpr_name, &dest->re_node);
15020Sstevel@tonic-gate 		else if (rpr->rpr_flags == REP_SNAPSHOT_ATTACH &&
15030Sstevel@tonic-gate 		    rpr->rpr_name[0] == 0)
15040Sstevel@tonic-gate 			result = rc_snapshot_take_attach(&src->re_node,
15050Sstevel@tonic-gate 			    &dest->re_node);
15060Sstevel@tonic-gate 		else
15070Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_BAD_REQUEST;
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 	entity_release(src);
15100Sstevel@tonic-gate 	entity_release(dest);
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	return (result);
15130Sstevel@tonic-gate }
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate static rep_protocol_responseid_t
snapshot_take_named(repcache_client_t * cp,struct rep_protocol_snapshot_take_named * rpr)15160Sstevel@tonic-gate snapshot_take_named(repcache_client_t *cp,
15170Sstevel@tonic-gate     struct rep_protocol_snapshot_take_named *rpr)
15180Sstevel@tonic-gate {
15190Sstevel@tonic-gate 	repcache_entity_t *src;
15200Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entityid_src;
15210Sstevel@tonic-gate 	repcache_entity_t *dest;
15220Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entityid_dest;
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	int result;
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
15270Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
15280Sstevel@tonic-gate 		return (result);
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 	if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
15310Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
15320Sstevel@tonic-gate 	} else {
15330Sstevel@tonic-gate 		rpr->rpr_svcname[sizeof (rpr->rpr_svcname) - 1] = 0;
15340Sstevel@tonic-gate 		rpr->rpr_instname[sizeof (rpr->rpr_instname) - 1] = 0;
15350Sstevel@tonic-gate 		rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 		result = rc_snapshot_take_new(&src->re_node, rpr->rpr_svcname,
15380Sstevel@tonic-gate 		    rpr->rpr_instname, rpr->rpr_name, &dest->re_node);
15390Sstevel@tonic-gate 	}
15400Sstevel@tonic-gate 	entity_release(src);
15410Sstevel@tonic-gate 	entity_release(dest);
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 	return (result);
15440Sstevel@tonic-gate }
15450Sstevel@tonic-gate 
15460Sstevel@tonic-gate static rep_protocol_responseid_t
snapshot_attach(repcache_client_t * cp,struct rep_protocol_snapshot_attach * rpr)15470Sstevel@tonic-gate snapshot_attach(repcache_client_t *cp, struct rep_protocol_snapshot_attach *rpr)
15480Sstevel@tonic-gate {
15490Sstevel@tonic-gate 	repcache_entity_t *src;
15500Sstevel@tonic-gate 	uint32_t srcid = rpr->rpr_entityid_src;
15510Sstevel@tonic-gate 	repcache_entity_t *dest;
15520Sstevel@tonic-gate 	uint32_t destid = rpr->rpr_entityid_dest;
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 	int result;
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate 	result = entity_find2(cp, srcid, &src, destid, &dest);
15570Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
15580Sstevel@tonic-gate 		return (result);
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	result = rc_snapshot_attach(&src->re_node, &dest->re_node);
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	entity_release(src);
15630Sstevel@tonic-gate 	entity_release(dest);
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	return (result);
15660Sstevel@tonic-gate }
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate /*ARGSUSED*/
15690Sstevel@tonic-gate static void
property_get_type(repcache_client_t * cp,const void * in,size_t insz,void * out_arg,size_t * outsz,void * arg)15700Sstevel@tonic-gate property_get_type(repcache_client_t *cp, const void *in, size_t insz,
15710Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
15720Sstevel@tonic-gate {
15730Sstevel@tonic-gate 	const struct rep_protocol_property_request *rpr = in;
15740Sstevel@tonic-gate 	struct rep_protocol_integer_response *out = out_arg;
15750Sstevel@tonic-gate 	repcache_entity_t *ep;
15760Sstevel@tonic-gate 	rep_protocol_value_type_t t = 0;
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 	if (ep == NULL) {
15830Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
15840Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
15850Sstevel@tonic-gate 		return;
15860Sstevel@tonic-gate 	}
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 	out->rpr_response = rc_node_get_property_type(&ep->re_node, &t);
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	entity_release(ep);
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS)
15930Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
15940Sstevel@tonic-gate 	else
15950Sstevel@tonic-gate 		out->rpr_value = t;
15960Sstevel@tonic-gate }
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate /*
15990Sstevel@tonic-gate  * Fails with:
16000Sstevel@tonic-gate  *	_UNKNOWN_ID - an id does not designate an active register
16010Sstevel@tonic-gate  *	_NOT_SET - The property is not set
16020Sstevel@tonic-gate  *	_DELETED - The property has been deleted
16030Sstevel@tonic-gate  *	_TYPE_MISMATCH - The object is not a property
16040Sstevel@tonic-gate  *	_NOT_FOUND - The property has no values.
16050Sstevel@tonic-gate  *
16060Sstevel@tonic-gate  * Succeeds with:
16070Sstevel@tonic-gate  *	_SUCCESS - The property has 1 value.
16080Sstevel@tonic-gate  *	_TRUNCATED - The property has >1 value.
16090Sstevel@tonic-gate  */
16100Sstevel@tonic-gate /*ARGSUSED*/
16110Sstevel@tonic-gate static void
property_get_value(repcache_client_t * cp,const void * in,size_t insz,void * out_arg,size_t * outsz,void * arg)16120Sstevel@tonic-gate property_get_value(repcache_client_t *cp, const void *in, size_t insz,
16130Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
16140Sstevel@tonic-gate {
16150Sstevel@tonic-gate 	const struct rep_protocol_property_request *rpr = in;
16160Sstevel@tonic-gate 	struct rep_protocol_value_response *out = out_arg;
16170Sstevel@tonic-gate 	repcache_entity_t *ep;
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	ep = entity_find(cp, rpr->rpr_entityid);
16220Sstevel@tonic-gate 	if (ep == NULL) {
16230Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
16240Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
16250Sstevel@tonic-gate 		return;
16260Sstevel@tonic-gate 	}
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	out->rpr_response = rc_node_get_property_value(&ep->re_node, out,
16290Sstevel@tonic-gate 	    outsz);
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	entity_release(ep);
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	/*
16340Sstevel@tonic-gate 	 * If we fail, we only return the response code.
16350Sstevel@tonic-gate 	 * If we succeed, rc_node_get_property_value has shortened *outsz
16360Sstevel@tonic-gate 	 * to only include the value bytes needed.
16370Sstevel@tonic-gate 	 */
16380Sstevel@tonic-gate 	if (out->rpr_response != REP_PROTOCOL_SUCCESS &&
16390Sstevel@tonic-gate 	    out->rpr_response != REP_PROTOCOL_FAIL_TRUNCATED)
16400Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
16410Sstevel@tonic-gate }
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate static rep_protocol_responseid_t
propertygrp_notify(repcache_client_t * cp,struct rep_protocol_propertygrp_request * rpr,int * out_fd)16440Sstevel@tonic-gate propertygrp_notify(repcache_client_t *cp,
16450Sstevel@tonic-gate     struct rep_protocol_propertygrp_request *rpr, int *out_fd)
16460Sstevel@tonic-gate {
16470Sstevel@tonic-gate 	int fds[2];
16480Sstevel@tonic-gate 	int ours, theirs;
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 	rep_protocol_responseid_t result;
16510Sstevel@tonic-gate 	repcache_entity_t *ep;
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 	if (pipe(fds) < 0)
16540Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	ours = fds[0];
16570Sstevel@tonic-gate 	theirs = fds[1];
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	if ((ep = entity_find(cp, rpr->rpr_entityid)) == NULL) {
16600Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
16610Sstevel@tonic-gate 		goto fail;
16620Sstevel@tonic-gate 	}
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 	/*
16650Sstevel@tonic-gate 	 * While the following can race with other threads setting up a
16660Sstevel@tonic-gate 	 * notification, the worst that can happen is that our fd has
16670Sstevel@tonic-gate 	 * already been closed before we return.
16680Sstevel@tonic-gate 	 */
16690Sstevel@tonic-gate 	result = rc_pg_notify_setup(&cp->rc_pg_notify, &ep->re_node,
16700Sstevel@tonic-gate 	    ours);
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 	entity_release(ep);
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
16750Sstevel@tonic-gate 		goto fail;
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	*out_fd = theirs;
16780Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate fail:
16810Sstevel@tonic-gate 	(void) close(ours);
16820Sstevel@tonic-gate 	(void) close(theirs);
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	return (result);
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate static rep_protocol_responseid_t
client_add_notify(repcache_client_t * cp,struct rep_protocol_notify_request * rpr)16880Sstevel@tonic-gate client_add_notify(repcache_client_t *cp,
16890Sstevel@tonic-gate     struct rep_protocol_notify_request *rpr)
16900Sstevel@tonic-gate {
16910Sstevel@tonic-gate 	rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0;
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 	switch (rpr->rpr_type) {
16940Sstevel@tonic-gate 	case REP_PROTOCOL_NOTIFY_PGNAME:
16950Sstevel@tonic-gate 		return (rc_notify_info_add_name(&cp->rc_notify_info,
16960Sstevel@tonic-gate 		    rpr->rpr_pattern));
16970Sstevel@tonic-gate 
16980Sstevel@tonic-gate 	case REP_PROTOCOL_NOTIFY_PGTYPE:
16990Sstevel@tonic-gate 		return (rc_notify_info_add_type(&cp->rc_notify_info,
17000Sstevel@tonic-gate 		    rpr->rpr_pattern));
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 	default:
17030Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
17040Sstevel@tonic-gate 	}
17050Sstevel@tonic-gate }
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate /*ARGSUSED*/
17080Sstevel@tonic-gate static void
client_wait(repcache_client_t * cp,const void * in,size_t insz,void * out_arg,size_t * outsz,void * arg)17090Sstevel@tonic-gate client_wait(repcache_client_t *cp, const void *in, size_t insz,
17100Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
17110Sstevel@tonic-gate {
17120Sstevel@tonic-gate 	int result;
17130Sstevel@tonic-gate 	repcache_entity_t *ep;
17140Sstevel@tonic-gate 	const struct rep_protocol_wait_request *rpr = in;
17150Sstevel@tonic-gate 	struct rep_protocol_fmri_response *out = out_arg;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
17200Sstevel@tonic-gate 	if (cp->rc_notify_thr != 0) {
17210Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cp->rc_lock);
17220Sstevel@tonic-gate 		out->rpr_response = REP_PROTOCOL_FAIL_EXISTS;
17230Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
17240Sstevel@tonic-gate 		return;
17250Sstevel@tonic-gate 	}
17260Sstevel@tonic-gate 	cp->rc_notify_thr = pthread_self();
17270Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	result = rc_notify_info_wait(&cp->rc_notify_info, &cp->rc_notify_ptr,
17300Sstevel@tonic-gate 	    out->rpr_fmri, sizeof (out->rpr_fmri));
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS) {
17330Sstevel@tonic-gate 		if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) {
17340Sstevel@tonic-gate 			if (ep->re_type == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
17350Sstevel@tonic-gate 				rc_node_ptr_assign(&ep->re_node,
17360Sstevel@tonic-gate 				    &cp->rc_notify_ptr);
17370Sstevel@tonic-gate 			} else {
17380Sstevel@tonic-gate 				result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
17390Sstevel@tonic-gate 			}
17400Sstevel@tonic-gate 			entity_release(ep);
17410Sstevel@tonic-gate 		} else {
17420Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
17430Sstevel@tonic-gate 		}
17440Sstevel@tonic-gate 		rc_node_clear(&cp->rc_notify_ptr, 0);
17450Sstevel@tonic-gate 	}
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
17480Sstevel@tonic-gate 	assert(cp->rc_notify_thr == pthread_self());
17490Sstevel@tonic-gate 	cp->rc_notify_thr = 0;
17500Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 	out->rpr_response = result;
17530Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
17540Sstevel@tonic-gate 		*outsz = sizeof (out->rpr_response);
17550Sstevel@tonic-gate }
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate /*
17580Sstevel@tonic-gate  * Can return:
17590Sstevel@tonic-gate  *	_PERMISSION_DENIED	not enough privileges to do request.
17600Sstevel@tonic-gate  *	_BAD_REQUEST		name is not valid or reserved
17610Sstevel@tonic-gate  *	_TRUNCATED		name is too long for current repository path
17620Sstevel@tonic-gate  *	_UNKNOWN		failed for unknown reason (details written to
17630Sstevel@tonic-gate  *				console)
17640Sstevel@tonic-gate  *	_BACKEND_READONLY	backend is not writable
17656035Sstevep  *	_NO_RESOURCES		out of memory
17660Sstevel@tonic-gate  *	_SUCCESS		Backup completed successfully.
17670Sstevel@tonic-gate  */
17680Sstevel@tonic-gate static rep_protocol_responseid_t
backup_repository(repcache_client_t * cp,struct rep_protocol_backup_request * rpr)17690Sstevel@tonic-gate backup_repository(repcache_client_t *cp,
17700Sstevel@tonic-gate     struct rep_protocol_backup_request *rpr)
17710Sstevel@tonic-gate {
17720Sstevel@tonic-gate 	rep_protocol_responseid_t result;
17730Sstevel@tonic-gate 	ucred_t *uc = get_ucred();
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	if (!client_is_privileged() && (uc == NULL || ucred_geteuid(uc) != 0))
17760Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 	rpr->rpr_name[REP_PROTOCOL_NAME_LEN - 1] = 0;
17790Sstevel@tonic-gate 	if (strcmp(rpr->rpr_name, REPOSITORY_BOOT_BACKUP) == 0)
17800Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cp->rc_lock);
17830Sstevel@tonic-gate 	if (rpr->rpr_changeid != cp->rc_changeid) {
17840Sstevel@tonic-gate 		result = backend_create_backup(rpr->rpr_name);
17850Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS)
17860Sstevel@tonic-gate 			cp->rc_changeid = rpr->rpr_changeid;
17870Sstevel@tonic-gate 	} else {
17880Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
17890Sstevel@tonic-gate 	}
17900Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cp->rc_lock);
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate 	return (result);
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate 
17955777Stw21770 /*
17965777Stw21770  * This function captures the information that will be used for an
17975777Stw21770  * annotation audit event.  Specifically, it captures the operation to be
17985777Stw21770  * performed and the name of the file that is being used.  These values are
17995777Stw21770  * copied from the rep_protocol_annotation request at rpr to the client
18005777Stw21770  * structure.  If both these values are null, the client is turning
18015777Stw21770  * annotation off.
18025777Stw21770  *
18035777Stw21770  * Fails with
18045777Stw21770  *	_NO_RESOURCES - unable to allocate memory
18055777Stw21770  */
18065777Stw21770 static rep_protocol_responseid_t
set_annotation(repcache_client_t * cp,struct rep_protocol_annotation * rpr)18075777Stw21770 set_annotation(repcache_client_t *cp, struct rep_protocol_annotation *rpr)
18085777Stw21770 {
18095777Stw21770 	au_id_t audit_uid;
18105777Stw21770 	const char *file = NULL;
18115777Stw21770 	const char *old_ptrs[2];
18125777Stw21770 	const char *operation = NULL;
18135777Stw21770 	rep_protocol_responseid_t rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
18145777Stw21770 	au_asid_t sessionid;
18155777Stw21770 
18165777Stw21770 	(void) memset((void *)old_ptrs, 0, sizeof (old_ptrs));
18175777Stw21770 
18185777Stw21770 	/* Copy rpr_operation and rpr_file if they are not empty strings. */
18195777Stw21770 	if (rpr->rpr_operation[0] != 0) {
18205777Stw21770 		/*
18215777Stw21770 		 * Make sure that client did not send us an unterminated buffer.
18225777Stw21770 		 */
18235777Stw21770 		rpr->rpr_operation[sizeof (rpr->rpr_operation) - 1] = 0;
18245777Stw21770 		if ((operation = strdup(rpr->rpr_operation)) == NULL)
18255777Stw21770 			goto out;
18265777Stw21770 	}
18275777Stw21770 	if (rpr->rpr_file[0] != 0) {
18285777Stw21770 		/*
18295777Stw21770 		 * Make sure that client did not send us an unterminated buffer.
18305777Stw21770 		 */
18315777Stw21770 		rpr->rpr_file[sizeof (rpr->rpr_file) - 1] = 0;
18325777Stw21770 		if ((file = strdup(rpr->rpr_file)) == NULL)
18335777Stw21770 			goto out;
18345777Stw21770 	}
18355777Stw21770 
18365777Stw21770 	(void) pthread_mutex_lock(&cp->rc_annotate_lock);
18375777Stw21770 	/* Save addresses of memory to free when not locked */
18385777Stw21770 	old_ptrs[0] = cp->rc_operation;
18395777Stw21770 	old_ptrs[1] = cp->rc_file;
18405777Stw21770 
18415777Stw21770 	/* Save pointers to annotation strings. */
18425777Stw21770 	cp->rc_operation = operation;
18435777Stw21770 	cp->rc_file = file;
18445777Stw21770 
18455777Stw21770 	/*
18465777Stw21770 	 * Set annotation flag.  Annotations should be turned on if either
18475777Stw21770 	 * operation or file are not NULL.
18485777Stw21770 	 */
18495777Stw21770 	cp->rc_annotate = (operation != NULL) || (file != NULL);
18505777Stw21770 	(void) pthread_mutex_unlock(&cp->rc_annotate_lock);
18515777Stw21770 
18525777Stw21770 	/*
18535777Stw21770 	 * operation and file pointers are saved in cp, so don't free them
18545777Stw21770 	 * during cleanup.
18555777Stw21770 	 */
18565777Stw21770 	operation = NULL;
18575777Stw21770 	file = NULL;
18585777Stw21770 	rc = REP_PROTOCOL_SUCCESS;
18595777Stw21770 
18605777Stw21770 	/*
18615777Stw21770 	 * Native builds are done to create svc.configd-native.  This
18625777Stw21770 	 * program runs only on the Open Solaris build machines to create
18635777Stw21770 	 * the seed repository.  Until the SMF auditing code is distributed
18645777Stw21770 	 * to the Open Solaris build machines, adt_get_unique_id() in the
18655777Stw21770 	 * following code is not a global function in libbsm.  Hence the
18665777Stw21770 	 * following conditional compilation.
18675777Stw21770 	 */
18685777Stw21770 #ifndef	NATIVE_BUILD
18695777Stw21770 	/*
18705777Stw21770 	 * Set the appropriate audit session id.
18715777Stw21770 	 */
18725777Stw21770 	if (cp->rc_annotate) {
18735777Stw21770 		/*
18745777Stw21770 		 * We're starting a group of annotated audit events, so
18755777Stw21770 		 * create and set an audit session ID for this annotation.
18765777Stw21770 		 */
18775777Stw21770 		adt_get_auid(cp->rc_adt_session, &audit_uid);
18785777Stw21770 		sessionid = adt_get_unique_id(audit_uid);
18795777Stw21770 	} else {
18805777Stw21770 		/*
18815777Stw21770 		 * Annotation is done so restore our client audit session
18825777Stw21770 		 * id.
18835777Stw21770 		 */
18845777Stw21770 		sessionid = cp->rc_adt_sessionid;
18855777Stw21770 	}
18865777Stw21770 	adt_set_asid(cp->rc_adt_session, sessionid);
18875777Stw21770 #endif	/* NATIVE_BUILD */
18885777Stw21770 
18895777Stw21770 out:
18905777Stw21770 	if (operation != NULL)
18915777Stw21770 		free((void *)operation);
18925777Stw21770 	if (file != NULL)
18935777Stw21770 		free((void *)file);
18945777Stw21770 	free((void *)old_ptrs[0]);
18955777Stw21770 	free((void *)old_ptrs[1]);
18965777Stw21770 	return (rc);
18975777Stw21770 }
18985777Stw21770 
18995777Stw21770 /*
19005777Stw21770  * Determine if an annotation event needs to be generated.  If it does
19015777Stw21770  * provide the operation and file name that should be used in the event.
19025777Stw21770  *
19035777Stw21770  * Can return:
19045777Stw21770  *	0		No annotation event needed or buffers are not large
19055777Stw21770  *			enough.  Either way an event should not be
19065777Stw21770  *			generated.
19075777Stw21770  *	1		Generate annotation event.
19085777Stw21770  */
19095777Stw21770 int
client_annotation_needed(char * operation,size_t oper_sz,char * file,size_t file_sz)19105777Stw21770 client_annotation_needed(char *operation, size_t oper_sz,
19115777Stw21770     char *file, size_t file_sz)
19125777Stw21770 {
19135777Stw21770 	thread_info_t *ti = thread_self();
19145777Stw21770 	repcache_client_t *cp = ti->ti_active_client;
19155777Stw21770 	int rc = 0;
19165777Stw21770 
19175777Stw21770 	(void) pthread_mutex_lock(&cp->rc_annotate_lock);
19185777Stw21770 	if (cp->rc_annotate) {
19195777Stw21770 		rc = 1;
19205777Stw21770 		if (cp->rc_operation == NULL) {
19215777Stw21770 			if (oper_sz > 0)
19225777Stw21770 				operation[0] = 0;
19235777Stw21770 		} else {
19245777Stw21770 			if (strlcpy(operation, cp->rc_operation, oper_sz) >=
19255777Stw21770 			    oper_sz) {
19265777Stw21770 				/* Buffer overflow, so do not generate event */
19275777Stw21770 				rc = 0;
19285777Stw21770 			}
19295777Stw21770 		}
19305777Stw21770 		if (cp->rc_file == NULL) {
19315777Stw21770 			if (file_sz > 0)
19325777Stw21770 				file[0] = 0;
19335777Stw21770 		} else if (rc == 1) {
19345777Stw21770 			if (strlcpy(file, cp->rc_file, file_sz) >= file_sz) {
19355777Stw21770 				/* Buffer overflow, so do not generate event */
19365777Stw21770 				rc = 0;
19375777Stw21770 			}
19385777Stw21770 		}
19395777Stw21770 	}
19405777Stw21770 	(void) pthread_mutex_unlock(&cp->rc_annotate_lock);
19415777Stw21770 	return (rc);
19425777Stw21770 }
19435777Stw21770 
19445777Stw21770 void
client_annotation_finished()19455777Stw21770 client_annotation_finished()
19465777Stw21770 {
19475777Stw21770 	thread_info_t *ti = thread_self();
19485777Stw21770 	repcache_client_t *cp = ti->ti_active_client;
19495777Stw21770 
19505777Stw21770 	(void) pthread_mutex_lock(&cp->rc_annotate_lock);
19515777Stw21770 	cp->rc_annotate = 0;
19525777Stw21770 	(void) pthread_mutex_unlock(&cp->rc_annotate_lock);
19535777Stw21770 }
19545777Stw21770 
19555777Stw21770 static void
start_audit_session(repcache_client_t * cp)19565777Stw21770 start_audit_session(repcache_client_t *cp)
19575777Stw21770 {
19585777Stw21770 	ucred_t *cred = NULL;
19595777Stw21770 	adt_session_data_t *session;
19605777Stw21770 
19618497SThomas.Whitten@Sun.COM 	/*
19628497SThomas.Whitten@Sun.COM 	 * A NULL session pointer value can legally be used in all
19638497SThomas.Whitten@Sun.COM 	 * subsequent calls to adt_* functions.
19648497SThomas.Whitten@Sun.COM 	 */
19658497SThomas.Whitten@Sun.COM 	cp->rc_adt_session = NULL;
19668497SThomas.Whitten@Sun.COM 
1967*12130SMarek.Pospisil@Sun.COM 	if (!adt_audit_state(AUC_AUDITING))
1968*12130SMarek.Pospisil@Sun.COM 		return;
1969*12130SMarek.Pospisil@Sun.COM 
19708497SThomas.Whitten@Sun.COM 	if (door_ucred(&cred) != 0) {
19718497SThomas.Whitten@Sun.COM 		switch (errno) {
19728497SThomas.Whitten@Sun.COM 		case EAGAIN:
19738497SThomas.Whitten@Sun.COM 		case ENOMEM:
19748497SThomas.Whitten@Sun.COM 			syslog(LOG_ERR, gettext("start_audit_session(): cannot "
19758497SThomas.Whitten@Sun.COM 			    "get ucred.  %m\n"));
19768497SThomas.Whitten@Sun.COM 			return;
19778497SThomas.Whitten@Sun.COM 		case EINVAL:
19788497SThomas.Whitten@Sun.COM 			/*
19798497SThomas.Whitten@Sun.COM 			 * Door client went away.  This is a normal,
19808497SThomas.Whitten@Sun.COM 			 * although infrequent event, so there is no need
19818497SThomas.Whitten@Sun.COM 			 * to create a syslog message.
19828497SThomas.Whitten@Sun.COM 			 */
19838497SThomas.Whitten@Sun.COM 			return;
19848497SThomas.Whitten@Sun.COM 		case EFAULT:
19858497SThomas.Whitten@Sun.COM 		default:
19868497SThomas.Whitten@Sun.COM 			bad_error("door_ucred", errno);
19878497SThomas.Whitten@Sun.COM 			return;
19888497SThomas.Whitten@Sun.COM 		}
19895777Stw21770 	}
19908497SThomas.Whitten@Sun.COM 	if (adt_start_session(&session, NULL, 0) != 0) {
19915777Stw21770 		syslog(LOG_ERR, gettext("start_audit_session(): could not "
19925777Stw21770 		    "start audit session.\n"));
19938497SThomas.Whitten@Sun.COM 		ucred_free(cred);
19948497SThomas.Whitten@Sun.COM 		return;
19955777Stw21770 	}
19968497SThomas.Whitten@Sun.COM 	if (adt_set_from_ucred(session, cred, ADT_NEW) != 0) {
19975777Stw21770 		syslog(LOG_ERR, gettext("start_audit_session(): cannot set "
19985777Stw21770 		    "audit session data from ucred\n"));
19998497SThomas.Whitten@Sun.COM 		/* Something went wrong.  End the session. */
20008497SThomas.Whitten@Sun.COM 		(void) adt_end_session(session);
20018497SThomas.Whitten@Sun.COM 		ucred_free(cred);
20028497SThomas.Whitten@Sun.COM 		return;
20035777Stw21770 	}
20048497SThomas.Whitten@Sun.COM 
20058497SThomas.Whitten@Sun.COM 	/* All went well.  Save the session data and session ID */
20068497SThomas.Whitten@Sun.COM 	cp->rc_adt_session = session;
20078497SThomas.Whitten@Sun.COM 	adt_get_asid(session, &cp->rc_adt_sessionid);
20085777Stw21770 
20095777Stw21770 	ucred_free(cred);
20105777Stw21770 }
20110Sstevel@tonic-gate 
20126035Sstevep /*
20136035Sstevep  * Handle switch client request
20146035Sstevep  *
20156035Sstevep  * This routine can return:
20166035Sstevep  *
20176035Sstevep  *	_PERMISSION_DENIED	not enough privileges to do request.
20186035Sstevep  *	_UNKNOWN		file operation error (details written to
20196035Sstevep  *				the console).
20206035Sstevep  *	_SUCCESS		switch operation is completed.
20216035Sstevep  *	_BACKEND_ACCESS		backend access fails.
20226035Sstevep  *	_NO_RESOURCES		out of memory.
20236035Sstevep  *	_BACKEND_READONLY	backend is not writable.
20246035Sstevep  */
20256035Sstevep static rep_protocol_responseid_t
repository_switch(repcache_client_t * cp,struct rep_protocol_switch_request * rpr)20266035Sstevep repository_switch(repcache_client_t *cp,
20276035Sstevep     struct rep_protocol_switch_request *rpr)
20286035Sstevep {
20296035Sstevep 	rep_protocol_responseid_t result;
20306035Sstevep 	ucred_t *uc = get_ucred();
20316035Sstevep 
20326035Sstevep 	if (!client_is_privileged() && (uc == NULL ||
20336035Sstevep 	    ucred_geteuid(uc) != 0)) {
20346035Sstevep 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
20356035Sstevep 	}
20366035Sstevep 
20376035Sstevep 	(void) pthread_mutex_lock(&cp->rc_lock);
20386035Sstevep 	if (rpr->rpr_changeid != cp->rc_changeid) {
20396035Sstevep 		if ((result = backend_switch(rpr->rpr_flag)) ==
20406035Sstevep 		    REP_PROTOCOL_SUCCESS)
20416035Sstevep 			cp->rc_changeid = rpr->rpr_changeid;
20426035Sstevep 	} else {
20436035Sstevep 		result = REP_PROTOCOL_SUCCESS;
20446035Sstevep 	}
20456035Sstevep 	(void) pthread_mutex_unlock(&cp->rc_lock);
20466035Sstevep 
20476035Sstevep 	return (result);
20486035Sstevep }
20496035Sstevep 
20500Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_f(repcache_client_t *cp,
20510Sstevel@tonic-gate     const void *rpr);
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate /*ARGSUSED*/
20540Sstevel@tonic-gate static void
simple_handler(repcache_client_t * cp,const void * in,size_t insz,void * out_arg,size_t * outsz,void * arg)20550Sstevel@tonic-gate simple_handler(repcache_client_t *cp, const void *in, size_t insz,
20560Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg)
20570Sstevel@tonic-gate {
20580Sstevel@tonic-gate 	protocol_simple_f *f = (protocol_simple_f *)arg;
20590Sstevel@tonic-gate 	rep_protocol_response_t *out = out_arg;
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
20620Sstevel@tonic-gate 	assert(f != NULL);
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate 	out->rpr_response = (*f)(cp, in);
20650Sstevel@tonic-gate }
20660Sstevel@tonic-gate 
20670Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_fd_f(repcache_client_t *cp,
20680Sstevel@tonic-gate     const void *rpr, int *out_fd);
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate /*ARGSUSED*/
20710Sstevel@tonic-gate static void
simple_fd_handler(repcache_client_t * cp,const void * in,size_t insz,void * out_arg,size_t * outsz,void * arg,int * out_fd)20720Sstevel@tonic-gate simple_fd_handler(repcache_client_t *cp, const void *in, size_t insz,
20730Sstevel@tonic-gate     void *out_arg, size_t *outsz, void *arg, int *out_fd)
20740Sstevel@tonic-gate {
20750Sstevel@tonic-gate 	protocol_simple_fd_f *f = (protocol_simple_fd_f *)arg;
20760Sstevel@tonic-gate 	rep_protocol_response_t *out = out_arg;
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	assert(*outsz == sizeof (*out));
20790Sstevel@tonic-gate 	assert(f != NULL);
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 	out->rpr_response = (*f)(cp, in, out_fd);
20820Sstevel@tonic-gate }
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate typedef void protocol_handler_f(repcache_client_t *, const void *in,
20850Sstevel@tonic-gate     size_t insz, void *out, size_t *outsz, void *arg);
20860Sstevel@tonic-gate 
20870Sstevel@tonic-gate typedef void protocol_handler_fdret_f(repcache_client_t *, const void *in,
20880Sstevel@tonic-gate     size_t insz, void *out, size_t *outsz, void *arg, int *fd_out);
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate #define	PROTO(p, f, in) {						\
20910Sstevel@tonic-gate 		p, #p, simple_handler, (void *)(&f), NULL,		\
20920Sstevel@tonic-gate 		    sizeof (in), sizeof (rep_protocol_response_t), 0	\
20930Sstevel@tonic-gate 	}
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate #define	PROTO_FD_OUT(p, f, in) {					\
20960Sstevel@tonic-gate 		p, #p, NULL, (void *)(&f), simple_fd_handler,		\
20970Sstevel@tonic-gate 		    sizeof (in),					\
20980Sstevel@tonic-gate 		    sizeof (rep_protocol_response_t),			\
20990Sstevel@tonic-gate 		    PROTO_FLAG_RETFD					\
21000Sstevel@tonic-gate 	}
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate #define	PROTO_VARIN(p, f, insz) {					\
21030Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
21040Sstevel@tonic-gate 		    insz, sizeof (rep_protocol_response_t),		\
21050Sstevel@tonic-gate 		    PROTO_FLAG_VARINPUT					\
21060Sstevel@tonic-gate 	}
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate #define	PROTO_UINT_OUT(p, f, in) {					\
21090Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
21100Sstevel@tonic-gate 		    sizeof (in),					\
21110Sstevel@tonic-gate 		    sizeof (struct rep_protocol_integer_response), 0	\
21120Sstevel@tonic-gate 	}
21130Sstevel@tonic-gate 
21140Sstevel@tonic-gate #define	PROTO_NAME_OUT(p, f, in) {					\
21150Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
21160Sstevel@tonic-gate 		    sizeof (in),					\
21170Sstevel@tonic-gate 		    sizeof (struct rep_protocol_name_response), 0	\
21180Sstevel@tonic-gate 	}
21190Sstevel@tonic-gate 
21200Sstevel@tonic-gate #define	PROTO_FMRI_OUT(p, f, in) {					\
21210Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
21220Sstevel@tonic-gate 		    sizeof (in),					\
21230Sstevel@tonic-gate 		    sizeof (struct rep_protocol_fmri_response), 0	\
21240Sstevel@tonic-gate 	}
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate #define	PROTO_VALUE_OUT(p, f, in) {					\
21270Sstevel@tonic-gate 		p, #p, &(f), NULL, NULL,				\
21280Sstevel@tonic-gate 		    sizeof (in),					\
21290Sstevel@tonic-gate 		    sizeof (struct rep_protocol_value_response), 0	\
21300Sstevel@tonic-gate 	}
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate #define	PROTO_PANIC(p)	{ p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
21330Sstevel@tonic-gate #define	PROTO_END()	{ 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate #define	PROTO_FLAG_PANIC	0x00000001	/* should never be called */
21360Sstevel@tonic-gate #define	PROTO_FLAG_VARINPUT	0x00000004	/* in_size is minimum size */
21370Sstevel@tonic-gate #define	PROTO_FLAG_RETFD	0x00000008	/* can also return an FD */
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate #define	PROTO_ALL_FLAGS		0x0000000f	/* all flags */
21400Sstevel@tonic-gate 
21410Sstevel@tonic-gate static struct protocol_entry {
21420Sstevel@tonic-gate 	enum rep_protocol_requestid	pt_request;
21430Sstevel@tonic-gate 	const char			*pt_name;
21440Sstevel@tonic-gate 	protocol_handler_f		*pt_handler;
21450Sstevel@tonic-gate 	void				*pt_arg;
21460Sstevel@tonic-gate 	protocol_handler_fdret_f	*pt_fd_handler;
21470Sstevel@tonic-gate 	size_t				pt_in_size;
21480Sstevel@tonic-gate 	size_t				pt_out_max;
21490Sstevel@tonic-gate 	uint32_t			pt_flags;
21500Sstevel@tonic-gate } protocol_table[] = {
21510Sstevel@tonic-gate 	PROTO_PANIC(REP_PROTOCOL_CLOSE),		/* special case */
21520Sstevel@tonic-gate 
21530Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_SETUP,		entity_setup,
21540Sstevel@tonic-gate 	    struct rep_protocol_entity_setup),
21550Sstevel@tonic-gate 	PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME,	entity_name,
21560Sstevel@tonic-gate 	    struct rep_protocol_entity_name),
21570Sstevel@tonic-gate 	PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE,	entity_parent_type,
21580Sstevel@tonic-gate 	    struct rep_protocol_entity_parent_type),
21590Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_GET_CHILD,		entity_get_child,
21600Sstevel@tonic-gate 	    struct rep_protocol_entity_get_child),
21610Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_GET_PARENT,		entity_get_parent,
21620Sstevel@tonic-gate 	    struct rep_protocol_entity_parent),
21630Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_GET,			entity_get,
21640Sstevel@tonic-gate 	    struct rep_protocol_entity_get),
21650Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_UPDATE,		entity_update,
21660Sstevel@tonic-gate 	    struct rep_protocol_entity_update),
21670Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD,		entity_create_child,
21680Sstevel@tonic-gate 	    struct rep_protocol_entity_create_child),
21690Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_CREATE_PG,		entity_create_pg,
21700Sstevel@tonic-gate 	    struct rep_protocol_entity_create_pg),
21710Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_DELETE,		entity_delete,
21720Sstevel@tonic-gate 	    struct rep_protocol_entity_delete),
21730Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_RESET,		entity_reset,
21740Sstevel@tonic-gate 	    struct rep_protocol_entity_reset),
21750Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ENTITY_TEARDOWN,		entity_teardown,
21760Sstevel@tonic-gate 	    struct rep_protocol_entity_teardown),
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_SETUP,			iter_setup,
21790Sstevel@tonic-gate 	    struct rep_protocol_iter_request),
21800Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_START,			iter_start,
21810Sstevel@tonic-gate 	    struct rep_protocol_iter_start),
21820Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_READ,			iter_read,
21830Sstevel@tonic-gate 	    struct rep_protocol_iter_read),
21840Sstevel@tonic-gate 	PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE,	iter_read_value,
21850Sstevel@tonic-gate 	    struct rep_protocol_iter_read_value),
21860Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_RESET,			iter_reset,
21870Sstevel@tonic-gate 	    struct rep_protocol_iter_request),
21880Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_ITER_TEARDOWN,		iter_teardown,
21890Sstevel@tonic-gate 	    struct rep_protocol_iter_request),
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL,		next_snaplevel,
21920Sstevel@tonic-gate 	    struct rep_protocol_entity_pair),
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_SNAPSHOT_TAKE,		snapshot_take,
21950Sstevel@tonic-gate 	    struct rep_protocol_snapshot_take),
21960Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED,		snapshot_take_named,
21970Sstevel@tonic-gate 	    struct rep_protocol_snapshot_take_named),
21980Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH,		snapshot_attach,
21990Sstevel@tonic-gate 	    struct rep_protocol_snapshot_attach),
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate 	PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE,	property_get_type,
22020Sstevel@tonic-gate 	    struct rep_protocol_property_request),
22030Sstevel@tonic-gate 	PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE, property_get_value,
22040Sstevel@tonic-gate 	    struct rep_protocol_property_request),
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate 	PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT, propertygrp_notify,
22070Sstevel@tonic-gate 	    struct rep_protocol_propertygrp_request),
22080Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START,	tx_start,
22090Sstevel@tonic-gate 	    struct rep_protocol_transaction_start),
22100Sstevel@tonic-gate 	PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT,	tx_commit,
22110Sstevel@tonic-gate 	    REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE),
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY,		client_add_notify,
22140Sstevel@tonic-gate 	    struct rep_protocol_notify_request),
22150Sstevel@tonic-gate 	PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT,	client_wait,
22160Sstevel@tonic-gate 	    struct rep_protocol_wait_request),
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate 	PROTO(REP_PROTOCOL_BACKUP,			backup_repository,
22190Sstevel@tonic-gate 	    struct rep_protocol_backup_request),
22200Sstevel@tonic-gate 
22215777Stw21770 	PROTO(REP_PROTOCOL_SET_AUDIT_ANNOTATION,	set_annotation,
22225777Stw21770 	    struct rep_protocol_annotation),
22235777Stw21770 
22246035Sstevep 	PROTO(REP_PROTOCOL_SWITCH,			repository_switch,
22256035Sstevep 	    struct rep_protocol_switch_request),
22266035Sstevep 
22270Sstevel@tonic-gate 	PROTO_END()
22280Sstevel@tonic-gate };
22290Sstevel@tonic-gate #undef PROTO
22300Sstevel@tonic-gate #undef PROTO_FMRI_OUT
22310Sstevel@tonic-gate #undef PROTO_NAME_OUT
22320Sstevel@tonic-gate #undef PROTO_UINT_OUT
22330Sstevel@tonic-gate #undef PROTO_PANIC
22340Sstevel@tonic-gate #undef PROTO_END
22350Sstevel@tonic-gate 
22360Sstevel@tonic-gate /*
22370Sstevel@tonic-gate  * The number of entries, sans PROTO_END()
22380Sstevel@tonic-gate  */
22390Sstevel@tonic-gate #define	PROTOCOL_ENTRIES \
22400Sstevel@tonic-gate 	    (sizeof (protocol_table) / sizeof (*protocol_table) - 1)
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate #define	PROTOCOL_PREFIX "REP_PROTOCOL_"
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate int
client_init(void)22450Sstevel@tonic-gate client_init(void)
22460Sstevel@tonic-gate {
22470Sstevel@tonic-gate 	int i;
22480Sstevel@tonic-gate 	struct protocol_entry *e;
22490Sstevel@tonic-gate 
22500Sstevel@tonic-gate 	if (!client_hash_init())
22510Sstevel@tonic-gate 		return (0);
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate 	if (request_log_size > 0) {
22540Sstevel@tonic-gate 		request_log = uu_zalloc(request_log_size *
22550Sstevel@tonic-gate 		    sizeof (request_log_entry_t));
22560Sstevel@tonic-gate 	}
22570Sstevel@tonic-gate 
22580Sstevel@tonic-gate 	/*
22590Sstevel@tonic-gate 	 * update the names to not include REP_PROTOCOL_
22600Sstevel@tonic-gate 	 */
22610Sstevel@tonic-gate 	for (i = 0; i < PROTOCOL_ENTRIES; i++) {
22620Sstevel@tonic-gate 		e = &protocol_table[i];
22630Sstevel@tonic-gate 		assert(strncmp(e->pt_name, PROTOCOL_PREFIX,
22640Sstevel@tonic-gate 		    strlen(PROTOCOL_PREFIX)) == 0);
22650Sstevel@tonic-gate 		e->pt_name += strlen(PROTOCOL_PREFIX);
22660Sstevel@tonic-gate 	}
22670Sstevel@tonic-gate 	/*
22680Sstevel@tonic-gate 	 * verify the protocol table is consistent
22690Sstevel@tonic-gate 	 */
22700Sstevel@tonic-gate 	for (i = 0; i < PROTOCOL_ENTRIES; i++) {
22710Sstevel@tonic-gate 		e = &protocol_table[i];
22720Sstevel@tonic-gate 		assert(e->pt_request == (REP_PROTOCOL_BASE + i));
22730Sstevel@tonic-gate 
22740Sstevel@tonic-gate 		assert((e->pt_flags & ~PROTO_ALL_FLAGS) == 0);
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 		if (e->pt_flags & PROTO_FLAG_PANIC)
22770Sstevel@tonic-gate 			assert(e->pt_in_size == 0 && e->pt_out_max == 0 &&
22780Sstevel@tonic-gate 			    e->pt_handler == NULL);
22790Sstevel@tonic-gate 		else
22800Sstevel@tonic-gate 			assert(e->pt_in_size != 0 && e->pt_out_max != 0 &&
22810Sstevel@tonic-gate 			    (e->pt_handler != NULL ||
22820Sstevel@tonic-gate 			    e->pt_fd_handler != NULL));
22830Sstevel@tonic-gate 	}
22840Sstevel@tonic-gate 	assert((REP_PROTOCOL_BASE + i) == REP_PROTOCOL_MAX_REQUEST);
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate 	assert(protocol_table[i].pt_request == 0);
22870Sstevel@tonic-gate 
22880Sstevel@tonic-gate 	return (1);
22890Sstevel@tonic-gate }
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate static void
client_switcher(void * cookie,char * argp,size_t arg_size,door_desc_t * desc_in,uint_t n_desc)22920Sstevel@tonic-gate client_switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *desc_in,
22930Sstevel@tonic-gate     uint_t n_desc)
22940Sstevel@tonic-gate {
22950Sstevel@tonic-gate 	thread_info_t *ti = thread_self();
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 	repcache_client_t *cp;
22980Sstevel@tonic-gate 	uint32_t id = (uint32_t)cookie;
22990Sstevel@tonic-gate 	enum rep_protocol_requestid request_code;
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 	rep_protocol_responseid_t result = INVALID_RESULT;
23020Sstevel@tonic-gate 
23030Sstevel@tonic-gate 	struct protocol_entry *e;
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 	char *retval = NULL;
23060Sstevel@tonic-gate 	size_t retsize = 0;
23070Sstevel@tonic-gate 
23080Sstevel@tonic-gate 	int retfd = -1;
23090Sstevel@tonic-gate 	door_desc_t desc;
23100Sstevel@tonic-gate 	request_log_entry_t *rlp;
23110Sstevel@tonic-gate 
23120Sstevel@tonic-gate 	rlp = start_log(id);
23130Sstevel@tonic-gate 
23140Sstevel@tonic-gate 	if (n_desc != 0)
23150Sstevel@tonic-gate 		uu_die("can't happen: %d descriptors @%p (cookie %p)",
23160Sstevel@tonic-gate 		    n_desc, desc_in, cookie);
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 	if (argp == DOOR_UNREF_DATA) {
23190Sstevel@tonic-gate 		client_destroy(id);
23200Sstevel@tonic-gate 		goto bad_end;
23210Sstevel@tonic-gate 	}
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 	thread_newstate(ti, TI_CLIENT_CALL);
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate 	/*
23260Sstevel@tonic-gate 	 * To simplify returning just a result code, we set up for
23270Sstevel@tonic-gate 	 * that case here.
23280Sstevel@tonic-gate 	 */
23290Sstevel@tonic-gate 	retval = (char *)&result;
23300Sstevel@tonic-gate 	retsize = sizeof (result);
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate 	if (arg_size < sizeof (request_code)) {
23330Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
23340Sstevel@tonic-gate 		goto end_unheld;
23350Sstevel@tonic-gate 	}
23360Sstevel@tonic-gate 
23370Sstevel@tonic-gate 	ti->ti_client_request = (void *)argp;
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	/* LINTED alignment */
23400Sstevel@tonic-gate 	request_code = *(uint32_t *)argp;
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate 	if (rlp != NULL) {
23430Sstevel@tonic-gate 		rlp->rl_request = request_code;
23440Sstevel@tonic-gate 	}
23450Sstevel@tonic-gate 	/*
23460Sstevel@tonic-gate 	 * In order to avoid locking problems on removal, we handle the
23470Sstevel@tonic-gate 	 * "close" case before doing a lookup.
23480Sstevel@tonic-gate 	 */
23490Sstevel@tonic-gate 	if (request_code == REP_PROTOCOL_CLOSE) {
23500Sstevel@tonic-gate 		client_destroy(id);
23510Sstevel@tonic-gate 		result = REP_PROTOCOL_SUCCESS;
23520Sstevel@tonic-gate 		goto end_unheld;
23530Sstevel@tonic-gate 	}
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 	cp = client_lookup(id);
23560Sstevel@tonic-gate 	/*
23570Sstevel@tonic-gate 	 * cp is held
23580Sstevel@tonic-gate 	 */
23590Sstevel@tonic-gate 
23600Sstevel@tonic-gate 	if (cp == NULL)
23610Sstevel@tonic-gate 		goto bad_end;
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 	if (rlp != NULL)
23640Sstevel@tonic-gate 		rlp->rl_client = cp;
23650Sstevel@tonic-gate 
23660Sstevel@tonic-gate 	ti->ti_active_client = cp;
23670Sstevel@tonic-gate 
23680Sstevel@tonic-gate 	if (request_code < REP_PROTOCOL_BASE ||
23690Sstevel@tonic-gate 	    request_code >= REP_PROTOCOL_BASE + PROTOCOL_ENTRIES) {
23700Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
23710Sstevel@tonic-gate 		goto end;
23720Sstevel@tonic-gate 	}
23730Sstevel@tonic-gate 
23740Sstevel@tonic-gate 	e = &protocol_table[request_code - REP_PROTOCOL_BASE];
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate 	assert(!(e->pt_flags & PROTO_FLAG_PANIC));
23770Sstevel@tonic-gate 
23780Sstevel@tonic-gate 	if (e->pt_flags & PROTO_FLAG_VARINPUT) {
23790Sstevel@tonic-gate 		if (arg_size < e->pt_in_size) {
23800Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_BAD_REQUEST;
23810Sstevel@tonic-gate 			goto end;
23820Sstevel@tonic-gate 		}
23830Sstevel@tonic-gate 	} else if (arg_size != e->pt_in_size) {
23840Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_BAD_REQUEST;
23850Sstevel@tonic-gate 		goto end;
23860Sstevel@tonic-gate 	}
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 	if (retsize != e->pt_out_max) {
23890Sstevel@tonic-gate 		retsize = e->pt_out_max;
23900Sstevel@tonic-gate 		retval = alloca(retsize);
23910Sstevel@tonic-gate 	}
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	if (e->pt_flags & PROTO_FLAG_RETFD)
23940Sstevel@tonic-gate 		e->pt_fd_handler(cp, argp, arg_size, retval, &retsize,
23950Sstevel@tonic-gate 		    e->pt_arg, &retfd);
23960Sstevel@tonic-gate 	else
23970Sstevel@tonic-gate 		e->pt_handler(cp, argp, arg_size, retval, &retsize, e->pt_arg);
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate end:
24000Sstevel@tonic-gate 	ti->ti_active_client = NULL;
24010Sstevel@tonic-gate 	client_release(cp);
24020Sstevel@tonic-gate 
24030Sstevel@tonic-gate end_unheld:
24040Sstevel@tonic-gate 	if (rlp != NULL) {
24050Sstevel@tonic-gate 		/* LINTED alignment */
24060Sstevel@tonic-gate 		rlp->rl_response = *(uint32_t *)retval;
24070Sstevel@tonic-gate 		end_log();
24080Sstevel@tonic-gate 		rlp = NULL;
24090Sstevel@tonic-gate 	}
24100Sstevel@tonic-gate 	ti->ti_client_request = NULL;
24110Sstevel@tonic-gate 	thread_newstate(ti, TI_DOOR_RETURN);
24120Sstevel@tonic-gate 
24130Sstevel@tonic-gate 	if (retval == (char *)&result) {
24140Sstevel@tonic-gate 		assert(result != INVALID_RESULT && retsize == sizeof (result));
24150Sstevel@tonic-gate 	} else {
24160Sstevel@tonic-gate 		/* LINTED alignment */
24170Sstevel@tonic-gate 		result = *(uint32_t *)retval;
24180Sstevel@tonic-gate 	}
24190Sstevel@tonic-gate 	if (retfd != -1) {
24200Sstevel@tonic-gate 		desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
24210Sstevel@tonic-gate 		desc.d_data.d_desc.d_descriptor = retfd;
24220Sstevel@tonic-gate 		(void) door_return(retval, retsize, &desc, 1);
24230Sstevel@tonic-gate 	} else {
24240Sstevel@tonic-gate 		(void) door_return(retval, retsize, NULL, 0);
24250Sstevel@tonic-gate 	}
24260Sstevel@tonic-gate bad_end:
24270Sstevel@tonic-gate 	if (rlp != NULL) {
24280Sstevel@tonic-gate 		rlp->rl_response = -1;
24290Sstevel@tonic-gate 		end_log();
24300Sstevel@tonic-gate 		rlp = NULL;
24310Sstevel@tonic-gate 	}
24320Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
24330Sstevel@tonic-gate }
24340Sstevel@tonic-gate 
24350Sstevel@tonic-gate int
create_client(pid_t pid,uint32_t debugflags,int privileged,int * out_fd)24360Sstevel@tonic-gate create_client(pid_t pid, uint32_t debugflags, int privileged, int *out_fd)
24370Sstevel@tonic-gate {
24380Sstevel@tonic-gate 	int fd;
24390Sstevel@tonic-gate 
24400Sstevel@tonic-gate 	repcache_client_t *cp;
24410Sstevel@tonic-gate 
24420Sstevel@tonic-gate 	struct door_info info;
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 	int door_flags = DOOR_UNREF | DOOR_REFUSE_DESC;
24450Sstevel@tonic-gate #ifdef DOOR_NO_CANCEL
24460Sstevel@tonic-gate 	door_flags |= DOOR_NO_CANCEL;
24470Sstevel@tonic-gate #endif
24480Sstevel@tonic-gate 
24490Sstevel@tonic-gate 	cp = client_alloc();
24500Sstevel@tonic-gate 	if (cp == NULL)
24510Sstevel@tonic-gate 		return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
24520Sstevel@tonic-gate 
24530Sstevel@tonic-gate 	(void) pthread_mutex_lock(&client_lock);
24540Sstevel@tonic-gate 	cp->rc_id = ++client_maxid;
24550Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&client_lock);
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	cp->rc_all_auths = privileged;
24580Sstevel@tonic-gate 	cp->rc_pid = pid;
24590Sstevel@tonic-gate 	cp->rc_debug = debugflags;
24600Sstevel@tonic-gate 
24615777Stw21770 	start_audit_session(cp);
24625777Stw21770 
24630Sstevel@tonic-gate 	cp->rc_doorfd = door_create(client_switcher, (void *)cp->rc_id,
24640Sstevel@tonic-gate 	    door_flags);
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate 	if (cp->rc_doorfd < 0) {
24670Sstevel@tonic-gate 		client_free(cp);
24680Sstevel@tonic-gate 		return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
24690Sstevel@tonic-gate 	}
24700Sstevel@tonic-gate #ifdef DOOR_PARAM_DATA_MIN
24710Sstevel@tonic-gate 	(void) door_setparam(cp->rc_doorfd, DOOR_PARAM_DATA_MIN,
24720Sstevel@tonic-gate 	    sizeof (enum rep_protocol_requestid));
24730Sstevel@tonic-gate #endif
24740Sstevel@tonic-gate 
24750Sstevel@tonic-gate 	if ((fd = dup(cp->rc_doorfd)) < 0 ||
24760Sstevel@tonic-gate 	    door_info(cp->rc_doorfd, &info) < 0) {
24770Sstevel@tonic-gate 		if (fd >= 0)
24780Sstevel@tonic-gate 			(void) close(fd);
24790Sstevel@tonic-gate 		(void) door_revoke(cp->rc_doorfd);
24800Sstevel@tonic-gate 		cp->rc_doorfd = -1;
24810Sstevel@tonic-gate 		client_free(cp);
24820Sstevel@tonic-gate 		return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
24830Sstevel@tonic-gate 	}
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 	rc_pg_notify_init(&cp->rc_pg_notify);
24860Sstevel@tonic-gate 	rc_notify_info_init(&cp->rc_notify_info);
24870Sstevel@tonic-gate 
24880Sstevel@tonic-gate 	client_insert(cp);
24890Sstevel@tonic-gate 
24900Sstevel@tonic-gate 	cp->rc_doorid = info.di_uniquifier;
24910Sstevel@tonic-gate 	*out_fd = fd;
24920Sstevel@tonic-gate 
24930Sstevel@tonic-gate 	return (REPOSITORY_DOOR_SUCCESS);
24940Sstevel@tonic-gate }
2495