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