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