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 5*f2fa366aSjeanm * Common Development and Distribution License (the "License"). 6*f2fa366aSjeanm * 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 */ 217c478bd9Sstevel@tonic-gate /* 22*f2fa366aSjeanm * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * This is the client layer for svc.configd. All direct protocol interactions 307c478bd9Sstevel@tonic-gate * are handled here. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * Essentially, the job of this layer is to turn the idempotent protocol 337c478bd9Sstevel@tonic-gate * into a series of non-idempotent calls into the object layer, while 347c478bd9Sstevel@tonic-gate * also handling the necessary locking. 357c478bd9Sstevel@tonic-gate */ 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <alloca.h> 387c478bd9Sstevel@tonic-gate #include <assert.h> 397c478bd9Sstevel@tonic-gate #include <door.h> 407c478bd9Sstevel@tonic-gate #include <errno.h> 417c478bd9Sstevel@tonic-gate #include <limits.h> 427c478bd9Sstevel@tonic-gate #include <pthread.h> 437c478bd9Sstevel@tonic-gate #include <stdio.h> 447c478bd9Sstevel@tonic-gate #include <stdlib.h> 457c478bd9Sstevel@tonic-gate #include <string.h> 467c478bd9Sstevel@tonic-gate #include <unistd.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include <libuutil.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include "configd.h" 517c478bd9Sstevel@tonic-gate #include "repcache_protocol.h" 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate #define INVALID_CHANGEID (0) 547c478bd9Sstevel@tonic-gate #define INVALID_DOORID ((door_id_t)-1) 557c478bd9Sstevel@tonic-gate #define INVALID_RESULT ((rep_protocol_responseid_t)INT_MIN) 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* 587c478bd9Sstevel@tonic-gate * lint doesn't like constant assertions 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate #ifdef lint 617c478bd9Sstevel@tonic-gate #define assert_nolint(x) (void)0 627c478bd9Sstevel@tonic-gate #else 637c478bd9Sstevel@tonic-gate #define assert_nolint(x) assert(x) 647c478bd9Sstevel@tonic-gate #endif 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* 677c478bd9Sstevel@tonic-gate * Protects client linkage and the freelist 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate #define CLIENT_HASH_SIZE 64 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate #pragma align 64(client_hash) 727c478bd9Sstevel@tonic-gate static client_bucket_t client_hash[CLIENT_HASH_SIZE]; 737c478bd9Sstevel@tonic-gate 748918dff3Sjwadams static uu_avl_pool_t *entity_pool; 758918dff3Sjwadams static uu_avl_pool_t *iter_pool; 767c478bd9Sstevel@tonic-gate static uu_list_pool_t *client_pool; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate #define CLIENT_HASH(id) (&client_hash[((id) & (CLIENT_HASH_SIZE - 1))]) 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate uint_t request_log_size = 1024; /* tunable, before we start */ 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate static pthread_mutex_t request_log_lock = PTHREAD_MUTEX_INITIALIZER; 837c478bd9Sstevel@tonic-gate static uint_t request_log_cur; 847c478bd9Sstevel@tonic-gate request_log_entry_t *request_log; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate static uint32_t client_maxid; 877c478bd9Sstevel@tonic-gate static pthread_mutex_t client_lock; /* protects client_maxid */ 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate static request_log_entry_t * 907c478bd9Sstevel@tonic-gate get_log(void) 917c478bd9Sstevel@tonic-gate { 927c478bd9Sstevel@tonic-gate thread_info_t *ti = thread_self(); 937c478bd9Sstevel@tonic-gate return (&ti->ti_log); 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate void 977c478bd9Sstevel@tonic-gate log_enter(request_log_entry_t *rlp) 987c478bd9Sstevel@tonic-gate { 997c478bd9Sstevel@tonic-gate if (rlp->rl_start != 0 && request_log != NULL) { 1007c478bd9Sstevel@tonic-gate request_log_entry_t *logrlp; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&request_log_lock); 1037c478bd9Sstevel@tonic-gate assert(request_log_cur < request_log_size); 1047c478bd9Sstevel@tonic-gate logrlp = &request_log[request_log_cur++]; 1057c478bd9Sstevel@tonic-gate if (request_log_cur == request_log_size) 1067c478bd9Sstevel@tonic-gate request_log_cur = 0; 1077c478bd9Sstevel@tonic-gate (void) memcpy(logrlp, rlp, sizeof (*rlp)); 1087c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&request_log_lock); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Note that the svc.configd dmod will join all of the per-thread log entries 1147c478bd9Sstevel@tonic-gate * with the main log, so that even if the log is disabled, there is some 1157c478bd9Sstevel@tonic-gate * information available. 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate static request_log_entry_t * 1187c478bd9Sstevel@tonic-gate start_log(uint32_t clientid) 1197c478bd9Sstevel@tonic-gate { 1207c478bd9Sstevel@tonic-gate request_log_entry_t *rlp = get_log(); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate log_enter(rlp); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate (void) memset(rlp, 0, sizeof (*rlp)); 1257c478bd9Sstevel@tonic-gate rlp->rl_start = gethrtime(); 1267c478bd9Sstevel@tonic-gate rlp->rl_tid = pthread_self(); 1277c478bd9Sstevel@tonic-gate rlp->rl_clientid = clientid; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate return (rlp); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate void 1337c478bd9Sstevel@tonic-gate end_log(void) 1347c478bd9Sstevel@tonic-gate { 1357c478bd9Sstevel@tonic-gate request_log_entry_t *rlp = get_log(); 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate rlp->rl_end = gethrtime(); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate static void 1417c478bd9Sstevel@tonic-gate add_log_ptr(request_log_entry_t *rlp, enum rc_ptr_type type, uint32_t id, 1427c478bd9Sstevel@tonic-gate void *ptr) 1437c478bd9Sstevel@tonic-gate { 1447c478bd9Sstevel@tonic-gate request_log_ptr_t *rpp; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate if (rlp == NULL) 1477c478bd9Sstevel@tonic-gate return; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate if (rlp->rl_num_ptrs >= MAX_PTRS) 1507c478bd9Sstevel@tonic-gate return; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate rpp = &rlp->rl_ptrs[rlp->rl_num_ptrs++]; 1537c478bd9Sstevel@tonic-gate rpp->rlp_type = type; 1547c478bd9Sstevel@tonic-gate rpp->rlp_id = id; 1557c478bd9Sstevel@tonic-gate rpp->rlp_ptr = ptr; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * For entities, it's useful to have the node pointer at the start 1597c478bd9Sstevel@tonic-gate * of the request. 1607c478bd9Sstevel@tonic-gate */ 1617c478bd9Sstevel@tonic-gate if (type == RC_PTR_TYPE_ENTITY && ptr != NULL) 1627c478bd9Sstevel@tonic-gate rpp->rlp_data = ((repcache_entity_t *)ptr)->re_node.rnp_node; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate int 1667c478bd9Sstevel@tonic-gate client_is_privileged(void) 1677c478bd9Sstevel@tonic-gate { 1687c478bd9Sstevel@tonic-gate thread_info_t *ti = thread_self(); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate ucred_t *uc; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate if (ti->ti_active_client != NULL && 1737c478bd9Sstevel@tonic-gate ti->ti_active_client->rc_all_auths) 1747c478bd9Sstevel@tonic-gate return (1); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if ((uc = get_ucred()) == NULL) 1777c478bd9Sstevel@tonic-gate return (0); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate return (ucred_is_privileged(uc)); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1837c478bd9Sstevel@tonic-gate static int 1847c478bd9Sstevel@tonic-gate client_compare(const void *lc_arg, const void *rc_arg, void *private) 1857c478bd9Sstevel@tonic-gate { 1867c478bd9Sstevel@tonic-gate uint32_t l_id = ((const repcache_client_t *)lc_arg)->rc_id; 1877c478bd9Sstevel@tonic-gate uint32_t r_id = ((const repcache_client_t *)rc_arg)->rc_id; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate if (l_id > r_id) 1907c478bd9Sstevel@tonic-gate return (1); 1917c478bd9Sstevel@tonic-gate if (l_id < r_id) 1927c478bd9Sstevel@tonic-gate return (-1); 1937c478bd9Sstevel@tonic-gate return (0); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1977c478bd9Sstevel@tonic-gate static int 1987c478bd9Sstevel@tonic-gate entity_compare(const void *lc_arg, const void *rc_arg, void *private) 1997c478bd9Sstevel@tonic-gate { 2007c478bd9Sstevel@tonic-gate uint32_t l_id = ((const repcache_entity_t *)lc_arg)->re_id; 2017c478bd9Sstevel@tonic-gate uint32_t r_id = ((const repcache_entity_t *)rc_arg)->re_id; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if (l_id > r_id) 2047c478bd9Sstevel@tonic-gate return (1); 2057c478bd9Sstevel@tonic-gate if (l_id < r_id) 2067c478bd9Sstevel@tonic-gate return (-1); 2077c478bd9Sstevel@tonic-gate return (0); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2117c478bd9Sstevel@tonic-gate static int 2127c478bd9Sstevel@tonic-gate iter_compare(const void *lc_arg, const void *rc_arg, void *private) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate uint32_t l_id = ((const repcache_iter_t *)lc_arg)->ri_id; 2157c478bd9Sstevel@tonic-gate uint32_t r_id = ((const repcache_iter_t *)rc_arg)->ri_id; 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate if (l_id > r_id) 2187c478bd9Sstevel@tonic-gate return (1); 2197c478bd9Sstevel@tonic-gate if (l_id < r_id) 2207c478bd9Sstevel@tonic-gate return (-1); 2217c478bd9Sstevel@tonic-gate return (0); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate static int 2257c478bd9Sstevel@tonic-gate client_hash_init(void) 2267c478bd9Sstevel@tonic-gate { 2277c478bd9Sstevel@tonic-gate int x; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate assert_nolint(offsetof(repcache_entity_t, re_id) == 0); 2308918dff3Sjwadams entity_pool = uu_avl_pool_create("repcache_entitys", 2317c478bd9Sstevel@tonic-gate sizeof (repcache_entity_t), offsetof(repcache_entity_t, re_link), 2328918dff3Sjwadams entity_compare, UU_AVL_POOL_DEBUG); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate assert_nolint(offsetof(repcache_iter_t, ri_id) == 0); 2358918dff3Sjwadams iter_pool = uu_avl_pool_create("repcache_iters", 2367c478bd9Sstevel@tonic-gate sizeof (repcache_iter_t), offsetof(repcache_iter_t, ri_link), 2378918dff3Sjwadams iter_compare, UU_AVL_POOL_DEBUG); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate assert_nolint(offsetof(repcache_client_t, rc_id) == 0); 2407c478bd9Sstevel@tonic-gate client_pool = uu_list_pool_create("repcache_clients", 2417c478bd9Sstevel@tonic-gate sizeof (repcache_client_t), offsetof(repcache_client_t, rc_link), 2427c478bd9Sstevel@tonic-gate client_compare, UU_LIST_POOL_DEBUG); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate if (entity_pool == NULL || iter_pool == NULL || client_pool == NULL) 2457c478bd9Sstevel@tonic-gate return (0); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate for (x = 0; x < CLIENT_HASH_SIZE; x++) { 2487c478bd9Sstevel@tonic-gate uu_list_t *lp = uu_list_create(client_pool, &client_hash[x], 2497c478bd9Sstevel@tonic-gate UU_LIST_SORTED); 2507c478bd9Sstevel@tonic-gate if (lp == NULL) 2517c478bd9Sstevel@tonic-gate return (0); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&client_hash[x].cb_lock, NULL); 2547c478bd9Sstevel@tonic-gate client_hash[x].cb_list = lp; 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate return (1); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate static repcache_client_t * 2617c478bd9Sstevel@tonic-gate client_alloc(void) 2627c478bd9Sstevel@tonic-gate { 2637c478bd9Sstevel@tonic-gate repcache_client_t *cp; 2647c478bd9Sstevel@tonic-gate cp = uu_zalloc(sizeof (*cp)); 2657c478bd9Sstevel@tonic-gate if (cp == NULL) 2667c478bd9Sstevel@tonic-gate return (NULL); 2677c478bd9Sstevel@tonic-gate 2688918dff3Sjwadams cp->rc_entities = uu_avl_create(entity_pool, cp, 0); 2698918dff3Sjwadams if (cp->rc_entities == NULL) 2707c478bd9Sstevel@tonic-gate goto fail; 2717c478bd9Sstevel@tonic-gate 2728918dff3Sjwadams cp->rc_iters = uu_avl_create(iter_pool, cp, 0); 2738918dff3Sjwadams if (cp->rc_iters == NULL) 2747c478bd9Sstevel@tonic-gate goto fail; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate uu_list_node_init(cp, &cp->rc_link, client_pool); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate cp->rc_doorfd = -1; 2797c478bd9Sstevel@tonic-gate cp->rc_doorid = INVALID_DOORID; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&cp->rc_lock, NULL); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate rc_node_ptr_init(&cp->rc_notify_ptr); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate return (cp); 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate fail: 2888918dff3Sjwadams if (cp->rc_iters != NULL) 2898918dff3Sjwadams uu_avl_destroy(cp->rc_iters); 2908918dff3Sjwadams if (cp->rc_entities != NULL) 2918918dff3Sjwadams uu_avl_destroy(cp->rc_entities); 2927c478bd9Sstevel@tonic-gate uu_free(cp); 2937c478bd9Sstevel@tonic-gate return (NULL); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate static void 2977c478bd9Sstevel@tonic-gate client_free(repcache_client_t *cp) 2987c478bd9Sstevel@tonic-gate { 2997c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == 0); 3007c478bd9Sstevel@tonic-gate assert(cp->rc_refcnt == 0); 3017c478bd9Sstevel@tonic-gate assert(cp->rc_doorfd == -1); 3027c478bd9Sstevel@tonic-gate assert(cp->rc_doorid == INVALID_DOORID); 3038918dff3Sjwadams assert(uu_avl_first(cp->rc_entities) == NULL); 3048918dff3Sjwadams assert(uu_avl_first(cp->rc_iters) == NULL); 3058918dff3Sjwadams uu_avl_destroy(cp->rc_entities); 3068918dff3Sjwadams uu_avl_destroy(cp->rc_iters); 3077c478bd9Sstevel@tonic-gate uu_list_node_fini(cp, &cp->rc_link, client_pool); 3087c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&cp->rc_lock); 3097c478bd9Sstevel@tonic-gate uu_free(cp); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate static void 3137c478bd9Sstevel@tonic-gate client_insert(repcache_client_t *cp) 3147c478bd9Sstevel@tonic-gate { 3157c478bd9Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(cp->rc_id); 3167c478bd9Sstevel@tonic-gate uu_list_index_t idx; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate assert(cp->rc_id > 0); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * We assume it does not already exist 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate (void) uu_list_find(bp->cb_list, cp, NULL, &idx); 3257c478bd9Sstevel@tonic-gate uu_list_insert(bp->cb_list, cp, idx); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate static repcache_client_t * 3317c478bd9Sstevel@tonic-gate client_lookup(uint32_t id) 3327c478bd9Sstevel@tonic-gate { 3337c478bd9Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(id); 3347c478bd9Sstevel@tonic-gate repcache_client_t *cp; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate cp = uu_list_find(bp->cb_list, &id, NULL, NULL); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* 3417c478bd9Sstevel@tonic-gate * Bump the reference count 3427c478bd9Sstevel@tonic-gate */ 3437c478bd9Sstevel@tonic-gate if (cp != NULL) { 3447c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3457c478bd9Sstevel@tonic-gate assert(!(cp->rc_flags & RC_CLIENT_DEAD)); 3467c478bd9Sstevel@tonic-gate cp->rc_refcnt++; 3477c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate return (cp); 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate static void 3557c478bd9Sstevel@tonic-gate client_release(repcache_client_t *cp) 3567c478bd9Sstevel@tonic-gate { 3577c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3587c478bd9Sstevel@tonic-gate assert(cp->rc_refcnt > 0); 3597c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr != pthread_self()); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate --cp->rc_refcnt; 3627c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&cp->rc_cv); 3637c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * We only allow one thread to be inserting at a time, to prevent 3687c478bd9Sstevel@tonic-gate * insert/insert races. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate static void 3717c478bd9Sstevel@tonic-gate client_start_insert(repcache_client_t *cp) 3727c478bd9Sstevel@tonic-gate { 3737c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3747c478bd9Sstevel@tonic-gate assert(cp->rc_refcnt > 0); 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate while (cp->rc_insert_thr != 0) { 3777c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr != pthread_self()); 3787c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate cp->rc_insert_thr = pthread_self(); 3817c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate static void 3857c478bd9Sstevel@tonic-gate client_end_insert(repcache_client_t *cp) 3867c478bd9Sstevel@tonic-gate { 3877c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3887c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 3897c478bd9Sstevel@tonic-gate cp->rc_insert_thr = 0; 3907c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&cp->rc_cv); 3917c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3957c478bd9Sstevel@tonic-gate static repcache_entity_t * 3967c478bd9Sstevel@tonic-gate entity_alloc(repcache_client_t *cp) 3977c478bd9Sstevel@tonic-gate { 3987c478bd9Sstevel@tonic-gate repcache_entity_t *ep = uu_zalloc(sizeof (repcache_entity_t)); 3997c478bd9Sstevel@tonic-gate if (ep != NULL) { 4008918dff3Sjwadams uu_avl_node_init(ep, &ep->re_link, entity_pool); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate return (ep); 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate static void 4067c478bd9Sstevel@tonic-gate entity_add(repcache_client_t *cp, repcache_entity_t *ep) 4077c478bd9Sstevel@tonic-gate { 4088918dff3Sjwadams uu_avl_index_t idx; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 4117c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 4127c478bd9Sstevel@tonic-gate 4138918dff3Sjwadams (void) uu_avl_find(cp->rc_entities, ep, NULL, &idx); 4148918dff3Sjwadams uu_avl_insert(cp->rc_entities, ep, idx); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate static repcache_entity_t * 4207c478bd9Sstevel@tonic-gate entity_find(repcache_client_t *cp, uint32_t id) 4217c478bd9Sstevel@tonic-gate { 4227c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 4258918dff3Sjwadams ep = uu_avl_find(cp->rc_entities, &id, NULL, NULL); 4267c478bd9Sstevel@tonic-gate if (ep != NULL) { 4277c478bd9Sstevel@tonic-gate add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, ep); 4287c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->re_lock); 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate return (ep); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * Fails with 4377c478bd9Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 4387c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate static int 4417c478bd9Sstevel@tonic-gate entity_find2(repcache_client_t *cp, uint32_t id1, repcache_entity_t **out1, 4427c478bd9Sstevel@tonic-gate uint32_t id2, repcache_entity_t **out2) 4437c478bd9Sstevel@tonic-gate { 4447c478bd9Sstevel@tonic-gate repcache_entity_t *e1, *e2; 4457c478bd9Sstevel@tonic-gate request_log_entry_t *rlp; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate if (id1 == id2) 4487c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DUPLICATE_ID); 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 4518918dff3Sjwadams e1 = uu_avl_find(cp->rc_entities, &id1, NULL, NULL); 4528918dff3Sjwadams e2 = uu_avl_find(cp->rc_entities, &id2, NULL, NULL); 4537c478bd9Sstevel@tonic-gate if (e1 == NULL || e2 == NULL) { 4547c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4557c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate assert(e1 != e2); 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * locks are ordered by id number 4627c478bd9Sstevel@tonic-gate */ 4637c478bd9Sstevel@tonic-gate if (id1 < id2) { 4647c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&e1->re_lock); 4657c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&e2->re_lock); 4667c478bd9Sstevel@tonic-gate } else { 4677c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&e2->re_lock); 4687c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&e1->re_lock); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate *out1 = e1; 4717c478bd9Sstevel@tonic-gate *out2 = e2; 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate if ((rlp = get_log()) != NULL) { 4767c478bd9Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id1, e1); 4777c478bd9Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id2, e2); 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate static void 4847c478bd9Sstevel@tonic-gate entity_release(repcache_entity_t *ep) 4857c478bd9Sstevel@tonic-gate { 4867c478bd9Sstevel@tonic-gate assert(ep->re_node.rnp_node == NULL || 4877c478bd9Sstevel@tonic-gate !MUTEX_HELD(&ep->re_node.rnp_node->rn_lock)); 4887c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ep->re_lock); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate static void 4927c478bd9Sstevel@tonic-gate entity_destroy(repcache_entity_t *entity) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&entity->re_lock); 4957c478bd9Sstevel@tonic-gate rc_node_clear(&entity->re_node, 0); 4967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&entity->re_lock); 4977c478bd9Sstevel@tonic-gate 4988918dff3Sjwadams uu_avl_node_fini(entity, &entity->re_link, entity_pool); 4997c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&entity->re_lock); 5007c478bd9Sstevel@tonic-gate uu_free(entity); 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate static void 5047c478bd9Sstevel@tonic-gate entity_remove(repcache_client_t *cp, uint32_t id) 5057c478bd9Sstevel@tonic-gate { 5067c478bd9Sstevel@tonic-gate repcache_entity_t *entity; 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5098918dff3Sjwadams entity = uu_avl_find(cp->rc_entities, &id, NULL, NULL); 5107c478bd9Sstevel@tonic-gate if (entity != NULL) 5118918dff3Sjwadams uu_avl_remove(cp->rc_entities, entity); 5127c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate if (entity != NULL) 5157c478bd9Sstevel@tonic-gate entity_destroy(entity); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate static void 5197c478bd9Sstevel@tonic-gate entity_cleanup(repcache_client_t *cp) 5207c478bd9Sstevel@tonic-gate { 5217c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 5227c478bd9Sstevel@tonic-gate void *cookie = NULL; 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5258918dff3Sjwadams while ((ep = uu_avl_teardown(cp->rc_entities, &cookie)) != NULL) { 5267c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5277c478bd9Sstevel@tonic-gate entity_destroy(ep); 5287c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5347c478bd9Sstevel@tonic-gate static repcache_iter_t * 5357c478bd9Sstevel@tonic-gate iter_alloc(repcache_client_t *cp) 5367c478bd9Sstevel@tonic-gate { 5377c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 5387c478bd9Sstevel@tonic-gate iter = uu_zalloc(sizeof (repcache_iter_t)); 5397c478bd9Sstevel@tonic-gate if (iter != NULL) 5408918dff3Sjwadams uu_avl_node_init(iter, &iter->ri_link, iter_pool); 5417c478bd9Sstevel@tonic-gate return (iter); 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate static void 5457c478bd9Sstevel@tonic-gate iter_add(repcache_client_t *cp, repcache_iter_t *iter) 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate uu_list_index_t idx; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5507c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 5517c478bd9Sstevel@tonic-gate 5528918dff3Sjwadams (void) uu_avl_find(cp->rc_iters, iter, NULL, &idx); 5538918dff3Sjwadams uu_avl_insert(cp->rc_iters, iter, idx); 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate static repcache_iter_t * 5597c478bd9Sstevel@tonic-gate iter_find(repcache_client_t *cp, uint32_t id) 5607c478bd9Sstevel@tonic-gate { 5617c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5647c478bd9Sstevel@tonic-gate 5658918dff3Sjwadams iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL); 5667c478bd9Sstevel@tonic-gate if (iter != NULL) { 5677c478bd9Sstevel@tonic-gate add_log_ptr(get_log(), RC_PTR_TYPE_ITER, id, iter); 5687c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate return (iter); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate /* 5767c478bd9Sstevel@tonic-gate * Fails with 5777c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - iter_id or entity_id does not designate an active register 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate static int 5807c478bd9Sstevel@tonic-gate iter_find_w_entity(repcache_client_t *cp, uint32_t iter_id, 5817c478bd9Sstevel@tonic-gate repcache_iter_t **iterp, uint32_t entity_id, repcache_entity_t **epp) 5827c478bd9Sstevel@tonic-gate { 5837c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 5847c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 5857c478bd9Sstevel@tonic-gate request_log_entry_t *rlp; 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5888918dff3Sjwadams iter = uu_avl_find(cp->rc_iters, &iter_id, NULL, NULL); 5898918dff3Sjwadams ep = uu_avl_find(cp->rc_entities, &entity_id, NULL, NULL); 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate assert(iter == NULL || !MUTEX_HELD(&iter->ri_lock)); 5927c478bd9Sstevel@tonic-gate assert(ep == NULL || !MUTEX_HELD(&ep->re_lock)); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if (iter == NULL || ep == NULL) { 5957c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5967c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 6007c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->re_lock); 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate *iterp = iter; 6057c478bd9Sstevel@tonic-gate *epp = ep; 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate if ((rlp = get_log()) != NULL) { 6087c478bd9Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, entity_id, ep); 6097c478bd9Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ITER, iter_id, iter); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate static void 6167c478bd9Sstevel@tonic-gate iter_release(repcache_iter_t *iter) 6177c478bd9Sstevel@tonic-gate { 6187c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&iter->ri_lock); 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate static void 6227c478bd9Sstevel@tonic-gate iter_destroy(repcache_iter_t *iter) 6237c478bd9Sstevel@tonic-gate { 6247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 6257c478bd9Sstevel@tonic-gate rc_iter_destroy(&iter->ri_iter); 6267c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&iter->ri_lock); 6277c478bd9Sstevel@tonic-gate 6288918dff3Sjwadams uu_avl_node_fini(iter, &iter->ri_link, iter_pool); 6297c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&iter->ri_lock); 6307c478bd9Sstevel@tonic-gate uu_free(iter); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate static void 6347c478bd9Sstevel@tonic-gate iter_remove(repcache_client_t *cp, uint32_t id) 6357c478bd9Sstevel@tonic-gate { 6367c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 6398918dff3Sjwadams iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL); 6407c478bd9Sstevel@tonic-gate if (iter != NULL) 6418918dff3Sjwadams uu_avl_remove(cp->rc_iters, iter); 6427c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate if (iter != NULL) 6457c478bd9Sstevel@tonic-gate iter_destroy(iter); 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate static void 6497c478bd9Sstevel@tonic-gate iter_cleanup(repcache_client_t *cp) 6507c478bd9Sstevel@tonic-gate { 6517c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 6527c478bd9Sstevel@tonic-gate void *cookie = NULL; 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 6558918dff3Sjwadams while ((iter = uu_avl_teardown(cp->rc_iters, &cookie)) != NULL) { 6567c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6577c478bd9Sstevel@tonic-gate iter_destroy(iter); 6587c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * Ensure that the passed client id is no longer usable, wait for any 6657c478bd9Sstevel@tonic-gate * outstanding invocations to complete, then destroy the client 6667c478bd9Sstevel@tonic-gate * structure. 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate static void 6697c478bd9Sstevel@tonic-gate client_destroy(uint32_t id) 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(id); 6727c478bd9Sstevel@tonic-gate repcache_client_t *cp; 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate cp = uu_list_find(bp->cb_list, &id, NULL, NULL); 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate if (cp == NULL) { 6797c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 6807c478bd9Sstevel@tonic-gate return; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate uu_list_remove(bp->cb_list, cp); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* kick the waiters out */ 6887c478bd9Sstevel@tonic-gate rc_notify_info_fini(&cp->rc_notify_info); 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 6917c478bd9Sstevel@tonic-gate assert(!(cp->rc_flags & RC_CLIENT_DEAD)); 6927c478bd9Sstevel@tonic-gate cp->rc_flags |= RC_CLIENT_DEAD; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate if (cp->rc_doorfd != -1) { 6957c478bd9Sstevel@tonic-gate if (door_revoke(cp->rc_doorfd) < 0) 6967c478bd9Sstevel@tonic-gate perror("door_revoke"); 6977c478bd9Sstevel@tonic-gate cp->rc_doorfd = -1; 6987c478bd9Sstevel@tonic-gate cp->rc_doorid = INVALID_DOORID; 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate while (cp->rc_refcnt > 0) 7027c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate assert(cp->rc_insert_thr == 0 && cp->rc_notify_thr == 0); 7057c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* 7087c478bd9Sstevel@tonic-gate * destroy outstanding objects 7097c478bd9Sstevel@tonic-gate */ 7107c478bd9Sstevel@tonic-gate entity_cleanup(cp); 7117c478bd9Sstevel@tonic-gate iter_cleanup(cp); 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* 7147c478bd9Sstevel@tonic-gate * clean up notifications 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate rc_pg_notify_fini(&cp->rc_pg_notify); 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate client_free(cp); 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate /* 7227c478bd9Sstevel@tonic-gate * Fails with 7237c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - the entity is already set up with a different type 7247c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate static int 7277c478bd9Sstevel@tonic-gate entity_setup(repcache_client_t *cp, struct rep_protocol_entity_setup *rpr) 7287c478bd9Sstevel@tonic-gate { 7297c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 7307c478bd9Sstevel@tonic-gate uint32_t type; 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate client_start_insert(cp); 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) { 7357c478bd9Sstevel@tonic-gate type = ep->re_type; 7367c478bd9Sstevel@tonic-gate entity_release(ep); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate client_end_insert(cp); 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate if (type != rpr->rpr_entitytype) 7417c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 7427c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate switch (type = rpr->rpr_entitytype) { 7467c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SCOPE: 7477c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE: 7487c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE: 7497c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPSHOT: 7507c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPLEVEL: 7517c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP: 7527c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTY: 7537c478bd9Sstevel@tonic-gate break; 7547c478bd9Sstevel@tonic-gate default: 7557c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate ep = entity_alloc(cp); 7597c478bd9Sstevel@tonic-gate if (ep == NULL) { 7607c478bd9Sstevel@tonic-gate client_end_insert(cp); 7617c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate ep->re_id = rpr->rpr_entityid; 7657c478bd9Sstevel@tonic-gate ep->re_changeid = INVALID_CHANGEID; 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate ep->re_type = type; 7687c478bd9Sstevel@tonic-gate rc_node_ptr_init(&ep->re_node); 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate entity_add(cp, ep); 7717c478bd9Sstevel@tonic-gate client_end_insert(cp); 7727c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7767c478bd9Sstevel@tonic-gate static void 7777c478bd9Sstevel@tonic-gate entity_name(repcache_client_t *cp, const void *in, size_t insz, void *out_arg, 7787c478bd9Sstevel@tonic-gate size_t *outsz, void *arg) 7797c478bd9Sstevel@tonic-gate { 7807c478bd9Sstevel@tonic-gate const struct rep_protocol_entity_name *rpr = in; 7817c478bd9Sstevel@tonic-gate struct rep_protocol_name_response *out = out_arg; 7827c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 7837c478bd9Sstevel@tonic-gate size_t sz = sizeof (out->rpr_name); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate if (ep == NULL) { 7907c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 7917c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 7927c478bd9Sstevel@tonic-gate return; 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate out->rpr_response = rc_node_name(&ep->re_node, out->rpr_name, 7957c478bd9Sstevel@tonic-gate sz, rpr->rpr_answertype, &sz); 7967c478bd9Sstevel@tonic-gate entity_release(ep); 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate /* 7997c478bd9Sstevel@tonic-gate * If we fail, we only return the response code. 8007c478bd9Sstevel@tonic-gate * If we succeed, we don't return anything after the '\0' in rpr_name. 8017c478bd9Sstevel@tonic-gate */ 8027c478bd9Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 8037c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8047c478bd9Sstevel@tonic-gate else 8057c478bd9Sstevel@tonic-gate *outsz = offsetof(struct rep_protocol_name_response, 8067c478bd9Sstevel@tonic-gate rpr_name[sz + 1]); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8107c478bd9Sstevel@tonic-gate static void 8117c478bd9Sstevel@tonic-gate entity_parent_type(repcache_client_t *cp, const void *in, size_t insz, 8127c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 8137c478bd9Sstevel@tonic-gate { 8147c478bd9Sstevel@tonic-gate const struct rep_protocol_entity_name *rpr = in; 8157c478bd9Sstevel@tonic-gate struct rep_protocol_integer_response *out = out_arg; 8167c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate if (ep == NULL) { 8237c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 8247c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8257c478bd9Sstevel@tonic-gate return; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate out->rpr_response = rc_node_parent_type(&ep->re_node, &out->rpr_value); 8297c478bd9Sstevel@tonic-gate entity_release(ep); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 8327c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate /* 8367c478bd9Sstevel@tonic-gate * Fails with 8377c478bd9Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 8387c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 8397c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 8407c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type 8417c478bd9Sstevel@tonic-gate * _DELETED - np has been deleted 8427c478bd9Sstevel@tonic-gate * _NOT_FOUND - no child with that name/type combo found 8437c478bd9Sstevel@tonic-gate * _NO_RESOURCES 8447c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate static int 8477c478bd9Sstevel@tonic-gate entity_get_child(repcache_client_t *cp, 8487c478bd9Sstevel@tonic-gate struct rep_protocol_entity_get_child *rpr) 8497c478bd9Sstevel@tonic-gate { 8507c478bd9Sstevel@tonic-gate repcache_entity_t *parent, *child; 8517c478bd9Sstevel@tonic-gate int result; 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 8547c478bd9Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate result = entity_find2(cp, childid, &child, parentid, &parent); 8577c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 8587c478bd9Sstevel@tonic-gate return (result); 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate result = rc_node_get_child(&parent->re_node, rpr->rpr_name, 8637c478bd9Sstevel@tonic-gate child->re_type, &child->re_node); 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate entity_release(child); 8667c478bd9Sstevel@tonic-gate entity_release(parent); 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate return (result); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate /* 8727c478bd9Sstevel@tonic-gate * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED, 8737c478bd9Sstevel@tonic-gate * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS. 8747c478bd9Sstevel@tonic-gate * Fails with 8757c478bd9Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 8767c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 8777c478bd9Sstevel@tonic-gate * _NOT_SET - child is not set 8787c478bd9Sstevel@tonic-gate * _DELETED - child has been deleted 8797c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - child's parent does not match that of the parent register 8807c478bd9Sstevel@tonic-gate * _NOT_FOUND - child has no parent (and is a scope) 8817c478bd9Sstevel@tonic-gate */ 8827c478bd9Sstevel@tonic-gate static int 8837c478bd9Sstevel@tonic-gate entity_get_parent(repcache_client_t *cp, struct rep_protocol_entity_parent *rpr) 8847c478bd9Sstevel@tonic-gate { 8857c478bd9Sstevel@tonic-gate repcache_entity_t *child, *parent; 8867c478bd9Sstevel@tonic-gate int result; 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate uint32_t childid = rpr->rpr_entityid; 8897c478bd9Sstevel@tonic-gate uint32_t outid = rpr->rpr_outid; 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate result = entity_find2(cp, childid, &child, outid, &parent); 8927c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 8937c478bd9Sstevel@tonic-gate return (result); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate result = rc_node_get_parent(&child->re_node, parent->re_type, 8967c478bd9Sstevel@tonic-gate &parent->re_node); 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate entity_release(child); 8997c478bd9Sstevel@tonic-gate entity_release(parent); 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate return (result); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate static int 9057c478bd9Sstevel@tonic-gate entity_get(repcache_client_t *cp, struct rep_protocol_entity_get *rpr) 9067c478bd9Sstevel@tonic-gate { 9077c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 9087c478bd9Sstevel@tonic-gate int result; 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate if (ep == NULL) 9137c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate switch (rpr->rpr_object) { 9167c478bd9Sstevel@tonic-gate case RP_ENTITY_GET_INVALIDATE: 9177c478bd9Sstevel@tonic-gate rc_node_clear(&ep->re_node, 0); 9187c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 9197c478bd9Sstevel@tonic-gate break; 9207c478bd9Sstevel@tonic-gate case RP_ENTITY_GET_MOST_LOCAL_SCOPE: 9217c478bd9Sstevel@tonic-gate result = rc_local_scope(ep->re_type, &ep->re_node); 9227c478bd9Sstevel@tonic-gate break; 9237c478bd9Sstevel@tonic-gate default: 9247c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 9257c478bd9Sstevel@tonic-gate break; 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate entity_release(ep); 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate return (result); 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate static int 9347c478bd9Sstevel@tonic-gate entity_update(repcache_client_t *cp, struct rep_protocol_entity_update *rpr) 9357c478bd9Sstevel@tonic-gate { 9367c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 9377c478bd9Sstevel@tonic-gate int result; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 9407c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate if (ep == NULL) 9457c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate if (ep->re_changeid == rpr->rpr_changeid) { 9487c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_DONE; 9497c478bd9Sstevel@tonic-gate } else { 9507c478bd9Sstevel@tonic-gate result = rc_node_update(&ep->re_node); 9517c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_DONE) 9527c478bd9Sstevel@tonic-gate ep->re_changeid = rpr->rpr_changeid; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate entity_release(ep); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate return (result); 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate static int 9617c478bd9Sstevel@tonic-gate entity_reset(repcache_client_t *cp, struct rep_protocol_entity_reset *rpr) 9627c478bd9Sstevel@tonic-gate { 9637c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 9667c478bd9Sstevel@tonic-gate if (ep == NULL) 9677c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate rc_node_clear(&ep->re_node, 0); 9707c478bd9Sstevel@tonic-gate ep->re_txstate = REPCACHE_TX_INIT; 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate entity_release(ep); 9737c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate /* 9777c478bd9Sstevel@tonic-gate * Fails with 9787c478bd9Sstevel@tonic-gate * _BAD_REQUEST - request has invalid changeid 9797c478bd9Sstevel@tonic-gate * rpr_name is invalid 9807c478bd9Sstevel@tonic-gate * cannot create children for parent's type of node 9817c478bd9Sstevel@tonic-gate * _DUPLICATE_ID - request has duplicate ids 9827c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - request has unknown id 9837c478bd9Sstevel@tonic-gate * _DELETED - parent has been deleted 9847c478bd9Sstevel@tonic-gate * _NOT_SET - parent is reset 9857c478bd9Sstevel@tonic-gate * _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP 9867c478bd9Sstevel@tonic-gate * _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid 9877c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have children of type rpr_childtype 9887c478bd9Sstevel@tonic-gate * _NO_RESOURCES 9897c478bd9Sstevel@tonic-gate * _PERMISSION_DENIED 9907c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 9917c478bd9Sstevel@tonic-gate * _BACKEND_READONLY 9927c478bd9Sstevel@tonic-gate * _EXISTS - child already exists 9937c478bd9Sstevel@tonic-gate */ 9947c478bd9Sstevel@tonic-gate static int 9957c478bd9Sstevel@tonic-gate entity_create_child(repcache_client_t *cp, 9967c478bd9Sstevel@tonic-gate struct rep_protocol_entity_create_child *rpr) 9977c478bd9Sstevel@tonic-gate { 9987c478bd9Sstevel@tonic-gate repcache_entity_t *parent; 9997c478bd9Sstevel@tonic-gate repcache_entity_t *child; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 10027c478bd9Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate int result; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 10077c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate result = entity_find2(cp, parentid, &parent, childid, &child); 10107c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 10117c478bd9Sstevel@tonic-gate return (result); 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate if (child->re_changeid == rpr->rpr_changeid) { 10167c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 10177c478bd9Sstevel@tonic-gate } else { 10187c478bd9Sstevel@tonic-gate result = rc_node_create_child(&parent->re_node, 10197c478bd9Sstevel@tonic-gate rpr->rpr_childtype, rpr->rpr_name, &child->re_node); 10207c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 10217c478bd9Sstevel@tonic-gate child->re_changeid = rpr->rpr_changeid; 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate entity_release(parent); 10257c478bd9Sstevel@tonic-gate entity_release(child); 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate return (result); 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate static int 10317c478bd9Sstevel@tonic-gate entity_create_pg(repcache_client_t *cp, 10327c478bd9Sstevel@tonic-gate struct rep_protocol_entity_create_pg *rpr) 10337c478bd9Sstevel@tonic-gate { 10347c478bd9Sstevel@tonic-gate repcache_entity_t *parent; 10357c478bd9Sstevel@tonic-gate repcache_entity_t *child; 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 10387c478bd9Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate int result; 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 10437c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate result = entity_find2(cp, parentid, &parent, childid, &child); 10467c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 10477c478bd9Sstevel@tonic-gate return (result); 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 10507c478bd9Sstevel@tonic-gate rpr->rpr_type[sizeof (rpr->rpr_type) - 1] = 0; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate if (child->re_changeid == rpr->rpr_changeid) { 10537c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 10547c478bd9Sstevel@tonic-gate } else { 10557c478bd9Sstevel@tonic-gate result = rc_node_create_child_pg(&parent->re_node, 10567c478bd9Sstevel@tonic-gate child->re_type, rpr->rpr_name, rpr->rpr_type, 10577c478bd9Sstevel@tonic-gate rpr->rpr_flags, &child->re_node); 10587c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 10597c478bd9Sstevel@tonic-gate child->re_changeid = rpr->rpr_changeid; 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate entity_release(parent); 10637c478bd9Sstevel@tonic-gate entity_release(child); 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate return (result); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate static int 10697c478bd9Sstevel@tonic-gate entity_delete(repcache_client_t *cp, 10707c478bd9Sstevel@tonic-gate struct rep_protocol_entity_delete *rpr) 10717c478bd9Sstevel@tonic-gate { 10727c478bd9Sstevel@tonic-gate repcache_entity_t *entity; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate uint32_t entityid = rpr->rpr_entityid; 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate int result; 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 10797c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate entity = entity_find(cp, entityid); 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate if (entity == NULL) 10847c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate if (entity->re_changeid == rpr->rpr_changeid) { 10877c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 10887c478bd9Sstevel@tonic-gate } else { 10897c478bd9Sstevel@tonic-gate result = rc_node_delete(&entity->re_node); 10907c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 10917c478bd9Sstevel@tonic-gate entity->re_changeid = rpr->rpr_changeid; 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate entity_release(entity); 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate return (result); 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 11007c478bd9Sstevel@tonic-gate entity_teardown(repcache_client_t *cp, struct rep_protocol_entity_teardown *rpr) 11017c478bd9Sstevel@tonic-gate { 11027c478bd9Sstevel@tonic-gate entity_remove(cp, rpr->rpr_entityid); 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate /* 11087c478bd9Sstevel@tonic-gate * Fails with 11097c478bd9Sstevel@tonic-gate * _MISORDERED - the iterator exists and is not reset 11107c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory 11117c478bd9Sstevel@tonic-gate */ 11127c478bd9Sstevel@tonic-gate static int 11137c478bd9Sstevel@tonic-gate iter_setup(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 11147c478bd9Sstevel@tonic-gate { 11157c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 11167c478bd9Sstevel@tonic-gate uint32_t sequence; 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate client_start_insert(cp); 11197c478bd9Sstevel@tonic-gate /* 11207c478bd9Sstevel@tonic-gate * If the iter already exists, and hasn't been read from, 11217c478bd9Sstevel@tonic-gate * we assume the previous call succeeded. 11227c478bd9Sstevel@tonic-gate */ 11237c478bd9Sstevel@tonic-gate if ((iter = iter_find(cp, rpr->rpr_iterid)) != NULL) { 11247c478bd9Sstevel@tonic-gate sequence = iter->ri_sequence; 11257c478bd9Sstevel@tonic-gate iter_release(iter); 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate client_end_insert(cp); 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate if (sequence != 0) 11307c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 11317c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate iter = iter_alloc(cp); 11357c478bd9Sstevel@tonic-gate if (iter == NULL) { 11367c478bd9Sstevel@tonic-gate client_end_insert(cp); 11377c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate iter->ri_id = rpr->rpr_iterid; 11417c478bd9Sstevel@tonic-gate iter->ri_type = REP_PROTOCOL_TYPE_INVALID; 11427c478bd9Sstevel@tonic-gate iter->ri_sequence = 0; 11437c478bd9Sstevel@tonic-gate iter_add(cp, iter); 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate client_end_insert(cp); 11467c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate /* 11507c478bd9Sstevel@tonic-gate * Fails with 11517c478bd9Sstevel@tonic-gate * _UNKNOWN_ID 11527c478bd9Sstevel@tonic-gate * _MISORDERED - iterator has already been started 11537c478bd9Sstevel@tonic-gate * _NOT_SET 11547c478bd9Sstevel@tonic-gate * _DELETED 11557c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - entity cannot have type children 11567c478bd9Sstevel@tonic-gate * _BAD_REQUEST - rpr_flags is invalid 11577c478bd9Sstevel@tonic-gate * rpr_pattern is invalid 11587c478bd9Sstevel@tonic-gate * _NO_RESOURCES 11597c478bd9Sstevel@tonic-gate * _INVALID_TYPE 11607c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 11617c478bd9Sstevel@tonic-gate */ 11627c478bd9Sstevel@tonic-gate static int 11637c478bd9Sstevel@tonic-gate iter_start(repcache_client_t *cp, struct rep_protocol_iter_start *rpr) 11647c478bd9Sstevel@tonic-gate { 11657c478bd9Sstevel@tonic-gate int result; 11667c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 11677c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter, 11707c478bd9Sstevel@tonic-gate rpr->rpr_entity, &ep); 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 11737c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate if (iter->ri_sequence > 1) { 11767c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 11777c478bd9Sstevel@tonic-gate goto end; 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate if (iter->ri_sequence == 1) { 11817c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 11827c478bd9Sstevel@tonic-gate goto end; 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0; 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate result = rc_node_setup_iter(&ep->re_node, &iter->ri_iter, 11887c478bd9Sstevel@tonic-gate rpr->rpr_itertype, rpr->rpr_flags, rpr->rpr_pattern); 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 11917c478bd9Sstevel@tonic-gate iter->ri_sequence++; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate end: 11947c478bd9Sstevel@tonic-gate iter_release(iter); 11957c478bd9Sstevel@tonic-gate entity_release(ep); 11967c478bd9Sstevel@tonic-gate return (result); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * Returns 12017c478bd9Sstevel@tonic-gate * _UNKNOWN_ID 12027c478bd9Sstevel@tonic-gate * _NOT_SET - iter has not been started 12037c478bd9Sstevel@tonic-gate * _MISORDERED 12047c478bd9Sstevel@tonic-gate * _BAD_REQUEST - iter walks values 12057c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - iter does not walk type entities 12067c478bd9Sstevel@tonic-gate * _DELETED - parent was deleted 12077c478bd9Sstevel@tonic-gate * _NO_RESOURCES 12087c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 12097c478bd9Sstevel@tonic-gate * _DONE 12107c478bd9Sstevel@tonic-gate * _SUCCESS 12117c478bd9Sstevel@tonic-gate * 12127c478bd9Sstevel@tonic-gate * For composed property group iterators, can also return 12137c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have type children 12147c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 12157c478bd9Sstevel@tonic-gate */ 12167c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 12177c478bd9Sstevel@tonic-gate iter_read(repcache_client_t *cp, struct rep_protocol_iter_read *rpr) 12187c478bd9Sstevel@tonic-gate { 12197c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 12207c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 12217c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 12227c478bd9Sstevel@tonic-gate uint32_t sequence; 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter, 12257c478bd9Sstevel@tonic-gate rpr->rpr_entityid, &ep); 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 12287c478bd9Sstevel@tonic-gate return (result); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate sequence = rpr->rpr_sequence; 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate if (iter->ri_sequence == 0) { 12337c478bd9Sstevel@tonic-gate iter_release(iter); 12347c478bd9Sstevel@tonic-gate entity_release(ep); 12357c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_SET); 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate if (sequence == 1) { 12397c478bd9Sstevel@tonic-gate iter_release(iter); 12407c478bd9Sstevel@tonic-gate entity_release(ep); 12417c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate if (sequence == iter->ri_sequence) { 12457c478bd9Sstevel@tonic-gate iter_release(iter); 12467c478bd9Sstevel@tonic-gate entity_release(ep); 12477c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 12487c478bd9Sstevel@tonic-gate } 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate if (sequence == iter->ri_sequence + 1) { 12517c478bd9Sstevel@tonic-gate result = rc_iter_next(iter->ri_iter, &ep->re_node, 12527c478bd9Sstevel@tonic-gate ep->re_type); 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 12557c478bd9Sstevel@tonic-gate iter->ri_sequence++; 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate iter_release(iter); 12587c478bd9Sstevel@tonic-gate entity_release(ep); 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate return (result); 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate iter_release(iter); 12647c478bd9Sstevel@tonic-gate entity_release(ep); 12657c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12697c478bd9Sstevel@tonic-gate static void 12707c478bd9Sstevel@tonic-gate iter_read_value(repcache_client_t *cp, const void *in, size_t insz, 12717c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 12727c478bd9Sstevel@tonic-gate { 12737c478bd9Sstevel@tonic-gate const struct rep_protocol_iter_read_value *rpr = in; 12747c478bd9Sstevel@tonic-gate struct rep_protocol_value_response *out = out_arg; 12757c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate repcache_iter_t *iter; 12787c478bd9Sstevel@tonic-gate uint32_t sequence; 12797c478bd9Sstevel@tonic-gate int repeat; 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate iter = iter_find(cp, rpr->rpr_iterid); 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate if (iter == NULL) { 12867c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 12877c478bd9Sstevel@tonic-gate goto out; 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate sequence = rpr->rpr_sequence; 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate if (iter->ri_sequence == 0) { 12937c478bd9Sstevel@tonic-gate iter_release(iter); 12947c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_NOT_SET; 12957c478bd9Sstevel@tonic-gate goto out; 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate repeat = (sequence == iter->ri_sequence); 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate if (sequence == 1 || (!repeat && sequence != iter->ri_sequence + 1)) { 13017c478bd9Sstevel@tonic-gate iter_release(iter); 13027c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 13037c478bd9Sstevel@tonic-gate goto out; 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate result = rc_iter_next_value(iter->ri_iter, out, outsz, repeat); 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate if (!repeat && result == REP_PROTOCOL_SUCCESS) 13097c478bd9Sstevel@tonic-gate iter->ri_sequence++; 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate iter_release(iter); 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate out: 13147c478bd9Sstevel@tonic-gate /* 13157c478bd9Sstevel@tonic-gate * If we fail, we only return the response code. 13167c478bd9Sstevel@tonic-gate * If we succeed, rc_iter_next_value has shortened *outsz 13177c478bd9Sstevel@tonic-gate * to only include the value bytes needed. 13187c478bd9Sstevel@tonic-gate */ 13197c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS && result != REP_PROTOCOL_DONE) 13207c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate out->rpr_response = result; 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate static int 13267c478bd9Sstevel@tonic-gate iter_reset(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 13277c478bd9Sstevel@tonic-gate { 13287c478bd9Sstevel@tonic-gate repcache_iter_t *iter = iter_find(cp, rpr->rpr_iterid); 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate if (iter == NULL) 13317c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate if (iter->ri_sequence != 0) { 13347c478bd9Sstevel@tonic-gate iter->ri_sequence = 0; 13357c478bd9Sstevel@tonic-gate rc_iter_destroy(&iter->ri_iter); 13367c478bd9Sstevel@tonic-gate } 13377c478bd9Sstevel@tonic-gate iter_release(iter); 13387c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 13427c478bd9Sstevel@tonic-gate iter_teardown(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 13437c478bd9Sstevel@tonic-gate { 13447c478bd9Sstevel@tonic-gate iter_remove(cp, rpr->rpr_iterid); 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 13507c478bd9Sstevel@tonic-gate tx_start(repcache_client_t *cp, struct rep_protocol_transaction_start *rpr) 13517c478bd9Sstevel@tonic-gate { 13527c478bd9Sstevel@tonic-gate repcache_entity_t *tx; 13537c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 13547c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate uint32_t txid = rpr->rpr_entityid_tx; 13577c478bd9Sstevel@tonic-gate uint32_t epid = rpr->rpr_entityid; 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate result = entity_find2(cp, txid, &tx, epid, &ep); 13607c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 13617c478bd9Sstevel@tonic-gate return (result); 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate if (tx->re_txstate == REPCACHE_TX_SETUP) { 13647c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 13657c478bd9Sstevel@tonic-gate goto end; 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate if (tx->re_txstate != REPCACHE_TX_INIT) { 13687c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 13697c478bd9Sstevel@tonic-gate goto end; 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate result = rc_node_setup_tx(&ep->re_node, &tx->re_node); 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate end: 13757c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 13767c478bd9Sstevel@tonic-gate tx->re_txstate = REPCACHE_TX_SETUP; 13777c478bd9Sstevel@tonic-gate else 13787c478bd9Sstevel@tonic-gate rc_node_clear(&tx->re_node, 0); 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate entity_release(ep); 13817c478bd9Sstevel@tonic-gate entity_release(tx); 13827c478bd9Sstevel@tonic-gate return (result); 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13867c478bd9Sstevel@tonic-gate static void 13877c478bd9Sstevel@tonic-gate tx_commit(repcache_client_t *cp, const void *in, size_t insz, 13887c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 13897c478bd9Sstevel@tonic-gate { 13907c478bd9Sstevel@tonic-gate struct rep_protocol_response *out = out_arg; 13917c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_commit *rpr = in; 13927c478bd9Sstevel@tonic-gate repcache_entity_t *tx; 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 13957c478bd9Sstevel@tonic-gate assert(insz >= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE); 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate if (rpr->rpr_size != insz) { 13987c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_BAD_REQUEST; 13997c478bd9Sstevel@tonic-gate return; 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate tx = entity_find(cp, rpr->rpr_entityid); 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate if (tx == NULL) { 14057c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 14067c478bd9Sstevel@tonic-gate return; 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate switch (tx->re_txstate) { 14107c478bd9Sstevel@tonic-gate case REPCACHE_TX_INIT: 14117c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_MISORDERED; 14127c478bd9Sstevel@tonic-gate break; 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate case REPCACHE_TX_SETUP: 14157c478bd9Sstevel@tonic-gate out->rpr_response = rc_tx_commit(&tx->re_node, rpr->rpr_cmd, 14167c478bd9Sstevel@tonic-gate insz - REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE); 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate if (out->rpr_response == REP_PROTOCOL_SUCCESS) { 14197c478bd9Sstevel@tonic-gate tx->re_txstate = REPCACHE_TX_COMMITTED; 14207c478bd9Sstevel@tonic-gate rc_node_clear(&tx->re_node, 0); 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate break; 14247c478bd9Sstevel@tonic-gate case REPCACHE_TX_COMMITTED: 14257c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_SUCCESS; 14267c478bd9Sstevel@tonic-gate break; 14277c478bd9Sstevel@tonic-gate default: 14287c478bd9Sstevel@tonic-gate assert(0); /* CAN'T HAPPEN */ 14297c478bd9Sstevel@tonic-gate break; 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate entity_release(tx); 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 14367c478bd9Sstevel@tonic-gate next_snaplevel(repcache_client_t *cp, struct rep_protocol_entity_pair *rpr) 14377c478bd9Sstevel@tonic-gate { 14387c478bd9Sstevel@tonic-gate repcache_entity_t *src; 14397c478bd9Sstevel@tonic-gate repcache_entity_t *dest; 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entity_src; 14427c478bd9Sstevel@tonic-gate uint32_t destid = rpr->rpr_entity_dst; 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate int result; 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 14477c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 14487c478bd9Sstevel@tonic-gate return (result); 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate result = rc_node_next_snaplevel(&src->re_node, &dest->re_node); 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate entity_release(src); 14537c478bd9Sstevel@tonic-gate entity_release(dest); 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate return (result); 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 14597c478bd9Sstevel@tonic-gate snapshot_take(repcache_client_t *cp, struct rep_protocol_snapshot_take *rpr) 14607c478bd9Sstevel@tonic-gate { 14617c478bd9Sstevel@tonic-gate repcache_entity_t *src; 14627c478bd9Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 14637c478bd9Sstevel@tonic-gate repcache_entity_t *dest; 14647c478bd9Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 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 if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 14737c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 14747c478bd9Sstevel@tonic-gate } else { 14757c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate if (rpr->rpr_flags == REP_SNAPSHOT_NEW) 14787c478bd9Sstevel@tonic-gate result = rc_snapshot_take_new(&src->re_node, NULL, 14797c478bd9Sstevel@tonic-gate NULL, rpr->rpr_name, &dest->re_node); 14807c478bd9Sstevel@tonic-gate else if (rpr->rpr_flags == REP_SNAPSHOT_ATTACH && 14817c478bd9Sstevel@tonic-gate rpr->rpr_name[0] == 0) 14827c478bd9Sstevel@tonic-gate result = rc_snapshot_take_attach(&src->re_node, 14837c478bd9Sstevel@tonic-gate &dest->re_node); 14847c478bd9Sstevel@tonic-gate else 14857c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate entity_release(src); 14887c478bd9Sstevel@tonic-gate entity_release(dest); 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate return (result); 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 14947c478bd9Sstevel@tonic-gate snapshot_take_named(repcache_client_t *cp, 14957c478bd9Sstevel@tonic-gate struct rep_protocol_snapshot_take_named *rpr) 14967c478bd9Sstevel@tonic-gate { 14977c478bd9Sstevel@tonic-gate repcache_entity_t *src; 14987c478bd9Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 14997c478bd9Sstevel@tonic-gate repcache_entity_t *dest; 15007c478bd9Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate int result; 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 15057c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 15067c478bd9Sstevel@tonic-gate return (result); 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 15097c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 15107c478bd9Sstevel@tonic-gate } else { 15117c478bd9Sstevel@tonic-gate rpr->rpr_svcname[sizeof (rpr->rpr_svcname) - 1] = 0; 15127c478bd9Sstevel@tonic-gate rpr->rpr_instname[sizeof (rpr->rpr_instname) - 1] = 0; 15137c478bd9Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate result = rc_snapshot_take_new(&src->re_node, rpr->rpr_svcname, 15167c478bd9Sstevel@tonic-gate rpr->rpr_instname, rpr->rpr_name, &dest->re_node); 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate entity_release(src); 15197c478bd9Sstevel@tonic-gate entity_release(dest); 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate return (result); 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 15257c478bd9Sstevel@tonic-gate snapshot_attach(repcache_client_t *cp, struct rep_protocol_snapshot_attach *rpr) 15267c478bd9Sstevel@tonic-gate { 15277c478bd9Sstevel@tonic-gate repcache_entity_t *src; 15287c478bd9Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 15297c478bd9Sstevel@tonic-gate repcache_entity_t *dest; 15307c478bd9Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate int result; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 15357c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 15367c478bd9Sstevel@tonic-gate return (result); 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate result = rc_snapshot_attach(&src->re_node, &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 /*ARGSUSED*/ 15477c478bd9Sstevel@tonic-gate static void 15487c478bd9Sstevel@tonic-gate property_get_type(repcache_client_t *cp, const void *in, size_t insz, 15497c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 15507c478bd9Sstevel@tonic-gate { 15517c478bd9Sstevel@tonic-gate const struct rep_protocol_property_request *rpr = in; 15527c478bd9Sstevel@tonic-gate struct rep_protocol_integer_response *out = out_arg; 15537c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 15547c478bd9Sstevel@tonic-gate rep_protocol_value_type_t t = 0; 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate if (ep == NULL) { 15617c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 15627c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 15637c478bd9Sstevel@tonic-gate return; 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate out->rpr_response = rc_node_get_property_type(&ep->re_node, &t); 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate entity_release(ep); 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 15717c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 15727c478bd9Sstevel@tonic-gate else 15737c478bd9Sstevel@tonic-gate out->rpr_value = t; 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate /* 15777c478bd9Sstevel@tonic-gate * Fails with: 15787c478bd9Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 15797c478bd9Sstevel@tonic-gate * _NOT_SET - The property is not set 15807c478bd9Sstevel@tonic-gate * _DELETED - The property has been deleted 15817c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - The object is not a property 15827c478bd9Sstevel@tonic-gate * _NOT_FOUND - The property has no values. 15837c478bd9Sstevel@tonic-gate * 15847c478bd9Sstevel@tonic-gate * Succeeds with: 15857c478bd9Sstevel@tonic-gate * _SUCCESS - The property has 1 value. 15867c478bd9Sstevel@tonic-gate * _TRUNCATED - The property has >1 value. 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15897c478bd9Sstevel@tonic-gate static void 15907c478bd9Sstevel@tonic-gate property_get_value(repcache_client_t *cp, const void *in, size_t insz, 15917c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 15927c478bd9Sstevel@tonic-gate { 15937c478bd9Sstevel@tonic-gate const struct rep_protocol_property_request *rpr = in; 15947c478bd9Sstevel@tonic-gate struct rep_protocol_value_response *out = out_arg; 15957c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 16007c478bd9Sstevel@tonic-gate if (ep == NULL) { 16017c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 16027c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 16037c478bd9Sstevel@tonic-gate return; 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate out->rpr_response = rc_node_get_property_value(&ep->re_node, out, 16077c478bd9Sstevel@tonic-gate outsz); 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate entity_release(ep); 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * If we fail, we only return the response code. 16137c478bd9Sstevel@tonic-gate * If we succeed, rc_node_get_property_value has shortened *outsz 16147c478bd9Sstevel@tonic-gate * to only include the value bytes needed. 16157c478bd9Sstevel@tonic-gate */ 16167c478bd9Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS && 16177c478bd9Sstevel@tonic-gate out->rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) 16187c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 16227c478bd9Sstevel@tonic-gate propertygrp_notify(repcache_client_t *cp, 16237c478bd9Sstevel@tonic-gate struct rep_protocol_propertygrp_request *rpr, int *out_fd) 16247c478bd9Sstevel@tonic-gate { 16257c478bd9Sstevel@tonic-gate int fds[2]; 16267c478bd9Sstevel@tonic-gate int ours, theirs; 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 16297c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate if (pipe(fds) < 0) 16327c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate ours = fds[0]; 16357c478bd9Sstevel@tonic-gate theirs = fds[1]; 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) == NULL) { 16387c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 16397c478bd9Sstevel@tonic-gate goto fail; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate /* 16437c478bd9Sstevel@tonic-gate * While the following can race with other threads setting up a 16447c478bd9Sstevel@tonic-gate * notification, the worst that can happen is that our fd has 16457c478bd9Sstevel@tonic-gate * already been closed before we return. 16467c478bd9Sstevel@tonic-gate */ 16477c478bd9Sstevel@tonic-gate result = rc_pg_notify_setup(&cp->rc_pg_notify, &ep->re_node, 16487c478bd9Sstevel@tonic-gate ours); 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate entity_release(ep); 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 16537c478bd9Sstevel@tonic-gate goto fail; 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate *out_fd = theirs; 16567c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate fail: 16597c478bd9Sstevel@tonic-gate (void) close(ours); 16607c478bd9Sstevel@tonic-gate (void) close(theirs); 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate return (result); 16637c478bd9Sstevel@tonic-gate } 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 16667c478bd9Sstevel@tonic-gate client_add_notify(repcache_client_t *cp, 16677c478bd9Sstevel@tonic-gate struct rep_protocol_notify_request *rpr) 16687c478bd9Sstevel@tonic-gate { 16697c478bd9Sstevel@tonic-gate rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0; 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate switch (rpr->rpr_type) { 16727c478bd9Sstevel@tonic-gate case REP_PROTOCOL_NOTIFY_PGNAME: 16737c478bd9Sstevel@tonic-gate return (rc_notify_info_add_name(&cp->rc_notify_info, 16747c478bd9Sstevel@tonic-gate rpr->rpr_pattern)); 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate case REP_PROTOCOL_NOTIFY_PGTYPE: 16777c478bd9Sstevel@tonic-gate return (rc_notify_info_add_type(&cp->rc_notify_info, 16787c478bd9Sstevel@tonic-gate rpr->rpr_pattern)); 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate default: 16817c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16867c478bd9Sstevel@tonic-gate static void 16877c478bd9Sstevel@tonic-gate client_wait(repcache_client_t *cp, const void *in, size_t insz, 16887c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 16897c478bd9Sstevel@tonic-gate { 16907c478bd9Sstevel@tonic-gate int result; 16917c478bd9Sstevel@tonic-gate repcache_entity_t *ep; 16927c478bd9Sstevel@tonic-gate const struct rep_protocol_wait_request *rpr = in; 16937c478bd9Sstevel@tonic-gate struct rep_protocol_fmri_response *out = out_arg; 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 16987c478bd9Sstevel@tonic-gate if (cp->rc_notify_thr != 0) { 16997c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17007c478bd9Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_EXISTS; 17017c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 17027c478bd9Sstevel@tonic-gate return; 17037c478bd9Sstevel@tonic-gate } 17047c478bd9Sstevel@tonic-gate cp->rc_notify_thr = pthread_self(); 17057c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate result = rc_notify_info_wait(&cp->rc_notify_info, &cp->rc_notify_ptr, 17087c478bd9Sstevel@tonic-gate out->rpr_fmri, sizeof (out->rpr_fmri)); 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) { 17117c478bd9Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) { 17127c478bd9Sstevel@tonic-gate if (ep->re_type == REP_PROTOCOL_ENTITY_PROPERTYGRP) { 17137c478bd9Sstevel@tonic-gate rc_node_ptr_assign(&ep->re_node, 17147c478bd9Sstevel@tonic-gate &cp->rc_notify_ptr); 17157c478bd9Sstevel@tonic-gate } else { 17167c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 17177c478bd9Sstevel@tonic-gate } 17187c478bd9Sstevel@tonic-gate entity_release(ep); 17197c478bd9Sstevel@tonic-gate } else { 17207c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate rc_node_clear(&cp->rc_notify_ptr, 0); 17237c478bd9Sstevel@tonic-gate } 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 17267c478bd9Sstevel@tonic-gate assert(cp->rc_notify_thr == pthread_self()); 17277c478bd9Sstevel@tonic-gate cp->rc_notify_thr = 0; 17287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate out->rpr_response = result; 17317c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 17327c478bd9Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate /* 17367c478bd9Sstevel@tonic-gate * Can return: 17377c478bd9Sstevel@tonic-gate * _PERMISSION_DENIED not enough privileges to do request. 17387c478bd9Sstevel@tonic-gate * _BAD_REQUEST name is not valid or reserved 17397c478bd9Sstevel@tonic-gate * _TRUNCATED name is too long for current repository path 17407c478bd9Sstevel@tonic-gate * _UNKNOWN failed for unknown reason (details written to 17417c478bd9Sstevel@tonic-gate * console) 17427c478bd9Sstevel@tonic-gate * _BACKEND_READONLY backend is not writable 17437c478bd9Sstevel@tonic-gate * 17447c478bd9Sstevel@tonic-gate * _SUCCESS Backup completed successfully. 17457c478bd9Sstevel@tonic-gate */ 17467c478bd9Sstevel@tonic-gate static rep_protocol_responseid_t 17477c478bd9Sstevel@tonic-gate backup_repository(repcache_client_t *cp, 17487c478bd9Sstevel@tonic-gate struct rep_protocol_backup_request *rpr) 17497c478bd9Sstevel@tonic-gate { 17507c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 17517c478bd9Sstevel@tonic-gate ucred_t *uc = get_ucred(); 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate if (!client_is_privileged() && (uc == NULL || ucred_geteuid(uc) != 0)) 17547c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate rpr->rpr_name[REP_PROTOCOL_NAME_LEN - 1] = 0; 17577c478bd9Sstevel@tonic-gate if (strcmp(rpr->rpr_name, REPOSITORY_BOOT_BACKUP) == 0) 17587c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 17617c478bd9Sstevel@tonic-gate if (rpr->rpr_changeid != cp->rc_changeid) { 17627c478bd9Sstevel@tonic-gate result = backend_create_backup(rpr->rpr_name); 17637c478bd9Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 17647c478bd9Sstevel@tonic-gate cp->rc_changeid = rpr->rpr_changeid; 17657c478bd9Sstevel@tonic-gate } else { 17667c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate return (result); 17717c478bd9Sstevel@tonic-gate } 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_f(repcache_client_t *cp, 17757c478bd9Sstevel@tonic-gate const void *rpr); 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17787c478bd9Sstevel@tonic-gate static void 17797c478bd9Sstevel@tonic-gate simple_handler(repcache_client_t *cp, const void *in, size_t insz, 17807c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 17817c478bd9Sstevel@tonic-gate { 17827c478bd9Sstevel@tonic-gate protocol_simple_f *f = (protocol_simple_f *)arg; 17837c478bd9Sstevel@tonic-gate rep_protocol_response_t *out = out_arg; 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 17867c478bd9Sstevel@tonic-gate assert(f != NULL); 17877c478bd9Sstevel@tonic-gate 17887c478bd9Sstevel@tonic-gate out->rpr_response = (*f)(cp, in); 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_fd_f(repcache_client_t *cp, 17927c478bd9Sstevel@tonic-gate const void *rpr, int *out_fd); 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17957c478bd9Sstevel@tonic-gate static void 17967c478bd9Sstevel@tonic-gate simple_fd_handler(repcache_client_t *cp, const void *in, size_t insz, 17977c478bd9Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg, int *out_fd) 17987c478bd9Sstevel@tonic-gate { 17997c478bd9Sstevel@tonic-gate protocol_simple_fd_f *f = (protocol_simple_fd_f *)arg; 18007c478bd9Sstevel@tonic-gate rep_protocol_response_t *out = out_arg; 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 18037c478bd9Sstevel@tonic-gate assert(f != NULL); 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate out->rpr_response = (*f)(cp, in, out_fd); 18067c478bd9Sstevel@tonic-gate } 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate typedef void protocol_handler_f(repcache_client_t *, const void *in, 18097c478bd9Sstevel@tonic-gate size_t insz, void *out, size_t *outsz, void *arg); 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate typedef void protocol_handler_fdret_f(repcache_client_t *, const void *in, 18127c478bd9Sstevel@tonic-gate size_t insz, void *out, size_t *outsz, void *arg, int *fd_out); 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate #define PROTO(p, f, in) { \ 18157c478bd9Sstevel@tonic-gate p, #p, simple_handler, (void *)(&f), NULL, \ 18167c478bd9Sstevel@tonic-gate sizeof (in), sizeof (rep_protocol_response_t), 0 \ 18177c478bd9Sstevel@tonic-gate } 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate #define PROTO_FD_OUT(p, f, in) { \ 18207c478bd9Sstevel@tonic-gate p, #p, NULL, (void *)(&f), simple_fd_handler, \ 18217c478bd9Sstevel@tonic-gate sizeof (in), \ 18227c478bd9Sstevel@tonic-gate sizeof (rep_protocol_response_t), \ 18237c478bd9Sstevel@tonic-gate PROTO_FLAG_RETFD \ 18247c478bd9Sstevel@tonic-gate } 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate #define PROTO_VARIN(p, f, insz) { \ 18277c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 18287c478bd9Sstevel@tonic-gate insz, sizeof (rep_protocol_response_t), \ 18297c478bd9Sstevel@tonic-gate PROTO_FLAG_VARINPUT \ 18307c478bd9Sstevel@tonic-gate } 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate #define PROTO_UINT_OUT(p, f, in) { \ 18337c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 18347c478bd9Sstevel@tonic-gate sizeof (in), \ 18357c478bd9Sstevel@tonic-gate sizeof (struct rep_protocol_integer_response), 0 \ 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate #define PROTO_NAME_OUT(p, f, in) { \ 18397c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 18407c478bd9Sstevel@tonic-gate sizeof (in), \ 18417c478bd9Sstevel@tonic-gate sizeof (struct rep_protocol_name_response), 0 \ 18427c478bd9Sstevel@tonic-gate } 18437c478bd9Sstevel@tonic-gate 18447c478bd9Sstevel@tonic-gate #define PROTO_FMRI_OUT(p, f, in) { \ 18457c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 18467c478bd9Sstevel@tonic-gate sizeof (in), \ 18477c478bd9Sstevel@tonic-gate sizeof (struct rep_protocol_fmri_response), 0 \ 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate #define PROTO_VALUE_OUT(p, f, in) { \ 18517c478bd9Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 18527c478bd9Sstevel@tonic-gate sizeof (in), \ 18537c478bd9Sstevel@tonic-gate sizeof (struct rep_protocol_value_response), 0 \ 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate #define PROTO_PANIC(p) { p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC } 18577c478bd9Sstevel@tonic-gate #define PROTO_END() { 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC } 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate #define PROTO_FLAG_PANIC 0x00000001 /* should never be called */ 18607c478bd9Sstevel@tonic-gate #define PROTO_FLAG_VARINPUT 0x00000004 /* in_size is minimum size */ 18617c478bd9Sstevel@tonic-gate #define PROTO_FLAG_RETFD 0x00000008 /* can also return an FD */ 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate #define PROTO_ALL_FLAGS 0x0000000f /* all flags */ 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate static struct protocol_entry { 18667c478bd9Sstevel@tonic-gate enum rep_protocol_requestid pt_request; 18677c478bd9Sstevel@tonic-gate const char *pt_name; 18687c478bd9Sstevel@tonic-gate protocol_handler_f *pt_handler; 18697c478bd9Sstevel@tonic-gate void *pt_arg; 18707c478bd9Sstevel@tonic-gate protocol_handler_fdret_f *pt_fd_handler; 18717c478bd9Sstevel@tonic-gate size_t pt_in_size; 18727c478bd9Sstevel@tonic-gate size_t pt_out_max; 18737c478bd9Sstevel@tonic-gate uint32_t pt_flags; 18747c478bd9Sstevel@tonic-gate } protocol_table[] = { 18757c478bd9Sstevel@tonic-gate PROTO_PANIC(REP_PROTOCOL_CLOSE), /* special case */ 18767c478bd9Sstevel@tonic-gate 18777c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_SETUP, entity_setup, 18787c478bd9Sstevel@tonic-gate struct rep_protocol_entity_setup), 18797c478bd9Sstevel@tonic-gate PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME, entity_name, 18807c478bd9Sstevel@tonic-gate struct rep_protocol_entity_name), 18817c478bd9Sstevel@tonic-gate PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE, entity_parent_type, 18827c478bd9Sstevel@tonic-gate struct rep_protocol_entity_parent_type), 18837c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET_CHILD, entity_get_child, 18847c478bd9Sstevel@tonic-gate struct rep_protocol_entity_get_child), 18857c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET_PARENT, entity_get_parent, 18867c478bd9Sstevel@tonic-gate struct rep_protocol_entity_parent), 18877c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET, entity_get, 18887c478bd9Sstevel@tonic-gate struct rep_protocol_entity_get), 18897c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_UPDATE, entity_update, 18907c478bd9Sstevel@tonic-gate struct rep_protocol_entity_update), 18917c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD, entity_create_child, 18927c478bd9Sstevel@tonic-gate struct rep_protocol_entity_create_child), 18937c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_CREATE_PG, entity_create_pg, 18947c478bd9Sstevel@tonic-gate struct rep_protocol_entity_create_pg), 18957c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_DELETE, entity_delete, 18967c478bd9Sstevel@tonic-gate struct rep_protocol_entity_delete), 18977c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_RESET, entity_reset, 18987c478bd9Sstevel@tonic-gate struct rep_protocol_entity_reset), 18997c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_TEARDOWN, entity_teardown, 19007c478bd9Sstevel@tonic-gate struct rep_protocol_entity_teardown), 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_SETUP, iter_setup, 19037c478bd9Sstevel@tonic-gate struct rep_protocol_iter_request), 19047c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_START, iter_start, 19057c478bd9Sstevel@tonic-gate struct rep_protocol_iter_start), 19067c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_READ, iter_read, 19077c478bd9Sstevel@tonic-gate struct rep_protocol_iter_read), 19087c478bd9Sstevel@tonic-gate PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE, iter_read_value, 19097c478bd9Sstevel@tonic-gate struct rep_protocol_iter_read_value), 19107c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_RESET, iter_reset, 19117c478bd9Sstevel@tonic-gate struct rep_protocol_iter_request), 19127c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_TEARDOWN, iter_teardown, 19137c478bd9Sstevel@tonic-gate struct rep_protocol_iter_request), 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL, next_snaplevel, 19167c478bd9Sstevel@tonic-gate struct rep_protocol_entity_pair), 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_TAKE, snapshot_take, 19197c478bd9Sstevel@tonic-gate struct rep_protocol_snapshot_take), 19207c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED, snapshot_take_named, 19217c478bd9Sstevel@tonic-gate struct rep_protocol_snapshot_take_named), 19227c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH, snapshot_attach, 19237c478bd9Sstevel@tonic-gate struct rep_protocol_snapshot_attach), 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE, property_get_type, 19267c478bd9Sstevel@tonic-gate struct rep_protocol_property_request), 19277c478bd9Sstevel@tonic-gate PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE, property_get_value, 19287c478bd9Sstevel@tonic-gate struct rep_protocol_property_request), 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT, propertygrp_notify, 19317c478bd9Sstevel@tonic-gate struct rep_protocol_propertygrp_request), 19327c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START, tx_start, 19337c478bd9Sstevel@tonic-gate struct rep_protocol_transaction_start), 19347c478bd9Sstevel@tonic-gate PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT, tx_commit, 19357c478bd9Sstevel@tonic-gate REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE), 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY, client_add_notify, 19387c478bd9Sstevel@tonic-gate struct rep_protocol_notify_request), 19397c478bd9Sstevel@tonic-gate PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT, client_wait, 19407c478bd9Sstevel@tonic-gate struct rep_protocol_wait_request), 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate PROTO(REP_PROTOCOL_BACKUP, backup_repository, 19437c478bd9Sstevel@tonic-gate struct rep_protocol_backup_request), 19447c478bd9Sstevel@tonic-gate 19457c478bd9Sstevel@tonic-gate PROTO_END() 19467c478bd9Sstevel@tonic-gate }; 19477c478bd9Sstevel@tonic-gate #undef PROTO 19487c478bd9Sstevel@tonic-gate #undef PROTO_FMRI_OUT 19497c478bd9Sstevel@tonic-gate #undef PROTO_NAME_OUT 19507c478bd9Sstevel@tonic-gate #undef PROTO_UINT_OUT 19517c478bd9Sstevel@tonic-gate #undef PROTO_PANIC 19527c478bd9Sstevel@tonic-gate #undef PROTO_END 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate /* 19557c478bd9Sstevel@tonic-gate * The number of entries, sans PROTO_END() 19567c478bd9Sstevel@tonic-gate */ 19577c478bd9Sstevel@tonic-gate #define PROTOCOL_ENTRIES \ 19587c478bd9Sstevel@tonic-gate (sizeof (protocol_table) / sizeof (*protocol_table) - 1) 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate #define PROTOCOL_PREFIX "REP_PROTOCOL_" 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate int 19637c478bd9Sstevel@tonic-gate client_init(void) 19647c478bd9Sstevel@tonic-gate { 19657c478bd9Sstevel@tonic-gate int i; 19667c478bd9Sstevel@tonic-gate struct protocol_entry *e; 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate if (!client_hash_init()) 19697c478bd9Sstevel@tonic-gate return (0); 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate if (request_log_size > 0) { 19727c478bd9Sstevel@tonic-gate request_log = uu_zalloc(request_log_size * 19737c478bd9Sstevel@tonic-gate sizeof (request_log_entry_t)); 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate /* 19777c478bd9Sstevel@tonic-gate * update the names to not include REP_PROTOCOL_ 19787c478bd9Sstevel@tonic-gate */ 19797c478bd9Sstevel@tonic-gate for (i = 0; i < PROTOCOL_ENTRIES; i++) { 19807c478bd9Sstevel@tonic-gate e = &protocol_table[i]; 19817c478bd9Sstevel@tonic-gate assert(strncmp(e->pt_name, PROTOCOL_PREFIX, 19827c478bd9Sstevel@tonic-gate strlen(PROTOCOL_PREFIX)) == 0); 19837c478bd9Sstevel@tonic-gate e->pt_name += strlen(PROTOCOL_PREFIX); 19847c478bd9Sstevel@tonic-gate } 19857c478bd9Sstevel@tonic-gate /* 19867c478bd9Sstevel@tonic-gate * verify the protocol table is consistent 19877c478bd9Sstevel@tonic-gate */ 19887c478bd9Sstevel@tonic-gate for (i = 0; i < PROTOCOL_ENTRIES; i++) { 19897c478bd9Sstevel@tonic-gate e = &protocol_table[i]; 19907c478bd9Sstevel@tonic-gate assert(e->pt_request == (REP_PROTOCOL_BASE + i)); 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate assert((e->pt_flags & ~PROTO_ALL_FLAGS) == 0); 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_PANIC) 19957c478bd9Sstevel@tonic-gate assert(e->pt_in_size == 0 && e->pt_out_max == 0 && 19967c478bd9Sstevel@tonic-gate e->pt_handler == NULL); 19977c478bd9Sstevel@tonic-gate else 19987c478bd9Sstevel@tonic-gate assert(e->pt_in_size != 0 && e->pt_out_max != 0 && 19997c478bd9Sstevel@tonic-gate (e->pt_handler != NULL || 20007c478bd9Sstevel@tonic-gate e->pt_fd_handler != NULL)); 20017c478bd9Sstevel@tonic-gate } 20027c478bd9Sstevel@tonic-gate assert((REP_PROTOCOL_BASE + i) == REP_PROTOCOL_MAX_REQUEST); 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate assert(protocol_table[i].pt_request == 0); 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate return (1); 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate static void 20107c478bd9Sstevel@tonic-gate client_switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *desc_in, 20117c478bd9Sstevel@tonic-gate uint_t n_desc) 20127c478bd9Sstevel@tonic-gate { 20137c478bd9Sstevel@tonic-gate thread_info_t *ti = thread_self(); 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate repcache_client_t *cp; 20167c478bd9Sstevel@tonic-gate uint32_t id = (uint32_t)cookie; 20177c478bd9Sstevel@tonic-gate enum rep_protocol_requestid request_code; 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result = INVALID_RESULT; 20207c478bd9Sstevel@tonic-gate 20217c478bd9Sstevel@tonic-gate struct protocol_entry *e; 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate char *retval = NULL; 20247c478bd9Sstevel@tonic-gate size_t retsize = 0; 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate int retfd = -1; 20277c478bd9Sstevel@tonic-gate door_desc_t desc; 20287c478bd9Sstevel@tonic-gate request_log_entry_t *rlp; 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate rlp = start_log(id); 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate if (n_desc != 0) 20337c478bd9Sstevel@tonic-gate uu_die("can't happen: %d descriptors @%p (cookie %p)", 20347c478bd9Sstevel@tonic-gate n_desc, desc_in, cookie); 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate if (argp == DOOR_UNREF_DATA) { 20377c478bd9Sstevel@tonic-gate client_destroy(id); 20387c478bd9Sstevel@tonic-gate goto bad_end; 20397c478bd9Sstevel@tonic-gate } 20407c478bd9Sstevel@tonic-gate 20417c478bd9Sstevel@tonic-gate thread_newstate(ti, TI_CLIENT_CALL); 20427c478bd9Sstevel@tonic-gate 20437c478bd9Sstevel@tonic-gate /* 20447c478bd9Sstevel@tonic-gate * To simplify returning just a result code, we set up for 20457c478bd9Sstevel@tonic-gate * that case here. 20467c478bd9Sstevel@tonic-gate */ 20477c478bd9Sstevel@tonic-gate retval = (char *)&result; 20487c478bd9Sstevel@tonic-gate retsize = sizeof (result); 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate if (arg_size < sizeof (request_code)) { 20517c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 20527c478bd9Sstevel@tonic-gate goto end_unheld; 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate ti->ti_client_request = (void *)argp; 20567c478bd9Sstevel@tonic-gate 20577c478bd9Sstevel@tonic-gate /* LINTED alignment */ 20587c478bd9Sstevel@tonic-gate request_code = *(uint32_t *)argp; 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate if (rlp != NULL) { 20617c478bd9Sstevel@tonic-gate rlp->rl_request = request_code; 20627c478bd9Sstevel@tonic-gate } 20637c478bd9Sstevel@tonic-gate /* 20647c478bd9Sstevel@tonic-gate * In order to avoid locking problems on removal, we handle the 20657c478bd9Sstevel@tonic-gate * "close" case before doing a lookup. 20667c478bd9Sstevel@tonic-gate */ 20677c478bd9Sstevel@tonic-gate if (request_code == REP_PROTOCOL_CLOSE) { 20687c478bd9Sstevel@tonic-gate client_destroy(id); 20697c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 20707c478bd9Sstevel@tonic-gate goto end_unheld; 20717c478bd9Sstevel@tonic-gate } 20727c478bd9Sstevel@tonic-gate 20737c478bd9Sstevel@tonic-gate cp = client_lookup(id); 20747c478bd9Sstevel@tonic-gate /* 20757c478bd9Sstevel@tonic-gate * cp is held 20767c478bd9Sstevel@tonic-gate */ 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate if (cp == NULL) 20797c478bd9Sstevel@tonic-gate goto bad_end; 20807c478bd9Sstevel@tonic-gate 20817c478bd9Sstevel@tonic-gate if (rlp != NULL) 20827c478bd9Sstevel@tonic-gate rlp->rl_client = cp; 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate ti->ti_active_client = cp; 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate if (request_code < REP_PROTOCOL_BASE || 20877c478bd9Sstevel@tonic-gate request_code >= REP_PROTOCOL_BASE + PROTOCOL_ENTRIES) { 20887c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 20897c478bd9Sstevel@tonic-gate goto end; 20907c478bd9Sstevel@tonic-gate } 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate e = &protocol_table[request_code - REP_PROTOCOL_BASE]; 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate assert(!(e->pt_flags & PROTO_FLAG_PANIC)); 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_VARINPUT) { 20977c478bd9Sstevel@tonic-gate if (arg_size < e->pt_in_size) { 20987c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 20997c478bd9Sstevel@tonic-gate goto end; 21007c478bd9Sstevel@tonic-gate } 21017c478bd9Sstevel@tonic-gate } else if (arg_size != e->pt_in_size) { 21027c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 21037c478bd9Sstevel@tonic-gate goto end; 21047c478bd9Sstevel@tonic-gate } 21057c478bd9Sstevel@tonic-gate 21067c478bd9Sstevel@tonic-gate if (retsize != e->pt_out_max) { 21077c478bd9Sstevel@tonic-gate retsize = e->pt_out_max; 21087c478bd9Sstevel@tonic-gate retval = alloca(retsize); 21097c478bd9Sstevel@tonic-gate } 21107c478bd9Sstevel@tonic-gate 21117c478bd9Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_RETFD) 21127c478bd9Sstevel@tonic-gate e->pt_fd_handler(cp, argp, arg_size, retval, &retsize, 21137c478bd9Sstevel@tonic-gate e->pt_arg, &retfd); 21147c478bd9Sstevel@tonic-gate else 21157c478bd9Sstevel@tonic-gate e->pt_handler(cp, argp, arg_size, retval, &retsize, e->pt_arg); 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate end: 21187c478bd9Sstevel@tonic-gate ti->ti_active_client = NULL; 21197c478bd9Sstevel@tonic-gate client_release(cp); 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate end_unheld: 21227c478bd9Sstevel@tonic-gate if (rlp != NULL) { 21237c478bd9Sstevel@tonic-gate /* LINTED alignment */ 21247c478bd9Sstevel@tonic-gate rlp->rl_response = *(uint32_t *)retval; 21257c478bd9Sstevel@tonic-gate end_log(); 21267c478bd9Sstevel@tonic-gate rlp = NULL; 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate ti->ti_client_request = NULL; 21297c478bd9Sstevel@tonic-gate thread_newstate(ti, TI_DOOR_RETURN); 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate if (retval == (char *)&result) { 21327c478bd9Sstevel@tonic-gate assert(result != INVALID_RESULT && retsize == sizeof (result)); 21337c478bd9Sstevel@tonic-gate } else { 21347c478bd9Sstevel@tonic-gate /* LINTED alignment */ 21357c478bd9Sstevel@tonic-gate result = *(uint32_t *)retval; 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate if (retfd != -1) { 21387c478bd9Sstevel@tonic-gate desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE; 21397c478bd9Sstevel@tonic-gate desc.d_data.d_desc.d_descriptor = retfd; 21407c478bd9Sstevel@tonic-gate (void) door_return(retval, retsize, &desc, 1); 21417c478bd9Sstevel@tonic-gate } else { 21427c478bd9Sstevel@tonic-gate (void) door_return(retval, retsize, NULL, 0); 21437c478bd9Sstevel@tonic-gate } 21447c478bd9Sstevel@tonic-gate bad_end: 21457c478bd9Sstevel@tonic-gate if (rlp != NULL) { 21467c478bd9Sstevel@tonic-gate rlp->rl_response = -1; 21477c478bd9Sstevel@tonic-gate end_log(); 21487c478bd9Sstevel@tonic-gate rlp = NULL; 21497c478bd9Sstevel@tonic-gate } 21507c478bd9Sstevel@tonic-gate (void) door_return(NULL, 0, NULL, 0); 21517c478bd9Sstevel@tonic-gate } 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate int 21547c478bd9Sstevel@tonic-gate create_client(pid_t pid, uint32_t debugflags, int privileged, int *out_fd) 21557c478bd9Sstevel@tonic-gate { 21567c478bd9Sstevel@tonic-gate int fd; 21577c478bd9Sstevel@tonic-gate 21587c478bd9Sstevel@tonic-gate repcache_client_t *cp; 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate struct door_info info; 21617c478bd9Sstevel@tonic-gate 21627c478bd9Sstevel@tonic-gate int door_flags = DOOR_UNREF | DOOR_REFUSE_DESC; 21637c478bd9Sstevel@tonic-gate #ifdef DOOR_NO_CANCEL 21647c478bd9Sstevel@tonic-gate door_flags |= DOOR_NO_CANCEL; 21657c478bd9Sstevel@tonic-gate #endif 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate cp = client_alloc(); 21687c478bd9Sstevel@tonic-gate if (cp == NULL) 21697c478bd9Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&client_lock); 21727c478bd9Sstevel@tonic-gate cp->rc_id = ++client_maxid; 21737c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&client_lock); 21747c478bd9Sstevel@tonic-gate 21757c478bd9Sstevel@tonic-gate cp->rc_all_auths = privileged; 21767c478bd9Sstevel@tonic-gate cp->rc_pid = pid; 21777c478bd9Sstevel@tonic-gate cp->rc_debug = debugflags; 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate cp->rc_doorfd = door_create(client_switcher, (void *)cp->rc_id, 21807c478bd9Sstevel@tonic-gate door_flags); 21817c478bd9Sstevel@tonic-gate 21827c478bd9Sstevel@tonic-gate if (cp->rc_doorfd < 0) { 21837c478bd9Sstevel@tonic-gate client_free(cp); 21847c478bd9Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate #ifdef DOOR_PARAM_DATA_MIN 21877c478bd9Sstevel@tonic-gate (void) door_setparam(cp->rc_doorfd, DOOR_PARAM_DATA_MIN, 21887c478bd9Sstevel@tonic-gate sizeof (enum rep_protocol_requestid)); 21897c478bd9Sstevel@tonic-gate #endif 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate if ((fd = dup(cp->rc_doorfd)) < 0 || 21927c478bd9Sstevel@tonic-gate door_info(cp->rc_doorfd, &info) < 0) { 21937c478bd9Sstevel@tonic-gate if (fd >= 0) 21947c478bd9Sstevel@tonic-gate (void) close(fd); 21957c478bd9Sstevel@tonic-gate (void) door_revoke(cp->rc_doorfd); 21967c478bd9Sstevel@tonic-gate cp->rc_doorfd = -1; 21977c478bd9Sstevel@tonic-gate client_free(cp); 21987c478bd9Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 21997c478bd9Sstevel@tonic-gate } 22007c478bd9Sstevel@tonic-gate 22017c478bd9Sstevel@tonic-gate rc_pg_notify_init(&cp->rc_pg_notify); 22027c478bd9Sstevel@tonic-gate rc_notify_info_init(&cp->rc_notify_info); 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate client_insert(cp); 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate cp->rc_doorid = info.di_uniquifier; 22077c478bd9Sstevel@tonic-gate *out_fd = fd; 22087c478bd9Sstevel@tonic-gate 22097c478bd9Sstevel@tonic-gate return (REPOSITORY_DOOR_SUCCESS); 22107c478bd9Sstevel@tonic-gate } 2211