138494Sobrien/*
2174313Sobrien * Copyright (c) 1997-2006 Erez Zadok
338494Sobrien * Copyright (c) 1989 Jan-Simon Pendry
438494Sobrien * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
538494Sobrien * Copyright (c) 1989 The Regents of the University of California.
638494Sobrien * All rights reserved.
738494Sobrien *
838494Sobrien * This code is derived from software contributed to Berkeley by
938494Sobrien * Jan-Simon Pendry at Imperial College, London.
1038494Sobrien *
1138494Sobrien * Redistribution and use in source and binary forms, with or without
1238494Sobrien * modification, are permitted provided that the following conditions
1338494Sobrien * are met:
1438494Sobrien * 1. Redistributions of source code must retain the above copyright
1538494Sobrien *    notice, this list of conditions and the following disclaimer.
1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1738494Sobrien *    notice, this list of conditions and the following disclaimer in the
1838494Sobrien *    documentation and/or other materials provided with the distribution.
1938494Sobrien * 3. All advertising materials mentioning features or use of this software
2042633Sobrien *    must display the following acknowledgment:
2138494Sobrien *      This product includes software developed by the University of
2238494Sobrien *      California, Berkeley and its contributors.
2338494Sobrien * 4. Neither the name of the University nor the names of its contributors
2438494Sobrien *    may be used to endorse or promote products derived from this software
2538494Sobrien *    without specific prior written permission.
2638494Sobrien *
2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3038494Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3738494Sobrien * SUCH DAMAGE.
3838494Sobrien *
3938494Sobrien *
40174313Sobrien * File: am-utils/hlfsd/hlfsd.c
4138494Sobrien *
4238494Sobrien * HLFSD was written at Columbia University Computer Science Department, by
4338494Sobrien * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
4438494Sobrien * It is being distributed under the same terms and conditions as amd does.
4538494Sobrien */
4638494Sobrien
4738494Sobrien#ifdef HAVE_CONFIG_H
4838494Sobrien# include <config.h>
4938494Sobrien#endif /* HAVE_CONFIG_H */
5038494Sobrien#include <am_defs.h>
5138494Sobrien#include <hlfsd.h>
5238494Sobrien
5338494Sobrien/*
5438494Sobrien * STATIC VARIABLES:
5538494Sobrien */
5638494Sobrienstatic RETSIGTYPE proceed(int);
5738494Sobrienstatic RETSIGTYPE reaper(int);
5838494Sobrienstatic RETSIGTYPE reload(int);
5938494Sobrienstatic char *hlfs_group = DEFAULT_HLFS_GROUP;
6038494Sobrienstatic char default_dir_name[] = DEFAULT_DIRNAME;
6138494Sobrienstatic char *dir_name = default_dir_name;
6238494Sobrienstatic int printpid = 0;
6338494Sobrienstatic int stoplight = 0;
6438494Sobrienstatic void hlfsd_init(void);
6538494Sobrienstatic void usage(void);
6638494Sobrien
6738494Sobrienstatic struct itimerval reloadinterval = {
6838494Sobrien  {DEFAULT_INTERVAL, 0},
6938494Sobrien  {DEFAULT_INTERVAL, 0}
7038494Sobrien};
7138494Sobrien
7238494Sobrien/*
7338494Sobrien * default mount options.
7438494Sobrien */
7538494Sobrienstatic char default_mntopts[] = "ro,noac";
7638494Sobrien
7738494Sobrien/*
7838494Sobrien * GLOBALS:
7938494Sobrien */
8038494SobrienSVCXPRT *nfsxprt;
8138494Sobrienchar *alt_spooldir = ALT_SPOOLDIR;
8238494Sobrienchar *home_subdir = HOME_SUBDIR;
8338494Sobrienchar *logfile = DEFAULT_LOGFILE;
8438494Sobrienchar *passwdfile = NULL;	/* alternate passwd file to use */
8538494Sobrienchar *slinkname = 0;
8638500Sobrienchar hostname[MAXHOSTNAMELEN + 1] = "localhost";
87174313Sobrienu_int cache_interval = DEFAULT_CACHE_INTERVAL;
8838494Sobriengid_t hlfs_gid = (gid_t) INVALIDID;
8938494Sobrienint masterpid = 0;
9038494Sobrienint noverify = 0;
9142633Sobrienint orig_umask = 022;
9238494Sobrienint serverpid = 0;
9338494Sobriennfstime startup;
9438494Sobrienu_short nfs_port;
9538494Sobrien
9638494Sobrien/* symbol must be available always */
9782804Sobrien#ifdef MNTTAB_FILE_NAME
9838494Sobrienchar *mnttab_file_name = MNTTAB_FILE_NAME;
9982804Sobrien#else /* not MNTTAB_FILE_NAME */
10038494Sobrienchar *mnttab_file_name = NULL;
10182804Sobrien#endif /* not MNTTAB_FILE_NAME */
10238494Sobrien
10338494Sobrien/* forward declarations */
10438494Sobrienvoid hlfsd_going_down(int rc);
10538494Sobrien
10638494Sobrien
10738494Sobrienstatic void
10838494Sobrienusage(void)
10938494Sobrien{
11038494Sobrien  fprintf(stderr,
11138494Sobrien	  "Usage: %s [-Cfhnpv] [-a altdir] [-c cache-interval] [-g group]\n",
11242633Sobrien	  am_get_progname());
11338494Sobrien  fprintf(stderr, "\t[-i interval] [-l logfile] [-o mntopts] [-P passwdfile]\n");
11438494Sobrien  show_opts('x', xlog_opt);
11538494Sobrien#ifdef DEBUG
11638494Sobrien  show_opts('D', dbg_opt);
11738494Sobrien#endif /* DEBUG */
11838494Sobrien  fprintf(stderr, "\t[dir_name [subdir]]\n");
11938494Sobrien  exit(2);
12038494Sobrien}
12138494Sobrien
12238494Sobrien
123174313Sobrienvoid
124174313Sobrienfatalerror(char *str)
125174313Sobrien{
126174313Sobrien#define ERRM ": %m"
127174313Sobrien  size_t l = strlen(str) + sizeof(ERRM) - 1;
128174313Sobrien  char *tmp = strnsave(str, l);
129174313Sobrien  xstrlcat(tmp, ERRM, l);
130174313Sobrien  fatal(tmp);
131174313Sobrien}
132174313Sobrien
133174313Sobrien
13438494Sobrienint
13538494Sobrienmain(int argc, char *argv[])
13638494Sobrien{
13738494Sobrien  char *dot;
13838494Sobrien  char *mntopts = (char *) NULL;
13938494Sobrien  char hostpid_fs[MAXHOSTNAMELEN + 1 + 16];	/* room for ":(pid###)" */
14038494Sobrien  char progpid_fs[PROGNAMESZ + 1 + 11];		/* room for ":pid" */
14138494Sobrien  char preopts[128];
14242633Sobrien  char *progname;
14338494Sobrien  int forcecache = 0;
14438494Sobrien  int forcefast = 0;
14538494Sobrien  int genflags = 0;
14638494Sobrien  int opt, ret;
14738494Sobrien  int opterrs = 0;
14838494Sobrien  int retry;
14938494Sobrien  int soNFS;			/* NFS socket */
15038494Sobrien  int s = -99;
15138494Sobrien  mntent_t mnt;
15238494Sobrien  nfs_args_t nfs_args;
15338494Sobrien  am_nfs_handle_t anh;
15438494Sobrien  struct dirent *direntry;
15538494Sobrien  struct group *grp;
15638494Sobrien  struct stat stmodes;
15738494Sobrien  DIR *mountdir;
15838494Sobrien  MTYPE_TYPE type = MOUNT_TYPE_NFS;
15938494Sobrien
16038494Sobrien#ifdef HAVE_SIGACTION
16138494Sobrien  struct sigaction sa;
16238494Sobrien#endif /* not HAVE_SIGACTION */
16338494Sobrien
16438494Sobrien#ifndef HAVE_TRANSPORT_TYPE_TLI
16538494Sobrien  struct sockaddr_in localsocket;
16638494Sobrien#endif /* not HAVE_TRANSPORT_TYPE_TLI */
16738494Sobrien
16838494Sobrien
16938494Sobrien  /* get program name and truncate so we don't overflow progpid_fs */
17038494Sobrien
17138494Sobrien  if ((progname = strrchr(argv[0], '/')) != NULL)
17238494Sobrien    progname++;
17338494Sobrien  else
17438494Sobrien    progname = argv[0];
17538494Sobrien  if ((int) strlen(progname) > PROGNAMESZ) /* truncate to reasonable size */
17638494Sobrien    progname[PROGNAMESZ] = '\0';
17742633Sobrien  am_set_progname(progname);
17838494Sobrien
17942633Sobrien  while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1)
18038494Sobrien    switch (opt) {
18138494Sobrien
18238494Sobrien    case 'a':
18338494Sobrien      if (!optarg || optarg[0] != '/') {
18438494Sobrien	printf("%s: invalid directory for -a: %s\n",
18542633Sobrien	       am_get_progname(), optarg);
18638494Sobrien	exit(3);
18738494Sobrien      }
18838494Sobrien      alt_spooldir = optarg;
18938494Sobrien      break;
19038494Sobrien
19138494Sobrien    case 'c':
19238494Sobrien      if (!atoi(optarg)) {
19338494Sobrien	printf("%s: invalid interval for -c: %s\n",
19442633Sobrien	       am_get_progname(), optarg);
19538494Sobrien	exit(3);
19638494Sobrien      }
19738494Sobrien      cache_interval = atoi(optarg);
19838494Sobrien      break;
19938494Sobrien
20038494Sobrien    case 'C':
20138494Sobrien      forcecache++;
20238494Sobrien      break;
20338494Sobrien
20438494Sobrien    case 'f':
20538494Sobrien      forcefast++;
20638494Sobrien      break;
20738494Sobrien
20838494Sobrien    case 'g':
20938494Sobrien      hlfs_group = optarg;
21038494Sobrien      break;
21138494Sobrien
21238494Sobrien    case 'i':
21338494Sobrien      if (!atoi(optarg)) {
21438494Sobrien	printf("%s: invalid interval for -i: %s\n",
21542633Sobrien	       am_get_progname(), optarg);
21638494Sobrien	exit(3);
21738494Sobrien      }
21838494Sobrien      reloadinterval.it_interval.tv_sec = atoi(optarg);
21938494Sobrien      reloadinterval.it_value.tv_sec = atoi(optarg);
22038494Sobrien      break;
22138494Sobrien
22238494Sobrien    case 'l':
22338494Sobrien      logfile = optarg;
22438494Sobrien      break;
22538494Sobrien
22638494Sobrien    case 'n':
22738494Sobrien      noverify++;
22838494Sobrien      break;
22938494Sobrien
23038494Sobrien    case 'o':
23138494Sobrien      mntopts = optarg;
23238494Sobrien      break;
23338494Sobrien
23438494Sobrien    case 'p':
23538494Sobrien      printpid++;
23638494Sobrien      break;
23738494Sobrien
23838494Sobrien    case 'P':
23938494Sobrien      passwdfile = optarg;
24038494Sobrien      break;
24138494Sobrien
24238494Sobrien    case 'v':
24338494Sobrien      fprintf(stderr, "%s\n", HLFSD_VERSION);
24438494Sobrien      exit(0);
24538494Sobrien
24638494Sobrien    case 'x':
24738494Sobrien      opterrs += switch_option(optarg);
24838494Sobrien      break;
24938494Sobrien
25038494Sobrien    case 'D':
25138494Sobrien#ifdef DEBUG
25238494Sobrien      opterrs += debug_option(optarg);
25338494Sobrien#else /* not DEBUG */
25442633Sobrien      fprintf(stderr, "%s: not compiled with DEBUG -- sorry.\n", am_get_progname());
25538494Sobrien#endif /* not DEBUG */
25638494Sobrien      break;
25738494Sobrien
25838494Sobrien    case 'h':
25938494Sobrien    case '?':
26038494Sobrien      opterrs++;
26138494Sobrien    }
26238494Sobrien
26338494Sobrien  /* set some default debugging options */
26438494Sobrien  if (xlog_level_init == ~0)
26538494Sobrien    switch_option("");
26638494Sobrien  /* need my pid before any dlog/plog */
26742633Sobrien  am_set_mypid();
26838494Sobrien#ifdef DEBUG
26938494Sobrien  switch_option("debug");
27038494Sobrien#endif /* DEBUG */
27138494Sobrien
27238494Sobrien/*
27338494Sobrien * Terminate if did not ask to forcecache (-C) and hlfsd would not be able
27438494Sobrien * to set the minimum cache intervals.
27538494Sobrien */
276119682Smbr#if !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN)
27738494Sobrien  if (!forcecache) {
27842633Sobrien    fprintf(stderr, "%s: will not be able to turn off attribute caches.\n", am_get_progname());
27938494Sobrien    exit(1);
28038494Sobrien  }
281119682Smbr#endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN) */
28238494Sobrien
28338494Sobrien
28438494Sobrien  switch (argc - optind) {
28538494Sobrien  case 2:
28638494Sobrien    home_subdir = argv[optind + 1];
28738494Sobrien  case 1:
28838494Sobrien    dir_name = argv[optind];
28938494Sobrien  case 0:
29038494Sobrien    break;
29138494Sobrien  default:
29238494Sobrien    opterrs++;
29338494Sobrien  }
29438494Sobrien
29538494Sobrien  if (opterrs)
29638494Sobrien    usage();
29738494Sobrien
29838494Sobrien  /* ensure that only root can run hlfsd */
29938494Sobrien  if (geteuid()) {
30038494Sobrien    fprintf(stderr, "hlfsd can only be run as root\n");
30138494Sobrien    exit(1);
30238494Sobrien  }
30338494Sobrien  setbuf(stdout, (char *) NULL);
30438494Sobrien  umask(0);
30538494Sobrien
30638494Sobrien  /* find gid for hlfs_group */
30738494Sobrien  if ((grp = getgrnam(hlfs_group)) == (struct group *) NULL) {
30838494Sobrien    fprintf(stderr, "%s: cannot get gid for group \"%s\".\n",
30942633Sobrien	    am_get_progname(), hlfs_group);
31038494Sobrien  } else {
31138494Sobrien    hlfs_gid = grp->gr_gid;
31238494Sobrien  }
31338494Sobrien
31438494Sobrien  /* get hostname for logging and open log before we reset umask */
31541145Sobrien  gethostname(hostname, sizeof(hostname));
31638500Sobrien  hostname[sizeof(hostname) - 1] = '\0';
31738494Sobrien  if ((dot = strchr(hostname, '.')) != NULL)
31838494Sobrien    *dot = '\0';
31942633Sobrien  orig_umask = umask(0);
32038494Sobrien  if (logfile)
321174313Sobrien    switch_to_logfile(logfile, orig_umask, 0);
32238494Sobrien
323174313Sobrien#ifndef MOUNT_TABLE_ON_FILE
324174313Sobrien  if (amuDebug(D_MTAB))
32538494Sobrien    dlog("-D mtab option ignored");
326174313Sobrien#endif /* not MOUNT_TABLE_ON_FILE */
32738494Sobrien
32838494Sobrien  /* avoid hanging on other NFS servers if started elsewhere */
32938494Sobrien  if (chdir("/") < 0)
33038494Sobrien    fatal("cannot chdir to /: %m");
33138494Sobrien
33238494Sobrien  if (geteuid() != 0)
33338494Sobrien    fatal("must be root to mount filesystems");
33438494Sobrien
33538494Sobrien  /*
33638494Sobrien   * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with
33738494Sobrien   * slinkname = `basename $dir_name` - requires dir_name be writable
33838494Sobrien   */
33938494Sobrien
34038494Sobrien  if (dir_name[0] != '/'
34138494Sobrien      || ((slinkname = strrchr(dir_name, '/')), *slinkname++ = '\0',
34238494Sobrien	  (dir_name[0] == '\0' || slinkname[0] == '\0'))) {
34338494Sobrien    if (slinkname)
34438494Sobrien      *--slinkname = '/';
34538494Sobrien    printf("%s: invalid mount directory/link %s\n",
34642633Sobrien	   am_get_progname(), dir_name);
34738494Sobrien    exit(3);
34838494Sobrien  }
34938494Sobrien
35038494Sobrien  if (!forcefast) {
35138494Sobrien    /* make sure mount point exists and is at least mode 555 */
35238494Sobrien    if (stat(dir_name, &stmodes) < 0)
35338494Sobrien      if (errno != ENOENT || mkdirs(dir_name, 0555) < 0
35438494Sobrien	  || stat(dir_name, &stmodes) < 0)
35538494Sobrien	fatalerror(dir_name);
35638494Sobrien
35738494Sobrien    if ((stmodes.st_mode & 0555) != 0555) {
35838494Sobrien      fprintf(stderr, "%s: directory %s not read/executable\n",
35942633Sobrien	      am_get_progname(), dir_name);
36038494Sobrien      plog(XLOG_WARNING, "directory %s not read/executable",
36138494Sobrien	   dir_name);
36238494Sobrien    }
36338494Sobrien
36438494Sobrien    /* warn if extraneous stuff will be hidden by mount */
36538494Sobrien    if ((mountdir = opendir(dir_name)) == NULL)
36638494Sobrien      fatalerror(dir_name);
36738494Sobrien
36838494Sobrien    while ((direntry = readdir(mountdir)) != NULL) {
36938494Sobrien      if (!NSTREQ(".", direntry->d_name, NAMLEN(direntry)) &&
37038494Sobrien	  !NSTREQ("..", direntry->d_name, NAMLEN(direntry)) &&
37138494Sobrien	  !NSTREQ(slinkname, direntry->d_name, NAMLEN(direntry)))
37238494Sobrien	break;
37338494Sobrien    }
37438494Sobrien
37538494Sobrien    if (direntry != NULL) {
37638494Sobrien      fprintf(stderr, "%s: %s/%s will be hidden by mount\n",
37742633Sobrien	      am_get_progname(), dir_name, direntry->d_name);
37838494Sobrien      plog(XLOG_WARNING, "%s/%s will be hidden by mount\n",
37938494Sobrien	   dir_name, direntry->d_name);
38038494Sobrien    }
38138494Sobrien    closedir(mountdir);
38238494Sobrien
38338494Sobrien    /* make sure alternate spool dir exists */
38438494Sobrien    if ((errno = mkdirs(alt_spooldir, OPEN_SPOOLMODE))) {
38538494Sobrien      fprintf(stderr, "%s: cannot create alternate dir ",
38642633Sobrien	      am_get_progname());
38738494Sobrien      perror(alt_spooldir);
38838494Sobrien      plog(XLOG_ERROR, "cannot create alternate dir %s: %m",
38938494Sobrien	   alt_spooldir);
39038494Sobrien    }
39138494Sobrien    chmod(alt_spooldir, OPEN_SPOOLMODE);
39238494Sobrien
39338494Sobrien    /* create failsafe link to alternate spool directory */
394174313Sobrien    *(slinkname-1) = '/';	/* unsplit dir_name to include link */
39538494Sobrien    if (lstat(dir_name, &stmodes) == 0 &&
39638494Sobrien	(stmodes.st_mode & S_IFMT) != S_IFLNK) {
39738494Sobrien      fprintf(stderr, "%s: failsafe %s not a symlink\n",
39842633Sobrien	      am_get_progname(), dir_name);
39938494Sobrien      plog(XLOG_WARNING, "failsafe %s not a symlink\n",
40038494Sobrien	   dir_name);
40138494Sobrien    } else {
40238494Sobrien      unlink(dir_name);
40338494Sobrien
40438494Sobrien      if (symlink(alt_spooldir, dir_name) < 0) {
40538494Sobrien	fprintf(stderr,
40638494Sobrien		"%s: cannot create failsafe symlink %s -> ",
40742633Sobrien		am_get_progname(), dir_name);
40838494Sobrien	perror(alt_spooldir);
40938494Sobrien	plog(XLOG_WARNING,
41038494Sobrien	     "cannot create failsafe symlink %s -> %s: %m",
41138494Sobrien	     dir_name, alt_spooldir);
41238494Sobrien      }
41338494Sobrien    }
41438494Sobrien
415174313Sobrien    *(slinkname-1) = '\0';	/* resplit dir_name */
41638494Sobrien  } /* end of "if (!forcefast) {" */
41738494Sobrien
41838494Sobrien  /*
41938494Sobrien   * Register hlfsd as an nfs service with the portmapper.
42038494Sobrien   */
42138494Sobrien#ifdef HAVE_TRANSPORT_TYPE_TLI
42238494Sobrien  ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
42338494Sobrien#else /* not HAVE_TRANSPORT_TYPE_TLI */
42438494Sobrien  ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
42538494Sobrien#endif /* not HAVE_TRANSPORT_TYPE_TLI */
42638494Sobrien  if (ret != 0)
42738494Sobrien    fatal("cannot create NFS service");
42838494Sobrien
42938494Sobrien#ifdef HAVE_SIGACTION
43038494Sobrien  sa.sa_handler = proceed;
431174313Sobrien  sa.sa_flags = 0;
43238494Sobrien  sigemptyset(&(sa.sa_mask));
43338494Sobrien  sigaddset(&(sa.sa_mask), SIGUSR2);
43438494Sobrien  sigaction(SIGUSR2, &sa, NULL);
43538494Sobrien#else /* not HAVE_SIGACTION */
43638494Sobrien  signal(SIGUSR2, proceed);
43738494Sobrien#endif /* not HAVE_SIGACTION */
43838494Sobrien
43938494Sobrien  plog(XLOG_INFO, "Initializing hlfsd...");
44038494Sobrien  hlfsd_init();			/* start up child (forking) to run svc_run */
44138494Sobrien
44238494Sobrien#ifdef HAVE_SIGACTION
44338494Sobrien  sa.sa_handler = reaper;
444174313Sobrien  sa.sa_flags = 0;
44538494Sobrien  sigemptyset(&(sa.sa_mask));
44638494Sobrien  sigaddset(&(sa.sa_mask), SIGCHLD);
44738494Sobrien  sigaction(SIGCHLD, &sa, NULL);
44838494Sobrien#else /* not HAVE_SIGACTION */
44938494Sobrien  signal(SIGCHLD, reaper);
45038494Sobrien#endif /* not HAVE_SIGACTION */
45138494Sobrien
45238494Sobrien  /*
453174313Sobrien   * In the parent, if -D daemon, we don't need to
45438494Sobrien   * set this signal handler.
45538494Sobrien   */
456174313Sobrien  if (!amuDebug(D_DAEMON)) {
45738494Sobrien    s = -99;
45838494Sobrien    while (stoplight != SIGUSR2) {
45938494Sobrien      plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight);
460174313Sobrien#ifdef HAVE_SIGSUSPEND
461174313Sobrien      {
462174313Sobrien	sigset_t mask;
463174313Sobrien	sigemptyset(&mask);
464174313Sobrien	s = sigsuspend(&mask);	/* wait for child to set up */
465174313Sobrien      }
466174313Sobrien#else /* not HAVE_SIGSUSPEND */
46738494Sobrien      s = sigpause(0);		/* wait for child to set up */
468174313Sobrien#endif /* not HAVE_SIGSUSPEND */
46938494Sobrien      sleep(1);
47038494Sobrien    }
47138494Sobrien  }
47238494Sobrien
47338494Sobrien  /*
47438494Sobrien   * setup options to mount table (/etc/{mtab,mnttab}) entry
47538494Sobrien   */
476174313Sobrien  xsnprintf(hostpid_fs, sizeof(hostpid_fs),
477174313Sobrien	    "%s:(pid%d)", hostname, masterpid);
47838494Sobrien  memset((char *) &mnt, 0, sizeof(mnt));
47938494Sobrien  mnt.mnt_dir = dir_name;	/* i.e., "/mail" */
48038494Sobrien  mnt.mnt_fsname = hostpid_fs;
48138494Sobrien  if (mntopts) {
48238494Sobrien    mnt.mnt_opts = mntopts;
48338494Sobrien  } else {
484174313Sobrien    xstrlcpy(preopts, default_mntopts, sizeof(preopts));
48538494Sobrien    /*
48638494Sobrien     * Turn off all kinds of attribute and symlink caches as
48738494Sobrien     * much as possible.  Also make sure that mount does not
48838494Sobrien     * show up to df.
48938494Sobrien     */
49038494Sobrien#ifdef MNTTAB_OPT_INTR
491174313Sobrien    xstrlcat(preopts, ",", sizeof(preopts));
492174313Sobrien    xstrlcat(preopts, MNTTAB_OPT_INTR, sizeof(preopts));
49338494Sobrien#endif /* MNTTAB_OPT_INTR */
49438494Sobrien#ifdef MNTTAB_OPT_IGNORE
495174313Sobrien    xstrlcat(preopts, ",", sizeof(preopts));
496174313Sobrien    xstrlcat(preopts, MNTTAB_OPT_IGNORE, sizeof(preopts));
49738494Sobrien#endif /* MNTTAB_OPT_IGNORE */
49838494Sobrien#ifdef MNT2_GEN_OPT_CACHE
499174313Sobrien    xstrlcat(preopts, ",nocache", sizeof(preopts));
50038494Sobrien#endif /* MNT2_GEN_OPT_CACHE */
50138494Sobrien#ifdef MNT2_NFS_OPT_SYMTTL
502174313Sobrien    xstrlcat(preopts, ",symttl=0", sizeof(preopts));
50338494Sobrien#endif /* MNT2_NFS_OPT_SYMTTL */
50438494Sobrien    mnt.mnt_opts = preopts;
50538494Sobrien  }
50638494Sobrien
50738494Sobrien  /*
50838494Sobrien   * Make sure that amd's top-level NFS mounts are hidden by default
50938494Sobrien   * from df.
51038494Sobrien   * If they don't appear to support the either the "ignore" mnttab
51138494Sobrien   * option entry, or the "auto" one, set the mount type to "nfs".
51238494Sobrien   */
513174313Sobrien#ifdef HIDE_MOUNT_TYPE
51438494Sobrien  mnt.mnt_type = HIDE_MOUNT_TYPE;
515174313Sobrien#else /* not HIDE_MOUNT_TYPE */
516174313Sobrien  mnt.mnt_type = "nfs";
517174313Sobrien#endif /* not HIDE_MOUNT_TYPE */
51838494Sobrien  /* some systems don't have a mount type, but a mount flag */
51938494Sobrien
52038494Sobrien#ifndef HAVE_TRANSPORT_TYPE_TLI
521174313Sobrien  amu_get_myaddress(&localsocket.sin_addr, NULL);
52238494Sobrien  localsocket.sin_family = AF_INET;
52338494Sobrien  localsocket.sin_port = htons(nfsxprt->xp_port);
52438494Sobrien#endif /* not HAVE_TRANSPORT_TYPE_TLI */
52538494Sobrien
52638494Sobrien  /*
52738494Sobrien   * Update hostname field.
52838494Sobrien   * Make some name prog:pid (i.e., hlfsd:174) for hostname
52938494Sobrien   */
530174313Sobrien  xsnprintf(progpid_fs, sizeof(progpid_fs),
531174313Sobrien	    "%s:%d", am_get_progname(), masterpid);
53238494Sobrien
53338494Sobrien  /* Most kernels have a name length restriction. */
53438494Sobrien  if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN)
535174313Sobrien    xstrlcpy(progpid_fs + MAXHOSTNAMELEN - 3, "..",
536174313Sobrien	     sizeof(progpid_fs) - MAXHOSTNAMELEN + 3);
53738494Sobrien
53838494Sobrien  genflags = compute_mount_flags(&mnt);
53938494Sobrien
54038494Sobrien  retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
54138494Sobrien  if (retry <= 0)
54238494Sobrien    retry = 1;			/* XXX */
54338494Sobrien
544174313Sobrien  memmove(&anh.v2, root_fhp, sizeof(*root_fhp));
54538494Sobrien#ifdef HAVE_TRANSPORT_TYPE_TLI
54638494Sobrien  compute_nfs_args(&nfs_args,
54738494Sobrien		   &mnt,
54838494Sobrien		   genflags,
54938494Sobrien		   nfsncp,
55038494Sobrien		   NULL,	/* remote host IP addr is set below */
55138494Sobrien		   NFS_VERSION,	/* version 2 */
55238494Sobrien		   "udp",	/* XXX: shouldn't this be "udp"? */
55338494Sobrien		   &anh,
55438494Sobrien		   progpid_fs,	/* host name for kernel */
55538494Sobrien		   hostpid_fs); /* filesystem name for kernel */
55638494Sobrien  /*
55738494Sobrien   * IMPORTANT: set the correct IP address AFTERWARDS.  It cannot
55838494Sobrien   * be done using the normal mechanism of compute_nfs_args(), because
55938494Sobrien   * that one will allocate a new address and use NFS_SA_DREF() to copy
56038494Sobrien   * parts to it, while assuming that the ip_addr passed is always
56138494Sobrien   * a "struct sockaddr_in".  That assumption is incorrect on TLI systems,
56238494Sobrien   * because they define a special macro HOST_SELF which is DIFFERENT
56338494Sobrien   * than localhost (127.0.0.1)!
56438494Sobrien   */
56538494Sobrien  nfs_args.addr = &nfsxprt->xp_ltaddr;
56638494Sobrien#else /* not HAVE_TRANSPORT_TYPE_TLI */
56738494Sobrien  compute_nfs_args(&nfs_args,
56838494Sobrien		   &mnt,
56938494Sobrien		   genflags,
570174313Sobrien		   NULL,
57138494Sobrien		   &localsocket,
57238494Sobrien		   NFS_VERSION, /* version 2 */
57338494Sobrien		   "udp",	/* XXX: shouldn't this be "udp"? */
57438494Sobrien		   &anh,
57538494Sobrien		   progpid_fs,	/* host name for kernel */
57638494Sobrien		   hostpid_fs); /* filesystem name for kernel */
57738494Sobrien#endif /* not HAVE_TRANSPORT_TYPE_TLI */
57838494Sobrien
57938494Sobrien  /*************************************************************************
58038494Sobrien   * NOTE: while compute_nfs_args() works ok for regular NFS mounts	   *
58138494Sobrien   * the toplvl one is not, and so some options must be corrected by hand  *
58238494Sobrien   * more carefully, *after* compute_nfs_args() runs.			   *
58338494Sobrien   *************************************************************************/
58438494Sobrien  compute_automounter_nfs_args(&nfs_args, &mnt);
58538494Sobrien
58638494Sobrien/*
58738494Sobrien * For some reason, this mount may have to be done in the background, if I am
588174313Sobrien * using -D daemon.  I suspect that the actual act of mounting requires
58938494Sobrien * calling to hlfsd itself to invoke one or more of its nfs calls, to stat
590174313Sobrien * /mail.  That means that even if you say -D daemon, at least the mount
59138494Sobrien * of hlfsd itself on top of /mail will be done in the background.
59238494Sobrien * The other alternative I have is to run svc_run, but set a special
59338494Sobrien * signal handler to perform the mount in N seconds via some alarm.
59438494Sobrien *      -Erez Zadok.
59538494Sobrien */
596174313Sobrien  if (!amuDebug(D_DAEMON)) {	/* Normal case */
597174313Sobrien    plog(XLOG_INFO, "normal NFS mounting hlfsd service points");
598174313Sobrien    if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0)
59938494Sobrien      fatal("nfsmount: %m");
600174313Sobrien  } else {			/* asked for -D daemon */
60138494Sobrien    if (fork() == 0) {		/* child runs mount */
60242633Sobrien      am_set_mypid();
60338494Sobrien      foreground = 0;
60438494Sobrien      plog(XLOG_INFO, "child NFS mounting hlfsd service points");
605174313Sobrien      if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0) {
60638494Sobrien	fatal("nfsmount: %m");
60738494Sobrien      }
60838494Sobrien      exit(0);			/* all went well */
60938494Sobrien    } else { /* fork failed or parent running */
61038494Sobrien      plog(XLOG_INFO, "parent waiting 1sec for mount...");
61138494Sobrien    }
61238494Sobrien  }
61338494Sobrien
61438494Sobrien#ifdef HAVE_TRANSPORT_TYPE_TLI
61538494Sobrien  /*
61638494Sobrien   * XXX: this free_knetconfig() was not done for hlfsd before,
61738494Sobrien   * and apparently there was a reason for it, but why? -Erez
61838494Sobrien   */
61938494Sobrien  free_knetconfig(nfs_args.knconf);
62038494Sobrien  /*
62138494Sobrien   * local automounter mounts do not allocate a special address, so
62238494Sobrien   * no need to XFREE(nfs_args.addr) under TLI.
62338494Sobrien   */
62438494Sobrien#endif /* HAVE_TRANSPORT_TYPE_TLI */
62538494Sobrien
62638494Sobrien  if (printpid)
62738494Sobrien    printf("%d\n", masterpid);
62838494Sobrien
62938494Sobrien  plog(XLOG_INFO, "hlfsd ready to serve");
63038494Sobrien  /*
631174313Sobrien   * If asked not to fork a daemon (-D daemon), then hlfsd_init()
63238494Sobrien   * will not run svc_run.  We must start svc_run here.
63338494Sobrien   */
634174313Sobrien  if (amuDebug(D_DAEMON)) {
635174313Sobrien    plog(XLOG_DEBUG, "starting no-daemon debugging svc_run");
63638494Sobrien    svc_run();
637174313Sobrien  }
63838494Sobrien
63938494Sobrien  cleanup(0);			/* should never happen here */
64038494Sobrien  return (0);			/* everything went fine? */
64138494Sobrien}
64238494Sobrien
64338494Sobrien
64438494Sobrienstatic void
64538494Sobrienhlfsd_init(void)
64638494Sobrien{
64738494Sobrien  int child = 0;
64838494Sobrien#ifdef HAVE_SIGACTION
64938494Sobrien  struct sigaction sa;
65038494Sobrien#endif /* HAVE_SIGACTION */
65138494Sobrien
65238494Sobrien  /*
65338494Sobrien   * Initialize file handles.
65438494Sobrien   */
65538494Sobrien  plog(XLOG_INFO, "initializing hlfsd file handles");
65638494Sobrien  hlfsd_init_filehandles();
65738494Sobrien
65838494Sobrien  /*
659174313Sobrien   * If not -D daemon then we must fork.
66038494Sobrien   */
661174313Sobrien  if (!amuDebug(D_DAEMON))
66238494Sobrien    child = fork();
66338494Sobrien
66438494Sobrien  if (child < 0)
66538494Sobrien    fatal("fork: %m");
66638494Sobrien
66738494Sobrien  if (child != 0) {		/* parent process - save child pid */
66838494Sobrien    masterpid = child;
66942633Sobrien    am_set_mypid();		/* for logging routines */
67038494Sobrien    return;
67138494Sobrien  }
67238494Sobrien
67338494Sobrien  /*
67438494Sobrien   * CHILD CODE:
67538494Sobrien   * initialize server
67638494Sobrien   */
67738494Sobrien
67838494Sobrien  plog(XLOG_INFO, "initializing home directory database");
67938494Sobrien  plt_init();			/* initialize database */
68038494Sobrien  plog(XLOG_INFO, "home directory database initialized");
68138494Sobrien
68242633Sobrien  masterpid = serverpid = am_set_mypid(); /* for logging routines */
68338494Sobrien
68438494Sobrien  /*
68538494Sobrien   * SIGALRM/SIGHUP: reload password database if timer expired
68638494Sobrien   * or user sent HUP signal.
68738494Sobrien   */
68838494Sobrien#ifdef HAVE_SIGACTION
68938494Sobrien  sa.sa_handler = reload;
690174313Sobrien  sa.sa_flags = 0;
69138494Sobrien  sigemptyset(&(sa.sa_mask));
69238494Sobrien  sigaddset(&(sa.sa_mask), SIGALRM);
69338494Sobrien  sigaddset(&(sa.sa_mask), SIGHUP);
69438494Sobrien  sigaction(SIGALRM, &sa, NULL);
69538494Sobrien  sigaction(SIGHUP, &sa, NULL);
69638494Sobrien#else /* not HAVE_SIGACTION */
69738494Sobrien  signal(SIGALRM, reload);
69838494Sobrien  signal(SIGHUP, reload);
69938494Sobrien#endif /* not HAVE_SIGACTION */
70038494Sobrien
70138494Sobrien  /*
70238494Sobrien   * SIGTERM: cleanup and exit.
70338494Sobrien   */
70438494Sobrien#ifdef HAVE_SIGACTION
70538494Sobrien  sa.sa_handler = cleanup;
706174313Sobrien  sa.sa_flags = 0;
70738494Sobrien  sigemptyset(&(sa.sa_mask));
70838494Sobrien  sigaddset(&(sa.sa_mask), SIGTERM);
70938494Sobrien  sigaction(SIGTERM, &sa, NULL);
71038494Sobrien#else /* not HAVE_SIGACTION */
71138494Sobrien  signal(SIGTERM, cleanup);
71238494Sobrien#endif /* not HAVE_SIGACTION */
71338494Sobrien
71438494Sobrien  /*
71542633Sobrien   * SIGCHLD: interlock synchronization and testing
71638494Sobrien   */
71738494Sobrien#ifdef HAVE_SIGACTION
71838494Sobrien  sa.sa_handler = interlock;
719174313Sobrien  sa.sa_flags = 0;
72038494Sobrien  sigemptyset(&(sa.sa_mask));
72138494Sobrien  sigaddset(&(sa.sa_mask), SIGCHLD);
72238494Sobrien  sigaction(SIGCHLD, &sa, NULL);
72338494Sobrien#else /* not HAVE_SIGACTION */
72438494Sobrien  signal(SIGCHLD, interlock);
72538494Sobrien#endif /* not HAVE_SIGACTION */
72638494Sobrien
72738494Sobrien  /*
72838494Sobrien   * SIGUSR1: dump internal hlfsd maps/cache to file
72938494Sobrien   */
73038494Sobrien#ifdef HAVE_SIGACTION
73138494Sobrien# if defined(DEBUG) || defined(DEBUG_PRINT)
73238494Sobrien  sa.sa_handler = plt_print;
73338494Sobrien# else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
73438494Sobrien  sa.sa_handler = SIG_IGN;
73538494Sobrien# endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
736174313Sobrien  sa.sa_flags = 0;
73738494Sobrien  sigemptyset(&(sa.sa_mask));
73838494Sobrien  sigaddset(&(sa.sa_mask), SIGUSR1);
73938494Sobrien  sigaction(SIGUSR1, &sa, NULL);
74038494Sobrien#else /* not HAVE_SIGACTION */
74138494Sobrien# if defined(DEBUG) || defined(DEBUG_PRINT)
74238494Sobrien  signal(SIGUSR1, plt_print);
74338494Sobrien# else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
74438494Sobrien  signal(SIGUSR1, SIG_IGN);
74538494Sobrien# endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
74638494Sobrien#endif /* not HAVE_SIGACTION */
74738494Sobrien
74838494Sobrien  if (setitimer(ITIMER_REAL, &reloadinterval, (struct itimerval *) 0) < 0)
74938494Sobrien    fatal("setitimer: %m");
75038494Sobrien
751174313Sobrien  clocktime(&startup);
75238494Sobrien
75338494Sobrien  /*
754174313Sobrien   * If not -D daemon, then start serving here in the child,
755174313Sobrien   * and the parent will exit.  But if -D daemon, then
75638494Sobrien   * skip this code and make sure svc_run is entered elsewhere.
75738494Sobrien   */
758174313Sobrien  if (!amuDebug(D_DAEMON)) {
75938494Sobrien    /*
76038494Sobrien     * Dissociate from the controlling terminal
76138494Sobrien     */
76238494Sobrien    amu_release_controlling_tty();
76338494Sobrien
76438494Sobrien    /*
76538494Sobrien     * signal parent we are ready. parent should
76638494Sobrien     * mount(2) and die.
76738494Sobrien     */
76838494Sobrien    if (kill(getppid(), SIGUSR2) < 0)
76938494Sobrien      fatal("kill: %m");
77038494Sobrien    plog(XLOG_INFO, "starting svc_run");
77138494Sobrien    svc_run();
77238494Sobrien    cleanup(0);		/* should never happen, just in case */
773174313Sobrien  }
77438494Sobrien
77538494Sobrien}
77638494Sobrien
77738494Sobrien
77838494Sobrienstatic RETSIGTYPE
77938494Sobrienproceed(int signum)
78038494Sobrien{
78138494Sobrien  stoplight = signum;
78238494Sobrien}
78338494Sobrien
78438494Sobrien
78538494Sobrienstatic RETSIGTYPE
78638494Sobrienreload(int signum)
78738494Sobrien{
78838494Sobrien  int child;
78938494Sobrien  int status;
79038494Sobrien
79138494Sobrien  if (getpid() != masterpid)
79238494Sobrien    return;
79338494Sobrien
79438494Sobrien  /*
79538494Sobrien   * If received a SIGHUP, close and reopen the log file (so that it
79638494Sobrien   * can be rotated)
79738494Sobrien   */
79838494Sobrien  if (signum == SIGHUP && logfile)
799174313Sobrien    switch_to_logfile(logfile, orig_umask, 0);
80038494Sobrien
80138494Sobrien  /*
80238494Sobrien   * parent performs the reload, while the child continues to serve
80338494Sobrien   * clients accessing the home dir link.
80438494Sobrien   */
80538494Sobrien  if ((child = fork()) > 0) {
80638494Sobrien    serverpid = child;		/* parent runs here */
80742633Sobrien    am_set_mypid();
80838494Sobrien
80938494Sobrien    plt_init();
81038494Sobrien
81138494Sobrien    if (kill(child, SIGKILL) < 0) {
81238494Sobrien      plog(XLOG_ERROR, "kill child: %m");
81338494Sobrien    } else {			/* wait for child to die before continue */
81438494Sobrien      if (wait(&status) != child) {
81538494Sobrien	/*
81638494Sobrien	 * I took out this line because it generates annoying output.  It
81738494Sobrien	 * indicates a very small bug in hlfsd which is totally harmless.
81838494Sobrien	 * It causes hlfsd to work a bit harder than it should.
81938494Sobrien	 * Nevertheless, I intend on fixing it in a future release.
82038494Sobrien	 * -Erez Zadok <ezk@cs.columbia.edu>
82138494Sobrien	 */
82238494Sobrien	/* plog(XLOG_ERROR, "unknown child"); */
82338494Sobrien      }
82438494Sobrien    }
82538494Sobrien    serverpid = masterpid;
82638494Sobrien  } else if (child < 0) {
82738494Sobrien    plog(XLOG_ERROR, "unable to fork: %m");
82838494Sobrien  } else {
82938494Sobrien    /* let child handle requests while we reload */
83038494Sobrien    serverpid = getpid();
83142633Sobrien    am_set_mypid();
83238494Sobrien  }
83338494Sobrien}
83438494Sobrien
83538494Sobrien
83638494SobrienRETSIGTYPE
83738494Sobriencleanup(int signum)
83838494Sobrien{
83938494Sobrien  struct stat stbuf;
84038494Sobrien  int umount_result;
84138494Sobrien
842174313Sobrien  if (!amuDebug(D_DAEMON)) {
84338494Sobrien    if (getpid() != masterpid)
844119682Smbr      return;
84538494Sobrien
84638494Sobrien    if (fork() != 0) {
847119682Smbr      masterpid = 0;
848119682Smbr      am_set_mypid();
849119682Smbr      return;
850119682Smbr    }
851174313Sobrien  }
85242633Sobrien  am_set_mypid();
85338494Sobrien
85438494Sobrien  for (;;) {
855174313Sobrien    while ((umount_result = UMOUNT_FS(dir_name, mnttab_file_name, 0)) == EBUSY) {
85638494Sobrien      dlog("cleanup(): umount delaying for 10 seconds");
85738494Sobrien      sleep(10);
85838494Sobrien    }
85938494Sobrien    if (stat(dir_name, &stbuf) == 0 && stbuf.st_ino == ROOTID) {
86038494Sobrien      plog(XLOG_ERROR, "unable to unmount %s", dir_name);
86138494Sobrien      plog(XLOG_ERROR, "suspending, unmount before terminating");
86242633Sobrien      kill(am_mypid, SIGSTOP);
86338494Sobrien      continue;			/* retry unmount */
86438494Sobrien    }
86538494Sobrien    break;
86638494Sobrien  }
86738494Sobrien
868174313Sobrien  if (!amuDebug(D_DAEMON)) {
869174313Sobrien    plog(XLOG_INFO, "cleanup(): killing processes and terminating");
87038494Sobrien    kill(masterpid, SIGKILL);
87138494Sobrien    kill(serverpid, SIGKILL);
872174313Sobrien  }
87338494Sobrien
87438494Sobrien  plog(XLOG_INFO, "hlfsd terminating with status 0\n");
875174313Sobrien  _exit(0);
87638494Sobrien}
87738494Sobrien
87838494Sobrien
87938494Sobrienstatic RETSIGTYPE
88038494Sobrienreaper(int signum)
88138494Sobrien{
88238494Sobrien  int result;
88338494Sobrien
88438494Sobrien  if (wait(&result) == masterpid) {
885174313Sobrien    _exit(4);
88638494Sobrien  }
88738494Sobrien}
88838494Sobrien
88938494Sobrien
89038494Sobrienvoid
89138494Sobrienhlfsd_going_down(int rc)
89238494Sobrien{
89342633Sobrien  int mypid = getpid();		/* XXX: should this be the global am_mypid */
89438494Sobrien
89538494Sobrien  if (mypid == masterpid)
89638494Sobrien    cleanup(0);
89738494Sobrien  else if (mypid == serverpid)
89838494Sobrien    kill(masterpid, SIGTERM);
89938494Sobrien
90038494Sobrien  exit(rc);
90138494Sobrien}
90238494Sobrien
90338494Sobrien
90438494Sobrienvoid
90538494Sobrienfatal(char *mess)
90638494Sobrien{
90738494Sobrien  if (logfile && !STREQ(logfile, "stderr")) {
90838494Sobrien    char lessmess[128];
90938494Sobrien    int messlen;
91038494Sobrien
91138494Sobrien    messlen = strlen(mess);
91238494Sobrien
91338494Sobrien    if (!STREQ(&mess[messlen + 1 - sizeof(ERRM)], ERRM))
91442633Sobrien      fprintf(stderr, "%s: %s\n", am_get_progname(), mess);
91538494Sobrien    else {
916174313Sobrien      xstrlcpy(lessmess, mess, sizeof(lessmess));
91738494Sobrien      lessmess[messlen - 4] = '\0';
91838494Sobrien
919119682Smbr      fprintf(stderr, "%s: %s: %s\n",
920119682Smbr	      am_get_progname(), lessmess, strerror(errno));
92138494Sobrien    }
92238494Sobrien  }
92382804Sobrien  plog(XLOG_FATAL, "%s", mess);
92438494Sobrien
92538494Sobrien  hlfsd_going_down(1);
92638494Sobrien}
927