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