Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / amd / hlfsd / hlfsd.c
1 /*
2  * Copyright (c) 1997-1999 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: hlfsd.c,v 1.5 1999/09/08 23:36:51 ezk Exp $
42  * $FreeBSD: src/contrib/amd/hlfsd/hlfsd.c,v 1.5 1999/09/15 05:45:15 obrien Exp $
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  * STATIC VARIABLES:
57  */
58 static RETSIGTYPE proceed(int);
59 static RETSIGTYPE reaper(int);
60 static RETSIGTYPE reload(int);
61 static char *hlfs_group = DEFAULT_HLFS_GROUP;
62 static char default_dir_name[] = DEFAULT_DIRNAME;
63 static char *dir_name = default_dir_name;
64 static int printpid = 0;
65 static int stoplight = 0;
66 static void hlfsd_init(void);
67 static void usage(void);
68
69 static struct itimerval reloadinterval = {
70   {DEFAULT_INTERVAL, 0},
71   {DEFAULT_INTERVAL, 0}
72 };
73
74 /*
75  * default mount options.
76  */
77 static char default_mntopts[] = "ro,noac";
78
79 /*
80  * GLOBALS:
81  */
82 SVCXPRT *nfsxprt;
83 char *alt_spooldir = ALT_SPOOLDIR;
84 char *home_subdir = HOME_SUBDIR;
85 char *logfile = DEFAULT_LOGFILE;
86 char *passwdfile = NULL;        /* alternate passwd file to use */
87 char *slinkname = 0;
88 char hostname[MAXHOSTNAMELEN + 1] = "localhost";
89 int cache_interval = DEFAULT_CACHE_INTERVAL;
90 gid_t hlfs_gid = (gid_t) INVALIDID;
91 int masterpid = 0;
92 int noverify = 0;
93 int orig_umask = 022;
94 int serverpid = 0;
95 nfstime startup;
96 u_short nfs_port;
97
98 /* symbol must be available always */
99 #ifdef MOUNT_TABLE_ON_FILE
100 char *mnttab_file_name = MNTTAB_FILE_NAME;
101 #else /* not MOUNT_TABLE_ON_FILE */
102 char *mnttab_file_name = NULL;
103 #endif /* not MOUNT_TABLE_ON_FILE */
104
105 /* forward declarations */
106 void hlfsd_going_down(int rc);
107
108
109 static void
110 usage(void)
111 {
112   fprintf(stderr,
113           "Usage: %s [-Cfhnpv] [-a altdir] [-c cache-interval] [-g group]\n",
114           am_get_progname());
115   fprintf(stderr, "\t[-i interval] [-l logfile] [-o mntopts] [-P passwdfile]\n");
116   show_opts('x', xlog_opt);
117 #ifdef DEBUG
118   show_opts('D', dbg_opt);
119 #endif /* DEBUG */
120   fprintf(stderr, "\t[dir_name [subdir]]\n");
121   exit(2);
122 }
123
124
125 int
126 main(int argc, char *argv[])
127 {
128   char *dot;
129   char *mntopts = (char *) NULL;
130   char hostpid_fs[MAXHOSTNAMELEN + 1 + 16];     /* room for ":(pid###)" */
131   char progpid_fs[PROGNAMESZ + 1 + 11];         /* room for ":pid" */
132   char preopts[128];
133   char *progname;
134   int forcecache = 0;
135   int forcefast = 0;
136   int genflags = 0;
137   int opt, ret;
138   int opterrs = 0;
139   int retry;
140   int soNFS;                    /* NFS socket */
141   int s = -99;
142   mntent_t mnt;
143   nfs_args_t nfs_args;
144   am_nfs_handle_t anh;
145   struct dirent *direntry;
146   struct group *grp;
147   struct stat stmodes;
148   DIR *mountdir;
149   MTYPE_TYPE type = MOUNT_TYPE_NFS;
150
151 #ifdef HAVE_SIGACTION
152   struct sigaction sa;
153 #endif /* not HAVE_SIGACTION */
154
155 #ifndef HAVE_TRANSPORT_TYPE_TLI
156   struct sockaddr_in localsocket;
157 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
158
159
160   /* get program name and truncate so we don't overflow progpid_fs */
161
162   if ((progname = strrchr(argv[0], '/')) != NULL)
163     progname++;
164   else
165     progname = argv[0];
166   if ((int) strlen(progname) > PROGNAMESZ) /* truncate to reasonable size */
167     progname[PROGNAMESZ] = '\0';
168   am_set_progname(progname);
169
170   while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1)
171     switch (opt) {
172
173     case 'a':
174       if (!optarg || optarg[0] != '/') {
175         printf("%s: invalid directory for -a: %s\n",
176                am_get_progname(), optarg);
177         exit(3);
178       }
179       alt_spooldir = optarg;
180       break;
181
182     case 'c':
183       if (!atoi(optarg)) {
184         printf("%s: invalid interval for -c: %s\n",
185                am_get_progname(), optarg);
186         exit(3);
187       }
188       cache_interval = atoi(optarg);
189       break;
190
191     case 'C':
192       forcecache++;
193       break;
194
195     case 'f':
196       forcefast++;
197       break;
198
199     case 'g':
200       hlfs_group = optarg;
201       break;
202
203     case 'i':
204       if (!atoi(optarg)) {
205         printf("%s: invalid interval for -i: %s\n",
206                am_get_progname(), optarg);
207         exit(3);
208       }
209       reloadinterval.it_interval.tv_sec = atoi(optarg);
210       reloadinterval.it_value.tv_sec = atoi(optarg);
211       break;
212
213     case 'l':
214       logfile = optarg;
215       break;
216
217     case 'n':
218       noverify++;
219       break;
220
221     case 'o':
222       mntopts = optarg;
223       break;
224
225     case 'p':
226       printpid++;
227       break;
228
229     case 'P':
230       passwdfile = optarg;
231       break;
232
233     case 'v':
234       fprintf(stderr, "%s\n", HLFSD_VERSION);
235       exit(0);
236
237     case 'x':
238       opterrs += switch_option(optarg);
239       break;
240
241     case 'D':
242 #ifdef DEBUG
243       opterrs += debug_option(optarg);
244 #else /* not DEBUG */
245       fprintf(stderr, "%s: not compiled with DEBUG -- sorry.\n", am_get_progname());
246 #endif /* not DEBUG */
247       break;
248
249     case 'h':
250     case '?':
251       opterrs++;
252     }
253
254   /* set some default debugging options */
255   if (xlog_level_init == ~0)
256     switch_option("");
257   /* need my pid before any dlog/plog */
258   am_set_mypid();
259 #ifdef DEBUG
260   switch_option("debug");
261 #endif /* DEBUG */
262
263 /*
264  * Terminate if did not ask to forcecache (-C) and hlfsd would not be able
265  * to set the minimum cache intervals.
266  */
267 #if !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_FIELD_NFS_ARGS_T_ACREGMIN)
268   if (!forcecache) {
269     fprintf(stderr, "%s: will not be able to turn off attribute caches.\n", am_get_progname());
270     exit(1);
271   }
272 #endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_FIELD_NFS_ARGS_T_ACREGMIN) */
273
274
275   switch (argc - optind) {
276   case 2:
277     home_subdir = argv[optind + 1];
278   case 1:
279     dir_name = argv[optind];
280   case 0:
281     break;
282   default:
283     opterrs++;
284   }
285
286   if (opterrs)
287     usage();
288
289   /* ensure that only root can run hlfsd */
290   if (geteuid()) {
291     fprintf(stderr, "hlfsd can only be run as root\n");
292     exit(1);
293   }
294   setbuf(stdout, (char *) NULL);
295   umask(0);
296
297   /* find gid for hlfs_group */
298   if ((grp = getgrnam(hlfs_group)) == (struct group *) NULL) {
299     fprintf(stderr, "%s: cannot get gid for group \"%s\".\n",
300             am_get_progname(), hlfs_group);
301   } else {
302     hlfs_gid = grp->gr_gid;
303   }
304
305   /* get hostname for logging and open log before we reset umask */
306   gethostname(hostname, sizeof(hostname));
307   hostname[sizeof(hostname) - 1] = '\0';
308   if ((dot = strchr(hostname, '.')) != NULL)
309     *dot = '\0';
310   orig_umask = umask(0);
311   if (logfile)
312     switch_to_logfile(logfile, orig_umask);
313
314 #if defined(DEBUG) && !defined(MOUNT_TABLE_ON_FILE)
315   if (debug_flags & D_MTAB)
316     dlog("-D mtab option ignored");
317 #endif /* defined(DEBUG) && !defined(MOUNT_TABLE_ON_FILE) */
318
319   /* avoid hanging on other NFS servers if started elsewhere */
320   if (chdir("/") < 0)
321     fatal("cannot chdir to /: %m");
322
323   if (geteuid() != 0)
324     fatal("must be root to mount filesystems");
325
326   /*
327    * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with
328    * slinkname = `basename $dir_name` - requires dir_name be writable
329    */
330
331   if (dir_name[0] != '/'
332       || ((slinkname = strrchr(dir_name, '/')), *slinkname++ = '\0',
333           (dir_name[0] == '\0' || slinkname[0] == '\0'))) {
334     if (slinkname)
335       *--slinkname = '/';
336     printf("%s: invalid mount directory/link %s\n",
337            am_get_progname(), dir_name);
338     exit(3);
339   }
340
341   clock_valid = 0;              /* invalidate logging clock */
342
343   if (!forcefast) {
344     /* make sure mount point exists and is at least mode 555 */
345     if (stat(dir_name, &stmodes) < 0)
346       if (errno != ENOENT || mkdirs(dir_name, 0555) < 0
347           || stat(dir_name, &stmodes) < 0)
348         fatalerror(dir_name);
349
350     if ((stmodes.st_mode & 0555) != 0555) {
351       fprintf(stderr, "%s: directory %s not read/executable\n",
352               am_get_progname(), dir_name);
353       plog(XLOG_WARNING, "directory %s not read/executable",
354            dir_name);
355     }
356
357     /* warn if extraneous stuff will be hidden by mount */
358     if ((mountdir = opendir(dir_name)) == NULL)
359       fatalerror(dir_name);
360
361     while ((direntry = readdir(mountdir)) != NULL) {
362       if (!NSTREQ(".", direntry->d_name, NAMLEN(direntry)) &&
363           !NSTREQ("..", direntry->d_name, NAMLEN(direntry)) &&
364           !NSTREQ(slinkname, direntry->d_name, NAMLEN(direntry)))
365         break;
366     }
367
368     if (direntry != NULL) {
369       fprintf(stderr, "%s: %s/%s will be hidden by mount\n",
370               am_get_progname(), dir_name, direntry->d_name);
371       plog(XLOG_WARNING, "%s/%s will be hidden by mount\n",
372            dir_name, direntry->d_name);
373     }
374     closedir(mountdir);
375
376     /* make sure alternate spool dir exists */
377     if ((errno = mkdirs(alt_spooldir, OPEN_SPOOLMODE))) {
378       fprintf(stderr, "%s: cannot create alternate dir ",
379               am_get_progname());
380       perror(alt_spooldir);
381       plog(XLOG_ERROR, "cannot create alternate dir %s: %m",
382            alt_spooldir);
383     }
384     chmod(alt_spooldir, OPEN_SPOOLMODE);
385
386     /* create failsafe link to alternate spool directory */
387     slinkname[-1] = '/';        /* unsplit dir_name to include link */
388     if (lstat(dir_name, &stmodes) == 0 &&
389         (stmodes.st_mode & S_IFMT) != S_IFLNK) {
390       fprintf(stderr, "%s: failsafe %s not a symlink\n",
391               am_get_progname(), dir_name);
392       plog(XLOG_WARNING, "failsafe %s not a symlink\n",
393            dir_name);
394     } else {
395       unlink(dir_name);
396
397       if (symlink(alt_spooldir, dir_name) < 0) {
398         fprintf(stderr,
399                 "%s: cannot create failsafe symlink %s -> ",
400                 am_get_progname(), dir_name);
401         perror(alt_spooldir);
402         plog(XLOG_WARNING,
403              "cannot create failsafe symlink %s -> %s: %m",
404              dir_name, alt_spooldir);
405       }
406     }
407
408     slinkname[-1] = '\0';       /* resplit dir_name */
409   } /* end of "if (!forcefast) {" */
410
411   /*
412    * Register hlfsd as an nfs service with the portmapper.
413    */
414 #ifdef HAVE_TRANSPORT_TYPE_TLI
415   ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
416 #else /* not HAVE_TRANSPORT_TYPE_TLI */
417   ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
418 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
419   if (ret != 0)
420     fatal("cannot create NFS service");
421
422 #ifdef HAVE_SIGACTION
423   sa.sa_handler = proceed;
424   sa.sa_flags = 0;
425   sigemptyset(&(sa.sa_mask));
426   sigaddset(&(sa.sa_mask), SIGUSR2);
427   sigaction(SIGUSR2, &sa, NULL);
428 #else /* not HAVE_SIGACTION */
429   signal(SIGUSR2, proceed);
430 #endif /* not HAVE_SIGACTION */
431
432   plog(XLOG_INFO, "Initializing hlfsd...");
433   hlfsd_init();                 /* start up child (forking) to run svc_run */
434
435 #ifdef HAVE_SIGACTION
436   sa.sa_handler = reaper;
437   sa.sa_flags = 0;
438   sigemptyset(&(sa.sa_mask));
439   sigaddset(&(sa.sa_mask), SIGCHLD);
440   sigaction(SIGCHLD, &sa, NULL);
441 #else /* not HAVE_SIGACTION */
442   signal(SIGCHLD, reaper);
443 #endif /* not HAVE_SIGACTION */
444
445 #ifdef DEBUG
446   /*
447    * In the parent, if -D nodaemon (or -D daemon) , we don't need to
448    * set this signal handler.
449    */
450   amuDebug(D_DAEMON) {
451 #endif /* DEBUG */
452     /* XXX: port to use pure svr4 signals */
453     s = -99;
454     while (stoplight != SIGUSR2) {
455       plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight);
456       s = sigpause(0);          /* wait for child to set up */
457       sleep(1);
458     }
459 #ifdef DEBUG
460   }
461 #endif /* DEBUG */
462
463   /*
464    * setup options to mount table (/etc/{mtab,mnttab}) entry
465    */
466   sprintf(hostpid_fs, "%s:(pid%d)", hostname, masterpid);
467   memset((char *) &mnt, 0, sizeof(mnt));
468   mnt.mnt_dir = dir_name;       /* i.e., "/mail" */
469   mnt.mnt_fsname = hostpid_fs;
470   if (mntopts) {
471     mnt.mnt_opts = mntopts;
472   } else {
473     strcpy(preopts, default_mntopts);
474     /*
475      * Turn off all kinds of attribute and symlink caches as
476      * much as possible.  Also make sure that mount does not
477      * show up to df.
478      */
479 #ifdef MNTTAB_OPT_INTR
480     strcat(preopts, ",");
481     strcat(preopts, MNTTAB_OPT_INTR);
482 #endif /* MNTTAB_OPT_INTR */
483 #ifdef MNTTAB_OPT_IGNORE
484     strcat(preopts, ",");
485     strcat(preopts, MNTTAB_OPT_IGNORE);
486 #endif /* MNTTAB_OPT_IGNORE */
487 #ifdef MNT2_GEN_OPT_CACHE
488     strcat(preopts, ",nocache");
489 #endif /* MNT2_GEN_OPT_CACHE */
490 #ifdef MNT2_NFS_OPT_SYMTTL
491     strcat(preopts, ",symttl=0");
492 #endif /* MNT2_NFS_OPT_SYMTTL */
493     mnt.mnt_opts = preopts;
494   }
495
496   /*
497    * Make sure that amd's top-level NFS mounts are hidden by default
498    * from df.
499    * If they don't appear to support the either the "ignore" mnttab
500    * option entry, or the "auto" one, set the mount type to "nfs".
501    */
502   mnt.mnt_type = HIDE_MOUNT_TYPE;
503   /* some systems don't have a mount type, but a mount flag */
504
505 #ifndef HAVE_TRANSPORT_TYPE_TLI
506   amu_get_myaddress(&localsocket.sin_addr);
507   localsocket.sin_family = AF_INET;
508   localsocket.sin_port = htons(nfsxprt->xp_port);
509 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
510
511   /*
512    * Update hostname field.
513    * Make some name prog:pid (i.e., hlfsd:174) for hostname
514    */
515   sprintf(progpid_fs, "%s:%d", am_get_progname(), masterpid);
516
517   /* Most kernels have a name length restriction. */
518   if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN)
519     strcpy(progpid_fs + MAXHOSTNAMELEN - 3, "..");
520
521   genflags = compute_mount_flags(&mnt);
522
523   retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
524   if (retry <= 0)
525     retry = 1;                  /* XXX */
526
527   memmove(&anh.v2.fhs_fh, root_fhp, sizeof(*root_fhp));
528 #ifdef HAVE_TRANSPORT_TYPE_TLI
529   compute_nfs_args(&nfs_args,
530                    &mnt,
531                    genflags,
532                    nfsncp,
533                    NULL,        /* remote host IP addr is set below */
534                    NFS_VERSION, /* version 2 */
535                    "udp",       /* XXX: shouldn't this be "udp"? */
536                    &anh,
537                    progpid_fs,  /* host name for kernel */
538                    hostpid_fs); /* filesystem name for kernel */
539   /*
540    * IMPORTANT: set the correct IP address AFTERWARDS.  It cannot
541    * be done using the normal mechanism of compute_nfs_args(), because
542    * that one will allocate a new address and use NFS_SA_DREF() to copy
543    * parts to it, while assuming that the ip_addr passed is always
544    * a "struct sockaddr_in".  That assumption is incorrect on TLI systems,
545    * because they define a special macro HOST_SELF which is DIFFERENT
546    * than localhost (127.0.0.1)!
547    */
548   nfs_args.addr = &nfsxprt->xp_ltaddr;
549 #else /* not HAVE_TRANSPORT_TYPE_TLI */
550   compute_nfs_args(&nfs_args,
551                    &mnt,
552                    genflags,
553                    &localsocket,
554                    NFS_VERSION, /* version 2 */
555                    "udp",       /* XXX: shouldn't this be "udp"? */
556                    &anh,
557                    progpid_fs,  /* host name for kernel */
558                    hostpid_fs); /* filesystem name for kernel */
559 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
560
561   /*************************************************************************
562    * NOTE: while compute_nfs_args() works ok for regular NFS mounts        *
563    * the toplvl one is not, and so some options must be corrected by hand  *
564    * more carefully, *after* compute_nfs_args() runs.                      *
565    *************************************************************************/
566   compute_automounter_nfs_args(&nfs_args, &mnt);
567
568   clock_valid = 0;              /* invalidate logging clock */
569
570 /*
571  * The following code could be cleverly ifdef-ed, but I duplicated the
572  * mount_fs call three times for simplicity and readability.
573  */
574 #ifdef DEBUG
575 /*
576  * For some reason, this mount may have to be done in the background, if I am
577  * using -D nodebug.  I suspect that the actual act of mounting requires
578  * calling to hlfsd itself to invoke one or more of its nfs calls, to stat
579  * /mail.  That means that even if you say -D nodaemon, at least the mount
580  * of hlfsd itself on top of /mail will be done in the background.
581  * The other alternative I have is to run svc_run, but set a special
582  * signal handler to perform the mount in N seconds via some alarm.
583  *      -Erez Zadok.
584  */
585   if (debug_flags & D_DAEMON) { /* asked for -D daemon */
586     plog(XLOG_INFO, "parent NFS mounting hlfsd service points");
587     if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name) < 0)
588       fatal("nfsmount: %m");
589   } else {                      /* asked for -D nodaemon */
590     if (fork() == 0) {          /* child runs mount */
591       am_set_mypid();
592       foreground = 0;
593       plog(XLOG_INFO, "child NFS mounting hlfsd service points");
594       if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name) < 0) {
595         fatal("nfsmount: %m");
596       }
597       exit(0);                  /* all went well */
598     } else { /* fork failed or parent running */
599       plog(XLOG_INFO, "parent waiting 1sec for mount...");
600     }
601   }
602 #else /* not DEBUG */
603   plog(XLOG_INFO, "normal NFS mounting hlfsd service points");
604   if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 2, "udp", mnttab_file_name) < 0)
605     fatal("nfsmount: %m");
606 #endif /* not DEBUG */
607
608 #ifdef HAVE_TRANSPORT_TYPE_TLI
609   /*
610    * XXX: this free_knetconfig() was not done for hlfsd before,
611    * and apparently there was a reason for it, but why? -Erez
612    */
613   free_knetconfig(nfs_args.knconf);
614   /*
615    * local automounter mounts do not allocate a special address, so
616    * no need to XFREE(nfs_args.addr) under TLI.
617    */
618 #endif /* HAVE_TRANSPORT_TYPE_TLI */
619
620   if (printpid)
621     printf("%d\n", masterpid);
622
623   plog(XLOG_INFO, "hlfsd ready to serve");
624 #ifdef DEBUG
625   /*
626    * If asked not to fork a daemon (-D nodaemon), then hlfsd_init()
627    * will not run svc_run.  We must start svc_run here.
628    */
629   dlog("starting no-daemon debugging svc_run");
630   amuDebugNo(D_DAEMON)
631     svc_run();
632 #endif /* DEBUG */
633
634   cleanup(0);                   /* should never happen here */
635   return (0);                   /* everything went fine? */
636 }
637
638
639 static void
640 hlfsd_init(void)
641 {
642   int child = 0;
643 #ifdef HAVE_SIGACTION
644   struct sigaction sa;
645 #endif /* HAVE_SIGACTION */
646
647   clock_valid = 0;              /* invalidate logging clock */
648
649   /*
650    * Initialize file handles.
651    */
652   plog(XLOG_INFO, "initializing hlfsd file handles");
653   hlfsd_init_filehandles();
654
655 #ifdef DEBUG
656   /*
657    * If -D daemon then we must fork.
658    */
659   amuDebug(D_DAEMON)
660 #endif /* DEBUG */
661     child = fork();
662
663   if (child < 0)
664     fatal("fork: %m");
665
666   if (child != 0) {             /* parent process - save child pid */
667     masterpid = child;
668     am_set_mypid();             /* for logging routines */
669     return;
670   }
671
672   /*
673    * CHILD CODE:
674    * initialize server
675    */
676
677   plog(XLOG_INFO, "initializing home directory database");
678   plt_init();                   /* initialize database */
679   plog(XLOG_INFO, "home directory database initialized");
680
681   masterpid = serverpid = am_set_mypid(); /* for logging routines */
682
683   /*
684    * SIGALRM/SIGHUP: reload password database if timer expired
685    * or user sent HUP signal.
686    */
687 #ifdef HAVE_SIGACTION
688   sa.sa_handler = reload;
689   sa.sa_flags = 0;
690   sigemptyset(&(sa.sa_mask));
691   sigaddset(&(sa.sa_mask), SIGALRM);
692   sigaddset(&(sa.sa_mask), SIGHUP);
693   sigaction(SIGALRM, &sa, NULL);
694   sigaction(SIGHUP, &sa, NULL);
695 #else /* not HAVE_SIGACTION */
696   signal(SIGALRM, reload);
697   signal(SIGHUP, reload);
698 #endif /* not HAVE_SIGACTION */
699
700   /*
701    * SIGTERM: cleanup and exit.
702    */
703 #ifdef HAVE_SIGACTION
704   sa.sa_handler = cleanup;
705   sa.sa_flags = 0;
706   sigemptyset(&(sa.sa_mask));
707   sigaddset(&(sa.sa_mask), SIGTERM);
708   sigaction(SIGTERM, &sa, NULL);
709 #else /* not HAVE_SIGACTION */
710   signal(SIGTERM, cleanup);
711 #endif /* not HAVE_SIGACTION */
712
713   /*
714    * SIGCHLD: interlock synchronization and testing
715    */
716 #ifdef HAVE_SIGACTION
717   sa.sa_handler = interlock;
718   sa.sa_flags = 0;
719   sigemptyset(&(sa.sa_mask));
720   sigaddset(&(sa.sa_mask), SIGCHLD);
721   sigaction(SIGCHLD, &sa, NULL);
722 #else /* not HAVE_SIGACTION */
723   signal(SIGCHLD, interlock);
724 #endif /* not HAVE_SIGACTION */
725
726   /*
727    * SIGUSR1: dump internal hlfsd maps/cache to file
728    */
729 #ifdef HAVE_SIGACTION
730 # if defined(DEBUG) || defined(DEBUG_PRINT)
731   sa.sa_handler = plt_print;
732 # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
733   sa.sa_handler = SIG_IGN;
734 # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
735   sa.sa_flags = 0;
736   sigemptyset(&(sa.sa_mask));
737   sigaddset(&(sa.sa_mask), SIGUSR1);
738   sigaction(SIGUSR1, &sa, NULL);
739 #else /* not HAVE_SIGACTION */
740 # if defined(DEBUG) || defined(DEBUG_PRINT)
741   signal(SIGUSR1, plt_print);
742 # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
743   signal(SIGUSR1, SIG_IGN);
744 # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
745 #endif /* not HAVE_SIGACTION */
746
747   if (setitimer(ITIMER_REAL, &reloadinterval, (struct itimerval *) 0) < 0)
748     fatal("setitimer: %m");
749
750   gettimeofday((struct timeval *) &startup, (struct timezone *) 0);
751
752 #ifdef DEBUG
753   /*
754    * If -D daemon, then start serving here in the child,
755    * and the parent will exit.  But if -D nodaemon, then
756    * skip this code and make sure svc_run is entered elsewhere.
757    */
758   amuDebug(D_DAEMON) {
759 #endif /* DEBUG */
760
761     /*
762      * Dissociate from the controlling terminal
763      */
764     amu_release_controlling_tty();
765
766     /*
767      * signal parent we are ready. parent should
768      * mount(2) and die.
769      */
770     if (kill(getppid(), SIGUSR2) < 0)
771       fatal("kill: %m");
772     plog(XLOG_INFO, "starting svc_run");
773     svc_run();
774     cleanup(0);         /* should never happen, just in case */
775 #ifdef DEBUG
776   } /* end of code that runs iff hlfsd daemonizes */
777 #endif /* DEBUG */
778
779 }
780
781
782 static RETSIGTYPE
783 proceed(int signum)
784 {
785   stoplight = signum;
786 }
787
788
789 static RETSIGTYPE
790 reload(int signum)
791 {
792   int child;
793   int status;
794
795   clock_valid = 0;              /* invalidate logging clock */
796
797   if (getpid() != masterpid)
798     return;
799
800   /*
801    * If received a SIGHUP, close and reopen the log file (so that it
802    * can be rotated)
803    */
804   if (signum == SIGHUP && logfile)
805     switch_to_logfile(logfile, orig_umask);
806
807   /*
808    * parent performs the reload, while the child continues to serve
809    * clients accessing the home dir link.
810    */
811   if ((child = fork()) > 0) {
812     serverpid = child;          /* parent runs here */
813     am_set_mypid();
814
815     plt_init();
816
817     if (kill(child, SIGKILL) < 0) {
818       plog(XLOG_ERROR, "kill child: %m");
819     } else {                    /* wait for child to die before continue */
820       if (wait(&status) != child) {
821         /*
822          * I took out this line because it generates annoying output.  It
823          * indicates a very small bug in hlfsd which is totally harmless.
824          * It causes hlfsd to work a bit harder than it should.
825          * Nevertheless, I intend on fixing it in a future release.
826          * -Erez Zadok <ezk@cs.columbia.edu>
827          */
828         /* plog(XLOG_ERROR, "unknown child"); */
829       }
830     }
831     serverpid = masterpid;
832   } else if (child < 0) {
833     plog(XLOG_ERROR, "unable to fork: %m");
834   } else {
835     /* let child handle requests while we reload */
836     serverpid = getpid();
837     am_set_mypid();
838   }
839 }
840
841
842 RETSIGTYPE
843 cleanup(int signum)
844 {
845   struct stat stbuf;
846   int umount_result;
847
848   clock_valid = 0;              /* invalidate logging clock */
849
850 #ifdef DEBUG
851   amuDebug(D_DAEMON)
852 #endif /* DEBUG */
853     if (getpid() != masterpid)
854     return;
855
856 #ifdef DEBUG
857   amuDebug(D_DAEMON)
858 #endif /* DEBUG */
859     if (fork() != 0) {
860     masterpid = 0;
861     am_set_mypid();
862     return;
863   }
864   am_set_mypid();
865
866   for (;;) {
867     while ((umount_result = UMOUNT_FS(dir_name, mnttab_file_name)) == EBUSY) {
868 #ifdef DEBUG
869       dlog("cleanup(): umount delaying for 10 seconds");
870 #endif /* DEBUG */
871       sleep(10);
872     }
873     if (stat(dir_name, &stbuf) == 0 && stbuf.st_ino == ROOTID) {
874       plog(XLOG_ERROR, "unable to unmount %s", dir_name);
875       plog(XLOG_ERROR, "suspending, unmount before terminating");
876       kill(am_mypid, SIGSTOP);
877       continue;                 /* retry unmount */
878     }
879     break;
880   }
881
882 #ifdef DEBUG
883   dlog("cleanup(): killing processes and terminating");
884   amuDebug(D_DAEMON)
885 #endif /* DEBUG */
886     kill(masterpid, SIGKILL);
887
888 #ifdef DEBUG
889   amuDebug(D_DAEMON)
890 #endif /* DEBUG */
891     kill(serverpid, SIGKILL);
892
893   plog(XLOG_INFO, "hlfsd terminating with status 0\n");
894   exit(0);
895 }
896
897
898 static RETSIGTYPE
899 reaper(int signum)
900 {
901   int result;
902
903   if (wait(&result) == masterpid) {
904     exit(4);
905   }
906 }
907
908
909 void
910 hlfsd_going_down(int rc)
911 {
912   int mypid = getpid();         /* XXX: should this be the global am_mypid */
913
914   if (mypid == masterpid)
915     cleanup(0);
916   else if (mypid == serverpid)
917     kill(masterpid, SIGTERM);
918
919   exit(rc);
920 }
921
922
923 void
924 fatal(char *mess)
925 {
926   if (logfile && !STREQ(logfile, "stderr")) {
927     char lessmess[128];
928     int messlen;
929
930     messlen = strlen(mess);
931
932     if (!STREQ(&mess[messlen + 1 - sizeof(ERRM)], ERRM))
933       fprintf(stderr, "%s: %s\n", am_get_progname(), mess);
934     else {
935       strcpy(lessmess, mess);
936       lessmess[messlen - 4] = '\0';
937
938       if (errno < sys_nerr)
939         fprintf(stderr, "%s: %s: %s\n", am_get_progname(), lessmess,
940 #ifdef HAVE_STRERROR
941                 strerror(errno)
942 #else /* not HAVE_STRERROR */
943                 sys_errlist[errno]
944 #endif /* not HAVE_STRERROR */
945                 );
946       else
947         fprintf(stderr, "%s: %s: Error %d\n",
948                 am_get_progname(), lessmess, errno);
949     }
950   }
951   plog(XLOG_FATAL, mess);
952
953   hlfsd_going_down(1);
954 }