17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5f2fa366aSjeanm * Common Development and Distribution License (the "License"). 6f2fa366aSjeanm * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*5b7f77adStw21770 227c478bd9Sstevel@tonic-gate /* 23*5b7f77adStw21770 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * This is the client layer for svc.configd. All direct protocol interactions 317c478bd9Sstevel@tonic-gate * are handled here. 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * Essentially, the job of this layer is to turn the idempotent protocol 347c478bd9Sstevel@tonic-gate * into a series of non-idempotent calls into the object layer, while 357c478bd9Sstevel@tonic-gate * also handling the necessary locking. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <alloca.h> 397c478bd9Sstevel@tonic-gate #include <assert.h> 40*5b7f77adStw21770 #include <bsm/adt_event.h> 417c478bd9Sstevel@tonic-gate #include <door.h> 427c478bd9Sstevel@tonic-gate #include <errno.h> 43*5b7f77adStw21770 #include <libintl.h> 447c478bd9Sstevel@tonic-gate #include <limits.h> 457c478bd9Sstevel@tonic-gate #include <pthread.h> 467c478bd9Sstevel@tonic-gate #include <stdio.h> 477c478bd9Sstevel@tonic-gate #include <stdlib.h> 487c478bd9Sstevel@tonic-gate #include <string.h> 49*5b7f77adStw21770 #include <syslog.h> 50*5b7f77adStw21770 #include <ucred.h> 517c478bd9Sstevel@tonic-gate #include <unistd.h> 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate #include <libuutil.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #include "configd.h" 567c478bd9Sstevel@tonic-gate #include "repcache_protocol.h" 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #define INVALID_CHANGEID (0) 597c478bd9Sstevel@tonic-gate #define INVALID_DOORID ((door_id_t)-1) 607c478bd9Sstevel@tonic-gate #define INVALID_RESULT ((rep_protocol_responseid_t)INT_MIN) 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * lint doesn't like constant assertions 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate #ifdef lint 667c478bd9Sstevel@tonic-gate #define assert_nolint(x) (void)0 677c478bd9Sstevel@tonic-gate #else 687c478bd9Sstevel@tonic-gate #define assert_nolint(x) assert(x) 697c478bd9Sstevel@tonic-gate #endif 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * Protects client linkage and the freelist 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate #define CLIENT_HASH_SIZE 64 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #pragma align 64(client_hash) 777c478bd9Sstevel@tonic-gate static client_bucket_t client_hash[CLIENT_HASH_SIZE]; 787c478bd9Sstevel@tonic-gate 798918dff3Sjwadams static uu_avl_pool_t *entity_pool; 808918dff3Sjwadams static uu_avl_pool_t *iter_pool; 817c478bd9Sstevel@tonic-gate static uu_list_pool_t *client_pool; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate #define CLIENT_HASH(id) (&client_hash[((id) & (CLIENT_HASH_SIZE - 1))]) 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate uint_t request_log_size = 1024; /* tunable, before we start */ 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate static pthread_mutex_t request_log_lock = PTHREAD_MUTEX_INITIALIZER; 887c478bd9Sstevel@tonic-gate static uint_t request_log_cur; 897c478bd9Sstevel@tonic-gate request_log_entry_t *request_log; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate static uint32_t client_maxid; 927c478bd9Sstevel@tonic-gate static pthread_mutex_t client_lock; /* protects client_maxid */ 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate static request_log_entry_t * 957c478bd9Sstevel@tonic-gate get_log(void) 967c478bd9Sstevel@tonic-gate { 977c478bd9Sstevel@tonic-gate thread_info_t *ti = thread_self(); 987c478bd9Sstevel@tonic-gate return (&ti->ti_log); 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate void 1027c478bd9Sstevel@tonic-gate log_enter(request_log_entry_t *rlp) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate if (rlp->rl_start != 0 && request_log != NULL) { 1057c478bd9Sstevel@tonic-gate request_log_entry_t *logrlp; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&request_log_lock); 1087c478bd9Sstevel@tonic-gate assert(request_log_cur < request_log_size); 1097c478bd9Sstevel@tonic-gate logrlp = &request_log[request_log_cur++]; 1107c478bd9Sstevel@tonic-gate if (request_log_cur == request_log_size) 1117c478bd9Sstevel@tonic-gate request_log_cur = 0; 1127c478bd9Sstevel@tonic-gate (void) memcpy(logrlp, rlp, sizeof (*rlp)); 1137c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&request_log_lock); 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * Note that the svc.configd dmod will join all of the per-thread log entries 1197c478bd9Sstevel@tonic-gate * with the main log, so that even if the log is disabled, there is some 1207c478bd9Sstevel@tonic-gate * information available. 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate static request_log_entry_t * 1237c478bd9Sstevel@tonic-gate start_log(uint32_t clientid) 1247c478bd9Sstevel@tonic-gate { 1257c478bd9Sstevel@tonic-gate request_log_entry_t *rlp = get_log(); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate log_enter(rlp); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate (void) memset(rlp, 0, sizeof (*rlp)); 1307c478bd9Sstevel@tonic-gate rlp->rl_start = gethrtime(); 1317c478bd9Sstevel@tonic-gate rlp->rl_tid = pthread_self(); 1327c478bd9Sstevel@tonic-gate rlp->rl_clientid = clientid; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate return (rlp); 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate void 1387c478bd9Sstevel@tonic-gate end_log(void) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate request_log_entry_t *rlp = get_log(); 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate rlp->rl_end = gethrtime(); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate static void 1467c478bd9Sstevel@tonic-gate add_log_ptr(request_log_entry_t *rlp, enum rc_ptr_type type, uint32_t id, 1477c478bd9Sstevel@tonic-gate void *ptr) 1487c478bd9Sstevel@tonic-gate { 1497c478bd9Sstevel@tonic-gate request_log_ptr_t *rpp; 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate if (rlp == NULL) 1527c478bd9Sstevel@tonic-gate return; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if (rlp->rl_num_ptrs >= MAX_PTRS) 1557c478bd9Sstevel@tonic-gate return; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate rpp = &rlp->rl_ptrs[rlp->rl_num_ptrs++]; 1587c478bd9Sstevel@tonic-gate rpp->rlp_type = type; 1597c478bd9Sstevel@tonic-gate rpp->rlp_id = id; 1607c478bd9Sstevel@tonic-gate rpp->rlp_ptr = ptr; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * For entities, it's useful to have the node pointer at the start 1647c478bd9Sstevel@tonic-gate * of the request. 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate if (type == RC_PTR_TYPE_ENTITY && ptr != NULL) 1677c478bd9Sstevel@tonic-gate rpp->rlp_data = ((repcache_entity_t *)ptr)->re_node.rnp_node; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate int 1717c478bd9Sstevel@tonic-gate client_is_privileged(void) 1727c478bd9Sstevel@tonic-gate { 1737c478bd9Sstevel@tonic-gate thread_info_t *ti = thread_self(); 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate ucred_t *uc; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate if (ti->ti_active_client != NULL && 1787c478bd9Sstevel@tonic-gate ti->ti_active_client->rc_all_auths) 1797c478bd9Sstevel@tonic-gate return (1); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate if ((uc = get_ucred()) == NULL) 1827c478bd9Sstevel@tonic-gate return (0); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate return (ucred_is_privileged(uc)); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1887c478bd9Sstevel@tonic-gate static int 1897c478bd9Sstevel@tonic-gate client_compare(const void *lc_arg, const void *rc_arg, void *private) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate uint32_t l_id = ((const repcache_client_t *)lc_arg)->rc_id; 1927c478bd9Sstevel@tonic-gate uint32_t r_id = ((const repcache_client_t *)rc_arg)->rc_id; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (l_id > r_id) 1957c478bd9Sstevel@tonic-gate return (1); 1967c478bd9Sstevel@tonic-gate if (l_id < r_id) 1977c478bd9Sstevel@tonic-gate return (-1); 1987c478bd9Sstevel@tonic-gate return (0); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2027c478bd9Sstevel@tonic-gate static int 2037c478bd9Sstevel@tonic-gate entity_compare(const void *lc_arg, const void *rc_arg, void *private) 2047c478bd9Sstevel@tonic-gate { 2057c478bd9Sstevel@tonic-gate uint32_t l_id = ((const repcache_entity_t *)lc_arg)->re_id; 2067c478bd9Sstevel@tonic-gate uint32_t r_id = ((const repcache_entity_t *)rc_arg)->re_id; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate if (l_id > r_id) 2097c478bd9Sstevel@tonic-gate return (1); 2107c478bd9Sstevel@tonic-gate if (l_id < r_id) 2117c478bd9Sstevel@tonic-gate return (-1); 2127c478bd9Sstevel@tonic-gate return (0); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2167c478bd9Sstevel@tonic-gate static int 2177c478bd9Sstevel@tonic-gate iter_compare(const void *lc_arg, const void *rc_arg, void *private) 2187c478bd9Sstevel@tonic-gate { 2197c478bd9Sstevel@tonic-gate uint32_t l_id = ((const repcache_iter_t *)lc_arg)->ri_id; 2207c478bd9Sstevel@tonic-gate uint32_t r_id = ((const repcache_iter_t *)rc_arg)->ri_id; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate if (l_id > r_id) 2237c478bd9Sstevel@tonic-gate return (1); 2247c478bd9Sstevel@tonic-gate if (l_id < r_id) 2257c478bd9Sstevel@tonic-gate return (-1); 2267c478bd9Sstevel@tonic-gate return (0); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate static int 2307c478bd9Sstevel@tonic-gate client_hash_init(void) 2317c478bd9Sstevel@tonic-gate { 2327c478bd9Sstevel@tonic-gate int x; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate assert_nolint(offsetof(repcache_entity_t, re_id) == 0); 2358918dff3Sjwadams entity_pool = uu_avl_pool_create("repcache_entitys", 2367c478bd9Sstevel@tonic-gate sizeof (repcache_entity_t), offsetof(repcache_entity_t, re_link), 2378918dff3Sjwadams entity_compare, UU_AVL_POOL_DEBUG); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate assert_nolint(offsetof(repcache_iter_t, ri_id) == 0); 2408918dff3Sjwadams iter_pool = uu_avl_pool_create("repcache_iters", 2417c478bd9Sstevel@tonic-gate sizeof (repcache_iter_t), offsetof(repcache_iter_t, ri_link), 2428918dff3Sjwadams iter_compare, UU_AVL_POOL_DEBUG); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate assert_nolint(offsetof(repcache_client_t, rc_id) == 0); 2457c478bd9Sstevel@tonic-gate client_pool = uu_list_pool_create("repcache_clients", 2467c478bd9Sstevel@tonic-gate sizeof (repcache_client_t), offsetof(repcache_client_t, rc_link), 2477c478bd9Sstevel@tonic-gate client_compare, UU_LIST_POOL_DEBUG); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if (entity_pool == NULL || iter_pool == NULL || client_pool == NULL) 2507c478bd9Sstevel@tonic-gate return (0); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate for (x = 0; x < CLIENT_HASH_SIZE; x++) { 2537c478bd9Sstevel@tonic-gate uu_list_t *lp = uu_list_create(client_pool, &client_hash[x], 2547c478bd9Sstevel@tonic-gate UU_LIST_SORTED); 2557c478bd9Sstevel@tonic-gate if (lp == NULL) 2567c478bd9Sstevel@tonic-gate return (0); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&client_hash[x].cb_lock, NULL); 2597c478bd9Sstevel@tonic-gate client_hash[x].cb_list = lp; 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate return (1); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate static repcache_client_t * 2667c478bd9Sstevel@tonic-gate client_alloc(void) 2677c478bd9Sstevel@tonic-gate { 2687c478bd9Sstevel@tonic-gate repcache_client_t *cp; 2697c478bd9Sstevel@tonic-gate cp = uu_zalloc(sizeof (*cp)); 2707c478bd9Sstevel@tonic-gate if (cp == NULL) 2717c478bd9Sstevel@tonic-gate return (NULL); 2727c478bd9Sstevel@tonic-gate 2738918dff3Sjwadams cp->rc_entities = uu_avl_create(entity_pool, cp, 0); 2748918dff3Sjwadams if (cp->rc_entities == NULL) 2757c478bd9Sstevel@tonic-gate goto fail; 2767c478bd9Sstevel@tonic-gate 2778918dff3Sjwadams cp->rc_iters = uu_avl_create(iter_pool, cp, 0); 2788918dff3Sjwadams if (cp->rc_iters == NULL) 2797c478bd9Sstevel@tonic-gate goto fail; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate uu_list_node_init(cp, &cp->rc_link, client_pool); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate cp->rc_doorfd = -1; 2847c478bd9Sstevel@tonic-gate cp->rc_doorid = INVALID_DOORID; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&cp->rc_lock, NULL); 287*5b7f77adStw21770 (void) pthread_mutex_init(&cp->rc_annotate_lock, NULL); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate rc_node_ptr_init(&cp->rc_notify_ptr); 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate return (cp); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate fail: 2948918dff3Sjwadams if (cp->rc_iters != NULL) 2958918dff3Sjwadams uu_avl_destroy(cp->rc_iters); 2968918dff3Sjwadams if (cp->rc_entities != NULL) 2978918dff3Sjwadams uu_avl_destroy(cp->rc_entities); 2987c478bd9Sstevel@tonic-gate uu_free(cp); 2997c478bd9Sstevel@tonic-gate return (NULL); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate static void 3037c478bd9Sstevel@tonic-gate client_free(repcache_client_t *cp) 3047c478bd9Sstevel@tonic-gate { 3057c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == 0); 3067c478bd9Sstevel@tonic-gate assert(cp->rc_refcnt == 0); 3077c478bd9Sstevel@tonic-gate assert(cp->rc_doorfd == -1); 3087c478bd9Sstevel@tonic-gate assert(cp->rc_doorid == INVALID_DOORID); 3098918dff3Sjwadams assert(uu_avl_first(cp->rc_entities) == NULL); 3108918dff3Sjwadams assert(uu_avl_first(cp->rc_iters) == NULL); 3118918dff3Sjwadams uu_avl_destroy(cp->rc_entities); 3128918dff3Sjwadams uu_avl_destroy(cp->rc_iters); 3137c478bd9Sstevel@tonic-gate uu_list_node_fini(cp, &cp->rc_link, client_pool); 3147c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&cp->rc_lock); 315*5b7f77adStw21770 (void) pthread_mutex_destroy(&cp->rc_annotate_lock); 316*5b7f77adStw21770 rc_node_ptr_free_mem(&cp->rc_notify_ptr); 3177c478bd9Sstevel@tonic-gate uu_free(cp); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate static void 3217c478bd9Sstevel@tonic-gate client_insert(repcache_client_t *cp) 3227c478bd9Sstevel@tonic-gate { 3237c478bd9Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(cp->rc_id); 3247c478bd9Sstevel@tonic-gate uu_list_index_t idx; 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate assert(cp->rc_id > 0); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * We assume it does not already exist 3317c478bd9Sstevel@tonic-gate */ 3327c478bd9Sstevel@tonic-gate (void) uu_list_find(bp->cb_list, cp, NULL, &idx); 3337c478bd9Sstevel@tonic-gate uu_list_insert(bp->cb_list, cp, idx); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate static repcache_client_t * 3397c478bd9Sstevel@tonic-gate client_lookup(uint32_t id) 3407c478bd9Sstevel@tonic-gate { 3417c478bd9Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(id); 3427c478bd9Sstevel@tonic-gate repcache_client_t *cp; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate cp = uu_list_find(bp->cb_list, &id, NULL, NULL); 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate /* 3497c478bd9Sstevel@tonic-gate * Bump the reference count 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate if (cp != NULL) { 3527c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3537c478bd9Sstevel@tonic-gate assert(!(cp->rc_flags & RC_CLIENT_DEAD)); 3547c478bd9Sstevel@tonic-gate cp->rc_refcnt++; 3557c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate return (cp); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate static void 3637c478bd9Sstevel@tonic-gate client_release(repcache_client_t *cp) 3647c478bd9Sstevel@tonic-gate { 3657c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3667c478bd9Sstevel@tonic-gate assert(cp->rc_refcnt > 0); 3677c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr != pthread_self()); 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate --cp->rc_refcnt; 3707c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&cp->rc_cv); 3717c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * We only allow one thread to be inserting at a time, to prevent 3767c478bd9Sstevel@tonic-gate * insert/insert races. 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate static void 3797c478bd9Sstevel@tonic-gate client_start_insert(repcache_client_t *cp) 3807c478bd9Sstevel@tonic-gate { 3817c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3827c478bd9Sstevel@tonic-gate assert(cp->rc_refcnt > 0); 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate while (cp->rc_insert_thr != 0) { 3857c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr != pthread_self()); 3867c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate cp->rc_insert_thr = pthread_self(); 3897c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate static void 3937c478bd9Sstevel@tonic-gate client_end_insert(repcache_client_t *cp) 3947c478bd9Sstevel@tonic-gate { 3957c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3967c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 3977c478bd9Sstevel@tonic-gate cp->rc_insert_thr = 0; 3987c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&cp->rc_cv); 3997c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4037c478bd9Sstevel@tonic-gate static repcache_entity_t * 4047c478bd9Sstevel@tonic-gate entity_alloc(repcache_client_t *cp) 4057c478bd9Sstevel@tonic-gate { 4067c478bd9Sstevel@tonic-gate repcache_entity_t *ep = uu_zalloc(sizeof (repcache_entity_t)); 4077c478bd9Sstevel@tonic-gate if (ep != NULL) { 4088918dff3Sjwadams uu_avl_node_init(ep, &ep->re_link, entity_pool); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate return (ep); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate static void 4147c478bd9Sstevel@tonic-gate entity_add(repcache_client_t *cp, repcache_entity_t *ep) 4157c478bd9Sstevel@tonic-gate { 4168918dff3Sjwadams uu_avl_index_t idx; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 4197c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 4207c478bd9Sstevel@tonic-gate 4218918dff3Sjwadams (void) uu_avl_find(cp->rc_entities, ep, NULL, &idx); 4228918dff3Sjwadams uu_avl_insert(cp->rc_entities, ep, idx); 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate static repcache_entity_t * 4287c478bd9Sstevel@tonic-gate entity_find(repcache_client_t *cp, uint32_t id) 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 4338918dff3Sjwadams ep = uu_avl_find(cp->rc_entities, &id, NULL, NULL); 4347c478bd9Sstevel@tonic-gate if (ep != NULL) { 4357c478bd9Sstevel@tonic-gate add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, ep); 4367c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->re_lock); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate return (ep); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* 4447c478bd9Sstevel@tonic-gate * Fails with 4457c478bd9Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 4467c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate static int 4497c478bd9Sstevel@tonic-gate entity_find2(repcache_client_t *cp, uint32_t id1, repcache_entity_t **out1, 4507c478bd9Sstevel@tonic-gate uint32_t id2, repcache_entity_t **out2) 4517c478bd9Sstevel@tonic-gate { 4527c478bd9Sstevel@tonic-gate repcache_entity_t *e1, *e2; 4537c478bd9Sstevel@tonic-gate request_log_entry_t *rlp; 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate if (id1 == id2) 4567c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DUPLICATE_ID); 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 4598918dff3Sjwadams e1 = uu_avl_find(cp->rc_entities, &id1, NULL, NULL); 4608918dff3Sjwadams e2 = uu_avl_find(cp->rc_entities, &id2, NULL, NULL); 4617c478bd9Sstevel@tonic-gate if (e1 == NULL || e2 == NULL) { 4627c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4637c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate assert(e1 != e2); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * locks are ordered by id number 4707c478bd9Sstevel@tonic-gate */ 4717c478bd9Sstevel@tonic-gate if (id1 < id2) { 4727c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&e1->re_lock); 4737c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&e2->re_lock); 4747c478bd9Sstevel@tonic-gate } else { 4757c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&e2->re_lock); 4767c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&e1->re_lock); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate *out1 = e1; 4797c478bd9Sstevel@tonic-gate *out2 = e2; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate if ((rlp = get_log()) != NULL) { 4847c478bd9Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id1, e1); 4857c478bd9Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id2, e2); 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate static void 4927c478bd9Sstevel@tonic-gate entity_release(repcache_entity_t *ep) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate assert(ep->re_node.rnp_node == NULL || 4957c478bd9Sstevel@tonic-gate !MUTEX_HELD(&ep->re_node.rnp_node->rn_lock)); 4967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ep->re_lock); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate static void 5007c478bd9Sstevel@tonic-gate entity_destroy(repcache_entity_t *entity) 5017c478bd9Sstevel@tonic-gate { 5027c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&entity->re_lock); 5037c478bd9Sstevel@tonic-gate rc_node_clear(&entity->re_node, 0); 5047c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&entity->re_lock); 5057c478bd9Sstevel@tonic-gate 5068918dff3Sjwadams uu_avl_node_fini(entity, &entity->re_link, entity_pool); 5077c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&entity->re_lock); 508*5b7f77adStw21770 rc_node_ptr_free_mem(&entity->re_node); 5097c478bd9Sstevel@tonic-gate uu_free(entity); 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate static void 5137c478bd9Sstevel@tonic-gate entity_remove(repcache_client_t *cp, uint32_t id) 5147c478bd9Sstevel@tonic-gate { 5157c478bd9Sstevel@tonic-gate repcache_entity_t *entity; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5188918dff3Sjwadams entity = uu_avl_find(cp->rc_entities, &id, NULL, NULL); 5197c478bd9Sstevel@tonic-gate if (entity != NULL) 5208918dff3Sjwadams uu_avl_remove(cp->rc_entities, entity); 5217c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate if (entity != NULL) 5247c478bd9Sstevel@tonic-gate entity_destroy(entity); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate static void 5287c478bd9Sstevel@tonic-gate entity_cleanup(repcache_client_t *cp) 5297c478bd9Sstevel@tonic-gate { 5307c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 5317c478bd9Sstevel@tonic-gate void *cookie = NULL; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5348918dff3Sjwadams while ((ep = uu_avl_teardown(cp->rc_entities, &cookie)) != NULL) { 5357c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5367c478bd9Sstevel@tonic-gate entity_destroy(ep); 5377c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5437c478bd9Sstevel@tonic-gate static repcache_iter_t * 5447c478bd9Sstevel@tonic-gate iter_alloc(repcache_client_t *cp) 5457c478bd9Sstevel@tonic-gate { 5467c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 5477c478bd9Sstevel@tonic-gate iter = uu_zalloc(sizeof (repcache_iter_t)); 5487c478bd9Sstevel@tonic-gate if (iter != NULL) 5498918dff3Sjwadams uu_avl_node_init(iter, &iter->ri_link, iter_pool); 5507c478bd9Sstevel@tonic-gate return (iter); 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate static void 5547c478bd9Sstevel@tonic-gate iter_add(repcache_client_t *cp, repcache_iter_t *iter) 5557c478bd9Sstevel@tonic-gate { 5567c478bd9Sstevel@tonic-gate uu_list_index_t idx; 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5597c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 5607c478bd9Sstevel@tonic-gate 5618918dff3Sjwadams (void) uu_avl_find(cp->rc_iters, iter, NULL, &idx); 5628918dff3Sjwadams uu_avl_insert(cp->rc_iters, iter, idx); 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate static repcache_iter_t * 5687c478bd9Sstevel@tonic-gate iter_find(repcache_client_t *cp, uint32_t id) 5697c478bd9Sstevel@tonic-gate { 5707c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5737c478bd9Sstevel@tonic-gate 5748918dff3Sjwadams iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL); 5757c478bd9Sstevel@tonic-gate if (iter != NULL) { 5767c478bd9Sstevel@tonic-gate add_log_ptr(get_log(), RC_PTR_TYPE_ITER, id, iter); 5777c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate return (iter); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * Fails with 5867c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - iter_id or entity_id does not designate an active register 5877c478bd9Sstevel@tonic-gate */ 5887c478bd9Sstevel@tonic-gate static int 5897c478bd9Sstevel@tonic-gate iter_find_w_entity(repcache_client_t *cp, uint32_t iter_id, 5907c478bd9Sstevel@tonic-gate repcache_iter_t **iterp, uint32_t entity_id, repcache_entity_t **epp) 5917c478bd9Sstevel@tonic-gate { 5927c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 5937c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 5947c478bd9Sstevel@tonic-gate request_log_entry_t *rlp; 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5978918dff3Sjwadams iter = uu_avl_find(cp->rc_iters, &iter_id, NULL, NULL); 5988918dff3Sjwadams ep = uu_avl_find(cp->rc_entities, &entity_id, NULL, NULL); 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate assert(iter == NULL || !MUTEX_HELD(&iter->ri_lock)); 6017c478bd9Sstevel@tonic-gate assert(ep == NULL || !MUTEX_HELD(&ep->re_lock)); 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate if (iter == NULL || ep == NULL) { 6047c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6057c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 6097c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->re_lock); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate *iterp = iter; 6147c478bd9Sstevel@tonic-gate *epp = ep; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate if ((rlp = get_log()) != NULL) { 6177c478bd9Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, entity_id, ep); 6187c478bd9Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ITER, iter_id, iter); 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate static void 6257c478bd9Sstevel@tonic-gate iter_release(repcache_iter_t *iter) 6267c478bd9Sstevel@tonic-gate { 6277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&iter->ri_lock); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate static void 6317c478bd9Sstevel@tonic-gate iter_destroy(repcache_iter_t *iter) 6327c478bd9Sstevel@tonic-gate { 6337c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 6347c478bd9Sstevel@tonic-gate rc_iter_destroy(&iter->ri_iter); 6357c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&iter->ri_lock); 6367c478bd9Sstevel@tonic-gate 6378918dff3Sjwadams uu_avl_node_fini(iter, &iter->ri_link, iter_pool); 6387c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&iter->ri_lock); 6397c478bd9Sstevel@tonic-gate uu_free(iter); 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate static void 6437c478bd9Sstevel@tonic-gate iter_remove(repcache_client_t *cp, uint32_t id) 6447c478bd9Sstevel@tonic-gate { 6457c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 6488918dff3Sjwadams iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL); 6497c478bd9Sstevel@tonic-gate if (iter != NULL) 6508918dff3Sjwadams uu_avl_remove(cp->rc_iters, iter); 6517c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate if (iter != NULL) 6547c478bd9Sstevel@tonic-gate iter_destroy(iter); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate static void 6587c478bd9Sstevel@tonic-gate iter_cleanup(repcache_client_t *cp) 6597c478bd9Sstevel@tonic-gate { 6607c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 6617c478bd9Sstevel@tonic-gate void *cookie = NULL; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 6648918dff3Sjwadams while ((iter = uu_avl_teardown(cp->rc_iters, &cookie)) != NULL) { 6657c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6667c478bd9Sstevel@tonic-gate iter_destroy(iter); 6677c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * Ensure that the passed client id is no longer usable, wait for any 6747c478bd9Sstevel@tonic-gate * outstanding invocations to complete, then destroy the client 6757c478bd9Sstevel@tonic-gate * structure. 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate static void 6787c478bd9Sstevel@tonic-gate client_destroy(uint32_t id) 6797c478bd9Sstevel@tonic-gate { 6807c478bd9Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(id); 6817c478bd9Sstevel@tonic-gate repcache_client_t *cp; 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate cp = uu_list_find(bp->cb_list, &id, NULL, NULL); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate if (cp == NULL) { 6887c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 6897c478bd9Sstevel@tonic-gate return; 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate uu_list_remove(bp->cb_list, cp); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* kick the waiters out */ 6977c478bd9Sstevel@tonic-gate rc_notify_info_fini(&cp->rc_notify_info); 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 7007c478bd9Sstevel@tonic-gate assert(!(cp->rc_flags & RC_CLIENT_DEAD)); 7017c478bd9Sstevel@tonic-gate cp->rc_flags |= RC_CLIENT_DEAD; 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate if (cp->rc_doorfd != -1) { 7047c478bd9Sstevel@tonic-gate if (door_revoke(cp->rc_doorfd) < 0) 7057c478bd9Sstevel@tonic-gate perror("door_revoke"); 7067c478bd9Sstevel@tonic-gate cp->rc_doorfd = -1; 7077c478bd9Sstevel@tonic-gate cp->rc_doorid = INVALID_DOORID; 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate while (cp->rc_refcnt > 0) 7117c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock); 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == 0 && cp->rc_notify_thr == 0); 7147c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate /* 7177c478bd9Sstevel@tonic-gate * destroy outstanding objects 7187c478bd9Sstevel@tonic-gate */ 7197c478bd9Sstevel@tonic-gate entity_cleanup(cp); 7207c478bd9Sstevel@tonic-gate iter_cleanup(cp); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate /* 7237c478bd9Sstevel@tonic-gate * clean up notifications 7247c478bd9Sstevel@tonic-gate */ 7257c478bd9Sstevel@tonic-gate rc_pg_notify_fini(&cp->rc_pg_notify); 7267c478bd9Sstevel@tonic-gate 727*5b7f77adStw21770 /* 728*5b7f77adStw21770 * clean up annotations 729*5b7f77adStw21770 */ 730*5b7f77adStw21770 if (cp->rc_operation != NULL) 731*5b7f77adStw21770 free((void *)cp->rc_operation); 732*5b7f77adStw21770 if (cp->rc_file != NULL) 733*5b7f77adStw21770 free((void *)cp->rc_file); 734*5b7f77adStw21770 735*5b7f77adStw21770 /* 736*5b7f77adStw21770 * End audit session. 737*5b7f77adStw21770 */ 738*5b7f77adStw21770 (void) adt_end_session(cp->rc_adt_session); 739*5b7f77adStw21770 7407c478bd9Sstevel@tonic-gate client_free(cp); 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* 7447c478bd9Sstevel@tonic-gate * Fails with 7457c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - the entity is already set up with a different type 7467c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory 7477c478bd9Sstevel@tonic-gate */ 7487c478bd9Sstevel@tonic-gate static int 7497c478bd9Sstevel@tonic-gate entity_setup(repcache_client_t *cp, struct rep_protocol_entity_setup *rpr) 7507c478bd9Sstevel@tonic-gate { 7517c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 7527c478bd9Sstevel@tonic-gate uint32_t type; 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate client_start_insert(cp); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) { 7577c478bd9Sstevel@tonic-gate type = ep->re_type; 7587c478bd9Sstevel@tonic-gate entity_release(ep); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate client_end_insert(cp); 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate if (type != rpr->rpr_entitytype) 7637c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 7647c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate switch (type = rpr->rpr_entitytype) { 7687c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SCOPE: 7697c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE: 7707c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE: 7717c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPSHOT: 7727c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPLEVEL: 7737c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP: 7747c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTY: 7757c478bd9Sstevel@tonic-gate break; 7767c478bd9Sstevel@tonic-gate default: 7777c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate ep = entity_alloc(cp); 7817c478bd9Sstevel@tonic-gate if (ep == NULL) { 7827c478bd9Sstevel@tonic-gate client_end_insert(cp); 7837c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate ep->re_id = rpr->rpr_entityid; 7877c478bd9Sstevel@tonic-gate ep->re_changeid = INVALID_CHANGEID; 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate ep->re_type = type; 7907c478bd9Sstevel@tonic-gate rc_node_ptr_init(&ep->re_node); 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate entity_add(cp, ep); 7937c478bd9Sstevel@tonic-gate client_end_insert(cp); 7947c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7987c478bd9Sstevel@tonic-gate static void 7997c478bd9Sstevel@tonic-gate entity_name(repcache_client_t *cp, const void *in, size_t insz, void *out_arg, 8007c478bd9Sstevel@tonic-gate size_t *outsz, void *arg) 8017c478bd9Sstevel@tonic-gate { 8027c478bd9Sstevel@tonic-gate const struct rep_protocol_entity_name *rpr = in; 8037c478bd9Sstevel@tonic-gate struct rep_protocol_name_response *out = out_arg; 8047c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 8057c478bd9Sstevel@tonic-gate size_t sz = sizeof (out->rpr_name); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate if (ep == NULL) { 8127c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 8137c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8147c478bd9Sstevel@tonic-gate return; 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate out->rpr_response = rc_node_name(&ep->re_node, out->rpr_name, 8177c478bd9Sstevel@tonic-gate sz, rpr->rpr_answertype, &sz); 8187c478bd9Sstevel@tonic-gate entity_release(ep); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * If we fail, we only return the response code. 8227c478bd9Sstevel@tonic-gate * If we succeed, we don't return anything after the '\0' in rpr_name. 8237c478bd9Sstevel@tonic-gate */ 8247c478bd9Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 8257c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8267c478bd9Sstevel@tonic-gate else 8277c478bd9Sstevel@tonic-gate *outsz = offsetof(struct rep_protocol_name_response, 8287c478bd9Sstevel@tonic-gate rpr_name[sz + 1]); 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8327c478bd9Sstevel@tonic-gate static void 8337c478bd9Sstevel@tonic-gate entity_parent_type(repcache_client_t *cp, const void *in, size_t insz, 8347c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 8357c478bd9Sstevel@tonic-gate { 8367c478bd9Sstevel@tonic-gate const struct rep_protocol_entity_name *rpr = in; 8377c478bd9Sstevel@tonic-gate struct rep_protocol_integer_response *out = out_arg; 8387c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate if (ep == NULL) { 8457c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 8467c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8477c478bd9Sstevel@tonic-gate return; 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate out->rpr_response = rc_node_parent_type(&ep->re_node, &out->rpr_value); 8517c478bd9Sstevel@tonic-gate entity_release(ep); 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 8547c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate /* 8587c478bd9Sstevel@tonic-gate * Fails with 8597c478bd9Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 8607c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 8617c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 8627c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type 8637c478bd9Sstevel@tonic-gate * _DELETED - np has been deleted 8647c478bd9Sstevel@tonic-gate * _NOT_FOUND - no child with that name/type combo found 8657c478bd9Sstevel@tonic-gate * _NO_RESOURCES 8667c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 8677c478bd9Sstevel@tonic-gate */ 8687c478bd9Sstevel@tonic-gate static int 8697c478bd9Sstevel@tonic-gate entity_get_child(repcache_client_t *cp, 8707c478bd9Sstevel@tonic-gate struct rep_protocol_entity_get_child *rpr) 8717c478bd9Sstevel@tonic-gate { 8727c478bd9Sstevel@tonic-gate repcache_entity_t *parent, *child; 8737c478bd9Sstevel@tonic-gate int result; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 8767c478bd9Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate result = entity_find2(cp, childid, &child, parentid, &parent); 8797c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 8807c478bd9Sstevel@tonic-gate return (result); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate result = rc_node_get_child(&parent->re_node, rpr->rpr_name, 8857c478bd9Sstevel@tonic-gate child->re_type, &child->re_node); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate entity_release(child); 8887c478bd9Sstevel@tonic-gate entity_release(parent); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate return (result); 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* 8947c478bd9Sstevel@tonic-gate * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED, 8957c478bd9Sstevel@tonic-gate * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS. 8967c478bd9Sstevel@tonic-gate * Fails with 8977c478bd9Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 8987c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 8997c478bd9Sstevel@tonic-gate * _NOT_SET - child is not set 9007c478bd9Sstevel@tonic-gate * _DELETED - child has been deleted 9017c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - child's parent does not match that of the parent register 9027c478bd9Sstevel@tonic-gate * _NOT_FOUND - child has no parent (and is a scope) 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate static int 9057c478bd9Sstevel@tonic-gate entity_get_parent(repcache_client_t *cp, struct rep_protocol_entity_parent *rpr) 9067c478bd9Sstevel@tonic-gate { 9077c478bd9Sstevel@tonic-gate repcache_entity_t *child, *parent; 9087c478bd9Sstevel@tonic-gate int result; 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate uint32_t childid = rpr->rpr_entityid; 9117c478bd9Sstevel@tonic-gate uint32_t outid = rpr->rpr_outid; 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate result = entity_find2(cp, childid, &child, outid, &parent); 9147c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 9157c478bd9Sstevel@tonic-gate return (result); 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate result = rc_node_get_parent(&child->re_node, parent->re_type, 9187c478bd9Sstevel@tonic-gate &parent->re_node); 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate entity_release(child); 9217c478bd9Sstevel@tonic-gate entity_release(parent); 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate return (result); 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate static int 9277c478bd9Sstevel@tonic-gate entity_get(repcache_client_t *cp, struct rep_protocol_entity_get *rpr) 9287c478bd9Sstevel@tonic-gate { 9297c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 9307c478bd9Sstevel@tonic-gate int result; 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate if (ep == NULL) 9357c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate switch (rpr->rpr_object) { 9387c478bd9Sstevel@tonic-gate case RP_ENTITY_GET_INVALIDATE: 9397c478bd9Sstevel@tonic-gate rc_node_clear(&ep->re_node, 0); 9407c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 9417c478bd9Sstevel@tonic-gate break; 9427c478bd9Sstevel@tonic-gate case RP_ENTITY_GET_MOST_LOCAL_SCOPE: 9437c478bd9Sstevel@tonic-gate result = rc_local_scope(ep->re_type, &ep->re_node); 9447c478bd9Sstevel@tonic-gate break; 9457c478bd9Sstevel@tonic-gate default: 9467c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 9477c478bd9Sstevel@tonic-gate break; 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate entity_release(ep); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate return (result); 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate static int 9567c478bd9Sstevel@tonic-gate entity_update(repcache_client_t *cp, struct rep_protocol_entity_update *rpr) 9577c478bd9Sstevel@tonic-gate { 9587c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 9597c478bd9Sstevel@tonic-gate int result; 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 9627c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate if (ep == NULL) 9677c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate if (ep->re_changeid == rpr->rpr_changeid) { 9707c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_DONE; 9717c478bd9Sstevel@tonic-gate } else { 9727c478bd9Sstevel@tonic-gate result = rc_node_update(&ep->re_node); 9737c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_DONE) 9747c478bd9Sstevel@tonic-gate ep->re_changeid = rpr->rpr_changeid; 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate entity_release(ep); 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate return (result); 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate static int 9837c478bd9Sstevel@tonic-gate entity_reset(repcache_client_t *cp, struct rep_protocol_entity_reset *rpr) 9847c478bd9Sstevel@tonic-gate { 9857c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 9887c478bd9Sstevel@tonic-gate if (ep == NULL) 9897c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate rc_node_clear(&ep->re_node, 0); 9927c478bd9Sstevel@tonic-gate ep->re_txstate = REPCACHE_TX_INIT; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate entity_release(ep); 9957c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate /* 9997c478bd9Sstevel@tonic-gate * Fails with 10007c478bd9Sstevel@tonic-gate * _BAD_REQUEST - request has invalid changeid 10017c478bd9Sstevel@tonic-gate * rpr_name is invalid 10027c478bd9Sstevel@tonic-gate * cannot create children for parent's type of node 10037c478bd9Sstevel@tonic-gate * _DUPLICATE_ID - request has duplicate ids 10047c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - request has unknown id 10057c478bd9Sstevel@tonic-gate * _DELETED - parent has been deleted 10067c478bd9Sstevel@tonic-gate * _NOT_SET - parent is reset 10077c478bd9Sstevel@tonic-gate * _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP 10087c478bd9Sstevel@tonic-gate * _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid 10097c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have children of type rpr_childtype 10107c478bd9Sstevel@tonic-gate * _NO_RESOURCES 10117c478bd9Sstevel@tonic-gate * _PERMISSION_DENIED 10127c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 10137c478bd9Sstevel@tonic-gate * _BACKEND_READONLY 10147c478bd9Sstevel@tonic-gate * _EXISTS - child already exists 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate static int 10177c478bd9Sstevel@tonic-gate entity_create_child(repcache_client_t *cp, 10187c478bd9Sstevel@tonic-gate struct rep_protocol_entity_create_child *rpr) 10197c478bd9Sstevel@tonic-gate { 10207c478bd9Sstevel@tonic-gate repcache_entity_t *parent; 10217c478bd9Sstevel@tonic-gate repcache_entity_t *child; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 10247c478bd9Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate int result; 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 10297c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate result = entity_find2(cp, parentid, &parent, childid, &child); 10327c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 10337c478bd9Sstevel@tonic-gate return (result); 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate if (child->re_changeid == rpr->rpr_changeid) { 10387c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 10397c478bd9Sstevel@tonic-gate } else { 10407c478bd9Sstevel@tonic-gate result = rc_node_create_child(&parent->re_node, 10417c478bd9Sstevel@tonic-gate rpr->rpr_childtype, rpr->rpr_name, &child->re_node); 10427c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 10437c478bd9Sstevel@tonic-gate child->re_changeid = rpr->rpr_changeid; 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate entity_release(parent); 10477c478bd9Sstevel@tonic-gate entity_release(child); 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate return (result); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate static int 10537c478bd9Sstevel@tonic-gate entity_create_pg(repcache_client_t *cp, 10547c478bd9Sstevel@tonic-gate struct rep_protocol_entity_create_pg *rpr) 10557c478bd9Sstevel@tonic-gate { 10567c478bd9Sstevel@tonic-gate repcache_entity_t *parent; 10577c478bd9Sstevel@tonic-gate repcache_entity_t *child; 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 10607c478bd9Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate int result; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 10657c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate result = entity_find2(cp, parentid, &parent, childid, &child); 10687c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 10697c478bd9Sstevel@tonic-gate return (result); 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 10727c478bd9Sstevel@tonic-gate rpr->rpr_type[sizeof (rpr->rpr_type) - 1] = 0; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate if (child->re_changeid == rpr->rpr_changeid) { 10757c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 10767c478bd9Sstevel@tonic-gate } else { 10777c478bd9Sstevel@tonic-gate result = rc_node_create_child_pg(&parent->re_node, 10787c478bd9Sstevel@tonic-gate child->re_type, rpr->rpr_name, rpr->rpr_type, 10797c478bd9Sstevel@tonic-gate rpr->rpr_flags, &child->re_node); 10807c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 10817c478bd9Sstevel@tonic-gate child->re_changeid = rpr->rpr_changeid; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate entity_release(parent); 10857c478bd9Sstevel@tonic-gate entity_release(child); 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate return (result); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate static int 10917c478bd9Sstevel@tonic-gate entity_delete(repcache_client_t *cp, 10927c478bd9Sstevel@tonic-gate struct rep_protocol_entity_delete *rpr) 10937c478bd9Sstevel@tonic-gate { 10947c478bd9Sstevel@tonic-gate repcache_entity_t *entity; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate uint32_t entityid = rpr->rpr_entityid; 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate int result; 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 11017c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate entity = entity_find(cp, entityid); 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate if (entity == NULL) 11067c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate if (entity->re_changeid == rpr->rpr_changeid) { 11097c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 11107c478bd9Sstevel@tonic-gate } else { 11117c478bd9Sstevel@tonic-gate result = rc_node_delete(&entity->re_node); 11127c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 11137c478bd9Sstevel@tonic-gate entity->re_changeid = rpr->rpr_changeid; 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate entity_release(entity); 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate return (result); 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 11227c478bd9Sstevel@tonic-gate entity_teardown(repcache_client_t *cp, struct rep_protocol_entity_teardown *rpr) 11237c478bd9Sstevel@tonic-gate { 11247c478bd9Sstevel@tonic-gate entity_remove(cp, rpr->rpr_entityid); 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate /* 11307c478bd9Sstevel@tonic-gate * Fails with 11317c478bd9Sstevel@tonic-gate * _MISORDERED - the iterator exists and is not reset 11327c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate static int 11357c478bd9Sstevel@tonic-gate iter_setup(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 11367c478bd9Sstevel@tonic-gate { 11377c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 11387c478bd9Sstevel@tonic-gate uint32_t sequence; 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate client_start_insert(cp); 11417c478bd9Sstevel@tonic-gate /* 11427c478bd9Sstevel@tonic-gate * If the iter already exists, and hasn't been read from, 11437c478bd9Sstevel@tonic-gate * we assume the previous call succeeded. 11447c478bd9Sstevel@tonic-gate */ 11457c478bd9Sstevel@tonic-gate if ((iter = iter_find(cp, rpr->rpr_iterid)) != NULL) { 11467c478bd9Sstevel@tonic-gate sequence = iter->ri_sequence; 11477c478bd9Sstevel@tonic-gate iter_release(iter); 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate client_end_insert(cp); 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate if (sequence != 0) 11527c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 11537c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate iter = iter_alloc(cp); 11577c478bd9Sstevel@tonic-gate if (iter == NULL) { 11587c478bd9Sstevel@tonic-gate client_end_insert(cp); 11597c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate iter->ri_id = rpr->rpr_iterid; 11637c478bd9Sstevel@tonic-gate iter->ri_type = REP_PROTOCOL_TYPE_INVALID; 11647c478bd9Sstevel@tonic-gate iter->ri_sequence = 0; 11657c478bd9Sstevel@tonic-gate iter_add(cp, iter); 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate client_end_insert(cp); 11687c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate /* 11727c478bd9Sstevel@tonic-gate * Fails with 11737c478bd9Sstevel@tonic-gate * _UNKNOWN_ID 11747c478bd9Sstevel@tonic-gate * _MISORDERED - iterator has already been started 11757c478bd9Sstevel@tonic-gate * _NOT_SET 11767c478bd9Sstevel@tonic-gate * _DELETED 11777c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - entity cannot have type children 11787c478bd9Sstevel@tonic-gate * _BAD_REQUEST - rpr_flags is invalid 11797c478bd9Sstevel@tonic-gate * rpr_pattern is invalid 11807c478bd9Sstevel@tonic-gate * _NO_RESOURCES 11817c478bd9Sstevel@tonic-gate * _INVALID_TYPE 11827c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 11837c478bd9Sstevel@tonic-gate */ 11847c478bd9Sstevel@tonic-gate static int 11857c478bd9Sstevel@tonic-gate iter_start(repcache_client_t *cp, struct rep_protocol_iter_start *rpr) 11867c478bd9Sstevel@tonic-gate { 11877c478bd9Sstevel@tonic-gate int result; 11887c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 11897c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter, 11927c478bd9Sstevel@tonic-gate rpr->rpr_entity, &ep); 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 11957c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate if (iter->ri_sequence > 1) { 11987c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 11997c478bd9Sstevel@tonic-gate goto end; 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate if (iter->ri_sequence == 1) { 12037c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 12047c478bd9Sstevel@tonic-gate goto end; 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0; 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate result = rc_node_setup_iter(&ep->re_node, &iter->ri_iter, 12107c478bd9Sstevel@tonic-gate rpr->rpr_itertype, rpr->rpr_flags, rpr->rpr_pattern); 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 12137c478bd9Sstevel@tonic-gate iter->ri_sequence++; 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate end: 12167c478bd9Sstevel@tonic-gate iter_release(iter); 12177c478bd9Sstevel@tonic-gate entity_release(ep); 12187c478bd9Sstevel@tonic-gate return (result); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate * Returns 12237c478bd9Sstevel@tonic-gate * _UNKNOWN_ID 12247c478bd9Sstevel@tonic-gate * _NOT_SET - iter has not been started 12257c478bd9Sstevel@tonic-gate * _MISORDERED 12267c478bd9Sstevel@tonic-gate * _BAD_REQUEST - iter walks values 12277c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - iter does not walk type entities 12287c478bd9Sstevel@tonic-gate * _DELETED - parent was deleted 12297c478bd9Sstevel@tonic-gate * _NO_RESOURCES 12307c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 12317c478bd9Sstevel@tonic-gate * _DONE 12327c478bd9Sstevel@tonic-gate * _SUCCESS 12337c478bd9Sstevel@tonic-gate * 12347c478bd9Sstevel@tonic-gate * For composed property group iterators, can also return 12357c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have type children 12367c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 12377c478bd9Sstevel@tonic-gate */ 12387c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 12397c478bd9Sstevel@tonic-gate iter_read(repcache_client_t *cp, struct rep_protocol_iter_read *rpr) 12407c478bd9Sstevel@tonic-gate { 12417c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 12427c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 12437c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 12447c478bd9Sstevel@tonic-gate uint32_t sequence; 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter, 12477c478bd9Sstevel@tonic-gate rpr->rpr_entityid, &ep); 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 12507c478bd9Sstevel@tonic-gate return (result); 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate sequence = rpr->rpr_sequence; 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate if (iter->ri_sequence == 0) { 12557c478bd9Sstevel@tonic-gate iter_release(iter); 12567c478bd9Sstevel@tonic-gate entity_release(ep); 12577c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_SET); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate if (sequence == 1) { 12617c478bd9Sstevel@tonic-gate iter_release(iter); 12627c478bd9Sstevel@tonic-gate entity_release(ep); 12637c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate if (sequence == iter->ri_sequence) { 12677c478bd9Sstevel@tonic-gate iter_release(iter); 12687c478bd9Sstevel@tonic-gate entity_release(ep); 12697c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate if (sequence == iter->ri_sequence + 1) { 12737c478bd9Sstevel@tonic-gate result = rc_iter_next(iter->ri_iter, &ep->re_node, 12747c478bd9Sstevel@tonic-gate ep->re_type); 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 12777c478bd9Sstevel@tonic-gate iter->ri_sequence++; 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate iter_release(iter); 12807c478bd9Sstevel@tonic-gate entity_release(ep); 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate return (result); 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate iter_release(iter); 12867c478bd9Sstevel@tonic-gate entity_release(ep); 12877c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12917c478bd9Sstevel@tonic-gate static void 12927c478bd9Sstevel@tonic-gate iter_read_value(repcache_client_t *cp, const void *in, size_t insz, 12937c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 12947c478bd9Sstevel@tonic-gate { 12957c478bd9Sstevel@tonic-gate const struct rep_protocol_iter_read_value *rpr = in; 12967c478bd9Sstevel@tonic-gate struct rep_protocol_value_response *out = out_arg; 12977c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 13007c478bd9Sstevel@tonic-gate uint32_t sequence; 13017c478bd9Sstevel@tonic-gate int repeat; 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate iter = iter_find(cp, rpr->rpr_iterid); 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate if (iter == NULL) { 13087c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 13097c478bd9Sstevel@tonic-gate goto out; 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate sequence = rpr->rpr_sequence; 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate if (iter->ri_sequence == 0) { 13157c478bd9Sstevel@tonic-gate iter_release(iter); 13167c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_NOT_SET; 13177c478bd9Sstevel@tonic-gate goto out; 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate repeat = (sequence == iter->ri_sequence); 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate if (sequence == 1 || (!repeat && sequence != iter->ri_sequence + 1)) { 13237c478bd9Sstevel@tonic-gate iter_release(iter); 13247c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 13257c478bd9Sstevel@tonic-gate goto out; 13267c478bd9Sstevel@tonic-gate } 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate result = rc_iter_next_value(iter->ri_iter, out, outsz, repeat); 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate if (!repeat && result == REP_PROTOCOL_SUCCESS) 13317c478bd9Sstevel@tonic-gate iter->ri_sequence++; 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate iter_release(iter); 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate out: 13367c478bd9Sstevel@tonic-gate /* 13377c478bd9Sstevel@tonic-gate * If we fail, we only return the response code. 13387c478bd9Sstevel@tonic-gate * If we succeed, rc_iter_next_value has shortened *outsz 13397c478bd9Sstevel@tonic-gate * to only include the value bytes needed. 13407c478bd9Sstevel@tonic-gate */ 13417c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS && result != REP_PROTOCOL_DONE) 13427c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate out->rpr_response = result; 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate static int 13487c478bd9Sstevel@tonic-gate iter_reset(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 13497c478bd9Sstevel@tonic-gate { 13507c478bd9Sstevel@tonic-gate repcache_iter_t *iter = iter_find(cp, rpr->rpr_iterid); 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate if (iter == NULL) 13537c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate if (iter->ri_sequence != 0) { 13567c478bd9Sstevel@tonic-gate iter->ri_sequence = 0; 13577c478bd9Sstevel@tonic-gate rc_iter_destroy(&iter->ri_iter); 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate iter_release(iter); 13607c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 13617c478bd9Sstevel@tonic-gate } 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 13647c478bd9Sstevel@tonic-gate iter_teardown(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 13657c478bd9Sstevel@tonic-gate { 13667c478bd9Sstevel@tonic-gate iter_remove(cp, rpr->rpr_iterid); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 13727c478bd9Sstevel@tonic-gate tx_start(repcache_client_t *cp, struct rep_protocol_transaction_start *rpr) 13737c478bd9Sstevel@tonic-gate { 13747c478bd9Sstevel@tonic-gate repcache_entity_t *tx; 13757c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 13767c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate uint32_t txid = rpr->rpr_entityid_tx; 13797c478bd9Sstevel@tonic-gate uint32_t epid = rpr->rpr_entityid; 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate result = entity_find2(cp, txid, &tx, epid, &ep); 13827c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 13837c478bd9Sstevel@tonic-gate return (result); 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate if (tx->re_txstate == REPCACHE_TX_SETUP) { 13867c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 13877c478bd9Sstevel@tonic-gate goto end; 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate if (tx->re_txstate != REPCACHE_TX_INIT) { 13907c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 13917c478bd9Sstevel@tonic-gate goto end; 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate result = rc_node_setup_tx(&ep->re_node, &tx->re_node); 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate end: 13977c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 13987c478bd9Sstevel@tonic-gate tx->re_txstate = REPCACHE_TX_SETUP; 13997c478bd9Sstevel@tonic-gate else 14007c478bd9Sstevel@tonic-gate rc_node_clear(&tx->re_node, 0); 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate entity_release(ep); 14037c478bd9Sstevel@tonic-gate entity_release(tx); 14047c478bd9Sstevel@tonic-gate return (result); 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14087c478bd9Sstevel@tonic-gate static void 14097c478bd9Sstevel@tonic-gate tx_commit(repcache_client_t *cp, const void *in, size_t insz, 14107c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 14117c478bd9Sstevel@tonic-gate { 14127c478bd9Sstevel@tonic-gate struct rep_protocol_response *out = out_arg; 14137c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_commit *rpr = in; 14147c478bd9Sstevel@tonic-gate repcache_entity_t *tx; 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 14177c478bd9Sstevel@tonic-gate assert(insz >= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE); 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate if (rpr->rpr_size != insz) { 14207c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_BAD_REQUEST; 14217c478bd9Sstevel@tonic-gate return; 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate tx = entity_find(cp, rpr->rpr_entityid); 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate if (tx == NULL) { 14277c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 14287c478bd9Sstevel@tonic-gate return; 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate switch (tx->re_txstate) { 14327c478bd9Sstevel@tonic-gate case REPCACHE_TX_INIT: 14337c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_MISORDERED; 14347c478bd9Sstevel@tonic-gate break; 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate case REPCACHE_TX_SETUP: 14377c478bd9Sstevel@tonic-gate out->rpr_response = rc_tx_commit(&tx->re_node, rpr->rpr_cmd, 14387c478bd9Sstevel@tonic-gate insz - REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE); 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate if (out->rpr_response == REP_PROTOCOL_SUCCESS) { 14417c478bd9Sstevel@tonic-gate tx->re_txstate = REPCACHE_TX_COMMITTED; 14427c478bd9Sstevel@tonic-gate rc_node_clear(&tx->re_node, 0); 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate break; 14467c478bd9Sstevel@tonic-gate case REPCACHE_TX_COMMITTED: 14477c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_SUCCESS; 14487c478bd9Sstevel@tonic-gate break; 14497c478bd9Sstevel@tonic-gate default: 14507c478bd9Sstevel@tonic-gate assert(0); /* CAN'T HAPPEN */ 14517c478bd9Sstevel@tonic-gate break; 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate entity_release(tx); 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 14587c478bd9Sstevel@tonic-gate next_snaplevel(repcache_client_t *cp, struct rep_protocol_entity_pair *rpr) 14597c478bd9Sstevel@tonic-gate { 14607c478bd9Sstevel@tonic-gate repcache_entity_t *src; 14617c478bd9Sstevel@tonic-gate repcache_entity_t *dest; 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entity_src; 14647c478bd9Sstevel@tonic-gate uint32_t destid = rpr->rpr_entity_dst; 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate int result; 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 14697c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 14707c478bd9Sstevel@tonic-gate return (result); 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate result = rc_node_next_snaplevel(&src->re_node, &dest->re_node); 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate entity_release(src); 14757c478bd9Sstevel@tonic-gate entity_release(dest); 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate return (result); 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 14817c478bd9Sstevel@tonic-gate snapshot_take(repcache_client_t *cp, struct rep_protocol_snapshot_take *rpr) 14827c478bd9Sstevel@tonic-gate { 14837c478bd9Sstevel@tonic-gate repcache_entity_t *src; 14847c478bd9Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 14857c478bd9Sstevel@tonic-gate repcache_entity_t *dest; 14867c478bd9Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate int result; 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 14917c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 14927c478bd9Sstevel@tonic-gate return (result); 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 14957c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 14967c478bd9Sstevel@tonic-gate } else { 14977c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate if (rpr->rpr_flags == REP_SNAPSHOT_NEW) 15007c478bd9Sstevel@tonic-gate result = rc_snapshot_take_new(&src->re_node, NULL, 15017c478bd9Sstevel@tonic-gate NULL, rpr->rpr_name, &dest->re_node); 15027c478bd9Sstevel@tonic-gate else if (rpr->rpr_flags == REP_SNAPSHOT_ATTACH && 15037c478bd9Sstevel@tonic-gate rpr->rpr_name[0] == 0) 15047c478bd9Sstevel@tonic-gate result = rc_snapshot_take_attach(&src->re_node, 15057c478bd9Sstevel@tonic-gate &dest->re_node); 15067c478bd9Sstevel@tonic-gate else 15077c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate entity_release(src); 15107c478bd9Sstevel@tonic-gate entity_release(dest); 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate return (result); 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 15167c478bd9Sstevel@tonic-gate snapshot_take_named(repcache_client_t *cp, 15177c478bd9Sstevel@tonic-gate struct rep_protocol_snapshot_take_named *rpr) 15187c478bd9Sstevel@tonic-gate { 15197c478bd9Sstevel@tonic-gate repcache_entity_t *src; 15207c478bd9Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 15217c478bd9Sstevel@tonic-gate repcache_entity_t *dest; 15227c478bd9Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate int result; 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 15277c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 15287c478bd9Sstevel@tonic-gate return (result); 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 15317c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 15327c478bd9Sstevel@tonic-gate } else { 15337c478bd9Sstevel@tonic-gate rpr->rpr_svcname[sizeof (rpr->rpr_svcname) - 1] = 0; 15347c478bd9Sstevel@tonic-gate rpr->rpr_instname[sizeof (rpr->rpr_instname) - 1] = 0; 15357c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate result = rc_snapshot_take_new(&src->re_node, rpr->rpr_svcname, 15387c478bd9Sstevel@tonic-gate rpr->rpr_instname, rpr->rpr_name, &dest->re_node); 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate entity_release(src); 15417c478bd9Sstevel@tonic-gate entity_release(dest); 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate return (result); 15447c478bd9Sstevel@tonic-gate } 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 15477c478bd9Sstevel@tonic-gate snapshot_attach(repcache_client_t *cp, struct rep_protocol_snapshot_attach *rpr) 15487c478bd9Sstevel@tonic-gate { 15497c478bd9Sstevel@tonic-gate repcache_entity_t *src; 15507c478bd9Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 15517c478bd9Sstevel@tonic-gate repcache_entity_t *dest; 15527c478bd9Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate int result; 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 15577c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 15587c478bd9Sstevel@tonic-gate return (result); 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate result = rc_snapshot_attach(&src->re_node, &dest->re_node); 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate entity_release(src); 15637c478bd9Sstevel@tonic-gate entity_release(dest); 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate return (result); 15667c478bd9Sstevel@tonic-gate } 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15697c478bd9Sstevel@tonic-gate static void 15707c478bd9Sstevel@tonic-gate property_get_type(repcache_client_t *cp, const void *in, size_t insz, 15717c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 15727c478bd9Sstevel@tonic-gate { 15737c478bd9Sstevel@tonic-gate const struct rep_protocol_property_request *rpr = in; 15747c478bd9Sstevel@tonic-gate struct rep_protocol_integer_response *out = out_arg; 15757c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 15767c478bd9Sstevel@tonic-gate rep_protocol_value_type_t t = 0; 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate if (ep == NULL) { 15837c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 15847c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 15857c478bd9Sstevel@tonic-gate return; 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate out->rpr_response = rc_node_get_property_type(&ep->re_node, &t); 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate entity_release(ep); 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 15937c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 15947c478bd9Sstevel@tonic-gate else 15957c478bd9Sstevel@tonic-gate out->rpr_value = t; 15967c478bd9Sstevel@tonic-gate } 15977c478bd9Sstevel@tonic-gate 15987c478bd9Sstevel@tonic-gate /* 15997c478bd9Sstevel@tonic-gate * Fails with: 16007c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 16017c478bd9Sstevel@tonic-gate * _NOT_SET - The property is not set 16027c478bd9Sstevel@tonic-gate * _DELETED - The property has been deleted 16037c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - The object is not a property 16047c478bd9Sstevel@tonic-gate * _NOT_FOUND - The property has no values. 16057c478bd9Sstevel@tonic-gate * 16067c478bd9Sstevel@tonic-gate * Succeeds with: 16077c478bd9Sstevel@tonic-gate * _SUCCESS - The property has 1 value. 16087c478bd9Sstevel@tonic-gate * _TRUNCATED - The property has >1 value. 16097c478bd9Sstevel@tonic-gate */ 16107c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16117c478bd9Sstevel@tonic-gate static void 16127c478bd9Sstevel@tonic-gate property_get_value(repcache_client_t *cp, const void *in, size_t insz, 16137c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 16147c478bd9Sstevel@tonic-gate { 16157c478bd9Sstevel@tonic-gate const struct rep_protocol_property_request *rpr = in; 16167c478bd9Sstevel@tonic-gate struct rep_protocol_value_response *out = out_arg; 16177c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 16227c478bd9Sstevel@tonic-gate if (ep == NULL) { 16237c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 16247c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 16257c478bd9Sstevel@tonic-gate return; 16267c478bd9Sstevel@tonic-gate } 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate out->rpr_response = rc_node_get_property_value(&ep->re_node, out, 16297c478bd9Sstevel@tonic-gate outsz); 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate entity_release(ep); 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate /* 16347c478bd9Sstevel@tonic-gate * If we fail, we only return the response code. 16357c478bd9Sstevel@tonic-gate * If we succeed, rc_node_get_property_value has shortened *outsz 16367c478bd9Sstevel@tonic-gate * to only include the value bytes needed. 16377c478bd9Sstevel@tonic-gate */ 16387c478bd9Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS && 16397c478bd9Sstevel@tonic-gate out->rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) 16407c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 16447c478bd9Sstevel@tonic-gate propertygrp_notify(repcache_client_t *cp, 16457c478bd9Sstevel@tonic-gate struct rep_protocol_propertygrp_request *rpr, int *out_fd) 16467c478bd9Sstevel@tonic-gate { 16477c478bd9Sstevel@tonic-gate int fds[2]; 16487c478bd9Sstevel@tonic-gate int ours, theirs; 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 16517c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate if (pipe(fds) < 0) 16547c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate ours = fds[0]; 16577c478bd9Sstevel@tonic-gate theirs = fds[1]; 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) == NULL) { 16607c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 16617c478bd9Sstevel@tonic-gate goto fail; 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate 16647c478bd9Sstevel@tonic-gate /* 16657c478bd9Sstevel@tonic-gate * While the following can race with other threads setting up a 16667c478bd9Sstevel@tonic-gate * notification, the worst that can happen is that our fd has 16677c478bd9Sstevel@tonic-gate * already been closed before we return. 16687c478bd9Sstevel@tonic-gate */ 16697c478bd9Sstevel@tonic-gate result = rc_pg_notify_setup(&cp->rc_pg_notify, &ep->re_node, 16707c478bd9Sstevel@tonic-gate ours); 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate entity_release(ep); 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 16757c478bd9Sstevel@tonic-gate goto fail; 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate *out_fd = theirs; 16787c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate fail: 16817c478bd9Sstevel@tonic-gate (void) close(ours); 16827c478bd9Sstevel@tonic-gate (void) close(theirs); 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate return (result); 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 16887c478bd9Sstevel@tonic-gate client_add_notify(repcache_client_t *cp, 16897c478bd9Sstevel@tonic-gate struct rep_protocol_notify_request *rpr) 16907c478bd9Sstevel@tonic-gate { 16917c478bd9Sstevel@tonic-gate rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0; 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate switch (rpr->rpr_type) { 16947c478bd9Sstevel@tonic-gate case REP_PROTOCOL_NOTIFY_PGNAME: 16957c478bd9Sstevel@tonic-gate return (rc_notify_info_add_name(&cp->rc_notify_info, 16967c478bd9Sstevel@tonic-gate rpr->rpr_pattern)); 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate case REP_PROTOCOL_NOTIFY_PGTYPE: 16997c478bd9Sstevel@tonic-gate return (rc_notify_info_add_type(&cp->rc_notify_info, 17007c478bd9Sstevel@tonic-gate rpr->rpr_pattern)); 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate default: 17037c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17087c478bd9Sstevel@tonic-gate static void 17097c478bd9Sstevel@tonic-gate client_wait(repcache_client_t *cp, const void *in, size_t insz, 17107c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 17117c478bd9Sstevel@tonic-gate { 17127c478bd9Sstevel@tonic-gate int result; 17137c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 17147c478bd9Sstevel@tonic-gate const struct rep_protocol_wait_request *rpr = in; 17157c478bd9Sstevel@tonic-gate struct rep_protocol_fmri_response *out = out_arg; 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 17187c478bd9Sstevel@tonic-gate 17197c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 17207c478bd9Sstevel@tonic-gate if (cp->rc_notify_thr != 0) { 17217c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17227c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_EXISTS; 17237c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 17247c478bd9Sstevel@tonic-gate return; 17257c478bd9Sstevel@tonic-gate } 17267c478bd9Sstevel@tonic-gate cp->rc_notify_thr = pthread_self(); 17277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate result = rc_notify_info_wait(&cp->rc_notify_info, &cp->rc_notify_ptr, 17307c478bd9Sstevel@tonic-gate out->rpr_fmri, sizeof (out->rpr_fmri)); 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) { 17337c478bd9Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) { 17347c478bd9Sstevel@tonic-gate if (ep->re_type == REP_PROTOCOL_ENTITY_PROPERTYGRP) { 17357c478bd9Sstevel@tonic-gate rc_node_ptr_assign(&ep->re_node, 17367c478bd9Sstevel@tonic-gate &cp->rc_notify_ptr); 17377c478bd9Sstevel@tonic-gate } else { 17387c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate entity_release(ep); 17417c478bd9Sstevel@tonic-gate } else { 17427c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 17437c478bd9Sstevel@tonic-gate } 17447c478bd9Sstevel@tonic-gate rc_node_clear(&cp->rc_notify_ptr, 0); 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 17487c478bd9Sstevel@tonic-gate assert(cp->rc_notify_thr == pthread_self()); 17497c478bd9Sstevel@tonic-gate cp->rc_notify_thr = 0; 17507c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate out->rpr_response = result; 17537c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 17547c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 17557c478bd9Sstevel@tonic-gate } 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate /* 17587c478bd9Sstevel@tonic-gate * Can return: 17597c478bd9Sstevel@tonic-gate * _PERMISSION_DENIED not enough privileges to do request. 17607c478bd9Sstevel@tonic-gate * _BAD_REQUEST name is not valid or reserved 17617c478bd9Sstevel@tonic-gate * _TRUNCATED name is too long for current repository path 17627c478bd9Sstevel@tonic-gate * _UNKNOWN failed for unknown reason (details written to 17637c478bd9Sstevel@tonic-gate * console) 17647c478bd9Sstevel@tonic-gate * _BACKEND_READONLY backend is not writable 17657c478bd9Sstevel@tonic-gate * 17667c478bd9Sstevel@tonic-gate * _SUCCESS Backup completed successfully. 17677c478bd9Sstevel@tonic-gate */ 17687c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 17697c478bd9Sstevel@tonic-gate backup_repository(repcache_client_t *cp, 17707c478bd9Sstevel@tonic-gate struct rep_protocol_backup_request *rpr) 17717c478bd9Sstevel@tonic-gate { 17727c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 17737c478bd9Sstevel@tonic-gate ucred_t *uc = get_ucred(); 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate if (!client_is_privileged() && (uc == NULL || ucred_geteuid(uc) != 0)) 17767c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate rpr->rpr_name[REP_PROTOCOL_NAME_LEN - 1] = 0; 17797c478bd9Sstevel@tonic-gate if (strcmp(rpr->rpr_name, REPOSITORY_BOOT_BACKUP) == 0) 17807c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 17837c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid != cp->rc_changeid) { 17847c478bd9Sstevel@tonic-gate result = backend_create_backup(rpr->rpr_name); 17857c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 17867c478bd9Sstevel@tonic-gate cp->rc_changeid = rpr->rpr_changeid; 17877c478bd9Sstevel@tonic-gate } else { 17887c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate return (result); 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate 1795*5b7f77adStw21770 /* 1796*5b7f77adStw21770 * This function captures the information that will be used for an 1797*5b7f77adStw21770 * annotation audit event. Specifically, it captures the operation to be 1798*5b7f77adStw21770 * performed and the name of the file that is being used. These values are 1799*5b7f77adStw21770 * copied from the rep_protocol_annotation request at rpr to the client 1800*5b7f77adStw21770 * structure. If both these values are null, the client is turning 1801*5b7f77adStw21770 * annotation off. 1802*5b7f77adStw21770 * 1803*5b7f77adStw21770 * Fails with 1804*5b7f77adStw21770 * _NO_RESOURCES - unable to allocate memory 1805*5b7f77adStw21770 */ 1806*5b7f77adStw21770 static rep_protocol_responseid_t 1807*5b7f77adStw21770 set_annotation(repcache_client_t *cp, struct rep_protocol_annotation *rpr) 1808*5b7f77adStw21770 { 1809*5b7f77adStw21770 au_id_t audit_uid; 1810*5b7f77adStw21770 const char *file = NULL; 1811*5b7f77adStw21770 const char *old_ptrs[2]; 1812*5b7f77adStw21770 const char *operation = NULL; 1813*5b7f77adStw21770 rep_protocol_responseid_t rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 1814*5b7f77adStw21770 au_asid_t sessionid; 1815*5b7f77adStw21770 1816*5b7f77adStw21770 (void) memset((void *)old_ptrs, 0, sizeof (old_ptrs)); 1817*5b7f77adStw21770 1818*5b7f77adStw21770 /* Copy rpr_operation and rpr_file if they are not empty strings. */ 1819*5b7f77adStw21770 if (rpr->rpr_operation[0] != 0) { 1820*5b7f77adStw21770 /* 1821*5b7f77adStw21770 * Make sure that client did not send us an unterminated buffer. 1822*5b7f77adStw21770 */ 1823*5b7f77adStw21770 rpr->rpr_operation[sizeof (rpr->rpr_operation) - 1] = 0; 1824*5b7f77adStw21770 if ((operation = strdup(rpr->rpr_operation)) == NULL) 1825*5b7f77adStw21770 goto out; 1826*5b7f77adStw21770 } 1827*5b7f77adStw21770 if (rpr->rpr_file[0] != 0) { 1828*5b7f77adStw21770 /* 1829*5b7f77adStw21770 * Make sure that client did not send us an unterminated buffer. 1830*5b7f77adStw21770 */ 1831*5b7f77adStw21770 rpr->rpr_file[sizeof (rpr->rpr_file) - 1] = 0; 1832*5b7f77adStw21770 if ((file = strdup(rpr->rpr_file)) == NULL) 1833*5b7f77adStw21770 goto out; 1834*5b7f77adStw21770 } 1835*5b7f77adStw21770 1836*5b7f77adStw21770 (void) pthread_mutex_lock(&cp->rc_annotate_lock); 1837*5b7f77adStw21770 /* Save addresses of memory to free when not locked */ 1838*5b7f77adStw21770 old_ptrs[0] = cp->rc_operation; 1839*5b7f77adStw21770 old_ptrs[1] = cp->rc_file; 1840*5b7f77adStw21770 1841*5b7f77adStw21770 /* Save pointers to annotation strings. */ 1842*5b7f77adStw21770 cp->rc_operation = operation; 1843*5b7f77adStw21770 cp->rc_file = file; 1844*5b7f77adStw21770 1845*5b7f77adStw21770 /* 1846*5b7f77adStw21770 * Set annotation flag. Annotations should be turned on if either 1847*5b7f77adStw21770 * operation or file are not NULL. 1848*5b7f77adStw21770 */ 1849*5b7f77adStw21770 cp->rc_annotate = (operation != NULL) || (file != NULL); 1850*5b7f77adStw21770 (void) pthread_mutex_unlock(&cp->rc_annotate_lock); 1851*5b7f77adStw21770 1852*5b7f77adStw21770 /* 1853*5b7f77adStw21770 * operation and file pointers are saved in cp, so don't free them 1854*5b7f77adStw21770 * during cleanup. 1855*5b7f77adStw21770 */ 1856*5b7f77adStw21770 operation = NULL; 1857*5b7f77adStw21770 file = NULL; 1858*5b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS; 1859*5b7f77adStw21770 1860*5b7f77adStw21770 /* 1861*5b7f77adStw21770 * Native builds are done to create svc.configd-native. This 1862*5b7f77adStw21770 * program runs only on the Open Solaris build machines to create 1863*5b7f77adStw21770 * the seed repository. Until the SMF auditing code is distributed 1864*5b7f77adStw21770 * to the Open Solaris build machines, adt_get_unique_id() in the 1865*5b7f77adStw21770 * following code is not a global function in libbsm. Hence the 1866*5b7f77adStw21770 * following conditional compilation. 1867*5b7f77adStw21770 */ 1868*5b7f77adStw21770 #ifndef NATIVE_BUILD 1869*5b7f77adStw21770 /* 1870*5b7f77adStw21770 * Set the appropriate audit session id. 1871*5b7f77adStw21770 */ 1872*5b7f77adStw21770 if (cp->rc_annotate) { 1873*5b7f77adStw21770 /* 1874*5b7f77adStw21770 * We're starting a group of annotated audit events, so 1875*5b7f77adStw21770 * create and set an audit session ID for this annotation. 1876*5b7f77adStw21770 */ 1877*5b7f77adStw21770 adt_get_auid(cp->rc_adt_session, &audit_uid); 1878*5b7f77adStw21770 sessionid = adt_get_unique_id(audit_uid); 1879*5b7f77adStw21770 } else { 1880*5b7f77adStw21770 /* 1881*5b7f77adStw21770 * Annotation is done so restore our client audit session 1882*5b7f77adStw21770 * id. 1883*5b7f77adStw21770 */ 1884*5b7f77adStw21770 sessionid = cp->rc_adt_sessionid; 1885*5b7f77adStw21770 } 1886*5b7f77adStw21770 adt_set_asid(cp->rc_adt_session, sessionid); 1887*5b7f77adStw21770 #endif /* NATIVE_BUILD */ 1888*5b7f77adStw21770 1889*5b7f77adStw21770 out: 1890*5b7f77adStw21770 if (operation != NULL) 1891*5b7f77adStw21770 free((void *)operation); 1892*5b7f77adStw21770 if (file != NULL) 1893*5b7f77adStw21770 free((void *)file); 1894*5b7f77adStw21770 free((void *)old_ptrs[0]); 1895*5b7f77adStw21770 free((void *)old_ptrs[1]); 1896*5b7f77adStw21770 return (rc); 1897*5b7f77adStw21770 } 1898*5b7f77adStw21770 1899*5b7f77adStw21770 /* 1900*5b7f77adStw21770 * Determine if an annotation event needs to be generated. If it does 1901*5b7f77adStw21770 * provide the operation and file name that should be used in the event. 1902*5b7f77adStw21770 * 1903*5b7f77adStw21770 * Can return: 1904*5b7f77adStw21770 * 0 No annotation event needed or buffers are not large 1905*5b7f77adStw21770 * enough. Either way an event should not be 1906*5b7f77adStw21770 * generated. 1907*5b7f77adStw21770 * 1 Generate annotation event. 1908*5b7f77adStw21770 */ 1909*5b7f77adStw21770 int 1910*5b7f77adStw21770 client_annotation_needed(char *operation, size_t oper_sz, 1911*5b7f77adStw21770 char *file, size_t file_sz) 1912*5b7f77adStw21770 { 1913*5b7f77adStw21770 thread_info_t *ti = thread_self(); 1914*5b7f77adStw21770 repcache_client_t *cp = ti->ti_active_client; 1915*5b7f77adStw21770 int rc = 0; 1916*5b7f77adStw21770 1917*5b7f77adStw21770 (void) pthread_mutex_lock(&cp->rc_annotate_lock); 1918*5b7f77adStw21770 if (cp->rc_annotate) { 1919*5b7f77adStw21770 rc = 1; 1920*5b7f77adStw21770 if (cp->rc_operation == NULL) { 1921*5b7f77adStw21770 if (oper_sz > 0) 1922*5b7f77adStw21770 operation[0] = 0; 1923*5b7f77adStw21770 } else { 1924*5b7f77adStw21770 if (strlcpy(operation, cp->rc_operation, oper_sz) >= 1925*5b7f77adStw21770 oper_sz) { 1926*5b7f77adStw21770 /* Buffer overflow, so do not generate event */ 1927*5b7f77adStw21770 rc = 0; 1928*5b7f77adStw21770 } 1929*5b7f77adStw21770 } 1930*5b7f77adStw21770 if (cp->rc_file == NULL) { 1931*5b7f77adStw21770 if (file_sz > 0) 1932*5b7f77adStw21770 file[0] = 0; 1933*5b7f77adStw21770 } else if (rc == 1) { 1934*5b7f77adStw21770 if (strlcpy(file, cp->rc_file, file_sz) >= file_sz) { 1935*5b7f77adStw21770 /* Buffer overflow, so do not generate event */ 1936*5b7f77adStw21770 rc = 0; 1937*5b7f77adStw21770 } 1938*5b7f77adStw21770 } 1939*5b7f77adStw21770 } 1940*5b7f77adStw21770 (void) pthread_mutex_unlock(&cp->rc_annotate_lock); 1941*5b7f77adStw21770 return (rc); 1942*5b7f77adStw21770 } 1943*5b7f77adStw21770 1944*5b7f77adStw21770 void 1945*5b7f77adStw21770 client_annotation_finished() 1946*5b7f77adStw21770 { 1947*5b7f77adStw21770 thread_info_t *ti = thread_self(); 1948*5b7f77adStw21770 repcache_client_t *cp = ti->ti_active_client; 1949*5b7f77adStw21770 1950*5b7f77adStw21770 (void) pthread_mutex_lock(&cp->rc_annotate_lock); 1951*5b7f77adStw21770 cp->rc_annotate = 0; 1952*5b7f77adStw21770 (void) pthread_mutex_unlock(&cp->rc_annotate_lock); 1953*5b7f77adStw21770 } 1954*5b7f77adStw21770 1955*5b7f77adStw21770 static void 1956*5b7f77adStw21770 start_audit_session(repcache_client_t *cp) 1957*5b7f77adStw21770 { 1958*5b7f77adStw21770 ucred_t *cred = NULL; 1959*5b7f77adStw21770 int adt_rc = 0; 1960*5b7f77adStw21770 adt_session_data_t *session; 1961*5b7f77adStw21770 1962*5b7f77adStw21770 if ((adt_rc = door_ucred(&cred)) != 0) { 1963*5b7f77adStw21770 syslog(LOG_ERR, gettext("start_audit_session(): cannot " 1964*5b7f77adStw21770 "get ucred. %m\n")); 1965*5b7f77adStw21770 } 1966*5b7f77adStw21770 if ((adt_rc == 0) && 1967*5b7f77adStw21770 (adt_rc = adt_start_session(&session, NULL, 0)) != 0) { 1968*5b7f77adStw21770 /* 1969*5b7f77adStw21770 * Log the failure, but don't quit because of inability to 1970*5b7f77adStw21770 * audit. 1971*5b7f77adStw21770 */ 1972*5b7f77adStw21770 syslog(LOG_ERR, gettext("start_audit_session(): could not " 1973*5b7f77adStw21770 "start audit session.\n")); 1974*5b7f77adStw21770 } 1975*5b7f77adStw21770 if ((adt_rc == 0) && 1976*5b7f77adStw21770 ((adt_rc = adt_set_from_ucred(session, cred, ADT_NEW)) != 0)) { 1977*5b7f77adStw21770 syslog(LOG_ERR, gettext("start_audit_session(): cannot set " 1978*5b7f77adStw21770 "audit session data from ucred\n")); 1979*5b7f77adStw21770 } 1980*5b7f77adStw21770 if (adt_rc == 0) { 1981*5b7f77adStw21770 /* All went well. Save the session data and session ID */ 1982*5b7f77adStw21770 cp->rc_adt_session = session; 1983*5b7f77adStw21770 adt_get_asid(session, &cp->rc_adt_sessionid); 1984*5b7f77adStw21770 } else { 1985*5b7f77adStw21770 /* 1986*5b7f77adStw21770 * Something went wrong. End the session. A NULL session 1987*5b7f77adStw21770 * pointer value can legally be used in all subsequent 1988*5b7f77adStw21770 * calls to adt_ functions. 1989*5b7f77adStw21770 */ 1990*5b7f77adStw21770 (void) adt_end_session(session); 1991*5b7f77adStw21770 cp->rc_adt_session = NULL; 1992*5b7f77adStw21770 } 1993*5b7f77adStw21770 1994*5b7f77adStw21770 ucred_free(cred); 1995*5b7f77adStw21770 } 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_f(repcache_client_t *cp, 19987c478bd9Sstevel@tonic-gate const void *rpr); 19997c478bd9Sstevel@tonic-gate 20007c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20017c478bd9Sstevel@tonic-gate static void 20027c478bd9Sstevel@tonic-gate simple_handler(repcache_client_t *cp, const void *in, size_t insz, 20037c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 20047c478bd9Sstevel@tonic-gate { 20057c478bd9Sstevel@tonic-gate protocol_simple_f *f = (protocol_simple_f *)arg; 20067c478bd9Sstevel@tonic-gate rep_protocol_response_t *out = out_arg; 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 20097c478bd9Sstevel@tonic-gate assert(f != NULL); 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate out->rpr_response = (*f)(cp, in); 20127c478bd9Sstevel@tonic-gate } 20137c478bd9Sstevel@tonic-gate 20147c478bd9Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_fd_f(repcache_client_t *cp, 20157c478bd9Sstevel@tonic-gate const void *rpr, int *out_fd); 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20187c478bd9Sstevel@tonic-gate static void 20197c478bd9Sstevel@tonic-gate simple_fd_handler(repcache_client_t *cp, const void *in, size_t insz, 20207c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg, int *out_fd) 20217c478bd9Sstevel@tonic-gate { 20227c478bd9Sstevel@tonic-gate protocol_simple_fd_f *f = (protocol_simple_fd_f *)arg; 20237c478bd9Sstevel@tonic-gate rep_protocol_response_t *out = out_arg; 20247c478bd9Sstevel@tonic-gate 20257c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 20267c478bd9Sstevel@tonic-gate assert(f != NULL); 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate out->rpr_response = (*f)(cp, in, out_fd); 20297c478bd9Sstevel@tonic-gate } 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate typedef void protocol_handler_f(repcache_client_t *, const void *in, 20327c478bd9Sstevel@tonic-gate size_t insz, void *out, size_t *outsz, void *arg); 20337c478bd9Sstevel@tonic-gate 20347c478bd9Sstevel@tonic-gate typedef void protocol_handler_fdret_f(repcache_client_t *, const void *in, 20357c478bd9Sstevel@tonic-gate size_t insz, void *out, size_t *outsz, void *arg, int *fd_out); 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate #define PROTO(p, f, in) { \ 20387c478bd9Sstevel@tonic-gate p, #p, simple_handler, (void *)(&f), NULL, \ 20397c478bd9Sstevel@tonic-gate sizeof (in), sizeof (rep_protocol_response_t), 0 \ 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate #define PROTO_FD_OUT(p, f, in) { \ 20437c478bd9Sstevel@tonic-gate p, #p, NULL, (void *)(&f), simple_fd_handler, \ 20447c478bd9Sstevel@tonic-gate sizeof (in), \ 20457c478bd9Sstevel@tonic-gate sizeof (rep_protocol_response_t), \ 20467c478bd9Sstevel@tonic-gate PROTO_FLAG_RETFD \ 20477c478bd9Sstevel@tonic-gate } 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate #define PROTO_VARIN(p, f, insz) { \ 20507c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 20517c478bd9Sstevel@tonic-gate insz, sizeof (rep_protocol_response_t), \ 20527c478bd9Sstevel@tonic-gate PROTO_FLAG_VARINPUT \ 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate #define PROTO_UINT_OUT(p, f, in) { \ 20567c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 20577c478bd9Sstevel@tonic-gate sizeof (in), \ 20587c478bd9Sstevel@tonic-gate sizeof (struct rep_protocol_integer_response), 0 \ 20597c478bd9Sstevel@tonic-gate } 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate #define PROTO_NAME_OUT(p, f, in) { \ 20627c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 20637c478bd9Sstevel@tonic-gate sizeof (in), \ 20647c478bd9Sstevel@tonic-gate sizeof (struct rep_protocol_name_response), 0 \ 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate #define PROTO_FMRI_OUT(p, f, in) { \ 20687c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 20697c478bd9Sstevel@tonic-gate sizeof (in), \ 20707c478bd9Sstevel@tonic-gate sizeof (struct rep_protocol_fmri_response), 0 \ 20717c478bd9Sstevel@tonic-gate } 20727c478bd9Sstevel@tonic-gate 20737c478bd9Sstevel@tonic-gate #define PROTO_VALUE_OUT(p, f, in) { \ 20747c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 20757c478bd9Sstevel@tonic-gate sizeof (in), \ 20767c478bd9Sstevel@tonic-gate sizeof (struct rep_protocol_value_response), 0 \ 20777c478bd9Sstevel@tonic-gate } 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate #define PROTO_PANIC(p) { p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC } 20807c478bd9Sstevel@tonic-gate #define PROTO_END() { 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC } 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate #define PROTO_FLAG_PANIC 0x00000001 /* should never be called */ 20837c478bd9Sstevel@tonic-gate #define PROTO_FLAG_VARINPUT 0x00000004 /* in_size is minimum size */ 20847c478bd9Sstevel@tonic-gate #define PROTO_FLAG_RETFD 0x00000008 /* can also return an FD */ 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate #define PROTO_ALL_FLAGS 0x0000000f /* all flags */ 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate static struct protocol_entry { 20897c478bd9Sstevel@tonic-gate enum rep_protocol_requestid pt_request; 20907c478bd9Sstevel@tonic-gate const char *pt_name; 20917c478bd9Sstevel@tonic-gate protocol_handler_f *pt_handler; 20927c478bd9Sstevel@tonic-gate void *pt_arg; 20937c478bd9Sstevel@tonic-gate protocol_handler_fdret_f *pt_fd_handler; 20947c478bd9Sstevel@tonic-gate size_t pt_in_size; 20957c478bd9Sstevel@tonic-gate size_t pt_out_max; 20967c478bd9Sstevel@tonic-gate uint32_t pt_flags; 20977c478bd9Sstevel@tonic-gate } protocol_table[] = { 20987c478bd9Sstevel@tonic-gate PROTO_PANIC(REP_PROTOCOL_CLOSE), /* special case */ 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_SETUP, entity_setup, 21017c478bd9Sstevel@tonic-gate struct rep_protocol_entity_setup), 21027c478bd9Sstevel@tonic-gate PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME, entity_name, 21037c478bd9Sstevel@tonic-gate struct rep_protocol_entity_name), 21047c478bd9Sstevel@tonic-gate PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE, entity_parent_type, 21057c478bd9Sstevel@tonic-gate struct rep_protocol_entity_parent_type), 21067c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET_CHILD, entity_get_child, 21077c478bd9Sstevel@tonic-gate struct rep_protocol_entity_get_child), 21087c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET_PARENT, entity_get_parent, 21097c478bd9Sstevel@tonic-gate struct rep_protocol_entity_parent), 21107c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET, entity_get, 21117c478bd9Sstevel@tonic-gate struct rep_protocol_entity_get), 21127c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_UPDATE, entity_update, 21137c478bd9Sstevel@tonic-gate struct rep_protocol_entity_update), 21147c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD, entity_create_child, 21157c478bd9Sstevel@tonic-gate struct rep_protocol_entity_create_child), 21167c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_CREATE_PG, entity_create_pg, 21177c478bd9Sstevel@tonic-gate struct rep_protocol_entity_create_pg), 21187c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_DELETE, entity_delete, 21197c478bd9Sstevel@tonic-gate struct rep_protocol_entity_delete), 21207c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_RESET, entity_reset, 21217c478bd9Sstevel@tonic-gate struct rep_protocol_entity_reset), 21227c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_TEARDOWN, entity_teardown, 21237c478bd9Sstevel@tonic-gate struct rep_protocol_entity_teardown), 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_SETUP, iter_setup, 21267c478bd9Sstevel@tonic-gate struct rep_protocol_iter_request), 21277c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_START, iter_start, 21287c478bd9Sstevel@tonic-gate struct rep_protocol_iter_start), 21297c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_READ, iter_read, 21307c478bd9Sstevel@tonic-gate struct rep_protocol_iter_read), 21317c478bd9Sstevel@tonic-gate PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE, iter_read_value, 21327c478bd9Sstevel@tonic-gate struct rep_protocol_iter_read_value), 21337c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_RESET, iter_reset, 21347c478bd9Sstevel@tonic-gate struct rep_protocol_iter_request), 21357c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_TEARDOWN, iter_teardown, 21367c478bd9Sstevel@tonic-gate struct rep_protocol_iter_request), 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL, next_snaplevel, 21397c478bd9Sstevel@tonic-gate struct rep_protocol_entity_pair), 21407c478bd9Sstevel@tonic-gate 21417c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_TAKE, snapshot_take, 21427c478bd9Sstevel@tonic-gate struct rep_protocol_snapshot_take), 21437c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED, snapshot_take_named, 21447c478bd9Sstevel@tonic-gate struct rep_protocol_snapshot_take_named), 21457c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH, snapshot_attach, 21467c478bd9Sstevel@tonic-gate struct rep_protocol_snapshot_attach), 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE, property_get_type, 21497c478bd9Sstevel@tonic-gate struct rep_protocol_property_request), 21507c478bd9Sstevel@tonic-gate PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE, property_get_value, 21517c478bd9Sstevel@tonic-gate struct rep_protocol_property_request), 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT, propertygrp_notify, 21547c478bd9Sstevel@tonic-gate struct rep_protocol_propertygrp_request), 21557c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START, tx_start, 21567c478bd9Sstevel@tonic-gate struct rep_protocol_transaction_start), 21577c478bd9Sstevel@tonic-gate PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT, tx_commit, 21587c478bd9Sstevel@tonic-gate REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE), 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY, client_add_notify, 21617c478bd9Sstevel@tonic-gate struct rep_protocol_notify_request), 21627c478bd9Sstevel@tonic-gate PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT, client_wait, 21637c478bd9Sstevel@tonic-gate struct rep_protocol_wait_request), 21647c478bd9Sstevel@tonic-gate 21657c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_BACKUP, backup_repository, 21667c478bd9Sstevel@tonic-gate struct rep_protocol_backup_request), 21677c478bd9Sstevel@tonic-gate 2168*5b7f77adStw21770 PROTO(REP_PROTOCOL_SET_AUDIT_ANNOTATION, set_annotation, 2169*5b7f77adStw21770 struct rep_protocol_annotation), 2170*5b7f77adStw21770 21717c478bd9Sstevel@tonic-gate PROTO_END() 21727c478bd9Sstevel@tonic-gate }; 21737c478bd9Sstevel@tonic-gate #undef PROTO 21747c478bd9Sstevel@tonic-gate #undef PROTO_FMRI_OUT 21757c478bd9Sstevel@tonic-gate #undef PROTO_NAME_OUT 21767c478bd9Sstevel@tonic-gate #undef PROTO_UINT_OUT 21777c478bd9Sstevel@tonic-gate #undef PROTO_PANIC 21787c478bd9Sstevel@tonic-gate #undef PROTO_END 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate /* 21817c478bd9Sstevel@tonic-gate * The number of entries, sans PROTO_END() 21827c478bd9Sstevel@tonic-gate */ 21837c478bd9Sstevel@tonic-gate #define PROTOCOL_ENTRIES \ 21847c478bd9Sstevel@tonic-gate (sizeof (protocol_table) / sizeof (*protocol_table) - 1) 21857c478bd9Sstevel@tonic-gate 21867c478bd9Sstevel@tonic-gate #define PROTOCOL_PREFIX "REP_PROTOCOL_" 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate int 21897c478bd9Sstevel@tonic-gate client_init(void) 21907c478bd9Sstevel@tonic-gate { 21917c478bd9Sstevel@tonic-gate int i; 21927c478bd9Sstevel@tonic-gate struct protocol_entry *e; 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate if (!client_hash_init()) 21957c478bd9Sstevel@tonic-gate return (0); 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate if (request_log_size > 0) { 21987c478bd9Sstevel@tonic-gate request_log = uu_zalloc(request_log_size * 21997c478bd9Sstevel@tonic-gate sizeof (request_log_entry_t)); 22007c478bd9Sstevel@tonic-gate } 22017c478bd9Sstevel@tonic-gate 22027c478bd9Sstevel@tonic-gate /* 22037c478bd9Sstevel@tonic-gate * update the names to not include REP_PROTOCOL_ 22047c478bd9Sstevel@tonic-gate */ 22057c478bd9Sstevel@tonic-gate for (i = 0; i < PROTOCOL_ENTRIES; i++) { 22067c478bd9Sstevel@tonic-gate e = &protocol_table[i]; 22077c478bd9Sstevel@tonic-gate assert(strncmp(e->pt_name, PROTOCOL_PREFIX, 22087c478bd9Sstevel@tonic-gate strlen(PROTOCOL_PREFIX)) == 0); 22097c478bd9Sstevel@tonic-gate e->pt_name += strlen(PROTOCOL_PREFIX); 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate /* 22127c478bd9Sstevel@tonic-gate * verify the protocol table is consistent 22137c478bd9Sstevel@tonic-gate */ 22147c478bd9Sstevel@tonic-gate for (i = 0; i < PROTOCOL_ENTRIES; i++) { 22157c478bd9Sstevel@tonic-gate e = &protocol_table[i]; 22167c478bd9Sstevel@tonic-gate assert(e->pt_request == (REP_PROTOCOL_BASE + i)); 22177c478bd9Sstevel@tonic-gate 22187c478bd9Sstevel@tonic-gate assert((e->pt_flags & ~PROTO_ALL_FLAGS) == 0); 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_PANIC) 22217c478bd9Sstevel@tonic-gate assert(e->pt_in_size == 0 && e->pt_out_max == 0 && 22227c478bd9Sstevel@tonic-gate e->pt_handler == NULL); 22237c478bd9Sstevel@tonic-gate else 22247c478bd9Sstevel@tonic-gate assert(e->pt_in_size != 0 && e->pt_out_max != 0 && 22257c478bd9Sstevel@tonic-gate (e->pt_handler != NULL || 22267c478bd9Sstevel@tonic-gate e->pt_fd_handler != NULL)); 22277c478bd9Sstevel@tonic-gate } 22287c478bd9Sstevel@tonic-gate assert((REP_PROTOCOL_BASE + i) == REP_PROTOCOL_MAX_REQUEST); 22297c478bd9Sstevel@tonic-gate 22307c478bd9Sstevel@tonic-gate assert(protocol_table[i].pt_request == 0); 22317c478bd9Sstevel@tonic-gate 22327c478bd9Sstevel@tonic-gate return (1); 22337c478bd9Sstevel@tonic-gate } 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate static void 22367c478bd9Sstevel@tonic-gate client_switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *desc_in, 22377c478bd9Sstevel@tonic-gate uint_t n_desc) 22387c478bd9Sstevel@tonic-gate { 22397c478bd9Sstevel@tonic-gate thread_info_t *ti = thread_self(); 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate repcache_client_t *cp; 22427c478bd9Sstevel@tonic-gate uint32_t id = (uint32_t)cookie; 22437c478bd9Sstevel@tonic-gate enum rep_protocol_requestid request_code; 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result = INVALID_RESULT; 22467c478bd9Sstevel@tonic-gate 22477c478bd9Sstevel@tonic-gate struct protocol_entry *e; 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate char *retval = NULL; 22507c478bd9Sstevel@tonic-gate size_t retsize = 0; 22517c478bd9Sstevel@tonic-gate 22527c478bd9Sstevel@tonic-gate int retfd = -1; 22537c478bd9Sstevel@tonic-gate door_desc_t desc; 22547c478bd9Sstevel@tonic-gate request_log_entry_t *rlp; 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate rlp = start_log(id); 22577c478bd9Sstevel@tonic-gate 22587c478bd9Sstevel@tonic-gate if (n_desc != 0) 22597c478bd9Sstevel@tonic-gate uu_die("can't happen: %d descriptors @%p (cookie %p)", 22607c478bd9Sstevel@tonic-gate n_desc, desc_in, cookie); 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate if (argp == DOOR_UNREF_DATA) { 22637c478bd9Sstevel@tonic-gate client_destroy(id); 22647c478bd9Sstevel@tonic-gate goto bad_end; 22657c478bd9Sstevel@tonic-gate } 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate thread_newstate(ti, TI_CLIENT_CALL); 22687c478bd9Sstevel@tonic-gate 22697c478bd9Sstevel@tonic-gate /* 22707c478bd9Sstevel@tonic-gate * To simplify returning just a result code, we set up for 22717c478bd9Sstevel@tonic-gate * that case here. 22727c478bd9Sstevel@tonic-gate */ 22737c478bd9Sstevel@tonic-gate retval = (char *)&result; 22747c478bd9Sstevel@tonic-gate retsize = sizeof (result); 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate if (arg_size < sizeof (request_code)) { 22777c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 22787c478bd9Sstevel@tonic-gate goto end_unheld; 22797c478bd9Sstevel@tonic-gate } 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate ti->ti_client_request = (void *)argp; 22827c478bd9Sstevel@tonic-gate 22837c478bd9Sstevel@tonic-gate /* LINTED alignment */ 22847c478bd9Sstevel@tonic-gate request_code = *(uint32_t *)argp; 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate if (rlp != NULL) { 22877c478bd9Sstevel@tonic-gate rlp->rl_request = request_code; 22887c478bd9Sstevel@tonic-gate } 22897c478bd9Sstevel@tonic-gate /* 22907c478bd9Sstevel@tonic-gate * In order to avoid locking problems on removal, we handle the 22917c478bd9Sstevel@tonic-gate * "close" case before doing a lookup. 22927c478bd9Sstevel@tonic-gate */ 22937c478bd9Sstevel@tonic-gate if (request_code == REP_PROTOCOL_CLOSE) { 22947c478bd9Sstevel@tonic-gate client_destroy(id); 22957c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 22967c478bd9Sstevel@tonic-gate goto end_unheld; 22977c478bd9Sstevel@tonic-gate } 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate cp = client_lookup(id); 23007c478bd9Sstevel@tonic-gate /* 23017c478bd9Sstevel@tonic-gate * cp is held 23027c478bd9Sstevel@tonic-gate */ 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate if (cp == NULL) 23057c478bd9Sstevel@tonic-gate goto bad_end; 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate if (rlp != NULL) 23087c478bd9Sstevel@tonic-gate rlp->rl_client = cp; 23097c478bd9Sstevel@tonic-gate 23107c478bd9Sstevel@tonic-gate ti->ti_active_client = cp; 23117c478bd9Sstevel@tonic-gate 23127c478bd9Sstevel@tonic-gate if (request_code < REP_PROTOCOL_BASE || 23137c478bd9Sstevel@tonic-gate request_code >= REP_PROTOCOL_BASE + PROTOCOL_ENTRIES) { 23147c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 23157c478bd9Sstevel@tonic-gate goto end; 23167c478bd9Sstevel@tonic-gate } 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate e = &protocol_table[request_code - REP_PROTOCOL_BASE]; 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate assert(!(e->pt_flags & PROTO_FLAG_PANIC)); 23217c478bd9Sstevel@tonic-gate 23227c478bd9Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_VARINPUT) { 23237c478bd9Sstevel@tonic-gate if (arg_size < e->pt_in_size) { 23247c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 23257c478bd9Sstevel@tonic-gate goto end; 23267c478bd9Sstevel@tonic-gate } 23277c478bd9Sstevel@tonic-gate } else if (arg_size != e->pt_in_size) { 23287c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 23297c478bd9Sstevel@tonic-gate goto end; 23307c478bd9Sstevel@tonic-gate } 23317c478bd9Sstevel@tonic-gate 23327c478bd9Sstevel@tonic-gate if (retsize != e->pt_out_max) { 23337c478bd9Sstevel@tonic-gate retsize = e->pt_out_max; 23347c478bd9Sstevel@tonic-gate retval = alloca(retsize); 23357c478bd9Sstevel@tonic-gate } 23367c478bd9Sstevel@tonic-gate 23377c478bd9Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_RETFD) 23387c478bd9Sstevel@tonic-gate e->pt_fd_handler(cp, argp, arg_size, retval, &retsize, 23397c478bd9Sstevel@tonic-gate e->pt_arg, &retfd); 23407c478bd9Sstevel@tonic-gate else 23417c478bd9Sstevel@tonic-gate e->pt_handler(cp, argp, arg_size, retval, &retsize, e->pt_arg); 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate end: 23447c478bd9Sstevel@tonic-gate ti->ti_active_client = NULL; 23457c478bd9Sstevel@tonic-gate client_release(cp); 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate end_unheld: 23487c478bd9Sstevel@tonic-gate if (rlp != NULL) { 23497c478bd9Sstevel@tonic-gate /* LINTED alignment */ 23507c478bd9Sstevel@tonic-gate rlp->rl_response = *(uint32_t *)retval; 23517c478bd9Sstevel@tonic-gate end_log(); 23527c478bd9Sstevel@tonic-gate rlp = NULL; 23537c478bd9Sstevel@tonic-gate } 23547c478bd9Sstevel@tonic-gate ti->ti_client_request = NULL; 23557c478bd9Sstevel@tonic-gate thread_newstate(ti, TI_DOOR_RETURN); 23567c478bd9Sstevel@tonic-gate 23577c478bd9Sstevel@tonic-gate if (retval == (char *)&result) { 23587c478bd9Sstevel@tonic-gate assert(result != INVALID_RESULT && retsize == sizeof (result)); 23597c478bd9Sstevel@tonic-gate } else { 23607c478bd9Sstevel@tonic-gate /* LINTED alignment */ 23617c478bd9Sstevel@tonic-gate result = *(uint32_t *)retval; 23627c478bd9Sstevel@tonic-gate } 23637c478bd9Sstevel@tonic-gate if (retfd != -1) { 23647c478bd9Sstevel@tonic-gate desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE; 23657c478bd9Sstevel@tonic-gate desc.d_data.d_desc.d_descriptor = retfd; 23667c478bd9Sstevel@tonic-gate (void) door_return(retval, retsize, &desc, 1); 23677c478bd9Sstevel@tonic-gate } else { 23687c478bd9Sstevel@tonic-gate (void) door_return(retval, retsize, NULL, 0); 23697c478bd9Sstevel@tonic-gate } 23707c478bd9Sstevel@tonic-gate bad_end: 23717c478bd9Sstevel@tonic-gate if (rlp != NULL) { 23727c478bd9Sstevel@tonic-gate rlp->rl_response = -1; 23737c478bd9Sstevel@tonic-gate end_log(); 23747c478bd9Sstevel@tonic-gate rlp = NULL; 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate (void) door_return(NULL, 0, NULL, 0); 23777c478bd9Sstevel@tonic-gate } 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate int 23807c478bd9Sstevel@tonic-gate create_client(pid_t pid, uint32_t debugflags, int privileged, int *out_fd) 23817c478bd9Sstevel@tonic-gate { 23827c478bd9Sstevel@tonic-gate int fd; 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate repcache_client_t *cp; 23857c478bd9Sstevel@tonic-gate 23867c478bd9Sstevel@tonic-gate struct door_info info; 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate int door_flags = DOOR_UNREF | DOOR_REFUSE_DESC; 23897c478bd9Sstevel@tonic-gate #ifdef DOOR_NO_CANCEL 23907c478bd9Sstevel@tonic-gate door_flags |= DOOR_NO_CANCEL; 23917c478bd9Sstevel@tonic-gate #endif 23927c478bd9Sstevel@tonic-gate 23937c478bd9Sstevel@tonic-gate cp = client_alloc(); 23947c478bd9Sstevel@tonic-gate if (cp == NULL) 23957c478bd9Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 23967c478bd9Sstevel@tonic-gate 23977c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&client_lock); 23987c478bd9Sstevel@tonic-gate cp->rc_id = ++client_maxid; 23997c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&client_lock); 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate cp->rc_all_auths = privileged; 24027c478bd9Sstevel@tonic-gate cp->rc_pid = pid; 24037c478bd9Sstevel@tonic-gate cp->rc_debug = debugflags; 24047c478bd9Sstevel@tonic-gate 2405*5b7f77adStw21770 start_audit_session(cp); 2406*5b7f77adStw21770 24077c478bd9Sstevel@tonic-gate cp->rc_doorfd = door_create(client_switcher, (void *)cp->rc_id, 24087c478bd9Sstevel@tonic-gate door_flags); 24097c478bd9Sstevel@tonic-gate 24107c478bd9Sstevel@tonic-gate if (cp->rc_doorfd < 0) { 24117c478bd9Sstevel@tonic-gate client_free(cp); 24127c478bd9Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 24137c478bd9Sstevel@tonic-gate } 24147c478bd9Sstevel@tonic-gate #ifdef DOOR_PARAM_DATA_MIN 24157c478bd9Sstevel@tonic-gate (void) door_setparam(cp->rc_doorfd, DOOR_PARAM_DATA_MIN, 24167c478bd9Sstevel@tonic-gate sizeof (enum rep_protocol_requestid)); 24177c478bd9Sstevel@tonic-gate #endif 24187c478bd9Sstevel@tonic-gate 24197c478bd9Sstevel@tonic-gate if ((fd = dup(cp->rc_doorfd)) < 0 || 24207c478bd9Sstevel@tonic-gate door_info(cp->rc_doorfd, &info) < 0) { 24217c478bd9Sstevel@tonic-gate if (fd >= 0) 24227c478bd9Sstevel@tonic-gate (void) close(fd); 24237c478bd9Sstevel@tonic-gate (void) door_revoke(cp->rc_doorfd); 24247c478bd9Sstevel@tonic-gate cp->rc_doorfd = -1; 24257c478bd9Sstevel@tonic-gate client_free(cp); 24267c478bd9Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 24277c478bd9Sstevel@tonic-gate } 24287c478bd9Sstevel@tonic-gate 24297c478bd9Sstevel@tonic-gate rc_pg_notify_init(&cp->rc_pg_notify); 24307c478bd9Sstevel@tonic-gate rc_notify_info_init(&cp->rc_notify_info); 24317c478bd9Sstevel@tonic-gate 24327c478bd9Sstevel@tonic-gate client_insert(cp); 24337c478bd9Sstevel@tonic-gate 24347c478bd9Sstevel@tonic-gate cp->rc_doorid = info.di_uniquifier; 24357c478bd9Sstevel@tonic-gate *out_fd = fd; 24367c478bd9Sstevel@tonic-gate 24377c478bd9Sstevel@tonic-gate return (REPOSITORY_DOOR_SUCCESS); 24387c478bd9Sstevel@tonic-gate } 2439