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