]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/amd/hlfsd/homedir.c
Implement pci_enable_msi() and pci_disable_msi() in the LinuxKPI.
[FreeBSD/FreeBSD.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   if (fgets(buf, 256, passwd_fp) == NULL)
494     return NULL;
495   passwd_line++;
496   if (buf[0] == '\0')
497     goto readent;
498
499   /* read user name */
500   cp = strtok(buf, ":");
501   if (!cp || cp[0] == '\0') {
502     plog(XLOG_ERROR, "no user name on line %d of %s", passwd_line, passwdfile);
503     goto readent;
504   }
505   /* pw_name will show up in passwd_ent.pw_name */
506   xstrlcpy(pw_name, cp, sizeof(pw_name));
507
508   /* skip passwd */
509   strtok(NULL, ":");
510
511   /* read uid */
512   cp = strtok(NULL, ":");
513   if (!cp || cp[0] == '\0') {
514     plog(XLOG_ERROR, "no uid on line %d of %s", passwd_line, passwdfile);
515     goto readent;
516   }
517   passwd_ent.pw_uid = atoi(cp);
518
519   /* skip gid and gcos */
520   strtok(NULL, ":");
521   strtok(NULL, ":");
522
523   /* read home dir */
524   cp = strtok(NULL, ":");
525   if (!cp || cp[0] == '\0') {
526     plog(XLOG_ERROR, "no home dir on line %d of %s", passwd_line,  passwdfile);
527     goto readent;
528   }
529   /* pw_dir will show up in passwd_ent.pw_dir */
530   xstrlcpy(pw_dir, cp, sizeof(pw_dir));
531
532   /* the rest of the fields are unimportant and not being considered */
533
534   plog(XLOG_USER, "hlfsd_getpwent: name=%s, uid=%ld, dir=%s",
535        passwd_ent.pw_name, (long) passwd_ent.pw_uid, passwd_ent.pw_dir);
536
537   return &passwd_ent;
538 }
539
540
541 /*
542  * read and hash the passwd file or NIS map
543  */
544 void
545 plt_init(void)
546 {
547   struct passwd *pent_p;
548
549   if (plt_reset() < 0)          /* could not reset table. skip. */
550     return;
551
552   plog(XLOG_INFO, "reading password map");
553
554   hlfsd_setpwent();                     /* prepare to read passwd entries */
555   while ((pent_p = hlfsd_getpwent()) != (struct passwd *) NULL) {
556     table_add(pent_p->pw_uid, pent_p->pw_dir, pent_p->pw_name);
557     if (STREQ("root", pent_p->pw_name)) {
558       int len;
559       if (root_home)
560         XFREE(root_home);
561       root_home = xstrdup(pent_p->pw_dir);
562       len = strlen(root_home);
563       /* remove any trailing '/' chars from root's home (even if just one) */
564       while (len > 0 && root_home[len - 1] == '/') {
565         len--;
566         root_home[len] = '\0';
567       }
568     }
569   }
570   hlfsd_endpwent();
571
572   qsort((char *) pwtab, cur_pwtab_num, sizeof(uid2home_t),
573         plt_compare_fxn);
574   qsort((char *) untab, cur_pwtab_num, sizeof(username2uid_t),
575         unt_compare_fxn);
576
577   if (!root_home)
578     root_home = xstrdup("");
579
580   plog(XLOG_INFO, "password map read and sorted");
581 }
582
583
584 /*
585  * This is essentially so that we don't reset known good lookup tables when a
586  * YP server goes down.
587  */
588 static int
589 plt_reset(void)
590 {
591   int i;
592
593   hlfsd_setpwent();
594   if (hlfsd_getpwent() == (struct passwd *) NULL) {
595     hlfsd_endpwent();
596     return -1;                  /* did not reset table */
597   }
598   hlfsd_endpwent();
599
600   lastchild = (uid2home_t *) NULL;
601
602   if (max_pwtab_num > 0)        /* was used already. cleanup old table */
603     for (i = 0; i < cur_pwtab_num; ++i) {
604       if (pwtab[i].home) {
605         XFREE(pwtab[i].home);
606         pwtab[i].home = (char *) NULL;
607       }
608       pwtab[i].uid = INVALIDID; /* not a valid uid (yet...) */
609       pwtab[i].child = (pid_t) 0;
610       pwtab[i].uname = (char *) NULL;   /* only a ptr to untab[i].username */
611       if (untab[i].username) {
612         XFREE(untab[i].username);
613         untab[i].username = (char *) NULL;
614       }
615       untab[i].uid = INVALIDID; /* invalid uid */
616       untab[i].home = (char *) NULL;    /* only a ptr to pwtab[i].home  */
617     }
618   cur_pwtab_num = 0;            /* zero current size */
619
620   if (root_home)
621     XFREE(root_home);
622
623   return 0;                     /* resetting ok */
624 }
625
626
627 /*
628  * u: uid number
629  * h: home directory
630  * n: user ID name
631  */
632 static void
633 table_add(u_int u, const char *h, const char *n)
634 {
635   int i;
636
637   if (max_pwtab_num <= 0) {     /* was never initialized */
638     max_pwtab_num = 1;
639     pwtab = (uid2home_t *) xmalloc(max_pwtab_num *
640                                    sizeof(uid2home_t));
641     memset((char *) &pwtab[0], 0, max_pwtab_num * sizeof(uid2home_t));
642     untab = (username2uid_t *) xmalloc(max_pwtab_num *
643                                        sizeof(username2uid_t));
644     memset((char *) &untab[0], 0, max_pwtab_num * sizeof(username2uid_t));
645   }
646
647   /* check if need more space. */
648   if (cur_pwtab_num + 1 > max_pwtab_num) {
649     /* need more space in table */
650     max_pwtab_num *= 2;
651     plog(XLOG_INFO, "reallocating table spaces to %d entries", max_pwtab_num);
652     pwtab = (uid2home_t *) xrealloc(pwtab,
653                                     sizeof(uid2home_t) * max_pwtab_num);
654     untab = (username2uid_t *) xrealloc(untab,
655                                         sizeof(username2uid_t) *
656                                         max_pwtab_num);
657     /* zero out newly added entries */
658     for (i=cur_pwtab_num; i<max_pwtab_num; ++i) {
659       memset((char *) &pwtab[i], 0, sizeof(uid2home_t));
660       memset((char *) &untab[i], 0, sizeof(username2uid_t));
661     }
662   }
663
664   /* do NOT add duplicate entries (this is an O(N^2) algorithm... */
665   for (i=0; i<cur_pwtab_num; ++i)
666     if (u == pwtab[i].uid  &&  u != 0 ) {
667       dlog("ignoring duplicate home %s for uid %d (already %s)",
668            h, u, pwtab[i].home);
669       return;
670     }
671
672   /* add new password entry */
673   pwtab[cur_pwtab_num].home = xstrdup(h);
674   pwtab[cur_pwtab_num].child = 0;
675   pwtab[cur_pwtab_num].last_access_time = 0;
676   pwtab[cur_pwtab_num].last_status = 0; /* assume best: used homedir */
677   pwtab[cur_pwtab_num].uid = u;
678
679   /* add new userhome entry */
680   untab[cur_pwtab_num].username = xstrdup(n);
681
682   /* just a second pointer */
683   pwtab[cur_pwtab_num].uname = untab[cur_pwtab_num].username;
684   untab[cur_pwtab_num].uid = u;
685   untab[cur_pwtab_num].home = pwtab[cur_pwtab_num].home;        /* a ptr */
686
687   /* increment counter */
688   ++cur_pwtab_num;
689 }
690
691
692 /*
693  * return entry in lookup table
694  */
695 uid2home_t *
696 plt_search(u_int u)
697 {
698   int max, min, mid;
699
700   /*
701    * empty table should not happen,
702    * but I have a bug with signals to trace...
703    */
704   if (pwtab == (uid2home_t *) NULL)
705     return (uid2home_t *) NULL;
706
707   max = cur_pwtab_num - 1;
708   min = 0;
709
710   do {
711     mid = (max + min) / 2;
712     if (pwtab[mid].uid == u)    /* record found! */
713       return &pwtab[mid];
714     if (pwtab[mid].uid > u)
715       max = mid;
716     else
717       min = mid;
718   } while (max > min + 1);
719
720   if (pwtab[max].uid == u)
721     return &pwtab[max];
722   if (pwtab[min].uid == u)
723     return &pwtab[min];
724
725   /* if gets here then record was not found */
726   return (uid2home_t *) NULL;
727 }
728
729
730 #if defined(DEBUG) || defined(DEBUG_PRINT)
731 void
732 plt_print(int signum)
733 {
734   FILE *dumpfile;
735   int dumpfd;
736   char dumptmp[] = "/usr/tmp/hlfsd.dump.XXXXXX";
737   int i;
738
739 #ifdef HAVE_MKSTEMP
740   dumpfd = mkstemp(dumptmp);
741 #else /* not HAVE_MKSTEMP */
742   mktemp(dumptmp);
743   if (!dumptmp) {
744     plog(XLOG_ERROR, "cannot create temporary dump file");
745     return;
746   }
747   dumpfd = open(dumptmp, O_RDONLY);
748 #endif /* not HAVE_MKSTEMP */
749   if (dumpfd < 0) {
750     plog(XLOG_ERROR, "cannot open temporary dump file");
751     return;
752   }
753   if ((dumpfile = fdopen(dumpfd, "a")) != NULL) {
754     plog(XLOG_INFO, "dumping internal state to file %s", dumptmp);
755     fprintf(dumpfile, "\n\nNew plt_dump():\n");
756     for (i = 0; i < cur_pwtab_num; ++i)
757       fprintf(dumpfile,
758               "%4d %5lu %10lu %1d %4lu \"%s\" uname=\"%s\"\n",
759               i,
760               (long) pwtab[i].child,
761               pwtab[i].last_access_time,
762               pwtab[i].last_status,
763               (long) pwtab[i].uid,
764               pwtab[i].home,
765               pwtab[i].uname);
766     fprintf(dumpfile, "\nUserName table by plt_print():\n");
767     for (i = 0; i < cur_pwtab_num; ++i)
768       fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i,
769               untab[i].username, (long) untab[i].uid, untab[i].home);
770     close(dumpfd);
771     fclose(dumpfile);
772   }
773 }
774
775
776 void
777 plt_dump(uid2home_t *lastc, pid_t this)
778 {
779   FILE *dumpfile;
780   int i;
781
782   if ((dumpfile = fopen("/var/tmp/hlfsdump", "a")) != NULL) {
783     fprintf(dumpfile, "\n\nNEW PLT_DUMP -- ");
784     fprintf(dumpfile, "lastchild->child=%d ",
785             (int) (lastc ? lastc->child : -999));
786     fprintf(dumpfile, ", child from wait3=%lu:\n", (long) this);
787     for (i = 0; i < cur_pwtab_num; ++i)
788       fprintf(dumpfile, "%4d %5lu: %4lu \"%s\" uname=\"%s\"\n", i,
789               (long) pwtab[i].child, (long) pwtab[i].uid,
790               pwtab[i].home, pwtab[i].uname);
791     fprintf(dumpfile, "\nUserName table by plt_dump():\n");
792     for (i = 0; i < cur_pwtab_num; ++i)
793       fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i,
794               untab[i].username, (long) untab[i].uid, untab[i].home);
795     fprintf(dumpfile, "ezk: ent=%d, uid=%lu, home=\"%s\"\n",
796             untab_index("ezk"),
797             (long) untab[untab_index("ezk")].uid,
798             pwtab[untab[untab_index("ezk")].uid].home);
799     fprintf(dumpfile, "rezk: ent=%d, uid=%lu, home=\"%s\"\n",
800             untab_index("rezk"),
801             (long) untab[untab_index("rezk")].uid,
802             pwtab[untab[untab_index("rezk")].uid].home);
803     fclose(dumpfile);
804   }
805 }
806 #endif /* defined(DEBUG) || defined(DEBUG_PRINT) */