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