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