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 2008 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 #include <stdlib.h> 29 #include <assert.h> 30 #include <string.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include "nscd_db.h" 34 #include "nscd_log.h" 35 #include "nscd_switch.h" 36 #include "nscd_door.h" 37 38 extern int _whoami; 39 static mutex_t getent_monitor_mutex = DEFAULTMUTEX; 40 static int getent_monitor_started = 0; 41 42 static rwlock_t getent_ctxDB_rwlock = DEFAULTRWLOCK; 43 static nscd_db_t *getent_ctxDB = NULL; 44 45 /* 46 * internal structure representing a nscd getent context 47 */ 48 typedef struct nscd_getent_ctx { 49 int to_delete; /* this ctx no longer valid */ 50 nscd_getent_context_t *ptr; 51 nscd_cookie_num_t cookie_num; 52 } nscd_getent_ctx_t; 53 54 /* 55 * nscd_getent_context_t list for each nss database. Protected 56 * by the readers/writer lock nscd_getent_ctx_lock. 57 */ 58 nscd_getent_ctx_base_t **nscd_getent_ctx_base; 59 static rwlock_t nscd_getent_ctx_base_lock = DEFAULTRWLOCK; 60 61 extern nscd_db_entry_t *_nscd_walk_db(nscd_db_t *db, void **cookie); 62 63 static nscd_rc_t _nscd_init_getent_ctx_monitor(); 64 65 /* 66 * FUNCTION: _nscd_create_getent_ctxDB 67 * 68 * Create the internal getent context database to keep track of the 69 * getent contexts currently being used. 70 */ 71 nscd_db_t * 72 _nscd_create_getent_ctxDB() 73 { 74 75 nscd_db_t *ret; 76 77 (void) rw_wrlock(&getent_ctxDB_rwlock); 78 79 if (getent_ctxDB != NULL) { 80 (void) rw_unlock(&getent_ctxDB_rwlock); 81 return (getent_ctxDB); 82 } 83 84 ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE); 85 86 if (ret != NULL) 87 getent_ctxDB = ret; 88 89 (void) rw_unlock(&getent_ctxDB_rwlock); 90 91 return (ret); 92 } 93 94 /* 95 * FUNCTION: _nscd_add_getent_ctx 96 * 97 * Add a getent context to the internal context database. 98 */ 99 static nscd_rc_t 100 _nscd_add_getent_ctx( 101 nscd_getent_context_t *ptr, 102 nscd_cookie_num_t cookie_num) 103 { 104 int size; 105 char buf[32]; 106 nscd_db_entry_t *db_entry; 107 nscd_getent_ctx_t *gnctx; 108 109 if (ptr == NULL) 110 return (NSCD_INVALID_ARGUMENT); 111 112 (void) snprintf(buf, sizeof (buf), "%lld", cookie_num); 113 114 size = sizeof (*gnctx); 115 116 db_entry = _nscd_alloc_db_entry(NSCD_DATA_CTX_ADDR, 117 (const char *)buf, size, 1, 1); 118 if (db_entry == NULL) 119 return (NSCD_NO_MEMORY); 120 121 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 122 gnctx->ptr = ptr; 123 gnctx->cookie_num = cookie_num; 124 125 (void) rw_wrlock(&getent_ctxDB_rwlock); 126 (void) _nscd_add_db_entry(getent_ctxDB, buf, db_entry, 127 NSCD_ADD_DB_ENTRY_FIRST); 128 (void) rw_unlock(&getent_ctxDB_rwlock); 129 130 return (NSCD_SUCCESS); 131 } 132 133 /* 134 * FUNCTION: _nscd_is_getent_ctx 135 * 136 * Check to see if a getent context can be found in the internal 137 * getent context database. 138 */ 139 nscd_getent_context_t * 140 _nscd_is_getent_ctx( 141 nscd_cookie_num_t cookie_num) 142 { 143 char ptrstr[32]; 144 const nscd_db_entry_t *db_entry; 145 nscd_getent_context_t *ret = NULL; 146 147 (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num); 148 149 (void) rw_rdlock(&getent_ctxDB_rwlock); 150 151 db_entry = _nscd_get_db_entry(getent_ctxDB, NSCD_DATA_CTX_ADDR, 152 (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0); 153 154 if (db_entry != NULL) { 155 nscd_getent_ctx_t *gnctx; 156 157 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 158 159 /* 160 * If the ctx is not to be deleted and the cookie number 161 * match, return the ctx if not aborted and not in use, 162 * Otherwise return NULL. 163 */ 164 if (gnctx->to_delete == 0 && gnctx->cookie_num == cookie_num) { 165 ret = gnctx->ptr; 166 (void) mutex_lock(&gnctx->ptr->getent_mutex); 167 if (ret->aborted == 1 || ret->in_use == 1) 168 ret = NULL; 169 else 170 ret->in_use = 1; 171 (void) mutex_unlock(&gnctx->ptr->getent_mutex); 172 } 173 } 174 175 (void) rw_unlock(&getent_ctxDB_rwlock); 176 177 return (ret); 178 } 179 180 /* 181 * FUNCTION: _nscd_free_ctx_if_aborted 182 * 183 * Check to see if the getent session associated with a getent context had 184 * been aborted. If so, return the getent context back to the pool. 185 */ 186 void 187 _nscd_free_ctx_if_aborted( 188 nscd_getent_context_t *ctx) 189 { 190 int aborted; 191 char *me = "_nscd_free_ctx_if_aborted"; 192 193 if (ctx->in_use != 1) 194 return; 195 196 (void) mutex_lock(&ctx->getent_mutex); 197 aborted = ctx->aborted; 198 (void) mutex_unlock(&ctx->getent_mutex); 199 200 if (aborted == 1) { 201 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 202 (me, "getent session aborted, return the getent context\n"); 203 _nscd_put_getent_ctx(ctx); 204 } 205 ctx->in_use = 0; 206 } 207 208 /* 209 * FUNCTION: _nscd_del_getent_ctx 210 * 211 * Delete a getent context from the internal getent context database. 212 */ 213 static void 214 _nscd_del_getent_ctx( 215 nscd_getent_context_t *ptr, 216 nscd_cookie_num_t cookie_num) 217 { 218 char ptrstr[32]; 219 nscd_getent_ctx_t *gnctx; 220 const nscd_db_entry_t *db_entry; 221 222 if (ptr == NULL) 223 return; 224 225 (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num); 226 227 (void) rw_rdlock(&getent_ctxDB_rwlock); 228 /* 229 * first find the db entry and make sure the 230 * sequence number matched, then delete it from 231 * the database. 232 */ 233 db_entry = _nscd_get_db_entry(getent_ctxDB, 234 NSCD_DATA_CTX_ADDR, 235 (const char *)ptrstr, 236 NSCD_GET_FIRST_DB_ENTRY, 0); 237 if (db_entry != NULL) { 238 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 239 if (gnctx->ptr == ptr && gnctx->cookie_num == cookie_num) { 240 241 (void) rw_unlock(&getent_ctxDB_rwlock); 242 (void) rw_wrlock(&getent_ctxDB_rwlock); 243 244 (void) _nscd_delete_db_entry(getent_ctxDB, 245 NSCD_DATA_CTX_ADDR, 246 (const char *)ptrstr, 247 NSCD_DEL_FIRST_DB_ENTRY, 0); 248 } 249 } 250 (void) rw_unlock(&getent_ctxDB_rwlock); 251 } 252 253 static void 254 _nscd_free_getent_ctx( 255 nscd_getent_context_t *gnctx) 256 { 257 258 char *me = "_nscd_free_getent_ctx"; 259 260 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 261 (me, "getent context %p\n", gnctx); 262 263 _nscd_put_nsw_state(gnctx->nsw_state); 264 _nscd_del_getent_ctx(gnctx, gnctx->cookie_num); 265 free(gnctx); 266 } 267 268 269 static void 270 _nscd_free_getent_ctx_base( 271 nscd_acc_data_t *data) 272 { 273 nscd_getent_ctx_base_t *base = (nscd_getent_ctx_base_t *)data; 274 nscd_getent_context_t *c, *tc; 275 char *me = "_nscd_free_getent_ctx_base"; 276 277 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 278 (me, "getent context base %p\n", base); 279 280 if (base == NULL) 281 return; 282 283 c = base->first; 284 while (c != NULL) { 285 tc = c->next; 286 _nscd_free_getent_ctx(c); 287 c = tc; 288 } 289 } 290 291 void 292 _nscd_free_all_getent_ctx_base() 293 { 294 nscd_getent_ctx_base_t *base; 295 int i; 296 char *me = "_nscd_free_all_getent_ctx_base"; 297 298 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 299 (me, "entering ..\n"); 300 301 (void) rw_wrlock(&nscd_getent_ctx_base_lock); 302 303 for (i = 0; i < NSCD_NUM_DB; i++) { 304 305 base = nscd_getent_ctx_base[i]; 306 if (base == NULL) 307 continue; 308 309 nscd_getent_ctx_base[i] = (nscd_getent_ctx_base_t *) 310 _nscd_set((nscd_acc_data_t *)base, NULL); 311 } 312 (void) rw_unlock(&nscd_getent_ctx_base_lock); 313 } 314 315 static nscd_getent_context_t * 316 _nscd_create_getent_ctx( 317 nscd_nsw_params_t *params) 318 { 319 nscd_getent_context_t *gnctx; 320 nss_db_root_t db_root; 321 char *me = "_nscd_create_getent_ctx"; 322 323 gnctx = calloc(1, sizeof (nscd_getent_context_t)); 324 if (gnctx == NULL) 325 return (NULL); 326 else { 327 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 328 (me, "getent context allocated %p\n", gnctx); 329 } 330 331 gnctx->dbi = params->dbi; 332 gnctx->cookie_num = _nscd_get_cookie_num(); 333 gnctx->pid = -1; 334 (void) mutex_init(&gnctx->getent_mutex, USYNC_THREAD, NULL); 335 336 if (_nscd_get_nsw_state(&db_root, params) != NSCD_SUCCESS) { 337 free(gnctx); 338 return (NULL); 339 } 340 gnctx->nsw_state = (nscd_nsw_state_t *)db_root.s; 341 /* this is a nsw_state used for getent processing */ 342 gnctx->nsw_state->getent = 1; 343 344 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 345 (me, "got nsw_state %p\n", gnctx->nsw_state); 346 347 return (gnctx); 348 } 349 350 351 nscd_rc_t 352 _nscd_get_getent_ctx( 353 nss_getent_t *contextpp, 354 nscd_nsw_params_t *params) 355 { 356 357 nscd_getent_context_t *c; 358 nscd_getent_ctx_base_t *base, *tmp; 359 nscd_rc_t rc; 360 char *me = "_nscd_get_getent_ctx"; 361 362 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 363 (me, "entering ...\n"); 364 365 (void) rw_rdlock(&nscd_getent_ctx_base_lock); 366 base = nscd_getent_ctx_base[params->dbi]; 367 (void) rw_unlock(&nscd_getent_ctx_base_lock); 368 assert(base != NULL); 369 370 /* 371 * If the context list is not empty, return the first one 372 * on the list. Otherwise, create and return a new one if 373 * limit is not reached. if reacehed, wait for the 'one is 374 * available' signal. 375 */ 376 tmp = (nscd_getent_ctx_base_t *)_nscd_mutex_lock( 377 (nscd_acc_data_t *)base); 378 assert(base == tmp); 379 if (base->first == NULL) { 380 if (base->num_getent_ctx == base->max_getent_ctx) { 381 base->num_waiter++; 382 while (base->first == NULL) { 383 384 _NSCD_LOG(NSCD_LOG_GETENT_CTX, 385 NSCD_LOG_LEVEL_DEBUG) 386 (me, "waiting for signal\n"); 387 388 _nscd_cond_wait((nscd_acc_data_t *)base, NULL); 389 390 _NSCD_LOG(NSCD_LOG_GETENT_CTX, 391 NSCD_LOG_LEVEL_DEBUG) 392 (me, "woke up\n"); 393 } 394 base->num_waiter--; 395 } else { 396 base->first = _nscd_create_getent_ctx(params); 397 if (base->first != NULL) { 398 base->first->base = base; 399 base->num_getent_ctx++; 400 } else { 401 /* not able to create an getent ctx */ 402 403 _NSCD_LOG(NSCD_LOG_GETENT_CTX, 404 NSCD_LOG_LEVEL_ERROR) 405 (me, "create getent ctx failed\n"); 406 407 _nscd_mutex_unlock((nscd_acc_data_t *)base); 408 return (NSCD_CREATE_GETENT_CTX_FAILED); 409 } 410 411 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 412 (me, "got a new getent ctx %p\n", base->first); 413 } 414 } 415 416 assert(base->first != NULL); 417 418 c = base->first; 419 base->first = c->next; 420 c->next = NULL; 421 c->seq_num = 1; 422 c->in_use = 1; 423 424 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 425 (me, "got a getent ctx %p\n", c); 426 427 _nscd_mutex_unlock((nscd_acc_data_t *)base); 428 429 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 430 (me, "adding new ctx %p, cookie # = %lld\n", c, c->cookie_num); 431 432 if ((rc = _nscd_add_getent_ctx(c, c->cookie_num)) != NSCD_SUCCESS) { 433 _nscd_put_getent_ctx(c); 434 return (rc); 435 } 436 contextpp->ctx = (struct nss_getent_context *)c; 437 438 /* start monitor and reclaim orphan getent context */ 439 if (getent_monitor_started == 0) { 440 (void) mutex_lock(&getent_monitor_mutex); 441 if (getent_monitor_started == 0) { 442 getent_monitor_started = 1; 443 (void) _nscd_init_getent_ctx_monitor(); 444 } 445 (void) mutex_unlock(&getent_monitor_mutex); 446 } 447 448 return (NSCD_SUCCESS); 449 } 450 451 void 452 _nscd_put_getent_ctx( 453 nscd_getent_context_t *gnctx) 454 { 455 456 nscd_getent_ctx_base_t *base; 457 char *me = "_nscd_put_getent_ctx"; 458 459 base = gnctx->base; 460 gnctx->seq_num = 0; 461 462 /* if context base is gone, so should this context */ 463 if ((_nscd_mutex_lock((nscd_acc_data_t *)base)) == NULL) { 464 _nscd_free_getent_ctx(gnctx); 465 return; 466 } 467 468 if (base->first != NULL) { 469 gnctx->next = base->first; 470 base->first = gnctx; 471 } else 472 base->first = gnctx; 473 474 /* put back the db state */ 475 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 476 (me, "putting back nsw state %p\n", gnctx->nsw_state); 477 478 /* this nsw_state is no longer used for getent processing */ 479 if (gnctx->nsw_state != NULL) 480 gnctx->nsw_state->getent = 0; 481 _nscd_put_nsw_state(gnctx->nsw_state); 482 gnctx->nsw_state = NULL; 483 484 gnctx->aborted = 0; 485 gnctx->in_use = 0; 486 _nscd_del_getent_ctx(gnctx, gnctx->cookie_num); 487 488 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 489 (me, "ctx (%p, cookie # = %lld) removed from getent ctx DB\n", 490 gnctx, gnctx->cookie_num); 491 492 if (base->num_waiter > 0) { 493 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 494 (me, "signaling (waiter = %d)\n", base->num_waiter); 495 496 _nscd_cond_signal((nscd_acc_data_t *)base); 497 } 498 499 _nscd_mutex_unlock((nscd_acc_data_t *)base); 500 } 501 502 nscd_rc_t 503 _nscd_init_getent_ctx_base( 504 int dbi, 505 int lock) 506 { 507 nscd_getent_ctx_base_t *base = NULL; 508 char *me = "_nscd_init_getent_ctx_base"; 509 510 if (lock) 511 (void) rw_rdlock(&nscd_getent_ctx_base_lock); 512 513 base = (nscd_getent_ctx_base_t *)_nscd_alloc( 514 NSCD_DATA_GETENT_CTX_BASE, 515 sizeof (nscd_getent_ctx_base_t), 516 _nscd_free_getent_ctx_base, 517 NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND); 518 519 if (base == NULL) { 520 if (lock) 521 (void) rw_unlock(&nscd_getent_ctx_base_lock); 522 return (NSCD_NO_MEMORY); 523 } 524 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 525 (me, "base %p allocated\n", base); 526 527 /* 528 * initialize and activate the new getent_ctx base 529 */ 530 base->dbi = dbi; 531 base->max_getent_ctx = NSCD_SW_CFG(dbi).max_getent_ctx_per_db; 532 nscd_getent_ctx_base[dbi] = 533 (nscd_getent_ctx_base_t *)_nscd_set( 534 (nscd_acc_data_t *)nscd_getent_ctx_base[dbi], 535 (nscd_acc_data_t *)base); 536 537 if (lock) 538 (void) rw_unlock(&nscd_getent_ctx_base_lock); 539 540 return (NSCD_SUCCESS); 541 } 542 543 nscd_rc_t 544 _nscd_init_all_getent_ctx_base() 545 { 546 int i; 547 nscd_rc_t rc; 548 char *me = "_nscd_init_all_getent_ctx_base"; 549 550 (void) rw_wrlock(&nscd_getent_ctx_base_lock); 551 552 for (i = 0; i < NSCD_NUM_DB; i++) { 553 554 rc = _nscd_init_getent_ctx_base(i, 0); 555 556 if (rc != NSCD_SUCCESS) { 557 (void) rw_unlock(&nscd_getent_ctx_base_lock); 558 return (rc); 559 } 560 } 561 562 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 563 (me, "all getent context base initialized\n"); 564 565 (void) rw_unlock(&nscd_getent_ctx_base_lock); 566 567 return (NSCD_SUCCESS); 568 } 569 nscd_rc_t 570 _nscd_alloc_getent_ctx_base() 571 { 572 573 (void) rw_wrlock(&nscd_getent_ctx_base_lock); 574 575 nscd_getent_ctx_base = calloc(NSCD_NUM_DB, 576 sizeof (nscd_getent_ctx_base_t *)); 577 if (nscd_getent_ctx_base == NULL) { 578 (void) rw_unlock(&nscd_getent_ctx_base_lock); 579 return (NSCD_NO_MEMORY); 580 } 581 582 (void) rw_unlock(&nscd_getent_ctx_base_lock); 583 584 return (NSCD_SUCCESS); 585 } 586 587 static int 588 process_exited(pid_t pid) 589 { 590 char pname[PATH_MAX]; 591 int fd; 592 593 (void) snprintf(pname, sizeof (pname), "/proc/%d/psinfo", pid); 594 if ((fd = open(pname, O_RDONLY)) == -1) 595 return (1); 596 else { 597 (void) close(fd); 598 return (0); 599 } 600 } 601 602 /* 603 * FUNCTION: reclaim_getent_ctx 604 */ 605 /*ARGSUSED*/ 606 static void * 607 reclaim_getent_ctx(void *arg) 608 { 609 void *cookie = NULL; 610 nscd_db_entry_t *ep; 611 nscd_getent_ctx_t *ctx; 612 nscd_getent_context_t *gctx, *c; 613 nscd_getent_context_t *first = NULL, *last = NULL; 614 char *me = "reclaim_getent_ctx"; 615 616 /*CONSTCOND*/ 617 while (1) { 618 619 (void) sleep(60); 620 621 (void) rw_rdlock(&getent_ctxDB_rwlock); 622 623 for (ep = _nscd_walk_db(getent_ctxDB, &cookie); ep != NULL; 624 ep = _nscd_walk_db(getent_ctxDB, &cookie)) { 625 626 ctx = (nscd_getent_ctx_t *)*(ep->data_array); 627 628 gctx = ctx->ptr; 629 630 /* 631 * if the client process, which did the setent, 632 * exited, add the context to the orphan list 633 */ 634 if (gctx->pid != -1 && process_exited(gctx->pid)) { 635 636 _NSCD_LOG(NSCD_LOG_GETENT_CTX, 637 NSCD_LOG_LEVEL_DEBUG) 638 (me, "process %d exited, " 639 "getent context = %p, " 640 "db index = %d, cookie # = %lld, " 641 "sequence # = %lld\n", 642 gctx->pid, gctx, gctx->dbi, 643 gctx->cookie_num, gctx->seq_num); 644 645 if (first != NULL) { 646 last->next = gctx; 647 last = gctx; 648 } else { 649 first = gctx; 650 last = gctx; 651 } 652 } 653 } 654 655 (void) rw_unlock(&getent_ctxDB_rwlock); 656 657 658 /* 659 * return all the orphan getent contexts to the pool if not 660 * in use 661 */ 662 for (gctx = first; gctx; ) { 663 int in_use; 664 c = gctx->next; 665 gctx->aborted = 1; 666 (void) mutex_lock(&gctx->getent_mutex); 667 in_use = gctx->in_use; 668 (void) mutex_unlock(&gctx->getent_mutex); 669 if (in_use != 1) { 670 gctx->next = NULL; 671 _nscd_put_getent_ctx(gctx); 672 } 673 gctx = c; 674 } 675 first = last = NULL; 676 } 677 /*NOTREACHED*/ 678 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 679 } 680 681 static nscd_rc_t 682 _nscd_init_getent_ctx_monitor() { 683 684 int errnum; 685 char *me = "_nscd_init_getent_ctx_monitor"; 686 687 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 688 (me, "initializing the getent context monitor\n"); 689 690 /* 691 * the forker nscd does not process getent requests 692 * so no need to monitor orphan getent contexts 693 */ 694 if (_whoami == NSCD_FORKER) 695 return (NSCD_SUCCESS); 696 697 /* 698 * start a thread to reclaim unused getent contexts 699 */ 700 if (thr_create(NULL, NULL, reclaim_getent_ctx, 701 NULL, THR_DETACHED, NULL) != 0) { 702 errnum = errno; 703 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR) 704 (me, "thr_create: %s\n", strerror(errnum)); 705 return (NSCD_THREAD_CREATE_ERROR); 706 } 707 708 return (NSCD_SUCCESS); 709 } 710