2 * Copyright (c) 1997-2014 Erez Zadok
3 * Copyright (c) 1989 Jan-Simon Pendry
4 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1989 The Regents of the University of California.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * File: am-utils/hlfsd/hlfsd.c
38 * HLFSD was written at Columbia University Computer Science Department, by
39 * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
40 * It is being distributed under the same terms and conditions as amd does.
45 #endif /* HAVE_CONFIG_H */
52 static RETSIGTYPE proceed(int);
53 static RETSIGTYPE reaper(int);
54 static RETSIGTYPE reload(int);
55 static char *hlfs_group = DEFAULT_HLFS_GROUP;
56 static char default_dir_name[] = DEFAULT_DIRNAME;
57 static char *dir_name = default_dir_name;
58 static int printpid = 0;
59 static int stoplight = 0;
60 static void hlfsd_init(void);
61 static void usage(void);
63 static struct itimerval reloadinterval = {
64 {DEFAULT_INTERVAL, 0},
69 * default mount options.
71 static char default_mntopts[] = "ro,noac";
77 char *alt_spooldir = ALT_SPOOLDIR;
78 char *home_subdir = HOME_SUBDIR;
79 char *logfile = DEFAULT_LOGFILE;
80 char *passwdfile = NULL; /* alternate passwd file to use */
81 char *slinkname = NULL;
82 char hostname[MAXHOSTNAMELEN + 1] = "localhost";
83 u_int cache_interval = DEFAULT_CACHE_INTERVAL;
84 gid_t hlfs_gid = (gid_t) INVALIDID;
92 /* symbol must be available always */
93 #ifdef MNTTAB_FILE_NAME
94 char *mnttab_file_name = MNTTAB_FILE_NAME;
95 #else /* not MNTTAB_FILE_NAME */
96 char *mnttab_file_name = NULL;
97 #endif /* not MNTTAB_FILE_NAME */
99 /* forward declarations */
100 void hlfsd_going_down(int rc);
101 void fatalerror(char *str);
108 "Usage: %s [-Cfhnpv] [-a altdir] [-c cache-interval] [-g group]\n",
110 fprintf(stderr, "\t[-i interval] [-l logfile] [-o mntopts] [-P passwdfile]\n");
111 show_opts('x', xlog_opt);
113 show_opts('D', dbg_opt);
115 fprintf(stderr, "\t[dir_name [subdir]]\n");
121 fatalerror(char *str)
124 size_t l = strlen(str) + sizeof(ERRM) - 1;
125 char *tmp = strnsave(str, l);
126 xstrlcat(tmp, ERRM, l);
132 main(int argc, char *argv[])
135 char *mntopts = (char *) NULL;
136 char hostpid_fs[MAXHOSTNAMELEN + 1 + 16]; /* room for ":(pid###)" */
137 char progpid_fs[PROGNAMESZ + 1 + 11]; /* room for ":pid" */
146 int soNFS; /* NFS socket */
151 struct dirent *direntry;
155 MTYPE_TYPE type = MOUNT_TYPE_NFS;
157 #ifdef HAVE_SIGACTION
159 #endif /* not HAVE_SIGACTION */
161 #ifndef HAVE_TRANSPORT_TYPE_TLI
162 struct sockaddr_in localsocket;
163 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
166 /* get program name and truncate so we don't overflow progpid_fs */
168 if ((progname = strrchr(argv[0], '/')) != NULL)
172 if ((int) strlen(progname) > PROGNAMESZ) /* truncate to reasonable size */
173 progname[PROGNAMESZ] = '\0';
174 am_set_progname(progname);
176 while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1)
180 if (!optarg || optarg[0] != '/') {
181 printf("%s: invalid directory for -a: %s\n",
182 am_get_progname(), optarg);
185 alt_spooldir = optarg;
190 printf("%s: invalid interval for -c: %s\n",
191 am_get_progname(), optarg);
194 cache_interval = atoi(optarg);
211 printf("%s: invalid interval for -i: %s\n",
212 am_get_progname(), optarg);
215 reloadinterval.it_interval.tv_sec = atoi(optarg);
216 reloadinterval.it_value.tv_sec = atoi(optarg);
240 fprintf(stderr, "%s\n", HLFSD_VERSION);
244 opterrs += switch_option(optarg);
249 opterrs += debug_option(optarg);
250 #else /* not DEBUG */
251 fprintf(stderr, "%s: not compiled with DEBUG -- sorry.\n", am_get_progname());
252 #endif /* not DEBUG */
260 /* need my pid before any dlog/plog */
263 switch_option("debug");
267 * Terminate if did not ask to forcecache (-C) and hlfsd would not be able
268 * to set the minimum cache intervals.
270 #if !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN)
272 fprintf(stderr, "%s: will not be able to turn off attribute caches.\n", am_get_progname());
275 #endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN) */
278 switch (argc - optind) {
280 home_subdir = argv[optind + 1];
282 dir_name = argv[optind];
292 /* ensure that only root can run hlfsd */
294 fprintf(stderr, "hlfsd can only be run as root\n");
297 setbuf(stdout, (char *) NULL);
300 /* find gid for hlfs_group */
301 if ((grp = getgrnam(hlfs_group)) == (struct group *) NULL) {
302 fprintf(stderr, "%s: cannot get gid for group \"%s\".\n",
303 am_get_progname(), hlfs_group);
305 hlfs_gid = grp->gr_gid;
308 /* get hostname for logging and open log before we reset umask */
309 if (gethostname(hostname, sizeof(hostname)) == -1) {
310 fprintf(stderr, "%s: gethostname failed \"%s\".\n",
311 am_get_progname(), strerror(errno));
314 hostname[sizeof(hostname) - 1] = '\0';
315 if ((dot = strchr(hostname, '.')) != NULL)
317 orig_umask = umask(0);
319 switch_to_logfile(logfile, orig_umask, 0);
321 #ifndef MOUNT_TABLE_ON_FILE
322 if (amuDebug(D_MTAB))
323 dlog("-D mtab option ignored");
324 #endif /* not MOUNT_TABLE_ON_FILE */
326 /* avoid hanging on other NFS servers if started elsewhere */
328 fatal("cannot chdir to /: %m");
331 fatal("must be root to mount filesystems");
334 * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with
335 * slinkname = `basename $dir_name` - requires dir_name be writable
338 if (dir_name[0] != '/'
339 || ((slinkname = strrchr(dir_name, '/')), *slinkname++ = '\0',
340 (dir_name[0] == '\0' || slinkname[0] == '\0'))) {
343 printf("%s: invalid mount directory/link %s\n",
344 am_get_progname(), dir_name);
349 /* make sure mount point exists and is at least mode 555 */
350 if (stat(dir_name, &stmodes) < 0)
351 if (errno != ENOENT || mkdirs(dir_name, 0555) < 0
352 || stat(dir_name, &stmodes) < 0)
353 fatalerror(dir_name);
355 if ((stmodes.st_mode & 0555) != 0555) {
356 fprintf(stderr, "%s: directory %s not read/executable\n",
357 am_get_progname(), dir_name);
358 plog(XLOG_WARNING, "directory %s not read/executable",
362 /* warn if extraneous stuff will be hidden by mount */
363 if ((mountdir = opendir(dir_name)) == NULL)
364 fatalerror(dir_name);
366 while ((direntry = readdir(mountdir)) != NULL) {
367 if (!NSTREQ(".", direntry->d_name, NAMLEN(direntry)) &&
368 !NSTREQ("..", direntry->d_name, NAMLEN(direntry)) &&
369 !NSTREQ(slinkname, direntry->d_name, NAMLEN(direntry)))
373 if (direntry != NULL) {
374 fprintf(stderr, "%s: %s/%s will be hidden by mount\n",
375 am_get_progname(), dir_name, direntry->d_name);
376 plog(XLOG_WARNING, "%s/%s will be hidden by mount\n",
377 dir_name, direntry->d_name);
381 /* make sure alternate spool dir exists */
382 if ((errno = mkdirs(alt_spooldir, OPEN_SPOOLMODE))) {
383 fprintf(stderr, "%s: cannot create alternate dir ",
385 perror(alt_spooldir);
386 plog(XLOG_ERROR, "cannot create alternate dir %s: %m",
389 chmod(alt_spooldir, OPEN_SPOOLMODE);
391 /* create failsafe link to alternate spool directory */
392 *(slinkname-1) = '/'; /* unsplit dir_name to include link */
393 if (lstat(dir_name, &stmodes) == 0 &&
394 (stmodes.st_mode & S_IFMT) != S_IFLNK) {
395 fprintf(stderr, "%s: failsafe %s not a symlink\n",
396 am_get_progname(), dir_name);
397 plog(XLOG_WARNING, "failsafe %s not a symlink\n",
402 if (symlink(alt_spooldir, dir_name) < 0) {
404 "%s: cannot create failsafe symlink %s -> ",
405 am_get_progname(), dir_name);
406 perror(alt_spooldir);
408 "cannot create failsafe symlink %s -> %s: %m",
409 dir_name, alt_spooldir);
413 *(slinkname-1) = '\0'; /* resplit dir_name */
414 } /* end of "if (!forcefast) {" */
417 * Register hlfsd as an nfs service with the portmapper.
419 ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2,
422 fatal("cannot create NFS service");
424 #ifdef HAVE_SIGACTION
425 sa.sa_handler = proceed;
427 sigemptyset(&(sa.sa_mask));
428 sigaddset(&(sa.sa_mask), SIGUSR2);
429 sigaction(SIGUSR2, &sa, NULL);
430 #else /* not HAVE_SIGACTION */
431 signal(SIGUSR2, proceed);
432 #endif /* not HAVE_SIGACTION */
434 plog(XLOG_INFO, "Initializing hlfsd...");
435 hlfsd_init(); /* start up child (forking) to run svc_run */
437 #ifdef HAVE_SIGACTION
438 sa.sa_handler = reaper;
440 sigemptyset(&(sa.sa_mask));
441 sigaddset(&(sa.sa_mask), SIGCHLD);
442 sigaction(SIGCHLD, &sa, NULL);
443 #else /* not HAVE_SIGACTION */
444 signal(SIGCHLD, reaper);
445 #endif /* not HAVE_SIGACTION */
448 * In the parent, if -D nodaemon, we don't need to
449 * set this signal handler.
451 if (amuDebug(D_DAEMON)) {
453 while (stoplight != SIGUSR2) {
454 plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight);
455 #ifdef HAVE_SIGSUSPEND
459 s = sigsuspend(&mask); /* wait for child to set up */
461 #else /* not HAVE_SIGSUSPEND */
462 s = sigpause(0); /* wait for child to set up */
463 #endif /* not HAVE_SIGSUSPEND */
469 * setup options to mount table (/etc/{mtab,mnttab}) entry
471 xsnprintf(hostpid_fs, sizeof(hostpid_fs),
472 "%s:(pid%d)", hostname, masterpid);
473 memset((char *) &mnt, 0, sizeof(mnt));
474 mnt.mnt_dir = dir_name; /* i.e., "/mail" */
475 mnt.mnt_fsname = hostpid_fs;
477 mnt.mnt_opts = mntopts;
479 xstrlcpy(preopts, default_mntopts, sizeof(preopts));
481 * Turn off all kinds of attribute and symlink caches as
482 * much as possible. Also make sure that mount does not
485 #ifdef MNTTAB_OPT_INTR
486 xstrlcat(preopts, ",", sizeof(preopts));
487 xstrlcat(preopts, MNTTAB_OPT_INTR, sizeof(preopts));
488 #endif /* MNTTAB_OPT_INTR */
489 #ifdef MNTTAB_OPT_IGNORE
490 xstrlcat(preopts, ",", sizeof(preopts));
491 xstrlcat(preopts, MNTTAB_OPT_IGNORE, sizeof(preopts));
492 #endif /* MNTTAB_OPT_IGNORE */
493 #ifdef MNT2_GEN_OPT_CACHE
494 xstrlcat(preopts, ",nocache", sizeof(preopts));
495 #endif /* MNT2_GEN_OPT_CACHE */
496 #ifdef MNT2_NFS_OPT_SYMTTL
497 xstrlcat(preopts, ",symttl=0", sizeof(preopts));
498 #endif /* MNT2_NFS_OPT_SYMTTL */
499 mnt.mnt_opts = preopts;
503 * Make sure that amd's top-level NFS mounts are hidden by default
505 * If they don't appear to support the either the "ignore" mnttab
506 * option entry, or the "auto" one, set the mount type to "nfs".
508 #ifdef HIDE_MOUNT_TYPE
509 mnt.mnt_type = HIDE_MOUNT_TYPE;
510 #else /* not HIDE_MOUNT_TYPE */
511 mnt.mnt_type = "nfs";
512 #endif /* not HIDE_MOUNT_TYPE */
513 /* some systems don't have a mount type, but a mount flag */
515 #ifndef HAVE_TRANSPORT_TYPE_TLI
516 amu_get_myaddress(&localsocket.sin_addr, NULL);
517 localsocket.sin_family = AF_INET;
518 localsocket.sin_port = htons(nfsxprt->xp_port);
519 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
522 * Update hostname field.
523 * Make some name prog:pid (i.e., hlfsd:174) for hostname
525 xsnprintf(progpid_fs, sizeof(progpid_fs),
526 "%s:%d", am_get_progname(), masterpid);
528 /* Most kernels have a name length restriction. */
529 if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN)
530 xstrlcpy(progpid_fs + MAXHOSTNAMELEN - 3, "..",
531 sizeof(progpid_fs) - MAXHOSTNAMELEN + 3);
533 genflags = compute_mount_flags(&mnt);
535 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
539 memmove(&anh.v2, root_fhp, sizeof(*root_fhp));
540 #ifdef HAVE_TRANSPORT_TYPE_TLI
541 compute_nfs_args(&nfs_args,
545 NULL, /* remote host IP addr is set below */
546 NFS_VERSION, /* version 2 */
547 "udp", /* XXX: shouldn't this be "udp"? */
549 progpid_fs, /* host name for kernel */
550 hostpid_fs); /* filesystem name for kernel */
552 * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
553 * be done using the normal mechanism of compute_nfs_args(), because
554 * that one will allocate a new address and use NFS_SA_DREF() to copy
555 * parts to it, while assuming that the ip_addr passed is always
556 * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
557 * because they define a special macro HOST_SELF which is DIFFERENT
558 * than localhost (127.0.0.1)!
560 nfs_args.addr = &nfsxprt->xp_ltaddr;
561 #else /* not HAVE_TRANSPORT_TYPE_TLI */
562 compute_nfs_args(&nfs_args,
567 NFS_VERSION, /* version 2 */
568 "udp", /* XXX: shouldn't this be "udp"? */
570 progpid_fs, /* host name for kernel */
571 hostpid_fs); /* filesystem name for kernel */
572 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
574 /*************************************************************************
575 * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
576 * the toplvl one is not, and so some options must be corrected by hand *
577 * more carefully, *after* compute_nfs_args() runs. *
578 *************************************************************************/
579 compute_automounter_nfs_args(&nfs_args, &mnt);
582 * For some reason, this mount may have to be done in the background, if I am
583 * using -D daemon. I suspect that the actual act of mounting requires
584 * calling to hlfsd itself to invoke one or more of its nfs calls, to stat
585 * /mail. That means that even if you say -D daemon, at least the mount
586 * of hlfsd itself on top of /mail will be done in the background.
587 * The other alternative I have is to run svc_run, but set a special
588 * signal handler to perform the mount in N seconds via some alarm.
591 if (!amuDebug(D_DAEMON)) { /* Normal case */
592 plog(XLOG_INFO, "normal NFS mounting hlfsd service points");
593 if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0)
594 fatal("nfsmount: %m");
595 } else { /* asked for -D daemon */
596 if (fork() == 0) { /* child runs mount */
599 plog(XLOG_INFO, "child NFS mounting hlfsd service points");
600 if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0) {
601 fatal("nfsmount: %m");
603 exit(0); /* all went well */
604 } else { /* fork failed or parent running */
605 plog(XLOG_INFO, "parent waiting 1sec for mount...");
609 #ifdef HAVE_TRANSPORT_TYPE_TLI
611 * XXX: this free_knetconfig() was not done for hlfsd before,
612 * and apparently there was a reason for it, but why? -Erez
614 free_knetconfig(nfs_args.knconf);
616 * local automounter mounts do not allocate a special address, so
617 * no need to XFREE(nfs_args.addr) under TLI.
619 #endif /* HAVE_TRANSPORT_TYPE_TLI */
622 printf("%d\n", masterpid);
624 plog(XLOG_INFO, "hlfsd ready to serve");
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.
629 if (!amuDebug(D_DAEMON)) {
630 plog(XLOG_DEBUG, "starting no-daemon debugging svc_run");
634 cleanup(0); /* should never happen here */
635 return (0); /* everything went fine? */
643 #ifdef HAVE_SIGACTION
645 #endif /* HAVE_SIGACTION */
648 * Initialize file handles.
650 plog(XLOG_INFO, "initializing hlfsd file handles");
651 hlfsd_init_filehandles();
654 * If -D daemon then we must fork.
656 if (amuDebug(D_DAEMON))
662 if (child != 0) { /* parent process - save child pid */
664 am_set_mypid(); /* for logging routines */
673 plog(XLOG_INFO, "initializing home directory database");
674 plt_init(); /* initialize database */
675 plog(XLOG_INFO, "home directory database initialized");
677 masterpid = serverpid = am_set_mypid(); /* for logging routines */
680 * SIGALRM/SIGHUP: reload password database if timer expired
681 * or user sent HUP signal.
683 #ifdef HAVE_SIGACTION
684 sa.sa_handler = reload;
686 sigemptyset(&(sa.sa_mask));
687 sigaddset(&(sa.sa_mask), SIGALRM);
688 sigaddset(&(sa.sa_mask), SIGHUP);
689 sigaction(SIGALRM, &sa, NULL);
690 sigaction(SIGHUP, &sa, NULL);
691 #else /* not HAVE_SIGACTION */
692 signal(SIGALRM, reload);
693 signal(SIGHUP, reload);
694 #endif /* not HAVE_SIGACTION */
697 * SIGTERM: cleanup and exit.
699 #ifdef HAVE_SIGACTION
700 sa.sa_handler = cleanup;
702 sigemptyset(&(sa.sa_mask));
703 sigaddset(&(sa.sa_mask), SIGTERM);
704 sigaction(SIGTERM, &sa, NULL);
705 #else /* not HAVE_SIGACTION */
706 signal(SIGTERM, cleanup);
707 #endif /* not HAVE_SIGACTION */
710 * SIGCHLD: interlock synchronization and testing
712 #ifdef HAVE_SIGACTION
713 sa.sa_handler = interlock;
715 sigemptyset(&(sa.sa_mask));
716 sigaddset(&(sa.sa_mask), SIGCHLD);
717 sigaction(SIGCHLD, &sa, NULL);
718 #else /* not HAVE_SIGACTION */
719 signal(SIGCHLD, interlock);
720 #endif /* not HAVE_SIGACTION */
723 * SIGUSR1: dump internal hlfsd maps/cache to file
725 #ifdef HAVE_SIGACTION
726 # if defined(DEBUG) || defined(DEBUG_PRINT)
727 sa.sa_handler = plt_print;
728 # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
729 sa.sa_handler = SIG_IGN;
730 # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
732 sigemptyset(&(sa.sa_mask));
733 sigaddset(&(sa.sa_mask), SIGUSR1);
734 sigaction(SIGUSR1, &sa, NULL);
735 #else /* not HAVE_SIGACTION */
736 # if defined(DEBUG) || defined(DEBUG_PRINT)
737 signal(SIGUSR1, plt_print);
738 # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
739 signal(SIGUSR1, SIG_IGN);
740 # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
741 #endif /* not HAVE_SIGACTION */
743 if (setitimer(ITIMER_REAL, &reloadinterval, (struct itimerval *) NULL) < 0)
744 fatal("setitimer: %m");
749 * If -D daemon, then start serving here in the child,
750 * and the parent will exit. But if -D nodaemon, then
751 * skip this code and make sure svc_run is entered elsewhere.
753 if (amuDebug(D_DAEMON)) {
755 * Dissociate from the controlling terminal
757 amu_release_controlling_tty();
760 * signal parent we are ready. parent should
763 if (kill(getppid(), SIGUSR2) < 0)
765 plog(XLOG_INFO, "starting svc_run");
767 cleanup(0); /* should never happen, just in case */
786 if (getpid() != masterpid)
790 * If received a SIGHUP, close and reopen the log file (so that it
793 if (signum == SIGHUP && logfile)
794 switch_to_logfile(logfile, orig_umask, 0);
797 * parent performs the reload, while the child continues to serve
798 * clients accessing the home dir link.
800 if ((child = fork()) > 0) {
801 serverpid = child; /* parent runs here */
806 if (kill(child, SIGKILL) < 0) {
807 plog(XLOG_ERROR, "kill child: %m");
808 } else { /* wait for child to die before continue */
809 if (wait(&status) != child) {
811 * I took out this line because it generates annoying output. It
812 * indicates a very small bug in hlfsd which is totally harmless.
813 * It causes hlfsd to work a bit harder than it should.
814 * Nevertheless, I intend on fixing it in a future release.
815 * -Erez Zadok <ezk@cs.columbia.edu>
817 /* plog(XLOG_ERROR, "unknown child"); */
820 serverpid = masterpid;
821 } else if (child < 0) {
822 plog(XLOG_ERROR, "unable to fork: %m");
824 /* let child handle requests while we reload */
825 serverpid = getpid();
837 if (amuDebug(D_DAEMON)) {
838 if (getpid() != masterpid)
850 while ((umount_result = UMOUNT_FS(dir_name, mnttab_file_name, 0)) == EBUSY) {
851 dlog("cleanup(): umount delaying for 10 seconds");
854 if (stat(dir_name, &stbuf) == 0 && stbuf.st_ino == ROOTID) {
855 plog(XLOG_ERROR, "unable to unmount %s", dir_name);
856 plog(XLOG_ERROR, "suspending, unmount before terminating");
857 kill(am_mypid, SIGSTOP);
858 continue; /* retry unmount */
863 if (amuDebug(D_DAEMON)) {
864 plog(XLOG_INFO, "cleanup(): killing processes and terminating");
865 kill(masterpid, SIGKILL);
866 kill(serverpid, SIGKILL);
869 plog(XLOG_INFO, "hlfsd terminating with status 0\n");
879 if (wait(&result) == masterpid) {
886 hlfsd_going_down(int rc)
888 int mypid = getpid(); /* XXX: should this be the global am_mypid */
890 if (mypid == masterpid)
892 else if (mypid == serverpid)
893 kill(masterpid, SIGTERM);
902 if (logfile && !STREQ(logfile, "stderr")) {
906 messlen = strlen(mess);
908 if (!STREQ(&mess[messlen + 1 - sizeof(ERRM)], ERRM))
909 fprintf(stderr, "%s: %s\n", am_get_progname(), mess);
911 xstrlcpy(lessmess, mess, sizeof(lessmess));
912 lessmess[messlen - 4] = '\0';
914 fprintf(stderr, "%s: %s: %s\n",
915 am_get_progname(), lessmess, strerror(errno));
918 plog(XLOG_FATAL, "%s", mess);