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