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