1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * This is the client layer for svc.configd. All direct protocol interactions 31*0Sstevel@tonic-gate * are handled here. 32*0Sstevel@tonic-gate * 33*0Sstevel@tonic-gate * Essentially, the job of this layer is to turn the idempotent protocol 34*0Sstevel@tonic-gate * into a series of non-idempotent calls into the object layer, while 35*0Sstevel@tonic-gate * also handling the necessary locking. 36*0Sstevel@tonic-gate */ 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate #include <alloca.h> 39*0Sstevel@tonic-gate #include <assert.h> 40*0Sstevel@tonic-gate #include <door.h> 41*0Sstevel@tonic-gate #include <errno.h> 42*0Sstevel@tonic-gate #include <limits.h> 43*0Sstevel@tonic-gate #include <pthread.h> 44*0Sstevel@tonic-gate #include <stdio.h> 45*0Sstevel@tonic-gate #include <stdlib.h> 46*0Sstevel@tonic-gate #include <string.h> 47*0Sstevel@tonic-gate #include <unistd.h> 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate #include <libuutil.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #include "configd.h" 52*0Sstevel@tonic-gate #include "repcache_protocol.h" 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate #define INVALID_CHANGEID (0) 55*0Sstevel@tonic-gate #define INVALID_DOORID ((door_id_t)-1) 56*0Sstevel@tonic-gate #define INVALID_RESULT ((rep_protocol_responseid_t)INT_MIN) 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate /* 59*0Sstevel@tonic-gate * lint doesn't like constant assertions 60*0Sstevel@tonic-gate */ 61*0Sstevel@tonic-gate #ifdef lint 62*0Sstevel@tonic-gate #define assert_nolint(x) (void)0 63*0Sstevel@tonic-gate #else 64*0Sstevel@tonic-gate #define assert_nolint(x) assert(x) 65*0Sstevel@tonic-gate #endif 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate /* 68*0Sstevel@tonic-gate * Protects client linkage and the freelist 69*0Sstevel@tonic-gate */ 70*0Sstevel@tonic-gate #define CLIENT_HASH_SIZE 64 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate #pragma align 64(client_hash) 73*0Sstevel@tonic-gate static client_bucket_t client_hash[CLIENT_HASH_SIZE]; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate static uu_list_pool_t *entity_pool; 76*0Sstevel@tonic-gate static uu_list_pool_t *iter_pool; 77*0Sstevel@tonic-gate static uu_list_pool_t *client_pool; 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate #define CLIENT_HASH(id) (&client_hash[((id) & (CLIENT_HASH_SIZE - 1))]) 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate uint_t request_log_size = 1024; /* tunable, before we start */ 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static pthread_mutex_t request_log_lock = PTHREAD_MUTEX_INITIALIZER; 84*0Sstevel@tonic-gate static uint_t request_log_cur; 85*0Sstevel@tonic-gate request_log_entry_t *request_log; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate static uint32_t client_maxid; 88*0Sstevel@tonic-gate static pthread_mutex_t client_lock; /* protects client_maxid */ 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate static request_log_entry_t * 91*0Sstevel@tonic-gate get_log(void) 92*0Sstevel@tonic-gate { 93*0Sstevel@tonic-gate thread_info_t *ti = thread_self(); 94*0Sstevel@tonic-gate return (&ti->ti_log); 95*0Sstevel@tonic-gate } 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate void 98*0Sstevel@tonic-gate log_enter(request_log_entry_t *rlp) 99*0Sstevel@tonic-gate { 100*0Sstevel@tonic-gate if (rlp->rl_start != 0 && request_log != NULL) { 101*0Sstevel@tonic-gate request_log_entry_t *logrlp; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate (void) pthread_mutex_lock(&request_log_lock); 104*0Sstevel@tonic-gate assert(request_log_cur < request_log_size); 105*0Sstevel@tonic-gate logrlp = &request_log[request_log_cur++]; 106*0Sstevel@tonic-gate if (request_log_cur == request_log_size) 107*0Sstevel@tonic-gate request_log_cur = 0; 108*0Sstevel@tonic-gate (void) memcpy(logrlp, rlp, sizeof (*rlp)); 109*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&request_log_lock); 110*0Sstevel@tonic-gate } 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* 114*0Sstevel@tonic-gate * Note that the svc.configd dmod will join all of the per-thread log entries 115*0Sstevel@tonic-gate * with the main log, so that even if the log is disabled, there is some 116*0Sstevel@tonic-gate * information available. 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate static request_log_entry_t * 119*0Sstevel@tonic-gate start_log(uint32_t clientid) 120*0Sstevel@tonic-gate { 121*0Sstevel@tonic-gate request_log_entry_t *rlp = get_log(); 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate log_enter(rlp); 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate (void) memset(rlp, 0, sizeof (*rlp)); 126*0Sstevel@tonic-gate rlp->rl_start = gethrtime(); 127*0Sstevel@tonic-gate rlp->rl_tid = pthread_self(); 128*0Sstevel@tonic-gate rlp->rl_clientid = clientid; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate return (rlp); 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate void 134*0Sstevel@tonic-gate end_log(void) 135*0Sstevel@tonic-gate { 136*0Sstevel@tonic-gate request_log_entry_t *rlp = get_log(); 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate rlp->rl_end = gethrtime(); 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate static void 142*0Sstevel@tonic-gate add_log_ptr(request_log_entry_t *rlp, enum rc_ptr_type type, uint32_t id, 143*0Sstevel@tonic-gate void *ptr) 144*0Sstevel@tonic-gate { 145*0Sstevel@tonic-gate request_log_ptr_t *rpp; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate if (rlp == NULL) 148*0Sstevel@tonic-gate return; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate if (rlp->rl_num_ptrs >= MAX_PTRS) 151*0Sstevel@tonic-gate return; 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate rpp = &rlp->rl_ptrs[rlp->rl_num_ptrs++]; 154*0Sstevel@tonic-gate rpp->rlp_type = type; 155*0Sstevel@tonic-gate rpp->rlp_id = id; 156*0Sstevel@tonic-gate rpp->rlp_ptr = ptr; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* 159*0Sstevel@tonic-gate * For entities, it's useful to have the node pointer at the start 160*0Sstevel@tonic-gate * of the request. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate if (type == RC_PTR_TYPE_ENTITY && ptr != NULL) 163*0Sstevel@tonic-gate rpp->rlp_data = ((repcache_entity_t *)ptr)->re_node.rnp_node; 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate int 167*0Sstevel@tonic-gate client_is_privileged(void) 168*0Sstevel@tonic-gate { 169*0Sstevel@tonic-gate thread_info_t *ti = thread_self(); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate ucred_t *uc; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate if (ti->ti_active_client != NULL && 174*0Sstevel@tonic-gate ti->ti_active_client->rc_all_auths) 175*0Sstevel@tonic-gate return (1); 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate if ((uc = get_ucred()) == NULL) 178*0Sstevel@tonic-gate return (0); 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate return (ucred_is_privileged(uc)); 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate /*ARGSUSED*/ 184*0Sstevel@tonic-gate static int 185*0Sstevel@tonic-gate client_compare(const void *lc_arg, const void *rc_arg, void *private) 186*0Sstevel@tonic-gate { 187*0Sstevel@tonic-gate uint32_t l_id = ((const repcache_client_t *)lc_arg)->rc_id; 188*0Sstevel@tonic-gate uint32_t r_id = ((const repcache_client_t *)rc_arg)->rc_id; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate if (l_id > r_id) 191*0Sstevel@tonic-gate return (1); 192*0Sstevel@tonic-gate if (l_id < r_id) 193*0Sstevel@tonic-gate return (-1); 194*0Sstevel@tonic-gate return (0); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /*ARGSUSED*/ 198*0Sstevel@tonic-gate static int 199*0Sstevel@tonic-gate entity_compare(const void *lc_arg, const void *rc_arg, void *private) 200*0Sstevel@tonic-gate { 201*0Sstevel@tonic-gate uint32_t l_id = ((const repcache_entity_t *)lc_arg)->re_id; 202*0Sstevel@tonic-gate uint32_t r_id = ((const repcache_entity_t *)rc_arg)->re_id; 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate if (l_id > r_id) 205*0Sstevel@tonic-gate return (1); 206*0Sstevel@tonic-gate if (l_id < r_id) 207*0Sstevel@tonic-gate return (-1); 208*0Sstevel@tonic-gate return (0); 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate /*ARGSUSED*/ 212*0Sstevel@tonic-gate static int 213*0Sstevel@tonic-gate iter_compare(const void *lc_arg, const void *rc_arg, void *private) 214*0Sstevel@tonic-gate { 215*0Sstevel@tonic-gate uint32_t l_id = ((const repcache_iter_t *)lc_arg)->ri_id; 216*0Sstevel@tonic-gate uint32_t r_id = ((const repcache_iter_t *)rc_arg)->ri_id; 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate if (l_id > r_id) 219*0Sstevel@tonic-gate return (1); 220*0Sstevel@tonic-gate if (l_id < r_id) 221*0Sstevel@tonic-gate return (-1); 222*0Sstevel@tonic-gate return (0); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate static int 226*0Sstevel@tonic-gate client_hash_init(void) 227*0Sstevel@tonic-gate { 228*0Sstevel@tonic-gate int x; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate assert_nolint(offsetof(repcache_entity_t, re_id) == 0); 231*0Sstevel@tonic-gate entity_pool = uu_list_pool_create("repcache_entitys", 232*0Sstevel@tonic-gate sizeof (repcache_entity_t), offsetof(repcache_entity_t, re_link), 233*0Sstevel@tonic-gate entity_compare, UU_LIST_POOL_DEBUG); 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate assert_nolint(offsetof(repcache_iter_t, ri_id) == 0); 236*0Sstevel@tonic-gate iter_pool = uu_list_pool_create("repcache_iters", 237*0Sstevel@tonic-gate sizeof (repcache_iter_t), offsetof(repcache_iter_t, ri_link), 238*0Sstevel@tonic-gate iter_compare, UU_LIST_POOL_DEBUG); 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate assert_nolint(offsetof(repcache_client_t, rc_id) == 0); 241*0Sstevel@tonic-gate client_pool = uu_list_pool_create("repcache_clients", 242*0Sstevel@tonic-gate sizeof (repcache_client_t), offsetof(repcache_client_t, rc_link), 243*0Sstevel@tonic-gate client_compare, UU_LIST_POOL_DEBUG); 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate if (entity_pool == NULL || iter_pool == NULL || client_pool == NULL) 246*0Sstevel@tonic-gate return (0); 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate for (x = 0; x < CLIENT_HASH_SIZE; x++) { 249*0Sstevel@tonic-gate uu_list_t *lp = uu_list_create(client_pool, &client_hash[x], 250*0Sstevel@tonic-gate UU_LIST_SORTED); 251*0Sstevel@tonic-gate if (lp == NULL) 252*0Sstevel@tonic-gate return (0); 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate (void) pthread_mutex_init(&client_hash[x].cb_lock, NULL); 255*0Sstevel@tonic-gate client_hash[x].cb_list = lp; 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate return (1); 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate static repcache_client_t * 262*0Sstevel@tonic-gate client_alloc(void) 263*0Sstevel@tonic-gate { 264*0Sstevel@tonic-gate repcache_client_t *cp; 265*0Sstevel@tonic-gate cp = uu_zalloc(sizeof (*cp)); 266*0Sstevel@tonic-gate if (cp == NULL) 267*0Sstevel@tonic-gate return (NULL); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate cp->rc_entity_list = uu_list_create(entity_pool, cp, UU_LIST_SORTED); 270*0Sstevel@tonic-gate if (cp->rc_entity_list == NULL) 271*0Sstevel@tonic-gate goto fail; 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate cp->rc_iter_list = uu_list_create(iter_pool, cp, UU_LIST_SORTED); 274*0Sstevel@tonic-gate if (cp->rc_iter_list == NULL) 275*0Sstevel@tonic-gate goto fail; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate uu_list_node_init(cp, &cp->rc_link, client_pool); 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate cp->rc_doorfd = -1; 280*0Sstevel@tonic-gate cp->rc_doorid = INVALID_DOORID; 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate (void) pthread_mutex_init(&cp->rc_lock, NULL); 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate rc_node_ptr_init(&cp->rc_notify_ptr); 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate return (cp); 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate fail: 289*0Sstevel@tonic-gate if (cp->rc_iter_list != NULL) 290*0Sstevel@tonic-gate uu_list_destroy(cp->rc_iter_list); 291*0Sstevel@tonic-gate if (cp->rc_entity_list != NULL) 292*0Sstevel@tonic-gate uu_list_destroy(cp->rc_entity_list); 293*0Sstevel@tonic-gate uu_free(cp); 294*0Sstevel@tonic-gate return (NULL); 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate static void 298*0Sstevel@tonic-gate client_free(repcache_client_t *cp) 299*0Sstevel@tonic-gate { 300*0Sstevel@tonic-gate assert(cp->rc_insert_thr == 0); 301*0Sstevel@tonic-gate assert(cp->rc_refcnt == 0); 302*0Sstevel@tonic-gate assert(cp->rc_doorfd == -1); 303*0Sstevel@tonic-gate assert(cp->rc_doorid == INVALID_DOORID); 304*0Sstevel@tonic-gate assert(uu_list_first(cp->rc_entity_list) == NULL); 305*0Sstevel@tonic-gate assert(uu_list_first(cp->rc_iter_list) == NULL); 306*0Sstevel@tonic-gate uu_list_destroy(cp->rc_entity_list); 307*0Sstevel@tonic-gate uu_list_destroy(cp->rc_iter_list); 308*0Sstevel@tonic-gate uu_list_node_fini(cp, &cp->rc_link, client_pool); 309*0Sstevel@tonic-gate (void) pthread_mutex_destroy(&cp->rc_lock); 310*0Sstevel@tonic-gate uu_free(cp); 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate static void 314*0Sstevel@tonic-gate client_insert(repcache_client_t *cp) 315*0Sstevel@tonic-gate { 316*0Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(cp->rc_id); 317*0Sstevel@tonic-gate uu_list_index_t idx; 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate assert(cp->rc_id > 0); 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 322*0Sstevel@tonic-gate /* 323*0Sstevel@tonic-gate * We assume it does not already exist 324*0Sstevel@tonic-gate */ 325*0Sstevel@tonic-gate (void) uu_list_find(bp->cb_list, cp, NULL, &idx); 326*0Sstevel@tonic-gate uu_list_insert(bp->cb_list, cp, idx); 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate static repcache_client_t * 332*0Sstevel@tonic-gate client_lookup(uint32_t id) 333*0Sstevel@tonic-gate { 334*0Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(id); 335*0Sstevel@tonic-gate repcache_client_t *cp; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate cp = uu_list_find(bp->cb_list, &id, NULL, NULL); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate /* 342*0Sstevel@tonic-gate * Bump the reference count 343*0Sstevel@tonic-gate */ 344*0Sstevel@tonic-gate if (cp != NULL) { 345*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 346*0Sstevel@tonic-gate assert(!(cp->rc_flags & RC_CLIENT_DEAD)); 347*0Sstevel@tonic-gate cp->rc_refcnt++; 348*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate return (cp); 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate static void 356*0Sstevel@tonic-gate client_release(repcache_client_t *cp) 357*0Sstevel@tonic-gate { 358*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 359*0Sstevel@tonic-gate assert(cp->rc_refcnt > 0); 360*0Sstevel@tonic-gate assert(cp->rc_insert_thr != pthread_self()); 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate --cp->rc_refcnt; 363*0Sstevel@tonic-gate (void) pthread_cond_broadcast(&cp->rc_cv); 364*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate /* 368*0Sstevel@tonic-gate * We only allow one thread to be inserting at a time, to prevent 369*0Sstevel@tonic-gate * insert/insert races. 370*0Sstevel@tonic-gate */ 371*0Sstevel@tonic-gate static void 372*0Sstevel@tonic-gate client_start_insert(repcache_client_t *cp) 373*0Sstevel@tonic-gate { 374*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 375*0Sstevel@tonic-gate assert(cp->rc_refcnt > 0); 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate while (cp->rc_insert_thr != 0) { 378*0Sstevel@tonic-gate assert(cp->rc_insert_thr != pthread_self()); 379*0Sstevel@tonic-gate (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate cp->rc_insert_thr = pthread_self(); 382*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate static void 386*0Sstevel@tonic-gate client_end_insert(repcache_client_t *cp) 387*0Sstevel@tonic-gate { 388*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 389*0Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 390*0Sstevel@tonic-gate cp->rc_insert_thr = 0; 391*0Sstevel@tonic-gate (void) pthread_cond_broadcast(&cp->rc_cv); 392*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate /*ARGSUSED*/ 396*0Sstevel@tonic-gate static repcache_entity_t * 397*0Sstevel@tonic-gate entity_alloc(repcache_client_t *cp) 398*0Sstevel@tonic-gate { 399*0Sstevel@tonic-gate repcache_entity_t *ep = uu_zalloc(sizeof (repcache_entity_t)); 400*0Sstevel@tonic-gate if (ep != NULL) { 401*0Sstevel@tonic-gate uu_list_node_init(ep, &ep->re_link, entity_pool); 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate return (ep); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate static void 407*0Sstevel@tonic-gate entity_add(repcache_client_t *cp, repcache_entity_t *ep) 408*0Sstevel@tonic-gate { 409*0Sstevel@tonic-gate uu_list_index_t idx; 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 412*0Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate (void) uu_list_find(cp->rc_entity_list, ep, NULL, &idx); 415*0Sstevel@tonic-gate uu_list_insert(cp->rc_entity_list, ep, idx); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 418*0Sstevel@tonic-gate } 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate static repcache_entity_t * 421*0Sstevel@tonic-gate entity_find(repcache_client_t *cp, uint32_t id) 422*0Sstevel@tonic-gate { 423*0Sstevel@tonic-gate repcache_entity_t *ep; 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 426*0Sstevel@tonic-gate ep = uu_list_find(cp->rc_entity_list, &id, NULL, NULL); 427*0Sstevel@tonic-gate if (ep != NULL) { 428*0Sstevel@tonic-gate add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, ep); 429*0Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->re_lock); 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate return (ep); 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate /* 437*0Sstevel@tonic-gate * Fails with 438*0Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 439*0Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 440*0Sstevel@tonic-gate */ 441*0Sstevel@tonic-gate static int 442*0Sstevel@tonic-gate entity_find2(repcache_client_t *cp, uint32_t id1, repcache_entity_t **out1, 443*0Sstevel@tonic-gate uint32_t id2, repcache_entity_t **out2) 444*0Sstevel@tonic-gate { 445*0Sstevel@tonic-gate repcache_entity_t *e1, *e2; 446*0Sstevel@tonic-gate request_log_entry_t *rlp; 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate if (id1 == id2) 449*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DUPLICATE_ID); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 452*0Sstevel@tonic-gate e1 = uu_list_find(cp->rc_entity_list, &id1, NULL, NULL); 453*0Sstevel@tonic-gate e2 = uu_list_find(cp->rc_entity_list, &id2, NULL, NULL); 454*0Sstevel@tonic-gate if (e1 == NULL || e2 == NULL) { 455*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 456*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate assert(e1 != e2); 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate /* 462*0Sstevel@tonic-gate * locks are ordered by id number 463*0Sstevel@tonic-gate */ 464*0Sstevel@tonic-gate if (id1 < id2) { 465*0Sstevel@tonic-gate (void) pthread_mutex_lock(&e1->re_lock); 466*0Sstevel@tonic-gate (void) pthread_mutex_lock(&e2->re_lock); 467*0Sstevel@tonic-gate } else { 468*0Sstevel@tonic-gate (void) pthread_mutex_lock(&e2->re_lock); 469*0Sstevel@tonic-gate (void) pthread_mutex_lock(&e1->re_lock); 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate *out1 = e1; 472*0Sstevel@tonic-gate *out2 = e2; 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate if ((rlp = get_log()) != NULL) { 477*0Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id1, e1); 478*0Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id2, e2); 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate static void 485*0Sstevel@tonic-gate entity_release(repcache_entity_t *ep) 486*0Sstevel@tonic-gate { 487*0Sstevel@tonic-gate assert(ep->re_node.rnp_node == NULL || 488*0Sstevel@tonic-gate !MUTEX_HELD(&ep->re_node.rnp_node->rn_lock)); 489*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&ep->re_lock); 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate static void 493*0Sstevel@tonic-gate entity_destroy(repcache_entity_t *entity) 494*0Sstevel@tonic-gate { 495*0Sstevel@tonic-gate (void) pthread_mutex_lock(&entity->re_lock); 496*0Sstevel@tonic-gate rc_node_clear(&entity->re_node, 0); 497*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&entity->re_lock); 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate uu_list_node_fini(entity, &entity->re_link, entity_pool); 500*0Sstevel@tonic-gate (void) pthread_mutex_destroy(&entity->re_lock); 501*0Sstevel@tonic-gate uu_free(entity); 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate static void 505*0Sstevel@tonic-gate entity_remove(repcache_client_t *cp, uint32_t id) 506*0Sstevel@tonic-gate { 507*0Sstevel@tonic-gate repcache_entity_t *entity; 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 510*0Sstevel@tonic-gate entity = uu_list_find(cp->rc_entity_list, &id, NULL, NULL); 511*0Sstevel@tonic-gate if (entity != NULL) 512*0Sstevel@tonic-gate uu_list_remove(cp->rc_entity_list, entity); 513*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate if (entity != NULL) 516*0Sstevel@tonic-gate entity_destroy(entity); 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate static void 520*0Sstevel@tonic-gate entity_cleanup(repcache_client_t *cp) 521*0Sstevel@tonic-gate { 522*0Sstevel@tonic-gate repcache_entity_t *ep; 523*0Sstevel@tonic-gate void *cookie = NULL; 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 526*0Sstevel@tonic-gate while ((ep = uu_list_teardown(cp->rc_entity_list, &cookie)) != NULL) { 527*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 528*0Sstevel@tonic-gate entity_destroy(ep); 529*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate /*ARGSUSED*/ 535*0Sstevel@tonic-gate static repcache_iter_t * 536*0Sstevel@tonic-gate iter_alloc(repcache_client_t *cp) 537*0Sstevel@tonic-gate { 538*0Sstevel@tonic-gate repcache_iter_t *iter; 539*0Sstevel@tonic-gate iter = uu_zalloc(sizeof (repcache_iter_t)); 540*0Sstevel@tonic-gate if (iter != NULL) 541*0Sstevel@tonic-gate uu_list_node_init(iter, &iter->ri_link, iter_pool); 542*0Sstevel@tonic-gate return (iter); 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate static void 546*0Sstevel@tonic-gate iter_add(repcache_client_t *cp, repcache_iter_t *iter) 547*0Sstevel@tonic-gate { 548*0Sstevel@tonic-gate uu_list_index_t idx; 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 551*0Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate (void) uu_list_find(cp->rc_iter_list, iter, NULL, &idx); 554*0Sstevel@tonic-gate uu_list_insert(cp->rc_iter_list, iter, idx); 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate static repcache_iter_t * 560*0Sstevel@tonic-gate iter_find(repcache_client_t *cp, uint32_t id) 561*0Sstevel@tonic-gate { 562*0Sstevel@tonic-gate repcache_iter_t *iter; 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate iter = uu_list_find(cp->rc_iter_list, &id, NULL, NULL); 567*0Sstevel@tonic-gate if (iter != NULL) { 568*0Sstevel@tonic-gate add_log_ptr(get_log(), RC_PTR_TYPE_ITER, id, iter); 569*0Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate return (iter); 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate /* 577*0Sstevel@tonic-gate * Fails with 578*0Sstevel@tonic-gate * _UNKNOWN_ID - iter_id or entity_id does not designate an active register 579*0Sstevel@tonic-gate */ 580*0Sstevel@tonic-gate static int 581*0Sstevel@tonic-gate iter_find_w_entity(repcache_client_t *cp, uint32_t iter_id, 582*0Sstevel@tonic-gate repcache_iter_t **iterp, uint32_t entity_id, repcache_entity_t **epp) 583*0Sstevel@tonic-gate { 584*0Sstevel@tonic-gate repcache_iter_t *iter; 585*0Sstevel@tonic-gate repcache_entity_t *ep; 586*0Sstevel@tonic-gate request_log_entry_t *rlp; 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 589*0Sstevel@tonic-gate iter = uu_list_find(cp->rc_iter_list, &iter_id, NULL, NULL); 590*0Sstevel@tonic-gate ep = uu_list_find(cp->rc_entity_list, &entity_id, NULL, NULL); 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate assert(iter == NULL || !MUTEX_HELD(&iter->ri_lock)); 593*0Sstevel@tonic-gate assert(ep == NULL || !MUTEX_HELD(&ep->re_lock)); 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate if (iter == NULL || ep == NULL) { 596*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 597*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 601*0Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->re_lock); 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate *iterp = iter; 606*0Sstevel@tonic-gate *epp = ep; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate if ((rlp = get_log()) != NULL) { 609*0Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, entity_id, ep); 610*0Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ITER, iter_id, iter); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 614*0Sstevel@tonic-gate } 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate static void 617*0Sstevel@tonic-gate iter_release(repcache_iter_t *iter) 618*0Sstevel@tonic-gate { 619*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&iter->ri_lock); 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate static void 623*0Sstevel@tonic-gate iter_destroy(repcache_iter_t *iter) 624*0Sstevel@tonic-gate { 625*0Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 626*0Sstevel@tonic-gate rc_iter_destroy(&iter->ri_iter); 627*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&iter->ri_lock); 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate uu_list_node_fini(iter, &iter->ri_link, iter_pool); 630*0Sstevel@tonic-gate (void) pthread_mutex_destroy(&iter->ri_lock); 631*0Sstevel@tonic-gate uu_free(iter); 632*0Sstevel@tonic-gate } 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate static void 635*0Sstevel@tonic-gate iter_remove(repcache_client_t *cp, uint32_t id) 636*0Sstevel@tonic-gate { 637*0Sstevel@tonic-gate repcache_iter_t *iter; 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 640*0Sstevel@tonic-gate iter = uu_list_find(cp->rc_iter_list, &id, NULL, NULL); 641*0Sstevel@tonic-gate if (iter != NULL) 642*0Sstevel@tonic-gate uu_list_remove(cp->rc_iter_list, iter); 643*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate if (iter != NULL) 646*0Sstevel@tonic-gate iter_destroy(iter); 647*0Sstevel@tonic-gate } 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate static void 650*0Sstevel@tonic-gate iter_cleanup(repcache_client_t *cp) 651*0Sstevel@tonic-gate { 652*0Sstevel@tonic-gate repcache_iter_t *iter; 653*0Sstevel@tonic-gate void *cookie = NULL; 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 656*0Sstevel@tonic-gate while ((iter = uu_list_teardown(cp->rc_iter_list, &cookie)) != NULL) { 657*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 658*0Sstevel@tonic-gate iter_destroy(iter); 659*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate /* 665*0Sstevel@tonic-gate * Ensure that the passed client id is no longer usable, wait for any 666*0Sstevel@tonic-gate * outstanding invocations to complete, then destroy the client 667*0Sstevel@tonic-gate * structure. 668*0Sstevel@tonic-gate */ 669*0Sstevel@tonic-gate static void 670*0Sstevel@tonic-gate client_destroy(uint32_t id) 671*0Sstevel@tonic-gate { 672*0Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(id); 673*0Sstevel@tonic-gate repcache_client_t *cp; 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate cp = uu_list_find(bp->cb_list, &id, NULL, NULL); 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate if (cp == NULL) { 680*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 681*0Sstevel@tonic-gate return; 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate uu_list_remove(bp->cb_list, cp); 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate /* kick the waiters out */ 689*0Sstevel@tonic-gate rc_notify_info_fini(&cp->rc_notify_info); 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 692*0Sstevel@tonic-gate assert(!(cp->rc_flags & RC_CLIENT_DEAD)); 693*0Sstevel@tonic-gate cp->rc_flags |= RC_CLIENT_DEAD; 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate if (cp->rc_doorfd != -1) { 696*0Sstevel@tonic-gate if (door_revoke(cp->rc_doorfd) < 0) 697*0Sstevel@tonic-gate perror("door_revoke"); 698*0Sstevel@tonic-gate cp->rc_doorfd = -1; 699*0Sstevel@tonic-gate cp->rc_doorid = INVALID_DOORID; 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate while (cp->rc_refcnt > 0) 703*0Sstevel@tonic-gate (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock); 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate assert(cp->rc_insert_thr == 0 && cp->rc_notify_thr == 0); 706*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate /* 709*0Sstevel@tonic-gate * destroy outstanding objects 710*0Sstevel@tonic-gate */ 711*0Sstevel@tonic-gate entity_cleanup(cp); 712*0Sstevel@tonic-gate iter_cleanup(cp); 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate /* 715*0Sstevel@tonic-gate * clean up notifications 716*0Sstevel@tonic-gate */ 717*0Sstevel@tonic-gate rc_pg_notify_fini(&cp->rc_pg_notify); 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate client_free(cp); 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate /* 723*0Sstevel@tonic-gate * Fails with 724*0Sstevel@tonic-gate * _TYPE_MISMATCH - the entity is already set up with a different type 725*0Sstevel@tonic-gate * _NO_RESOURCES - out of memory 726*0Sstevel@tonic-gate */ 727*0Sstevel@tonic-gate static int 728*0Sstevel@tonic-gate entity_setup(repcache_client_t *cp, struct rep_protocol_entity_setup *rpr) 729*0Sstevel@tonic-gate { 730*0Sstevel@tonic-gate repcache_entity_t *ep; 731*0Sstevel@tonic-gate uint32_t type; 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate client_start_insert(cp); 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) { 736*0Sstevel@tonic-gate type = ep->re_type; 737*0Sstevel@tonic-gate entity_release(ep); 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate client_end_insert(cp); 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate if (type != rpr->rpr_entitytype) 742*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 743*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate switch (type = rpr->rpr_entitytype) { 747*0Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SCOPE: 748*0Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE: 749*0Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE: 750*0Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPSHOT: 751*0Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPLEVEL: 752*0Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP: 753*0Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTY: 754*0Sstevel@tonic-gate break; 755*0Sstevel@tonic-gate default: 756*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate ep = entity_alloc(cp); 760*0Sstevel@tonic-gate if (ep == NULL) { 761*0Sstevel@tonic-gate client_end_insert(cp); 762*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate ep->re_id = rpr->rpr_entityid; 766*0Sstevel@tonic-gate ep->re_changeid = INVALID_CHANGEID; 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate ep->re_type = type; 769*0Sstevel@tonic-gate rc_node_ptr_init(&ep->re_node); 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate entity_add(cp, ep); 772*0Sstevel@tonic-gate client_end_insert(cp); 773*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 774*0Sstevel@tonic-gate } 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate /*ARGSUSED*/ 777*0Sstevel@tonic-gate static void 778*0Sstevel@tonic-gate entity_name(repcache_client_t *cp, const void *in, size_t insz, void *out_arg, 779*0Sstevel@tonic-gate size_t *outsz, void *arg) 780*0Sstevel@tonic-gate { 781*0Sstevel@tonic-gate const struct rep_protocol_entity_name *rpr = in; 782*0Sstevel@tonic-gate struct rep_protocol_name_response *out = out_arg; 783*0Sstevel@tonic-gate repcache_entity_t *ep; 784*0Sstevel@tonic-gate size_t sz = sizeof (out->rpr_name); 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate if (ep == NULL) { 791*0Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 792*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 793*0Sstevel@tonic-gate return; 794*0Sstevel@tonic-gate } 795*0Sstevel@tonic-gate out->rpr_response = rc_node_name(&ep->re_node, out->rpr_name, 796*0Sstevel@tonic-gate sz, rpr->rpr_answertype, &sz); 797*0Sstevel@tonic-gate entity_release(ep); 798*0Sstevel@tonic-gate 799*0Sstevel@tonic-gate /* 800*0Sstevel@tonic-gate * If we fail, we only return the response code. 801*0Sstevel@tonic-gate * If we succeed, we don't return anything after the '\0' in rpr_name. 802*0Sstevel@tonic-gate */ 803*0Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 804*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 805*0Sstevel@tonic-gate else 806*0Sstevel@tonic-gate *outsz = offsetof(struct rep_protocol_name_response, 807*0Sstevel@tonic-gate rpr_name[sz + 1]); 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate /*ARGSUSED*/ 811*0Sstevel@tonic-gate static void 812*0Sstevel@tonic-gate entity_parent_type(repcache_client_t *cp, const void *in, size_t insz, 813*0Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 814*0Sstevel@tonic-gate { 815*0Sstevel@tonic-gate const struct rep_protocol_entity_name *rpr = in; 816*0Sstevel@tonic-gate struct rep_protocol_integer_response *out = out_arg; 817*0Sstevel@tonic-gate repcache_entity_t *ep; 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate if (ep == NULL) { 824*0Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 825*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 826*0Sstevel@tonic-gate return; 827*0Sstevel@tonic-gate } 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate out->rpr_response = rc_node_parent_type(&ep->re_node, &out->rpr_value); 830*0Sstevel@tonic-gate entity_release(ep); 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 833*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate /* 837*0Sstevel@tonic-gate * Fails with 838*0Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 839*0Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 840*0Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 841*0Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type 842*0Sstevel@tonic-gate * _DELETED - np has been deleted 843*0Sstevel@tonic-gate * _NOT_FOUND - no child with that name/type combo found 844*0Sstevel@tonic-gate * _NO_RESOURCES 845*0Sstevel@tonic-gate * _BACKEND_ACCESS 846*0Sstevel@tonic-gate */ 847*0Sstevel@tonic-gate static int 848*0Sstevel@tonic-gate entity_get_child(repcache_client_t *cp, 849*0Sstevel@tonic-gate struct rep_protocol_entity_get_child *rpr) 850*0Sstevel@tonic-gate { 851*0Sstevel@tonic-gate repcache_entity_t *parent, *child; 852*0Sstevel@tonic-gate int result; 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 855*0Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate result = entity_find2(cp, childid, &child, parentid, &parent); 858*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 859*0Sstevel@tonic-gate return (result); 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate result = rc_node_get_child(&parent->re_node, rpr->rpr_name, 864*0Sstevel@tonic-gate child->re_type, &child->re_node); 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate entity_release(child); 867*0Sstevel@tonic-gate entity_release(parent); 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate return (result); 870*0Sstevel@tonic-gate } 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate /* 873*0Sstevel@tonic-gate * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED, 874*0Sstevel@tonic-gate * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS. 875*0Sstevel@tonic-gate * Fails with 876*0Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 877*0Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 878*0Sstevel@tonic-gate * _NOT_SET - child is not set 879*0Sstevel@tonic-gate * _DELETED - child has been deleted 880*0Sstevel@tonic-gate * _TYPE_MISMATCH - child's parent does not match that of the parent register 881*0Sstevel@tonic-gate * _NOT_FOUND - child has no parent (and is a scope) 882*0Sstevel@tonic-gate */ 883*0Sstevel@tonic-gate static int 884*0Sstevel@tonic-gate entity_get_parent(repcache_client_t *cp, struct rep_protocol_entity_parent *rpr) 885*0Sstevel@tonic-gate { 886*0Sstevel@tonic-gate repcache_entity_t *child, *parent; 887*0Sstevel@tonic-gate int result; 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate uint32_t childid = rpr->rpr_entityid; 890*0Sstevel@tonic-gate uint32_t outid = rpr->rpr_outid; 891*0Sstevel@tonic-gate 892*0Sstevel@tonic-gate result = entity_find2(cp, childid, &child, outid, &parent); 893*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 894*0Sstevel@tonic-gate return (result); 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate result = rc_node_get_parent(&child->re_node, parent->re_type, 897*0Sstevel@tonic-gate &parent->re_node); 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate entity_release(child); 900*0Sstevel@tonic-gate entity_release(parent); 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gate return (result); 903*0Sstevel@tonic-gate } 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate static int 906*0Sstevel@tonic-gate entity_get(repcache_client_t *cp, struct rep_protocol_entity_get *rpr) 907*0Sstevel@tonic-gate { 908*0Sstevel@tonic-gate repcache_entity_t *ep; 909*0Sstevel@tonic-gate int result; 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate if (ep == NULL) 914*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate switch (rpr->rpr_object) { 917*0Sstevel@tonic-gate case RP_ENTITY_GET_INVALIDATE: 918*0Sstevel@tonic-gate rc_node_clear(&ep->re_node, 0); 919*0Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 920*0Sstevel@tonic-gate break; 921*0Sstevel@tonic-gate case RP_ENTITY_GET_MOST_LOCAL_SCOPE: 922*0Sstevel@tonic-gate result = rc_local_scope(ep->re_type, &ep->re_node); 923*0Sstevel@tonic-gate break; 924*0Sstevel@tonic-gate default: 925*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 926*0Sstevel@tonic-gate break; 927*0Sstevel@tonic-gate } 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate entity_release(ep); 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate return (result); 932*0Sstevel@tonic-gate } 933*0Sstevel@tonic-gate 934*0Sstevel@tonic-gate static int 935*0Sstevel@tonic-gate entity_update(repcache_client_t *cp, struct rep_protocol_entity_update *rpr) 936*0Sstevel@tonic-gate { 937*0Sstevel@tonic-gate repcache_entity_t *ep; 938*0Sstevel@tonic-gate int result; 939*0Sstevel@tonic-gate 940*0Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 941*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate if (ep == NULL) 946*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate if (ep->re_changeid == rpr->rpr_changeid) { 949*0Sstevel@tonic-gate result = REP_PROTOCOL_DONE; 950*0Sstevel@tonic-gate } else { 951*0Sstevel@tonic-gate result = rc_node_update(&ep->re_node); 952*0Sstevel@tonic-gate if (result == REP_PROTOCOL_DONE) 953*0Sstevel@tonic-gate ep->re_changeid = rpr->rpr_changeid; 954*0Sstevel@tonic-gate } 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate entity_release(ep); 957*0Sstevel@tonic-gate 958*0Sstevel@tonic-gate return (result); 959*0Sstevel@tonic-gate } 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate static int 962*0Sstevel@tonic-gate entity_reset(repcache_client_t *cp, struct rep_protocol_entity_reset *rpr) 963*0Sstevel@tonic-gate { 964*0Sstevel@tonic-gate repcache_entity_t *ep; 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 967*0Sstevel@tonic-gate if (ep == NULL) 968*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate rc_node_clear(&ep->re_node, 0); 971*0Sstevel@tonic-gate ep->re_txstate = REPCACHE_TX_INIT; 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate entity_release(ep); 974*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 975*0Sstevel@tonic-gate } 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate /* 978*0Sstevel@tonic-gate * Fails with 979*0Sstevel@tonic-gate * _BAD_REQUEST - request has invalid changeid 980*0Sstevel@tonic-gate * rpr_name is invalid 981*0Sstevel@tonic-gate * cannot create children for parent's type of node 982*0Sstevel@tonic-gate * _DUPLICATE_ID - request has duplicate ids 983*0Sstevel@tonic-gate * _UNKNOWN_ID - request has unknown id 984*0Sstevel@tonic-gate * _DELETED - parent has been deleted 985*0Sstevel@tonic-gate * _NOT_SET - parent is reset 986*0Sstevel@tonic-gate * _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP 987*0Sstevel@tonic-gate * _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid 988*0Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have children of type rpr_childtype 989*0Sstevel@tonic-gate * _NO_RESOURCES 990*0Sstevel@tonic-gate * _PERMISSION_DENIED 991*0Sstevel@tonic-gate * _BACKEND_ACCESS 992*0Sstevel@tonic-gate * _BACKEND_READONLY 993*0Sstevel@tonic-gate * _EXISTS - child already exists 994*0Sstevel@tonic-gate * _NOT_FOUND - could not allocate new id 995*0Sstevel@tonic-gate */ 996*0Sstevel@tonic-gate static int 997*0Sstevel@tonic-gate entity_create_child(repcache_client_t *cp, 998*0Sstevel@tonic-gate struct rep_protocol_entity_create_child *rpr) 999*0Sstevel@tonic-gate { 1000*0Sstevel@tonic-gate repcache_entity_t *parent; 1001*0Sstevel@tonic-gate repcache_entity_t *child; 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 1004*0Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate int result; 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 1009*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 1010*0Sstevel@tonic-gate 1011*0Sstevel@tonic-gate result = entity_find2(cp, parentid, &parent, childid, &child); 1012*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1013*0Sstevel@tonic-gate return (result); 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate if (child->re_changeid == rpr->rpr_changeid) { 1018*0Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 1019*0Sstevel@tonic-gate } else { 1020*0Sstevel@tonic-gate result = rc_node_create_child(&parent->re_node, 1021*0Sstevel@tonic-gate rpr->rpr_childtype, rpr->rpr_name, &child->re_node); 1022*0Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 1023*0Sstevel@tonic-gate child->re_changeid = rpr->rpr_changeid; 1024*0Sstevel@tonic-gate } 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate entity_release(parent); 1027*0Sstevel@tonic-gate entity_release(child); 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate return (result); 1030*0Sstevel@tonic-gate } 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate static int 1033*0Sstevel@tonic-gate entity_create_pg(repcache_client_t *cp, 1034*0Sstevel@tonic-gate struct rep_protocol_entity_create_pg *rpr) 1035*0Sstevel@tonic-gate { 1036*0Sstevel@tonic-gate repcache_entity_t *parent; 1037*0Sstevel@tonic-gate repcache_entity_t *child; 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 1040*0Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate int result; 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 1045*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate result = entity_find2(cp, parentid, &parent, childid, &child); 1048*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1049*0Sstevel@tonic-gate return (result); 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 1052*0Sstevel@tonic-gate rpr->rpr_type[sizeof (rpr->rpr_type) - 1] = 0; 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate if (child->re_changeid == rpr->rpr_changeid) { 1055*0Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 1056*0Sstevel@tonic-gate } else { 1057*0Sstevel@tonic-gate result = rc_node_create_child_pg(&parent->re_node, 1058*0Sstevel@tonic-gate child->re_type, rpr->rpr_name, rpr->rpr_type, 1059*0Sstevel@tonic-gate rpr->rpr_flags, &child->re_node); 1060*0Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 1061*0Sstevel@tonic-gate child->re_changeid = rpr->rpr_changeid; 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate entity_release(parent); 1065*0Sstevel@tonic-gate entity_release(child); 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate return (result); 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate 1070*0Sstevel@tonic-gate static int 1071*0Sstevel@tonic-gate entity_delete(repcache_client_t *cp, 1072*0Sstevel@tonic-gate struct rep_protocol_entity_delete *rpr) 1073*0Sstevel@tonic-gate { 1074*0Sstevel@tonic-gate repcache_entity_t *entity; 1075*0Sstevel@tonic-gate 1076*0Sstevel@tonic-gate uint32_t entityid = rpr->rpr_entityid; 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate int result; 1079*0Sstevel@tonic-gate 1080*0Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 1081*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 1082*0Sstevel@tonic-gate 1083*0Sstevel@tonic-gate entity = entity_find(cp, entityid); 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate if (entity == NULL) 1086*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate if (entity->re_changeid == rpr->rpr_changeid) { 1089*0Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 1090*0Sstevel@tonic-gate } else { 1091*0Sstevel@tonic-gate result = rc_node_delete(&entity->re_node); 1092*0Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 1093*0Sstevel@tonic-gate entity->re_changeid = rpr->rpr_changeid; 1094*0Sstevel@tonic-gate } 1095*0Sstevel@tonic-gate 1096*0Sstevel@tonic-gate entity_release(entity); 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate return (result); 1099*0Sstevel@tonic-gate } 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate static rep_protocol_responseid_t 1102*0Sstevel@tonic-gate entity_teardown(repcache_client_t *cp, struct rep_protocol_entity_teardown *rpr) 1103*0Sstevel@tonic-gate { 1104*0Sstevel@tonic-gate entity_remove(cp, rpr->rpr_entityid); 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 1107*0Sstevel@tonic-gate } 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate /* 1110*0Sstevel@tonic-gate * Fails with 1111*0Sstevel@tonic-gate * _MISORDERED - the iterator exists and is not reset 1112*0Sstevel@tonic-gate * _NO_RESOURCES - out of memory 1113*0Sstevel@tonic-gate */ 1114*0Sstevel@tonic-gate static int 1115*0Sstevel@tonic-gate iter_setup(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 1116*0Sstevel@tonic-gate { 1117*0Sstevel@tonic-gate repcache_iter_t *iter; 1118*0Sstevel@tonic-gate uint32_t sequence; 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate client_start_insert(cp); 1121*0Sstevel@tonic-gate /* 1122*0Sstevel@tonic-gate * If the iter already exists, and hasn't been read from, 1123*0Sstevel@tonic-gate * we assume the previous call succeeded. 1124*0Sstevel@tonic-gate */ 1125*0Sstevel@tonic-gate if ((iter = iter_find(cp, rpr->rpr_iterid)) != NULL) { 1126*0Sstevel@tonic-gate sequence = iter->ri_sequence; 1127*0Sstevel@tonic-gate iter_release(iter); 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate client_end_insert(cp); 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate if (sequence != 0) 1132*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 1133*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 1134*0Sstevel@tonic-gate } 1135*0Sstevel@tonic-gate 1136*0Sstevel@tonic-gate iter = iter_alloc(cp); 1137*0Sstevel@tonic-gate if (iter == NULL) { 1138*0Sstevel@tonic-gate client_end_insert(cp); 1139*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 1140*0Sstevel@tonic-gate } 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate iter->ri_id = rpr->rpr_iterid; 1143*0Sstevel@tonic-gate iter->ri_type = REP_PROTOCOL_TYPE_INVALID; 1144*0Sstevel@tonic-gate iter->ri_sequence = 0; 1145*0Sstevel@tonic-gate iter_add(cp, iter); 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate client_end_insert(cp); 1148*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 1149*0Sstevel@tonic-gate } 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate /* 1152*0Sstevel@tonic-gate * Fails with 1153*0Sstevel@tonic-gate * _UNKNOWN_ID 1154*0Sstevel@tonic-gate * _MISORDERED - iterator has already been started 1155*0Sstevel@tonic-gate * _NOT_SET 1156*0Sstevel@tonic-gate * _DELETED 1157*0Sstevel@tonic-gate * _TYPE_MISMATCH - entity cannot have type children 1158*0Sstevel@tonic-gate * _BAD_REQUEST - rpr_flags is invalid 1159*0Sstevel@tonic-gate * rpr_pattern is invalid 1160*0Sstevel@tonic-gate * _NO_RESOURCES 1161*0Sstevel@tonic-gate * _INVALID_TYPE 1162*0Sstevel@tonic-gate * _BACKEND_ACCESS 1163*0Sstevel@tonic-gate */ 1164*0Sstevel@tonic-gate static int 1165*0Sstevel@tonic-gate iter_start(repcache_client_t *cp, struct rep_protocol_iter_start *rpr) 1166*0Sstevel@tonic-gate { 1167*0Sstevel@tonic-gate int result; 1168*0Sstevel@tonic-gate repcache_iter_t *iter; 1169*0Sstevel@tonic-gate repcache_entity_t *ep; 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter, 1172*0Sstevel@tonic-gate rpr->rpr_entity, &ep); 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1175*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate if (iter->ri_sequence > 1) { 1178*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 1179*0Sstevel@tonic-gate goto end; 1180*0Sstevel@tonic-gate } 1181*0Sstevel@tonic-gate 1182*0Sstevel@tonic-gate if (iter->ri_sequence == 1) { 1183*0Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 1184*0Sstevel@tonic-gate goto end; 1185*0Sstevel@tonic-gate } 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0; 1188*0Sstevel@tonic-gate 1189*0Sstevel@tonic-gate result = rc_node_setup_iter(&ep->re_node, &iter->ri_iter, 1190*0Sstevel@tonic-gate rpr->rpr_itertype, rpr->rpr_flags, rpr->rpr_pattern); 1191*0Sstevel@tonic-gate 1192*0Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 1193*0Sstevel@tonic-gate iter->ri_sequence++; 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate end: 1196*0Sstevel@tonic-gate iter_release(iter); 1197*0Sstevel@tonic-gate entity_release(ep); 1198*0Sstevel@tonic-gate return (result); 1199*0Sstevel@tonic-gate } 1200*0Sstevel@tonic-gate 1201*0Sstevel@tonic-gate /* 1202*0Sstevel@tonic-gate * Returns 1203*0Sstevel@tonic-gate * _UNKNOWN_ID 1204*0Sstevel@tonic-gate * _NOT_SET - iter has not been started 1205*0Sstevel@tonic-gate * _MISORDERED 1206*0Sstevel@tonic-gate * _BAD_REQUEST - iter walks values 1207*0Sstevel@tonic-gate * _TYPE_MISMATCH - iter does not walk type entities 1208*0Sstevel@tonic-gate * _DELETED - parent was deleted 1209*0Sstevel@tonic-gate * _NO_RESOURCES 1210*0Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 1211*0Sstevel@tonic-gate * _DONE 1212*0Sstevel@tonic-gate * _SUCCESS 1213*0Sstevel@tonic-gate * 1214*0Sstevel@tonic-gate * For composed property group iterators, can also return 1215*0Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have type children 1216*0Sstevel@tonic-gate * _BACKEND_ACCESS 1217*0Sstevel@tonic-gate */ 1218*0Sstevel@tonic-gate static rep_protocol_responseid_t 1219*0Sstevel@tonic-gate iter_read(repcache_client_t *cp, struct rep_protocol_iter_read *rpr) 1220*0Sstevel@tonic-gate { 1221*0Sstevel@tonic-gate rep_protocol_responseid_t result; 1222*0Sstevel@tonic-gate repcache_iter_t *iter; 1223*0Sstevel@tonic-gate repcache_entity_t *ep; 1224*0Sstevel@tonic-gate uint32_t sequence; 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter, 1227*0Sstevel@tonic-gate rpr->rpr_entityid, &ep); 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1230*0Sstevel@tonic-gate return (result); 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate sequence = rpr->rpr_sequence; 1233*0Sstevel@tonic-gate 1234*0Sstevel@tonic-gate if (iter->ri_sequence == 0) { 1235*0Sstevel@tonic-gate iter_release(iter); 1236*0Sstevel@tonic-gate entity_release(ep); 1237*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_SET); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate if (sequence == 1) { 1241*0Sstevel@tonic-gate iter_release(iter); 1242*0Sstevel@tonic-gate entity_release(ep); 1243*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 1244*0Sstevel@tonic-gate } 1245*0Sstevel@tonic-gate 1246*0Sstevel@tonic-gate if (sequence == iter->ri_sequence) { 1247*0Sstevel@tonic-gate iter_release(iter); 1248*0Sstevel@tonic-gate entity_release(ep); 1249*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 1250*0Sstevel@tonic-gate } 1251*0Sstevel@tonic-gate 1252*0Sstevel@tonic-gate if (sequence == iter->ri_sequence + 1) { 1253*0Sstevel@tonic-gate result = rc_iter_next(iter->ri_iter, &ep->re_node, 1254*0Sstevel@tonic-gate ep->re_type); 1255*0Sstevel@tonic-gate 1256*0Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 1257*0Sstevel@tonic-gate iter->ri_sequence++; 1258*0Sstevel@tonic-gate 1259*0Sstevel@tonic-gate iter_release(iter); 1260*0Sstevel@tonic-gate entity_release(ep); 1261*0Sstevel@tonic-gate 1262*0Sstevel@tonic-gate return (result); 1263*0Sstevel@tonic-gate } 1264*0Sstevel@tonic-gate 1265*0Sstevel@tonic-gate iter_release(iter); 1266*0Sstevel@tonic-gate entity_release(ep); 1267*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 1268*0Sstevel@tonic-gate } 1269*0Sstevel@tonic-gate 1270*0Sstevel@tonic-gate /*ARGSUSED*/ 1271*0Sstevel@tonic-gate static void 1272*0Sstevel@tonic-gate iter_read_value(repcache_client_t *cp, const void *in, size_t insz, 1273*0Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 1274*0Sstevel@tonic-gate { 1275*0Sstevel@tonic-gate const struct rep_protocol_iter_read_value *rpr = in; 1276*0Sstevel@tonic-gate struct rep_protocol_value_response *out = out_arg; 1277*0Sstevel@tonic-gate rep_protocol_responseid_t result; 1278*0Sstevel@tonic-gate 1279*0Sstevel@tonic-gate repcache_iter_t *iter; 1280*0Sstevel@tonic-gate uint32_t sequence; 1281*0Sstevel@tonic-gate int repeat; 1282*0Sstevel@tonic-gate 1283*0Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 1284*0Sstevel@tonic-gate 1285*0Sstevel@tonic-gate iter = iter_find(cp, rpr->rpr_iterid); 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate if (iter == NULL) { 1288*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 1289*0Sstevel@tonic-gate goto out; 1290*0Sstevel@tonic-gate } 1291*0Sstevel@tonic-gate 1292*0Sstevel@tonic-gate sequence = rpr->rpr_sequence; 1293*0Sstevel@tonic-gate 1294*0Sstevel@tonic-gate if (iter->ri_sequence == 0) { 1295*0Sstevel@tonic-gate iter_release(iter); 1296*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_NOT_SET; 1297*0Sstevel@tonic-gate goto out; 1298*0Sstevel@tonic-gate } 1299*0Sstevel@tonic-gate 1300*0Sstevel@tonic-gate repeat = (sequence == iter->ri_sequence); 1301*0Sstevel@tonic-gate 1302*0Sstevel@tonic-gate if (sequence == 1 || (!repeat && sequence != iter->ri_sequence + 1)) { 1303*0Sstevel@tonic-gate iter_release(iter); 1304*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 1305*0Sstevel@tonic-gate goto out; 1306*0Sstevel@tonic-gate } 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate result = rc_iter_next_value(iter->ri_iter, out, outsz, repeat); 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gate if (!repeat && result == REP_PROTOCOL_SUCCESS) 1311*0Sstevel@tonic-gate iter->ri_sequence++; 1312*0Sstevel@tonic-gate 1313*0Sstevel@tonic-gate iter_release(iter); 1314*0Sstevel@tonic-gate 1315*0Sstevel@tonic-gate out: 1316*0Sstevel@tonic-gate /* 1317*0Sstevel@tonic-gate * If we fail, we only return the response code. 1318*0Sstevel@tonic-gate * If we succeed, rc_iter_next_value has shortened *outsz 1319*0Sstevel@tonic-gate * to only include the value bytes needed. 1320*0Sstevel@tonic-gate */ 1321*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS && result != REP_PROTOCOL_DONE) 1322*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate out->rpr_response = result; 1325*0Sstevel@tonic-gate } 1326*0Sstevel@tonic-gate 1327*0Sstevel@tonic-gate static int 1328*0Sstevel@tonic-gate iter_reset(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 1329*0Sstevel@tonic-gate { 1330*0Sstevel@tonic-gate repcache_iter_t *iter = iter_find(cp, rpr->rpr_iterid); 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate if (iter == NULL) 1333*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 1334*0Sstevel@tonic-gate 1335*0Sstevel@tonic-gate if (iter->ri_sequence != 0) { 1336*0Sstevel@tonic-gate iter->ri_sequence = 0; 1337*0Sstevel@tonic-gate rc_iter_destroy(&iter->ri_iter); 1338*0Sstevel@tonic-gate } 1339*0Sstevel@tonic-gate iter_release(iter); 1340*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 1341*0Sstevel@tonic-gate } 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate static rep_protocol_responseid_t 1344*0Sstevel@tonic-gate iter_teardown(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 1345*0Sstevel@tonic-gate { 1346*0Sstevel@tonic-gate iter_remove(cp, rpr->rpr_iterid); 1347*0Sstevel@tonic-gate 1348*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 1349*0Sstevel@tonic-gate } 1350*0Sstevel@tonic-gate 1351*0Sstevel@tonic-gate static rep_protocol_responseid_t 1352*0Sstevel@tonic-gate tx_start(repcache_client_t *cp, struct rep_protocol_transaction_start *rpr) 1353*0Sstevel@tonic-gate { 1354*0Sstevel@tonic-gate repcache_entity_t *tx; 1355*0Sstevel@tonic-gate repcache_entity_t *ep; 1356*0Sstevel@tonic-gate rep_protocol_responseid_t result; 1357*0Sstevel@tonic-gate 1358*0Sstevel@tonic-gate uint32_t txid = rpr->rpr_entityid_tx; 1359*0Sstevel@tonic-gate uint32_t epid = rpr->rpr_entityid; 1360*0Sstevel@tonic-gate 1361*0Sstevel@tonic-gate result = entity_find2(cp, txid, &tx, epid, &ep); 1362*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1363*0Sstevel@tonic-gate return (result); 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate if (tx->re_txstate == REPCACHE_TX_SETUP) { 1366*0Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 1367*0Sstevel@tonic-gate goto end; 1368*0Sstevel@tonic-gate } 1369*0Sstevel@tonic-gate if (tx->re_txstate != REPCACHE_TX_INIT) { 1370*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 1371*0Sstevel@tonic-gate goto end; 1372*0Sstevel@tonic-gate } 1373*0Sstevel@tonic-gate 1374*0Sstevel@tonic-gate result = rc_node_setup_tx(&ep->re_node, &tx->re_node); 1375*0Sstevel@tonic-gate 1376*0Sstevel@tonic-gate end: 1377*0Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 1378*0Sstevel@tonic-gate tx->re_txstate = REPCACHE_TX_SETUP; 1379*0Sstevel@tonic-gate else 1380*0Sstevel@tonic-gate rc_node_clear(&tx->re_node, 0); 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate entity_release(ep); 1383*0Sstevel@tonic-gate entity_release(tx); 1384*0Sstevel@tonic-gate return (result); 1385*0Sstevel@tonic-gate } 1386*0Sstevel@tonic-gate 1387*0Sstevel@tonic-gate /*ARGSUSED*/ 1388*0Sstevel@tonic-gate static void 1389*0Sstevel@tonic-gate tx_commit(repcache_client_t *cp, const void *in, size_t insz, 1390*0Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 1391*0Sstevel@tonic-gate { 1392*0Sstevel@tonic-gate struct rep_protocol_response *out = out_arg; 1393*0Sstevel@tonic-gate const struct rep_protocol_transaction_commit *rpr = in; 1394*0Sstevel@tonic-gate repcache_entity_t *tx; 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 1397*0Sstevel@tonic-gate assert(insz >= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE); 1398*0Sstevel@tonic-gate 1399*0Sstevel@tonic-gate if (rpr->rpr_size != insz) { 1400*0Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_BAD_REQUEST; 1401*0Sstevel@tonic-gate return; 1402*0Sstevel@tonic-gate } 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate tx = entity_find(cp, rpr->rpr_entityid); 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate if (tx == NULL) { 1407*0Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 1408*0Sstevel@tonic-gate return; 1409*0Sstevel@tonic-gate } 1410*0Sstevel@tonic-gate 1411*0Sstevel@tonic-gate switch (tx->re_txstate) { 1412*0Sstevel@tonic-gate case REPCACHE_TX_INIT: 1413*0Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_MISORDERED; 1414*0Sstevel@tonic-gate break; 1415*0Sstevel@tonic-gate 1416*0Sstevel@tonic-gate case REPCACHE_TX_SETUP: 1417*0Sstevel@tonic-gate out->rpr_response = rc_tx_commit(&tx->re_node, rpr->rpr_cmd, 1418*0Sstevel@tonic-gate insz - REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE); 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate if (out->rpr_response == REP_PROTOCOL_SUCCESS) { 1421*0Sstevel@tonic-gate tx->re_txstate = REPCACHE_TX_COMMITTED; 1422*0Sstevel@tonic-gate rc_node_clear(&tx->re_node, 0); 1423*0Sstevel@tonic-gate } 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate break; 1426*0Sstevel@tonic-gate case REPCACHE_TX_COMMITTED: 1427*0Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_SUCCESS; 1428*0Sstevel@tonic-gate break; 1429*0Sstevel@tonic-gate default: 1430*0Sstevel@tonic-gate assert(0); /* CAN'T HAPPEN */ 1431*0Sstevel@tonic-gate break; 1432*0Sstevel@tonic-gate } 1433*0Sstevel@tonic-gate 1434*0Sstevel@tonic-gate entity_release(tx); 1435*0Sstevel@tonic-gate } 1436*0Sstevel@tonic-gate 1437*0Sstevel@tonic-gate static rep_protocol_responseid_t 1438*0Sstevel@tonic-gate next_snaplevel(repcache_client_t *cp, struct rep_protocol_entity_pair *rpr) 1439*0Sstevel@tonic-gate { 1440*0Sstevel@tonic-gate repcache_entity_t *src; 1441*0Sstevel@tonic-gate repcache_entity_t *dest; 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entity_src; 1444*0Sstevel@tonic-gate uint32_t destid = rpr->rpr_entity_dst; 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate int result; 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 1449*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1450*0Sstevel@tonic-gate return (result); 1451*0Sstevel@tonic-gate 1452*0Sstevel@tonic-gate result = rc_node_next_snaplevel(&src->re_node, &dest->re_node); 1453*0Sstevel@tonic-gate 1454*0Sstevel@tonic-gate entity_release(src); 1455*0Sstevel@tonic-gate entity_release(dest); 1456*0Sstevel@tonic-gate 1457*0Sstevel@tonic-gate return (result); 1458*0Sstevel@tonic-gate } 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate static rep_protocol_responseid_t 1461*0Sstevel@tonic-gate snapshot_take(repcache_client_t *cp, struct rep_protocol_snapshot_take *rpr) 1462*0Sstevel@tonic-gate { 1463*0Sstevel@tonic-gate repcache_entity_t *src; 1464*0Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 1465*0Sstevel@tonic-gate repcache_entity_t *dest; 1466*0Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 1467*0Sstevel@tonic-gate 1468*0Sstevel@tonic-gate int result; 1469*0Sstevel@tonic-gate 1470*0Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 1471*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1472*0Sstevel@tonic-gate return (result); 1473*0Sstevel@tonic-gate 1474*0Sstevel@tonic-gate if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 1475*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 1476*0Sstevel@tonic-gate } else { 1477*0Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate if (rpr->rpr_flags == REP_SNAPSHOT_NEW) 1480*0Sstevel@tonic-gate result = rc_snapshot_take_new(&src->re_node, NULL, 1481*0Sstevel@tonic-gate NULL, rpr->rpr_name, &dest->re_node); 1482*0Sstevel@tonic-gate else if (rpr->rpr_flags == REP_SNAPSHOT_ATTACH && 1483*0Sstevel@tonic-gate rpr->rpr_name[0] == 0) 1484*0Sstevel@tonic-gate result = rc_snapshot_take_attach(&src->re_node, 1485*0Sstevel@tonic-gate &dest->re_node); 1486*0Sstevel@tonic-gate else 1487*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 1488*0Sstevel@tonic-gate } 1489*0Sstevel@tonic-gate entity_release(src); 1490*0Sstevel@tonic-gate entity_release(dest); 1491*0Sstevel@tonic-gate 1492*0Sstevel@tonic-gate return (result); 1493*0Sstevel@tonic-gate } 1494*0Sstevel@tonic-gate 1495*0Sstevel@tonic-gate static rep_protocol_responseid_t 1496*0Sstevel@tonic-gate snapshot_take_named(repcache_client_t *cp, 1497*0Sstevel@tonic-gate struct rep_protocol_snapshot_take_named *rpr) 1498*0Sstevel@tonic-gate { 1499*0Sstevel@tonic-gate repcache_entity_t *src; 1500*0Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 1501*0Sstevel@tonic-gate repcache_entity_t *dest; 1502*0Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 1503*0Sstevel@tonic-gate 1504*0Sstevel@tonic-gate int result; 1505*0Sstevel@tonic-gate 1506*0Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 1507*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1508*0Sstevel@tonic-gate return (result); 1509*0Sstevel@tonic-gate 1510*0Sstevel@tonic-gate if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 1511*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 1512*0Sstevel@tonic-gate } else { 1513*0Sstevel@tonic-gate rpr->rpr_svcname[sizeof (rpr->rpr_svcname) - 1] = 0; 1514*0Sstevel@tonic-gate rpr->rpr_instname[sizeof (rpr->rpr_instname) - 1] = 0; 1515*0Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 1516*0Sstevel@tonic-gate 1517*0Sstevel@tonic-gate result = rc_snapshot_take_new(&src->re_node, rpr->rpr_svcname, 1518*0Sstevel@tonic-gate rpr->rpr_instname, rpr->rpr_name, &dest->re_node); 1519*0Sstevel@tonic-gate } 1520*0Sstevel@tonic-gate entity_release(src); 1521*0Sstevel@tonic-gate entity_release(dest); 1522*0Sstevel@tonic-gate 1523*0Sstevel@tonic-gate return (result); 1524*0Sstevel@tonic-gate } 1525*0Sstevel@tonic-gate 1526*0Sstevel@tonic-gate static rep_protocol_responseid_t 1527*0Sstevel@tonic-gate snapshot_attach(repcache_client_t *cp, struct rep_protocol_snapshot_attach *rpr) 1528*0Sstevel@tonic-gate { 1529*0Sstevel@tonic-gate repcache_entity_t *src; 1530*0Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 1531*0Sstevel@tonic-gate repcache_entity_t *dest; 1532*0Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 1533*0Sstevel@tonic-gate 1534*0Sstevel@tonic-gate int result; 1535*0Sstevel@tonic-gate 1536*0Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 1537*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1538*0Sstevel@tonic-gate return (result); 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate result = rc_snapshot_attach(&src->re_node, &dest->re_node); 1541*0Sstevel@tonic-gate 1542*0Sstevel@tonic-gate entity_release(src); 1543*0Sstevel@tonic-gate entity_release(dest); 1544*0Sstevel@tonic-gate 1545*0Sstevel@tonic-gate return (result); 1546*0Sstevel@tonic-gate } 1547*0Sstevel@tonic-gate 1548*0Sstevel@tonic-gate /*ARGSUSED*/ 1549*0Sstevel@tonic-gate static void 1550*0Sstevel@tonic-gate property_get_type(repcache_client_t *cp, const void *in, size_t insz, 1551*0Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 1552*0Sstevel@tonic-gate { 1553*0Sstevel@tonic-gate const struct rep_protocol_property_request *rpr = in; 1554*0Sstevel@tonic-gate struct rep_protocol_integer_response *out = out_arg; 1555*0Sstevel@tonic-gate repcache_entity_t *ep; 1556*0Sstevel@tonic-gate rep_protocol_value_type_t t = 0; 1557*0Sstevel@tonic-gate 1558*0Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 1559*0Sstevel@tonic-gate 1560*0Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 1561*0Sstevel@tonic-gate 1562*0Sstevel@tonic-gate if (ep == NULL) { 1563*0Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 1564*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 1565*0Sstevel@tonic-gate return; 1566*0Sstevel@tonic-gate } 1567*0Sstevel@tonic-gate 1568*0Sstevel@tonic-gate out->rpr_response = rc_node_get_property_type(&ep->re_node, &t); 1569*0Sstevel@tonic-gate 1570*0Sstevel@tonic-gate entity_release(ep); 1571*0Sstevel@tonic-gate 1572*0Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 1573*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 1574*0Sstevel@tonic-gate else 1575*0Sstevel@tonic-gate out->rpr_value = t; 1576*0Sstevel@tonic-gate } 1577*0Sstevel@tonic-gate 1578*0Sstevel@tonic-gate /* 1579*0Sstevel@tonic-gate * Fails with: 1580*0Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 1581*0Sstevel@tonic-gate * _NOT_SET - The property is not set 1582*0Sstevel@tonic-gate * _DELETED - The property has been deleted 1583*0Sstevel@tonic-gate * _TYPE_MISMATCH - The object is not a property 1584*0Sstevel@tonic-gate * _NOT_FOUND - The property has no values. 1585*0Sstevel@tonic-gate * 1586*0Sstevel@tonic-gate * Succeeds with: 1587*0Sstevel@tonic-gate * _SUCCESS - The property has 1 value. 1588*0Sstevel@tonic-gate * _TRUNCATED - The property has >1 value. 1589*0Sstevel@tonic-gate */ 1590*0Sstevel@tonic-gate /*ARGSUSED*/ 1591*0Sstevel@tonic-gate static void 1592*0Sstevel@tonic-gate property_get_value(repcache_client_t *cp, const void *in, size_t insz, 1593*0Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 1594*0Sstevel@tonic-gate { 1595*0Sstevel@tonic-gate const struct rep_protocol_property_request *rpr = in; 1596*0Sstevel@tonic-gate struct rep_protocol_value_response *out = out_arg; 1597*0Sstevel@tonic-gate repcache_entity_t *ep; 1598*0Sstevel@tonic-gate 1599*0Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 1600*0Sstevel@tonic-gate 1601*0Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 1602*0Sstevel@tonic-gate if (ep == NULL) { 1603*0Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 1604*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 1605*0Sstevel@tonic-gate return; 1606*0Sstevel@tonic-gate } 1607*0Sstevel@tonic-gate 1608*0Sstevel@tonic-gate out->rpr_response = rc_node_get_property_value(&ep->re_node, out, 1609*0Sstevel@tonic-gate outsz); 1610*0Sstevel@tonic-gate 1611*0Sstevel@tonic-gate entity_release(ep); 1612*0Sstevel@tonic-gate 1613*0Sstevel@tonic-gate /* 1614*0Sstevel@tonic-gate * If we fail, we only return the response code. 1615*0Sstevel@tonic-gate * If we succeed, rc_node_get_property_value has shortened *outsz 1616*0Sstevel@tonic-gate * to only include the value bytes needed. 1617*0Sstevel@tonic-gate */ 1618*0Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS && 1619*0Sstevel@tonic-gate out->rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) 1620*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 1621*0Sstevel@tonic-gate } 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate static rep_protocol_responseid_t 1624*0Sstevel@tonic-gate propertygrp_notify(repcache_client_t *cp, 1625*0Sstevel@tonic-gate struct rep_protocol_propertygrp_request *rpr, int *out_fd) 1626*0Sstevel@tonic-gate { 1627*0Sstevel@tonic-gate int fds[2]; 1628*0Sstevel@tonic-gate int ours, theirs; 1629*0Sstevel@tonic-gate 1630*0Sstevel@tonic-gate rep_protocol_responseid_t result; 1631*0Sstevel@tonic-gate repcache_entity_t *ep; 1632*0Sstevel@tonic-gate 1633*0Sstevel@tonic-gate if (pipe(fds) < 0) 1634*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 1635*0Sstevel@tonic-gate 1636*0Sstevel@tonic-gate ours = fds[0]; 1637*0Sstevel@tonic-gate theirs = fds[1]; 1638*0Sstevel@tonic-gate 1639*0Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) == NULL) { 1640*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 1641*0Sstevel@tonic-gate goto fail; 1642*0Sstevel@tonic-gate } 1643*0Sstevel@tonic-gate 1644*0Sstevel@tonic-gate /* 1645*0Sstevel@tonic-gate * While the following can race with other threads setting up a 1646*0Sstevel@tonic-gate * notification, the worst that can happen is that our fd has 1647*0Sstevel@tonic-gate * already been closed before we return. 1648*0Sstevel@tonic-gate */ 1649*0Sstevel@tonic-gate result = rc_pg_notify_setup(&cp->rc_pg_notify, &ep->re_node, 1650*0Sstevel@tonic-gate ours); 1651*0Sstevel@tonic-gate 1652*0Sstevel@tonic-gate entity_release(ep); 1653*0Sstevel@tonic-gate 1654*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1655*0Sstevel@tonic-gate goto fail; 1656*0Sstevel@tonic-gate 1657*0Sstevel@tonic-gate *out_fd = theirs; 1658*0Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 1659*0Sstevel@tonic-gate 1660*0Sstevel@tonic-gate fail: 1661*0Sstevel@tonic-gate (void) close(ours); 1662*0Sstevel@tonic-gate (void) close(theirs); 1663*0Sstevel@tonic-gate 1664*0Sstevel@tonic-gate return (result); 1665*0Sstevel@tonic-gate } 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate static rep_protocol_responseid_t 1668*0Sstevel@tonic-gate client_add_notify(repcache_client_t *cp, 1669*0Sstevel@tonic-gate struct rep_protocol_notify_request *rpr) 1670*0Sstevel@tonic-gate { 1671*0Sstevel@tonic-gate rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0; 1672*0Sstevel@tonic-gate 1673*0Sstevel@tonic-gate switch (rpr->rpr_type) { 1674*0Sstevel@tonic-gate case REP_PROTOCOL_NOTIFY_PGNAME: 1675*0Sstevel@tonic-gate return (rc_notify_info_add_name(&cp->rc_notify_info, 1676*0Sstevel@tonic-gate rpr->rpr_pattern)); 1677*0Sstevel@tonic-gate 1678*0Sstevel@tonic-gate case REP_PROTOCOL_NOTIFY_PGTYPE: 1679*0Sstevel@tonic-gate return (rc_notify_info_add_type(&cp->rc_notify_info, 1680*0Sstevel@tonic-gate rpr->rpr_pattern)); 1681*0Sstevel@tonic-gate 1682*0Sstevel@tonic-gate default: 1683*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 1684*0Sstevel@tonic-gate } 1685*0Sstevel@tonic-gate } 1686*0Sstevel@tonic-gate 1687*0Sstevel@tonic-gate /*ARGSUSED*/ 1688*0Sstevel@tonic-gate static void 1689*0Sstevel@tonic-gate client_wait(repcache_client_t *cp, const void *in, size_t insz, 1690*0Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 1691*0Sstevel@tonic-gate { 1692*0Sstevel@tonic-gate int result; 1693*0Sstevel@tonic-gate repcache_entity_t *ep; 1694*0Sstevel@tonic-gate const struct rep_protocol_wait_request *rpr = in; 1695*0Sstevel@tonic-gate struct rep_protocol_fmri_response *out = out_arg; 1696*0Sstevel@tonic-gate 1697*0Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 1698*0Sstevel@tonic-gate 1699*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 1700*0Sstevel@tonic-gate if (cp->rc_notify_thr != 0) { 1701*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 1702*0Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_EXISTS; 1703*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 1704*0Sstevel@tonic-gate return; 1705*0Sstevel@tonic-gate } 1706*0Sstevel@tonic-gate cp->rc_notify_thr = pthread_self(); 1707*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 1708*0Sstevel@tonic-gate 1709*0Sstevel@tonic-gate result = rc_notify_info_wait(&cp->rc_notify_info, &cp->rc_notify_ptr, 1710*0Sstevel@tonic-gate out->rpr_fmri, sizeof (out->rpr_fmri)); 1711*0Sstevel@tonic-gate 1712*0Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) { 1713*0Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) { 1714*0Sstevel@tonic-gate if (ep->re_type == REP_PROTOCOL_ENTITY_PROPERTYGRP) { 1715*0Sstevel@tonic-gate rc_node_ptr_assign(&ep->re_node, 1716*0Sstevel@tonic-gate &cp->rc_notify_ptr); 1717*0Sstevel@tonic-gate } else { 1718*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 1719*0Sstevel@tonic-gate } 1720*0Sstevel@tonic-gate entity_release(ep); 1721*0Sstevel@tonic-gate } else { 1722*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 1723*0Sstevel@tonic-gate } 1724*0Sstevel@tonic-gate rc_node_clear(&cp->rc_notify_ptr, 0); 1725*0Sstevel@tonic-gate } 1726*0Sstevel@tonic-gate 1727*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 1728*0Sstevel@tonic-gate assert(cp->rc_notify_thr == pthread_self()); 1729*0Sstevel@tonic-gate cp->rc_notify_thr = 0; 1730*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 1731*0Sstevel@tonic-gate 1732*0Sstevel@tonic-gate out->rpr_response = result; 1733*0Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 1734*0Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 1735*0Sstevel@tonic-gate } 1736*0Sstevel@tonic-gate 1737*0Sstevel@tonic-gate /* 1738*0Sstevel@tonic-gate * Can return: 1739*0Sstevel@tonic-gate * _PERMISSION_DENIED not enough privileges to do request. 1740*0Sstevel@tonic-gate * _BAD_REQUEST name is not valid or reserved 1741*0Sstevel@tonic-gate * _TRUNCATED name is too long for current repository path 1742*0Sstevel@tonic-gate * _UNKNOWN failed for unknown reason (details written to 1743*0Sstevel@tonic-gate * console) 1744*0Sstevel@tonic-gate * _BACKEND_READONLY backend is not writable 1745*0Sstevel@tonic-gate * 1746*0Sstevel@tonic-gate * _SUCCESS Backup completed successfully. 1747*0Sstevel@tonic-gate */ 1748*0Sstevel@tonic-gate static rep_protocol_responseid_t 1749*0Sstevel@tonic-gate backup_repository(repcache_client_t *cp, 1750*0Sstevel@tonic-gate struct rep_protocol_backup_request *rpr) 1751*0Sstevel@tonic-gate { 1752*0Sstevel@tonic-gate rep_protocol_responseid_t result; 1753*0Sstevel@tonic-gate ucred_t *uc = get_ucred(); 1754*0Sstevel@tonic-gate 1755*0Sstevel@tonic-gate if (!client_is_privileged() && (uc == NULL || ucred_geteuid(uc) != 0)) 1756*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 1757*0Sstevel@tonic-gate 1758*0Sstevel@tonic-gate rpr->rpr_name[REP_PROTOCOL_NAME_LEN - 1] = 0; 1759*0Sstevel@tonic-gate if (strcmp(rpr->rpr_name, REPOSITORY_BOOT_BACKUP) == 0) 1760*0Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 1761*0Sstevel@tonic-gate 1762*0Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 1763*0Sstevel@tonic-gate if (rpr->rpr_changeid != cp->rc_changeid) { 1764*0Sstevel@tonic-gate result = backend_create_backup(rpr->rpr_name); 1765*0Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 1766*0Sstevel@tonic-gate cp->rc_changeid = rpr->rpr_changeid; 1767*0Sstevel@tonic-gate } else { 1768*0Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 1769*0Sstevel@tonic-gate } 1770*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 1771*0Sstevel@tonic-gate 1772*0Sstevel@tonic-gate return (result); 1773*0Sstevel@tonic-gate } 1774*0Sstevel@tonic-gate 1775*0Sstevel@tonic-gate 1776*0Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_f(repcache_client_t *cp, 1777*0Sstevel@tonic-gate const void *rpr); 1778*0Sstevel@tonic-gate 1779*0Sstevel@tonic-gate /*ARGSUSED*/ 1780*0Sstevel@tonic-gate static void 1781*0Sstevel@tonic-gate simple_handler(repcache_client_t *cp, const void *in, size_t insz, 1782*0Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 1783*0Sstevel@tonic-gate { 1784*0Sstevel@tonic-gate protocol_simple_f *f = (protocol_simple_f *)arg; 1785*0Sstevel@tonic-gate rep_protocol_response_t *out = out_arg; 1786*0Sstevel@tonic-gate 1787*0Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 1788*0Sstevel@tonic-gate assert(f != NULL); 1789*0Sstevel@tonic-gate 1790*0Sstevel@tonic-gate out->rpr_response = (*f)(cp, in); 1791*0Sstevel@tonic-gate } 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_fd_f(repcache_client_t *cp, 1794*0Sstevel@tonic-gate const void *rpr, int *out_fd); 1795*0Sstevel@tonic-gate 1796*0Sstevel@tonic-gate /*ARGSUSED*/ 1797*0Sstevel@tonic-gate static void 1798*0Sstevel@tonic-gate simple_fd_handler(repcache_client_t *cp, const void *in, size_t insz, 1799*0Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg, int *out_fd) 1800*0Sstevel@tonic-gate { 1801*0Sstevel@tonic-gate protocol_simple_fd_f *f = (protocol_simple_fd_f *)arg; 1802*0Sstevel@tonic-gate rep_protocol_response_t *out = out_arg; 1803*0Sstevel@tonic-gate 1804*0Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 1805*0Sstevel@tonic-gate assert(f != NULL); 1806*0Sstevel@tonic-gate 1807*0Sstevel@tonic-gate out->rpr_response = (*f)(cp, in, out_fd); 1808*0Sstevel@tonic-gate } 1809*0Sstevel@tonic-gate 1810*0Sstevel@tonic-gate typedef void protocol_handler_f(repcache_client_t *, const void *in, 1811*0Sstevel@tonic-gate size_t insz, void *out, size_t *outsz, void *arg); 1812*0Sstevel@tonic-gate 1813*0Sstevel@tonic-gate typedef void protocol_handler_fdret_f(repcache_client_t *, const void *in, 1814*0Sstevel@tonic-gate size_t insz, void *out, size_t *outsz, void *arg, int *fd_out); 1815*0Sstevel@tonic-gate 1816*0Sstevel@tonic-gate #define PROTO(p, f, in) { \ 1817*0Sstevel@tonic-gate p, #p, simple_handler, (void *)(&f), NULL, \ 1818*0Sstevel@tonic-gate sizeof (in), sizeof (rep_protocol_response_t), 0 \ 1819*0Sstevel@tonic-gate } 1820*0Sstevel@tonic-gate 1821*0Sstevel@tonic-gate #define PROTO_FD_OUT(p, f, in) { \ 1822*0Sstevel@tonic-gate p, #p, NULL, (void *)(&f), simple_fd_handler, \ 1823*0Sstevel@tonic-gate sizeof (in), \ 1824*0Sstevel@tonic-gate sizeof (rep_protocol_response_t), \ 1825*0Sstevel@tonic-gate PROTO_FLAG_RETFD \ 1826*0Sstevel@tonic-gate } 1827*0Sstevel@tonic-gate 1828*0Sstevel@tonic-gate #define PROTO_VARIN(p, f, insz) { \ 1829*0Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 1830*0Sstevel@tonic-gate insz, sizeof (rep_protocol_response_t), \ 1831*0Sstevel@tonic-gate PROTO_FLAG_VARINPUT \ 1832*0Sstevel@tonic-gate } 1833*0Sstevel@tonic-gate 1834*0Sstevel@tonic-gate #define PROTO_UINT_OUT(p, f, in) { \ 1835*0Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 1836*0Sstevel@tonic-gate sizeof (in), \ 1837*0Sstevel@tonic-gate sizeof (struct rep_protocol_integer_response), 0 \ 1838*0Sstevel@tonic-gate } 1839*0Sstevel@tonic-gate 1840*0Sstevel@tonic-gate #define PROTO_NAME_OUT(p, f, in) { \ 1841*0Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 1842*0Sstevel@tonic-gate sizeof (in), \ 1843*0Sstevel@tonic-gate sizeof (struct rep_protocol_name_response), 0 \ 1844*0Sstevel@tonic-gate } 1845*0Sstevel@tonic-gate 1846*0Sstevel@tonic-gate #define PROTO_FMRI_OUT(p, f, in) { \ 1847*0Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 1848*0Sstevel@tonic-gate sizeof (in), \ 1849*0Sstevel@tonic-gate sizeof (struct rep_protocol_fmri_response), 0 \ 1850*0Sstevel@tonic-gate } 1851*0Sstevel@tonic-gate 1852*0Sstevel@tonic-gate #define PROTO_VALUE_OUT(p, f, in) { \ 1853*0Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 1854*0Sstevel@tonic-gate sizeof (in), \ 1855*0Sstevel@tonic-gate sizeof (struct rep_protocol_value_response), 0 \ 1856*0Sstevel@tonic-gate } 1857*0Sstevel@tonic-gate 1858*0Sstevel@tonic-gate #define PROTO_PANIC(p) { p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC } 1859*0Sstevel@tonic-gate #define PROTO_END() { 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC } 1860*0Sstevel@tonic-gate 1861*0Sstevel@tonic-gate #define PROTO_FLAG_PANIC 0x00000001 /* should never be called */ 1862*0Sstevel@tonic-gate #define PROTO_FLAG_VARINPUT 0x00000004 /* in_size is minimum size */ 1863*0Sstevel@tonic-gate #define PROTO_FLAG_RETFD 0x00000008 /* can also return an FD */ 1864*0Sstevel@tonic-gate 1865*0Sstevel@tonic-gate #define PROTO_ALL_FLAGS 0x0000000f /* all flags */ 1866*0Sstevel@tonic-gate 1867*0Sstevel@tonic-gate static struct protocol_entry { 1868*0Sstevel@tonic-gate enum rep_protocol_requestid pt_request; 1869*0Sstevel@tonic-gate const char *pt_name; 1870*0Sstevel@tonic-gate protocol_handler_f *pt_handler; 1871*0Sstevel@tonic-gate void *pt_arg; 1872*0Sstevel@tonic-gate protocol_handler_fdret_f *pt_fd_handler; 1873*0Sstevel@tonic-gate size_t pt_in_size; 1874*0Sstevel@tonic-gate size_t pt_out_max; 1875*0Sstevel@tonic-gate uint32_t pt_flags; 1876*0Sstevel@tonic-gate } protocol_table[] = { 1877*0Sstevel@tonic-gate PROTO_PANIC(REP_PROTOCOL_CLOSE), /* special case */ 1878*0Sstevel@tonic-gate 1879*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_SETUP, entity_setup, 1880*0Sstevel@tonic-gate struct rep_protocol_entity_setup), 1881*0Sstevel@tonic-gate PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME, entity_name, 1882*0Sstevel@tonic-gate struct rep_protocol_entity_name), 1883*0Sstevel@tonic-gate PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE, entity_parent_type, 1884*0Sstevel@tonic-gate struct rep_protocol_entity_parent_type), 1885*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET_CHILD, entity_get_child, 1886*0Sstevel@tonic-gate struct rep_protocol_entity_get_child), 1887*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET_PARENT, entity_get_parent, 1888*0Sstevel@tonic-gate struct rep_protocol_entity_parent), 1889*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET, entity_get, 1890*0Sstevel@tonic-gate struct rep_protocol_entity_get), 1891*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_UPDATE, entity_update, 1892*0Sstevel@tonic-gate struct rep_protocol_entity_update), 1893*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD, entity_create_child, 1894*0Sstevel@tonic-gate struct rep_protocol_entity_create_child), 1895*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_CREATE_PG, entity_create_pg, 1896*0Sstevel@tonic-gate struct rep_protocol_entity_create_pg), 1897*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_DELETE, entity_delete, 1898*0Sstevel@tonic-gate struct rep_protocol_entity_delete), 1899*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_RESET, entity_reset, 1900*0Sstevel@tonic-gate struct rep_protocol_entity_reset), 1901*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_TEARDOWN, entity_teardown, 1902*0Sstevel@tonic-gate struct rep_protocol_entity_teardown), 1903*0Sstevel@tonic-gate 1904*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_SETUP, iter_setup, 1905*0Sstevel@tonic-gate struct rep_protocol_iter_request), 1906*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_START, iter_start, 1907*0Sstevel@tonic-gate struct rep_protocol_iter_start), 1908*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_READ, iter_read, 1909*0Sstevel@tonic-gate struct rep_protocol_iter_read), 1910*0Sstevel@tonic-gate PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE, iter_read_value, 1911*0Sstevel@tonic-gate struct rep_protocol_iter_read_value), 1912*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_RESET, iter_reset, 1913*0Sstevel@tonic-gate struct rep_protocol_iter_request), 1914*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_TEARDOWN, iter_teardown, 1915*0Sstevel@tonic-gate struct rep_protocol_iter_request), 1916*0Sstevel@tonic-gate 1917*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL, next_snaplevel, 1918*0Sstevel@tonic-gate struct rep_protocol_entity_pair), 1919*0Sstevel@tonic-gate 1920*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_TAKE, snapshot_take, 1921*0Sstevel@tonic-gate struct rep_protocol_snapshot_take), 1922*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED, snapshot_take_named, 1923*0Sstevel@tonic-gate struct rep_protocol_snapshot_take_named), 1924*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH, snapshot_attach, 1925*0Sstevel@tonic-gate struct rep_protocol_snapshot_attach), 1926*0Sstevel@tonic-gate 1927*0Sstevel@tonic-gate PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE, property_get_type, 1928*0Sstevel@tonic-gate struct rep_protocol_property_request), 1929*0Sstevel@tonic-gate PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE, property_get_value, 1930*0Sstevel@tonic-gate struct rep_protocol_property_request), 1931*0Sstevel@tonic-gate 1932*0Sstevel@tonic-gate PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT, propertygrp_notify, 1933*0Sstevel@tonic-gate struct rep_protocol_propertygrp_request), 1934*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START, tx_start, 1935*0Sstevel@tonic-gate struct rep_protocol_transaction_start), 1936*0Sstevel@tonic-gate PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT, tx_commit, 1937*0Sstevel@tonic-gate REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE), 1938*0Sstevel@tonic-gate 1939*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY, client_add_notify, 1940*0Sstevel@tonic-gate struct rep_protocol_notify_request), 1941*0Sstevel@tonic-gate PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT, client_wait, 1942*0Sstevel@tonic-gate struct rep_protocol_wait_request), 1943*0Sstevel@tonic-gate 1944*0Sstevel@tonic-gate PROTO(REP_PROTOCOL_BACKUP, backup_repository, 1945*0Sstevel@tonic-gate struct rep_protocol_backup_request), 1946*0Sstevel@tonic-gate 1947*0Sstevel@tonic-gate PROTO_END() 1948*0Sstevel@tonic-gate }; 1949*0Sstevel@tonic-gate #undef PROTO 1950*0Sstevel@tonic-gate #undef PROTO_FMRI_OUT 1951*0Sstevel@tonic-gate #undef PROTO_NAME_OUT 1952*0Sstevel@tonic-gate #undef PROTO_UINT_OUT 1953*0Sstevel@tonic-gate #undef PROTO_PANIC 1954*0Sstevel@tonic-gate #undef PROTO_END 1955*0Sstevel@tonic-gate 1956*0Sstevel@tonic-gate /* 1957*0Sstevel@tonic-gate * The number of entries, sans PROTO_END() 1958*0Sstevel@tonic-gate */ 1959*0Sstevel@tonic-gate #define PROTOCOL_ENTRIES \ 1960*0Sstevel@tonic-gate (sizeof (protocol_table) / sizeof (*protocol_table) - 1) 1961*0Sstevel@tonic-gate 1962*0Sstevel@tonic-gate #define PROTOCOL_PREFIX "REP_PROTOCOL_" 1963*0Sstevel@tonic-gate 1964*0Sstevel@tonic-gate int 1965*0Sstevel@tonic-gate client_init(void) 1966*0Sstevel@tonic-gate { 1967*0Sstevel@tonic-gate int i; 1968*0Sstevel@tonic-gate struct protocol_entry *e; 1969*0Sstevel@tonic-gate 1970*0Sstevel@tonic-gate if (!client_hash_init()) 1971*0Sstevel@tonic-gate return (0); 1972*0Sstevel@tonic-gate 1973*0Sstevel@tonic-gate if (request_log_size > 0) { 1974*0Sstevel@tonic-gate request_log = uu_zalloc(request_log_size * 1975*0Sstevel@tonic-gate sizeof (request_log_entry_t)); 1976*0Sstevel@tonic-gate } 1977*0Sstevel@tonic-gate 1978*0Sstevel@tonic-gate /* 1979*0Sstevel@tonic-gate * update the names to not include REP_PROTOCOL_ 1980*0Sstevel@tonic-gate */ 1981*0Sstevel@tonic-gate for (i = 0; i < PROTOCOL_ENTRIES; i++) { 1982*0Sstevel@tonic-gate e = &protocol_table[i]; 1983*0Sstevel@tonic-gate assert(strncmp(e->pt_name, PROTOCOL_PREFIX, 1984*0Sstevel@tonic-gate strlen(PROTOCOL_PREFIX)) == 0); 1985*0Sstevel@tonic-gate e->pt_name += strlen(PROTOCOL_PREFIX); 1986*0Sstevel@tonic-gate } 1987*0Sstevel@tonic-gate /* 1988*0Sstevel@tonic-gate * verify the protocol table is consistent 1989*0Sstevel@tonic-gate */ 1990*0Sstevel@tonic-gate for (i = 0; i < PROTOCOL_ENTRIES; i++) { 1991*0Sstevel@tonic-gate e = &protocol_table[i]; 1992*0Sstevel@tonic-gate assert(e->pt_request == (REP_PROTOCOL_BASE + i)); 1993*0Sstevel@tonic-gate 1994*0Sstevel@tonic-gate assert((e->pt_flags & ~PROTO_ALL_FLAGS) == 0); 1995*0Sstevel@tonic-gate 1996*0Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_PANIC) 1997*0Sstevel@tonic-gate assert(e->pt_in_size == 0 && e->pt_out_max == 0 && 1998*0Sstevel@tonic-gate e->pt_handler == NULL); 1999*0Sstevel@tonic-gate else 2000*0Sstevel@tonic-gate assert(e->pt_in_size != 0 && e->pt_out_max != 0 && 2001*0Sstevel@tonic-gate (e->pt_handler != NULL || 2002*0Sstevel@tonic-gate e->pt_fd_handler != NULL)); 2003*0Sstevel@tonic-gate } 2004*0Sstevel@tonic-gate assert((REP_PROTOCOL_BASE + i) == REP_PROTOCOL_MAX_REQUEST); 2005*0Sstevel@tonic-gate 2006*0Sstevel@tonic-gate assert(protocol_table[i].pt_request == 0); 2007*0Sstevel@tonic-gate 2008*0Sstevel@tonic-gate return (1); 2009*0Sstevel@tonic-gate } 2010*0Sstevel@tonic-gate 2011*0Sstevel@tonic-gate static void 2012*0Sstevel@tonic-gate client_switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *desc_in, 2013*0Sstevel@tonic-gate uint_t n_desc) 2014*0Sstevel@tonic-gate { 2015*0Sstevel@tonic-gate thread_info_t *ti = thread_self(); 2016*0Sstevel@tonic-gate 2017*0Sstevel@tonic-gate repcache_client_t *cp; 2018*0Sstevel@tonic-gate uint32_t id = (uint32_t)cookie; 2019*0Sstevel@tonic-gate enum rep_protocol_requestid request_code; 2020*0Sstevel@tonic-gate 2021*0Sstevel@tonic-gate rep_protocol_responseid_t result = INVALID_RESULT; 2022*0Sstevel@tonic-gate 2023*0Sstevel@tonic-gate struct protocol_entry *e; 2024*0Sstevel@tonic-gate 2025*0Sstevel@tonic-gate char *retval = NULL; 2026*0Sstevel@tonic-gate size_t retsize = 0; 2027*0Sstevel@tonic-gate 2028*0Sstevel@tonic-gate int retfd = -1; 2029*0Sstevel@tonic-gate door_desc_t desc; 2030*0Sstevel@tonic-gate request_log_entry_t *rlp; 2031*0Sstevel@tonic-gate 2032*0Sstevel@tonic-gate rlp = start_log(id); 2033*0Sstevel@tonic-gate 2034*0Sstevel@tonic-gate if (n_desc != 0) 2035*0Sstevel@tonic-gate uu_die("can't happen: %d descriptors @%p (cookie %p)", 2036*0Sstevel@tonic-gate n_desc, desc_in, cookie); 2037*0Sstevel@tonic-gate 2038*0Sstevel@tonic-gate if (argp == DOOR_UNREF_DATA) { 2039*0Sstevel@tonic-gate client_destroy(id); 2040*0Sstevel@tonic-gate goto bad_end; 2041*0Sstevel@tonic-gate } 2042*0Sstevel@tonic-gate 2043*0Sstevel@tonic-gate thread_newstate(ti, TI_CLIENT_CALL); 2044*0Sstevel@tonic-gate 2045*0Sstevel@tonic-gate /* 2046*0Sstevel@tonic-gate * To simplify returning just a result code, we set up for 2047*0Sstevel@tonic-gate * that case here. 2048*0Sstevel@tonic-gate */ 2049*0Sstevel@tonic-gate retval = (char *)&result; 2050*0Sstevel@tonic-gate retsize = sizeof (result); 2051*0Sstevel@tonic-gate 2052*0Sstevel@tonic-gate if (arg_size < sizeof (request_code)) { 2053*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 2054*0Sstevel@tonic-gate goto end_unheld; 2055*0Sstevel@tonic-gate } 2056*0Sstevel@tonic-gate 2057*0Sstevel@tonic-gate ti->ti_client_request = (void *)argp; 2058*0Sstevel@tonic-gate 2059*0Sstevel@tonic-gate /* LINTED alignment */ 2060*0Sstevel@tonic-gate request_code = *(uint32_t *)argp; 2061*0Sstevel@tonic-gate 2062*0Sstevel@tonic-gate if (rlp != NULL) { 2063*0Sstevel@tonic-gate rlp->rl_request = request_code; 2064*0Sstevel@tonic-gate } 2065*0Sstevel@tonic-gate /* 2066*0Sstevel@tonic-gate * In order to avoid locking problems on removal, we handle the 2067*0Sstevel@tonic-gate * "close" case before doing a lookup. 2068*0Sstevel@tonic-gate */ 2069*0Sstevel@tonic-gate if (request_code == REP_PROTOCOL_CLOSE) { 2070*0Sstevel@tonic-gate client_destroy(id); 2071*0Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 2072*0Sstevel@tonic-gate goto end_unheld; 2073*0Sstevel@tonic-gate } 2074*0Sstevel@tonic-gate 2075*0Sstevel@tonic-gate cp = client_lookup(id); 2076*0Sstevel@tonic-gate /* 2077*0Sstevel@tonic-gate * cp is held 2078*0Sstevel@tonic-gate */ 2079*0Sstevel@tonic-gate 2080*0Sstevel@tonic-gate if (cp == NULL) 2081*0Sstevel@tonic-gate goto bad_end; 2082*0Sstevel@tonic-gate 2083*0Sstevel@tonic-gate if (rlp != NULL) 2084*0Sstevel@tonic-gate rlp->rl_client = cp; 2085*0Sstevel@tonic-gate 2086*0Sstevel@tonic-gate ti->ti_active_client = cp; 2087*0Sstevel@tonic-gate 2088*0Sstevel@tonic-gate if (request_code < REP_PROTOCOL_BASE || 2089*0Sstevel@tonic-gate request_code >= REP_PROTOCOL_BASE + PROTOCOL_ENTRIES) { 2090*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 2091*0Sstevel@tonic-gate goto end; 2092*0Sstevel@tonic-gate } 2093*0Sstevel@tonic-gate 2094*0Sstevel@tonic-gate e = &protocol_table[request_code - REP_PROTOCOL_BASE]; 2095*0Sstevel@tonic-gate 2096*0Sstevel@tonic-gate assert(!(e->pt_flags & PROTO_FLAG_PANIC)); 2097*0Sstevel@tonic-gate 2098*0Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_VARINPUT) { 2099*0Sstevel@tonic-gate if (arg_size < e->pt_in_size) { 2100*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 2101*0Sstevel@tonic-gate goto end; 2102*0Sstevel@tonic-gate } 2103*0Sstevel@tonic-gate } else if (arg_size != e->pt_in_size) { 2104*0Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 2105*0Sstevel@tonic-gate goto end; 2106*0Sstevel@tonic-gate } 2107*0Sstevel@tonic-gate 2108*0Sstevel@tonic-gate if (retsize != e->pt_out_max) { 2109*0Sstevel@tonic-gate retsize = e->pt_out_max; 2110*0Sstevel@tonic-gate retval = alloca(retsize); 2111*0Sstevel@tonic-gate } 2112*0Sstevel@tonic-gate 2113*0Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_RETFD) 2114*0Sstevel@tonic-gate e->pt_fd_handler(cp, argp, arg_size, retval, &retsize, 2115*0Sstevel@tonic-gate e->pt_arg, &retfd); 2116*0Sstevel@tonic-gate else 2117*0Sstevel@tonic-gate e->pt_handler(cp, argp, arg_size, retval, &retsize, e->pt_arg); 2118*0Sstevel@tonic-gate 2119*0Sstevel@tonic-gate end: 2120*0Sstevel@tonic-gate ti->ti_active_client = NULL; 2121*0Sstevel@tonic-gate client_release(cp); 2122*0Sstevel@tonic-gate 2123*0Sstevel@tonic-gate end_unheld: 2124*0Sstevel@tonic-gate if (rlp != NULL) { 2125*0Sstevel@tonic-gate /* LINTED alignment */ 2126*0Sstevel@tonic-gate rlp->rl_response = *(uint32_t *)retval; 2127*0Sstevel@tonic-gate end_log(); 2128*0Sstevel@tonic-gate rlp = NULL; 2129*0Sstevel@tonic-gate } 2130*0Sstevel@tonic-gate ti->ti_client_request = NULL; 2131*0Sstevel@tonic-gate thread_newstate(ti, TI_DOOR_RETURN); 2132*0Sstevel@tonic-gate 2133*0Sstevel@tonic-gate if (retval == (char *)&result) { 2134*0Sstevel@tonic-gate assert(result != INVALID_RESULT && retsize == sizeof (result)); 2135*0Sstevel@tonic-gate } else { 2136*0Sstevel@tonic-gate /* LINTED alignment */ 2137*0Sstevel@tonic-gate result = *(uint32_t *)retval; 2138*0Sstevel@tonic-gate } 2139*0Sstevel@tonic-gate if (retfd != -1) { 2140*0Sstevel@tonic-gate desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE; 2141*0Sstevel@tonic-gate desc.d_data.d_desc.d_descriptor = retfd; 2142*0Sstevel@tonic-gate (void) door_return(retval, retsize, &desc, 1); 2143*0Sstevel@tonic-gate } else { 2144*0Sstevel@tonic-gate (void) door_return(retval, retsize, NULL, 0); 2145*0Sstevel@tonic-gate } 2146*0Sstevel@tonic-gate bad_end: 2147*0Sstevel@tonic-gate if (rlp != NULL) { 2148*0Sstevel@tonic-gate rlp->rl_response = -1; 2149*0Sstevel@tonic-gate end_log(); 2150*0Sstevel@tonic-gate rlp = NULL; 2151*0Sstevel@tonic-gate } 2152*0Sstevel@tonic-gate (void) door_return(NULL, 0, NULL, 0); 2153*0Sstevel@tonic-gate } 2154*0Sstevel@tonic-gate 2155*0Sstevel@tonic-gate int 2156*0Sstevel@tonic-gate create_client(pid_t pid, uint32_t debugflags, int privileged, int *out_fd) 2157*0Sstevel@tonic-gate { 2158*0Sstevel@tonic-gate int fd; 2159*0Sstevel@tonic-gate 2160*0Sstevel@tonic-gate repcache_client_t *cp; 2161*0Sstevel@tonic-gate 2162*0Sstevel@tonic-gate struct door_info info; 2163*0Sstevel@tonic-gate 2164*0Sstevel@tonic-gate int door_flags = DOOR_UNREF | DOOR_REFUSE_DESC; 2165*0Sstevel@tonic-gate #ifdef DOOR_NO_CANCEL 2166*0Sstevel@tonic-gate door_flags |= DOOR_NO_CANCEL; 2167*0Sstevel@tonic-gate #endif 2168*0Sstevel@tonic-gate 2169*0Sstevel@tonic-gate cp = client_alloc(); 2170*0Sstevel@tonic-gate if (cp == NULL) 2171*0Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 2172*0Sstevel@tonic-gate 2173*0Sstevel@tonic-gate (void) pthread_mutex_lock(&client_lock); 2174*0Sstevel@tonic-gate cp->rc_id = ++client_maxid; 2175*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&client_lock); 2176*0Sstevel@tonic-gate 2177*0Sstevel@tonic-gate cp->rc_all_auths = privileged; 2178*0Sstevel@tonic-gate cp->rc_pid = pid; 2179*0Sstevel@tonic-gate cp->rc_debug = debugflags; 2180*0Sstevel@tonic-gate 2181*0Sstevel@tonic-gate cp->rc_doorfd = door_create(client_switcher, (void *)cp->rc_id, 2182*0Sstevel@tonic-gate door_flags); 2183*0Sstevel@tonic-gate 2184*0Sstevel@tonic-gate if (cp->rc_doorfd < 0) { 2185*0Sstevel@tonic-gate client_free(cp); 2186*0Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 2187*0Sstevel@tonic-gate } 2188*0Sstevel@tonic-gate #ifdef DOOR_PARAM_DATA_MIN 2189*0Sstevel@tonic-gate (void) door_setparam(cp->rc_doorfd, DOOR_PARAM_DATA_MIN, 2190*0Sstevel@tonic-gate sizeof (enum rep_protocol_requestid)); 2191*0Sstevel@tonic-gate #endif 2192*0Sstevel@tonic-gate 2193*0Sstevel@tonic-gate if ((fd = dup(cp->rc_doorfd)) < 0 || 2194*0Sstevel@tonic-gate door_info(cp->rc_doorfd, &info) < 0) { 2195*0Sstevel@tonic-gate if (fd >= 0) 2196*0Sstevel@tonic-gate (void) close(fd); 2197*0Sstevel@tonic-gate (void) door_revoke(cp->rc_doorfd); 2198*0Sstevel@tonic-gate cp->rc_doorfd = -1; 2199*0Sstevel@tonic-gate client_free(cp); 2200*0Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 2201*0Sstevel@tonic-gate } 2202*0Sstevel@tonic-gate 2203*0Sstevel@tonic-gate rc_pg_notify_init(&cp->rc_pg_notify); 2204*0Sstevel@tonic-gate rc_notify_info_init(&cp->rc_notify_info); 2205*0Sstevel@tonic-gate 2206*0Sstevel@tonic-gate client_insert(cp); 2207*0Sstevel@tonic-gate 2208*0Sstevel@tonic-gate cp->rc_doorid = info.di_uniquifier; 2209*0Sstevel@tonic-gate *out_fd = fd; 2210*0Sstevel@tonic-gate 2211*0Sstevel@tonic-gate return (REPOSITORY_DOOR_SUCCESS); 2212*0Sstevel@tonic-gate } 2213