homedir.c revision 38494
1/* 2 * Copyright (c) 1997-1998 Erez Zadok 3 * Copyright (c) 1989 Jan-Simon Pendry 4 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine 5 * Copyright (c) 1989 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry at Imperial College, London. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * %W% (Berkeley) %G% 40 * 41 * $Id: homedir.c,v 1.16 1993/09/13 15:11:00 ezk Exp $ 42 * 43 * HLFSD was written at Columbia University Computer Science Department, by 44 * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu> 45 * It is being distributed under the same terms and conditions as amd does. 46 */ 47 48#ifdef HAVE_CONFIG_H 49# include <config.h> 50#endif /* HAVE_CONFIG_H */ 51#include <am_defs.h> 52#include <hlfsd.h> 53 54 55/* 56 * STATIC VARIABLES AND FUNCTIONS: 57 */ 58static FILE *passwd_fp = NULL; 59static char pw_name[16], pw_dir[128]; 60static int cur_pwtab_num = 0, max_pwtab_num = 0; 61static int hlfsd_diskspace(char *); 62static int hlfsd_stat(char *, struct stat *); 63static int passwd_line = 0; 64static int plt_reset(void); 65static struct passwd passwd_ent; 66static uid2home_t *lastchild; 67static uid2home_t *pwtab; 68static void delay(uid2home_t *, int); 69static void table_add(int, char *, char *); 70 71/* GLOBAL FUNCTIONS */ 72char *homeof(char *username); 73int uidof(char *username); 74 75/* GLOBALS VARIABLES */ 76char mboxfile[MAXPATHLEN]; 77username2uid_t *untab; /* user name table */ 78 79 80/* 81 * Return the home directory pathname for the user with uid "userid". 82 */ 83char * 84homedir(int userid) 85{ 86 static char linkval[MAXPATHLEN + 1]; 87 static struct timeval tp; 88 uid2home_t *found; 89 char *homename; 90 struct stat homestat; 91 92 clock_valid = 0; /* invalidate logging clock */ 93 94 if ((int) userid == 0) { /* force superuser to use "/" as home */ 95 sprintf(linkval, "/%s", home_subdir); 96 return linkval; 97 } 98 if ((found = plt_search(userid)) == (uid2home_t *) NULL) { 99 return alt_spooldir; /* use alt spool for unknown uid */ 100 } 101 homename = found->home; 102 103 if (homename[0] != '/' || homename[1] == '\0') { 104 found->last_status = 1; 105 return alt_spooldir; /* use alt spool for / or rel. home */ 106 } 107 sprintf(linkval, "%s/%s", homename, home_subdir); 108 109 if (noverify) { 110 found->last_status = 0; 111 return linkval; 112 } 113 114 /* 115 * To optimize hlfsd, we don't actually check the validity of the 116 * symlink if it has been in checked in the last N seconds. It is 117 * very likely that the link, machine, and filesystem are still 118 * valid, as long as N is small. But if N ls large, that may not be 119 * true. That's why the default N is 5 minutes, but we allow the 120 * user to override this value via a command line option. Note that 121 * we do not update the last_access_time each time it is accessed, 122 * but only once every N seconds. 123 */ 124 if (gettimeofday(&tp, (struct timezone *) NULL) < 0) { 125 tp.tv_sec = 0; 126 } else { 127 if ((tp.tv_sec - found->last_access_time) < cache_interval) { 128 if (found->last_status == 0) { 129 return linkval; 130 } else { 131 return alt_spooldir; 132 } 133 } else { 134 found->last_access_time = tp.tv_sec; 135 } 136 } 137 138#ifdef DEBUG 139 /* 140 * only run this forking code if asked for -D fork 141 * or if did not ask for -D nofork 142 */ 143 amuDebug(D_FORK) { 144#endif /* DEBUG */ 145 /* fork child to process request if none in progress */ 146 if (found->child && kill(found->child, 0)) 147 found->child = 0; 148 149 if (found->child) 150 delay(found, 5); /* wait a bit if in progress */ 151 if (found->child) { /* better safe than sorry - maybe */ 152 found->last_status = 1; 153 return alt_spooldir; 154 } 155 if ((found->child = fork()) < 0) { 156 found->last_status = 1; 157 return alt_spooldir; 158 } 159 if (found->child) { /* PARENT */ 160#ifdef DEBUG 161 if (lastchild) 162 plog(XLOG_INFO, "cache spill uid = %d, pid = %d, home = %s", 163 lastchild->uid, lastchild->child, 164 lastchild->home); 165#endif /* DEBUG */ 166 lastchild = found; 167 return (char *) NULL; /* return NULL to parent, so it can continue */ 168 } 169#ifdef DEBUG 170 } /* end of Debug(D_FORK) */ 171#endif /* DEBUG */ 172 173 /* 174 * CHILD: (or parent if -D nofork) 175 * 176 * Check and create dir if needed. 177 * Check disk space and/or quotas too. 178 * 179 * We don't need to set the _last_status field of found after the fork 180 * in the child, b/c that information would be later determined in 181 * nfsproc_readlink_2() and the correct exit status would be returned 182 * to the parent upon SIGCHLD in interlock(). 183 * 184 */ 185 mypid = getpid(); /* for logging routines */ 186 if (seteuid(userid) < 0) { 187 plog(XLOG_WARNING, "could not seteuid to %d: %m", userid); 188 return linkval; 189 } 190 if (hlfsd_stat(linkval, &homestat) < 0) { 191 if (errno == ENOENT) { /* make the spool dir if possible */ 192 /* don't use recursive mkdirs here */ 193 if (mkdir(linkval, PERS_SPOOLMODE) < 0) { 194 seteuid(0); 195 plog(XLOG_WARNING, "can't make directory %s: %m", linkval); 196 return alt_spooldir; 197 } 198 /* fall through to testing the disk space / quota */ 199 } else { /* the home dir itself must not exist then */ 200 seteuid(0); 201 plog(XLOG_WARNING, "bad link to %s: %m", linkval); 202 return alt_spooldir; 203 } 204 } 205 206 /* 207 * If gets here, then either the spool dir in the home dir exists, 208 * or it was just created. In either case, we now need to 209 * test if we can create a small file and write at least one 210 * byte into it. This will test that we have both enough inodes 211 * and disk blocks to spare, or they fall within the user's quotas too. 212 * We are still seteuid to the user at this point. 213 */ 214 if (hlfsd_diskspace(linkval) < 0) { 215 seteuid(0); 216 plog(XLOG_WARNING, "no more space in %s: %m", linkval); 217 return alt_spooldir; 218 } else { 219 seteuid(0); 220 return linkval; 221 } 222} 223 224 225static int 226hlfsd_diskspace(char *path) 227{ 228 char buf[MAXPATHLEN]; 229 int fd, len; 230 231 clock_valid = 0; /* invalidate logging clock */ 232 233 sprintf(buf, "%s/._hlfstmp_%lu", path, (long) getpid()); 234 if ((fd = open(buf, O_RDWR | O_CREAT, 0600)) < 0) { 235 plog(XLOG_ERROR, "cannot open %s: %m", buf); 236 return -1; 237 } 238 len = strlen(buf); 239 if (write(fd, buf, len) < len) { 240 plog(XLOG_ERROR, "cannot write \"%s\" (%d bytes) to %s : %m", buf, len, buf); 241 close(fd); 242 unlink(buf); /* cleanup just in case */ 243 return -1; 244 } 245 if (unlink(buf) < 0) { 246 plog(XLOG_ERROR, "cannot unlink %s : %m", buf); 247 } 248 close(fd); 249 return 0; 250} 251 252 253static int 254hlfsd_stat(char *path, struct stat *statp) 255{ 256 if (stat(path, statp) < 0) 257 return -1; 258 else if (!S_ISDIR(statp->st_mode)) { 259 errno = ENOTDIR; 260 return -1; 261 } 262 return 0; 263} 264 265 266static void 267delay(uid2home_t *found, int secs) 268{ 269 struct timeval tv; 270 271#ifdef DEBUG 272 if (found) 273 dlog("delaying on child %d for %d seconds", found->child, secs); 274#endif /* DEBUG */ 275 276 tv.tv_usec = 0; 277 278 do { 279 tv.tv_sec = secs; 280 if (select(0, 0, 0, 0, &tv) == 0) 281 break; 282 } while (--secs && found->child); 283} 284 285 286/* 287 * This function is called when a child has terminated after 288 * servicing an nfs request. We need to check the exit status and 289 * update the last_status field of the requesting user. 290 */ 291RETSIGTYPE 292interlock(int signum) 293{ 294 int child; 295 uid2home_t *lostchild; 296 int status; 297 298#ifdef HAVE_WAITPID 299 while ((child = waitpid((pid_t) -1, &status, WNOHANG)) > 0) { 300#else /* not HAVE_WAITPID */ 301 while ((child = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0) { 302#endif /* not HAVE_WAITPID */ 303 304 /* high chances this was the last child forked */ 305 if (lastchild && lastchild->child == child) { 306 lastchild->child = 0; 307 308 if (WIFEXITED(status)) 309 lastchild->last_status = WEXITSTATUS(status); 310 lastchild = (uid2home_t *) NULL; 311 } else { 312 /* and if not, we have to search for it... */ 313 for (lostchild = pwtab; lostchild < &pwtab[cur_pwtab_num]; lostchild++) { 314 if (lostchild->child == child) { 315 if (WIFEXITED(status)) 316 lostchild->last_status = WEXITSTATUS(status); 317 lostchild->child = 0; 318 break; 319 } 320 } 321 } 322 } 323} 324 325 326/* 327 * PASSWORD AND USERNAME LOOKUP TABLES FUNCTIONS 328 */ 329 330/* 331 * get index of UserName table entry which matches username. 332 * must not return uid_t because we want to return a negative number. 333 */ 334int 335untab_index(char *username) 336{ 337 int max, min, mid, cmp; 338 339 max = cur_pwtab_num - 1; 340 min = 0; 341 342 do { 343 mid = (max + min) / 2; 344 cmp = strcmp(untab[mid].username, username); 345 if (cmp == 0) /* record found! */ 346 return mid; 347 if (cmp > 0) 348 max = mid; 349 else 350 min = mid; 351 } while (max > min + 1); 352 353 if (STREQ(untab[max].username, username)) 354 return max; 355 if (STREQ(untab[min].username, username)) 356 return min; 357 358 /* if gets here then record was not found */ 359 return -1; 360} 361 362 363/* 364 * Don't make this return a uid_t, because we need to return negative 365 * numbers as well (error codes.) 366 */ 367int 368uidof(char *username) 369{ 370 int idx; 371 372 if ((idx = untab_index(username)) < 0) /* not found */ 373 return INVALIDID; /* an invalid user id */ 374 return untab[idx].uid; 375} 376 377 378/* 379 * Don't make this return a uid_t, because we need to return negative 380 * numbers as well (error codes.) 381 */ 382char * 383homeof(char *username) 384{ 385 int idx; 386 387 if ((idx = untab_index(username)) < 0) /* not found */ 388 return (char *) NULL; /* an invalid user id */ 389 return untab[idx].home; 390} 391 392 393char * 394mailbox(int uid, char *username) 395{ 396 char *home; 397 398 if (uid < 0) 399 return (char *) NULL; /* not found */ 400 401 if ((home = homeof(username)) == (char *) NULL) 402 return (char *) NULL; 403 if (STREQ(home, "/")) 404 sprintf(mboxfile, "/%s/%s", home_subdir, username); 405 else 406 sprintf(mboxfile, "%s/%s/%s", home, home_subdir, username); 407 return mboxfile; 408} 409 410 411static int 412plt_compare_fxn(const voidp x, const voidp y) 413 414{ 415 uid2home_t *i = (uid2home_t *) x; 416 uid2home_t *j = (uid2home_t *) y; 417 418 return i->uid - j->uid; 419} 420 421 422static int 423unt_compare_fxn(const voidp x, const voidp y) 424{ 425 username2uid_t *i = (username2uid_t *) x; 426 username2uid_t *j = (username2uid_t *) y; 427 428 return strcmp(i->username, j->username); 429} 430 431 432/* perform initialization of user passwd database */ 433static void 434hlfsd_setpwent(void) 435{ 436 if (!passwdfile) { 437 setpwent(); 438 return; 439 } 440 441 passwd_fp = fopen(passwdfile, "r"); 442 if (!passwd_fp) { 443 plog(XLOG_ERROR, "unable to read passwd file %s: %m", passwdfile); 444 return; 445 } 446 plog(XLOG_INFO, "reading password entries from file %s", passwdfile); 447 448 passwd_line = 0; 449 memset((char *) &passwd_ent, 0, sizeof(struct passwd)); 450 passwd_ent.pw_name = (char *) &pw_name; 451 passwd_ent.pw_dir = (char *) &pw_dir; 452} 453 454 455/* perform de-initialization of user passwd database */ 456static void 457hlfsd_endpwent(void) 458{ 459 if (!passwdfile) { 460 /* 461 * Don't actually run this because we will be making more passwd calls 462 * afterwards. On Solaris 2.5.1, making getpwent() calls after calling 463 * endpwent() results in a memory leak! (and no, even Purify didn't 464 * detect it...) 465 * 466 endpwent(); 467 */ 468 return; 469 } 470 471 if (passwd_fp) { 472 fclose(passwd_fp); 473 } 474} 475 476 477/* perform record reading/parsing of individual passwd database records */ 478static struct passwd * 479hlfsd_getpwent(void) 480{ 481 char buf[256], *cp; 482 483 /* check if to perform standard unix function */ 484 if (!passwdfile) { 485 return getpwent(); 486 } 487 488 clock_valid = 0; /* invalidate logging clock */ 489 490 /* return here to read another entry */ 491readent: 492 493 /* return NULL if reached end of file */ 494 if (feof(passwd_fp)) 495 return NULL; 496 497 pw_name[0] = pw_dir[0] = '\0'; 498 499 /* read records */ 500 buf[0] = '\0'; 501 fgets(buf, 256, passwd_fp); 502 passwd_line++; 503 if (!buf || buf[0] == '\0') 504 goto readent; 505 506 /* read user name */ 507 cp = strtok(buf, ":"); 508 if (!cp || cp[0] == '\0') { 509 plog(XLOG_ERROR, "no user name on line %d of %s", passwd_line, passwdfile); 510 goto readent; 511 } 512 strcpy(pw_name, cp); /* will show up in passwd_ent.pw_name */ 513 514 /* skip passwd */ 515 strtok(NULL, ":"); 516 517 /* read uid */ 518 cp = strtok(NULL, ":"); 519 if (!cp || cp[0] == '\0') { 520 plog(XLOG_ERROR, "no uid on line %d of %s", passwd_line, passwdfile); 521 goto readent; 522 } 523 passwd_ent.pw_uid = atoi(cp); 524 525 /* skip gid and gcos */ 526 strtok(NULL, ":"); 527 strtok(NULL, ":"); 528 529 /* read home dir */ 530 cp = strtok(NULL, ":"); 531 if (!cp || cp[0] == '\0') { 532 plog(XLOG_ERROR, "no home dir on line %d of %s", passwd_line, passwdfile); 533 goto readent; 534 } 535 strcpy(pw_dir, cp); /* will show up in passwd_ent.pw_dir */ 536 537 /* the rest of the fields are unimportant and not being considered */ 538 539 plog(XLOG_USER, "hlfsd_getpwent: name=%s, uid=%d, dir=%s", 540 passwd_ent.pw_name, passwd_ent.pw_uid, passwd_ent.pw_dir); 541 542 return &passwd_ent; 543} 544 545 546/* 547 * read and hash the passwd file or NIS map 548 */ 549void 550plt_init(void) 551{ 552 struct passwd *pent_p; 553 554 if (plt_reset() < 0) /* could not reset table. skip. */ 555 return; 556 557 plog(XLOG_INFO, "reading password map"); 558 559 hlfsd_setpwent(); /* prepare to read passwd entries */ 560 while ((pent_p = hlfsd_getpwent()) != (struct passwd *) NULL) { 561 table_add(pent_p->pw_uid, pent_p->pw_dir, pent_p->pw_name); 562 } 563 hlfsd_endpwent(); 564 565 qsort((char *) pwtab, cur_pwtab_num, sizeof(uid2home_t), 566 plt_compare_fxn); 567 qsort((char *) untab, cur_pwtab_num, sizeof(username2uid_t), 568 unt_compare_fxn); 569 570 plog(XLOG_INFO, "password map read and sorted"); 571} 572 573 574/* 575 * This is essentially so that we don't reset known good lookup tables when a 576 * YP server goes down. 577 */ 578static int 579plt_reset(void) 580{ 581 int i; 582 583 clock_valid = 0; /* invalidate logging clock */ 584 585 hlfsd_setpwent(); 586 if (hlfsd_getpwent() == (struct passwd *) NULL) { 587 hlfsd_endpwent(); 588 return -1; /* did not reset table */ 589 } 590 hlfsd_endpwent(); 591 592 lastchild = (uid2home_t *) NULL; 593 594 if (max_pwtab_num > 0) /* was used already. cleanup old table */ 595 for (i = 0; i < cur_pwtab_num; ++i) { 596 if (pwtab[i].home) { 597 XFREE(pwtab[i].home); 598 pwtab[i].home = (char *) NULL; 599 } 600 pwtab[i].uid = INVALIDID; /* not a valid uid (yet...) */ 601 pwtab[i].child = (pid_t) 0; 602 pwtab[i].uname = (char *) NULL; /* only a ptr to untab[i].username */ 603 if (untab[i].username) { 604 XFREE(untab[i].username); 605 untab[i].username = (char *) NULL; 606 } 607 untab[i].uid = INVALIDID; /* invalid uid */ 608 untab[i].home = (char *) NULL; /* only a ptr to pwtab[i].home */ 609 } 610 cur_pwtab_num = 0; /* zero current size */ 611 612 return 0; /* resetting ok */ 613} 614 615 616/* 617 * u: uid number 618 * h: home directory 619 * n: user ID name 620 */ 621static void 622table_add(int u, char *h, char *n) 623{ 624 int i; 625 626 clock_valid = 0; /* invalidate logging clock */ 627 628 if (max_pwtab_num <= 0) { /* was never initialized */ 629 max_pwtab_num = 1; 630 pwtab = (uid2home_t *) xmalloc(max_pwtab_num * 631 sizeof(uid2home_t)); 632 memset((char *) &pwtab[0], 0, max_pwtab_num * sizeof(uid2home_t)); 633 untab = (username2uid_t *) xmalloc(max_pwtab_num * 634 sizeof(username2uid_t)); 635 memset((char *) &untab[0], 0, max_pwtab_num * sizeof(username2uid_t)); 636 } 637 638 /* check if need more space. */ 639 if (cur_pwtab_num + 1 > max_pwtab_num) { 640 /* need more space in table */ 641 max_pwtab_num *= 2; 642 plog(XLOG_INFO, "reallocating table spaces to %d entries", max_pwtab_num); 643 pwtab = (uid2home_t *) xrealloc(pwtab, 644 sizeof(uid2home_t) * max_pwtab_num); 645 untab = (username2uid_t *) xrealloc(untab, 646 sizeof(username2uid_t) * 647 max_pwtab_num); 648 /* zero out newly added entries */ 649 for (i=cur_pwtab_num; i<max_pwtab_num; ++i) { 650 memset((char *) &pwtab[i], 0, sizeof(uid2home_t)); 651 memset((char *) &untab[i], 0, sizeof(username2uid_t)); 652 } 653 } 654 655 /* do NOT add duplicate entries (this is an O(N^2) algorithm... */ 656 for (i=0; i<cur_pwtab_num; ++i) 657 if (u == pwtab[i].uid && u != 0 ) { 658#ifdef DEBUG 659 dlog("ignoring duplicate home %s for uid %d (already %s)", 660 h, u, pwtab[i].home); 661#endif /* DEBUG */ 662 return; 663 } 664 665 /* add new password entry */ 666 pwtab[cur_pwtab_num].home = strdup(h); 667 pwtab[cur_pwtab_num].child = 0; 668 pwtab[cur_pwtab_num].last_access_time = 0; 669 pwtab[cur_pwtab_num].last_status = 0; /* assume best: used homedir */ 670 pwtab[cur_pwtab_num].uid = u; 671 672 /* add new userhome entry */ 673 untab[cur_pwtab_num].username = strdup(n); 674 675 /* just a second pointer */ 676 pwtab[cur_pwtab_num].uname = untab[cur_pwtab_num].username; 677 untab[cur_pwtab_num].uid = u; 678 untab[cur_pwtab_num].home = pwtab[cur_pwtab_num].home; /* a ptr */ 679 680 /* increment counter */ 681 ++cur_pwtab_num; 682} 683 684 685/* 686 * return entry in lookup table 687 */ 688uid2home_t * 689plt_search(int u) 690{ 691 int max, min, mid; 692 693 /* 694 * empty table should not happen, 695 * but I have a bug with signals to trace... 696 */ 697 if (pwtab == (uid2home_t *) NULL) 698 return (uid2home_t *) NULL; 699 700 max = cur_pwtab_num - 1; 701 min = 0; 702 703 do { 704 mid = (max + min) / 2; 705 if (pwtab[mid].uid == u) /* record found! */ 706 return &pwtab[mid]; 707 if (pwtab[mid].uid > u) 708 max = mid; 709 else 710 min = mid; 711 } while (max > min + 1); 712 713 if (pwtab[max].uid == u) 714 return &pwtab[max]; 715 if (pwtab[min].uid == u) 716 return &pwtab[min]; 717 718 /* if gets here then record was not found */ 719 return (uid2home_t *) NULL; 720} 721 722 723#if defined(DEBUG) || defined(DEBUG_PRINT) 724void 725plt_print(int signum) 726{ 727 FILE *dumpfile; 728 int dumpfd; 729 char dumptmp[] = "/usr/tmp/hlfsd.dump.XXXXXX"; 730 int i; 731 732#ifdef HAVE_MKSTEMP 733 dumpfd = mkstemp(dumptmp); 734#else /* not HAVE_MKSTEMP */ 735 mktemp(dumptmp); 736 if (!dumptmp) { 737 plot(XLOG_ERROR, "cannot create temporary dump file"); 738 return; 739 } 740 dumpfd = open(dumptmp, O_RDONLY); 741#endif /* not HAVE_MKSTEMP */ 742 if (dumpfd < 0) { 743 plog(XLOG_ERROR, "cannot open temporary dump file"); 744 return; 745 } 746 if ((dumpfile = fdopen(dumpfd, "a")) != NULL) { 747 plog(XLOG_INFO, "dumping internal state to file %s", dumptmp); 748 fprintf(dumpfile, "\n\nNew plt_dump():\n"); 749 for (i = 0; i < cur_pwtab_num; ++i) 750 fprintf(dumpfile, 751 "%4d %5lu %10lu %1d %4lu \"%s\" uname=\"%s\"\n", 752 i, 753 (long) pwtab[i].child, 754 pwtab[i].last_access_time, 755 pwtab[i].last_status, 756 (long) pwtab[i].uid, 757 pwtab[i].home, 758 pwtab[i].uname); 759 fprintf(dumpfile, "\nUserName table by plt_print():\n"); 760 for (i = 0; i < cur_pwtab_num; ++i) 761 fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i, 762 untab[i].username, (long) untab[i].uid, untab[i].home); 763 close(dumpfd); 764 fclose(dumpfile); 765 } 766} 767 768 769void 770plt_dump(uid2home_t *lastc, pid_t this) 771{ 772 FILE *dumpfile; 773 int i; 774 775 if ((dumpfile = fopen("/var/tmp/hlfsdump", "a")) != NULL) { 776 fprintf(dumpfile, "\n\nNEW PLT_DUMP -- "); 777 fprintf(dumpfile, "lastchild->child=%d ", 778 (int) (lastc ? lastc->child : -999)); 779 fprintf(dumpfile, ", child from wait3=%lu:\n", (long) this); 780 for (i = 0; i < cur_pwtab_num; ++i) 781 fprintf(dumpfile, "%4d %5lu: %4lu \"%s\" uname=\"%s\"\n", i, 782 (long) pwtab[i].child, (long) pwtab[i].uid, 783 pwtab[i].home, pwtab[i].uname); 784 fprintf(dumpfile, "\nUserName table by plt_dump():\n"); 785 for (i = 0; i < cur_pwtab_num; ++i) 786 fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i, 787 untab[i].username, (long) untab[i].uid, untab[i].home); 788 fprintf(dumpfile, "ezk: ent=%d, uid=%lu, home=\"%s\"\n", 789 untab_index("ezk"), 790 (long) untab[untab_index("ezk")].uid, 791 pwtab[untab[untab_index("ezk")].uid].home); 792 fprintf(dumpfile, "rezk: ent=%d, uid=%lu, home=\"%s\"\n", 793 untab_index("rezk"), 794 (long) untab[untab_index("rezk")].uid, 795 pwtab[untab[untab_index("rezk")].uid].home); 796 fclose(dumpfile); 797 } 798} 799#endif /* defined(DEBUG) || defined(DEBUG_PRINT) */ 800