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