2 * Copyright (c) 1997-2006 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. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * File: am-utils/hlfsd/hlfsd.c
42 * HLFSD was written at Columbia University Computer Science Department, by
43 * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
44 * It is being distributed under the same terms and conditions as amd does.
49 #endif /* HAVE_CONFIG_H */
56 static RETSIGTYPE proceed(int);
57 static RETSIGTYPE reaper(int);
58 static RETSIGTYPE reload(int);
59 static char *hlfs_group = DEFAULT_HLFS_GROUP;
60 static char default_dir_name[] = DEFAULT_DIRNAME;
61 static char *dir_name = default_dir_name;
62 static int printpid = 0;
63 static int stoplight = 0;
64 static void hlfsd_init(void);
65 static void usage(void);
67 static struct itimerval reloadinterval = {
68 {DEFAULT_INTERVAL, 0},
73 * default mount options.
75 static char default_mntopts[] = "ro,noac";
81 char *alt_spooldir = ALT_SPOOLDIR;
82 char *home_subdir = HOME_SUBDIR;
83 char *logfile = DEFAULT_LOGFILE;
84 char *passwdfile = NULL; /* alternate passwd file to use */
86 char hostname[MAXHOSTNAMELEN + 1] = "localhost";
87 u_int cache_interval = DEFAULT_CACHE_INTERVAL;
88 gid_t hlfs_gid = (gid_t) INVALIDID;
96 /* symbol must be available always */
97 #ifdef MNTTAB_FILE_NAME
98 char *mnttab_file_name = MNTTAB_FILE_NAME;
99 #else /* not MNTTAB_FILE_NAME */
100 char *mnttab_file_name = NULL;
101 #endif /* not MNTTAB_FILE_NAME */
103 /* forward declarations */
104 void hlfsd_going_down(int rc);
111 "Usage: %s [-Cfhnpv] [-a altdir] [-c cache-interval] [-g group]\n",
113 fprintf(stderr, "\t[-i interval] [-l logfile] [-o mntopts] [-P passwdfile]\n");
114 show_opts('x', xlog_opt);
116 show_opts('D', dbg_opt);
118 fprintf(stderr, "\t[dir_name [subdir]]\n");
124 fatalerror(char *str)
127 size_t l = strlen(str) + sizeof(ERRM) - 1;
128 char *tmp = strnsave(str, l);
129 xstrlcat(tmp, ERRM, l);
135 main(int argc, char *argv[])
138 char *mntopts = (char *) NULL;
139 char hostpid_fs[MAXHOSTNAMELEN + 1 + 16]; /* room for ":(pid###)" */
140 char progpid_fs[PROGNAMESZ + 1 + 11]; /* room for ":pid" */
149 int soNFS; /* NFS socket */
154 struct dirent *direntry;
158 MTYPE_TYPE type = MOUNT_TYPE_NFS;
160 #ifdef HAVE_SIGACTION
162 #endif /* not HAVE_SIGACTION */
164 #ifndef HAVE_TRANSPORT_TYPE_TLI
165 struct sockaddr_in localsocket;
166 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
169 /* get program name and truncate so we don't overflow progpid_fs */
171 if ((progname = strrchr(argv[0], '/')) != NULL)
175 if ((int) strlen(progname) > PROGNAMESZ) /* truncate to reasonable size */
176 progname[PROGNAMESZ] = '\0';
177 am_set_progname(progname);
179 while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1)
183 if (!optarg || optarg[0] != '/') {
184 printf("%s: invalid directory for -a: %s\n",
185 am_get_progname(), optarg);
188 alt_spooldir = optarg;
193 printf("%s: invalid interval for -c: %s\n",
194 am_get_progname(), optarg);
197 cache_interval = atoi(optarg);
214 printf("%s: invalid interval for -i: %s\n",
215 am_get_progname(), optarg);
218 reloadinterval.it_interval.tv_sec = atoi(optarg);
219 reloadinterval.it_value.tv_sec = atoi(optarg);
243 fprintf(stderr, "%s\n", HLFSD_VERSION);
247 opterrs += switch_option(optarg);
252 opterrs += debug_option(optarg);
253 #else /* not DEBUG */
254 fprintf(stderr, "%s: not compiled with DEBUG -- sorry.\n", am_get_progname());
255 #endif /* not DEBUG */
263 /* set some default debugging options */
264 if (xlog_level_init == ~0)
266 /* need my pid before any dlog/plog */
269 switch_option("debug");
273 * Terminate if did not ask to forcecache (-C) and hlfsd would not be able
274 * to set the minimum cache intervals.
276 #if !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN)
278 fprintf(stderr, "%s: will not be able to turn off attribute caches.\n", am_get_progname());
281 #endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN) */
284 switch (argc - optind) {
286 home_subdir = argv[optind + 1];
288 dir_name = argv[optind];
298 /* ensure that only root can run hlfsd */
300 fprintf(stderr, "hlfsd can only be run as root\n");
303 setbuf(stdout, (char *) NULL);
306 /* find gid for hlfs_group */
307 if ((grp = getgrnam(hlfs_group)) == (struct group *) NULL) {
308 fprintf(stderr, "%s: cannot get gid for group \"%s\".\n",
309 am_get_progname(), hlfs_group);
311 hlfs_gid = grp->gr_gid;
314 /* get hostname for logging and open log before we reset umask */
315 gethostname(hostname, sizeof(hostname));
316 hostname[sizeof(hostname) - 1] = '\0';
317 if ((dot = strchr(hostname, '.')) != NULL)
319 orig_umask = umask(0);
321 switch_to_logfile(logfile, orig_umask, 0);
323 #ifndef MOUNT_TABLE_ON_FILE
324 if (amuDebug(D_MTAB))
325 dlog("-D mtab option ignored");
326 #endif /* not MOUNT_TABLE_ON_FILE */
328 /* avoid hanging on other NFS servers if started elsewhere */
330 fatal("cannot chdir to /: %m");
333 fatal("must be root to mount filesystems");
336 * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with
337 * slinkname = `basename $dir_name` - requires dir_name be writable
340 if (dir_name[0] != '/'
341 || ((slinkname = strrchr(dir_name, '/')), *slinkname++ = '\0',
342 (dir_name[0] == '\0' || slinkname[0] == '\0'))) {
345 printf("%s: invalid mount directory/link %s\n",
346 am_get_progname(), dir_name);
351 /* make sure mount point exists and is at least mode 555 */
352 if (stat(dir_name, &stmodes) < 0)
353 if (errno != ENOENT || mkdirs(dir_name, 0555) < 0
354 || stat(dir_name, &stmodes) < 0)
355 fatalerror(dir_name);
357 if ((stmodes.st_mode & 0555) != 0555) {
358 fprintf(stderr, "%s: directory %s not read/executable\n",
359 am_get_progname(), dir_name);
360 plog(XLOG_WARNING, "directory %s not read/executable",
364 /* warn if extraneous stuff will be hidden by mount */
365 if ((mountdir = opendir(dir_name)) == NULL)
366 fatalerror(dir_name);
368 while ((direntry = readdir(mountdir)) != NULL) {
369 if (!NSTREQ(".", direntry->d_name, NAMLEN(direntry)) &&
370 !NSTREQ("..", direntry->d_name, NAMLEN(direntry)) &&
371 !NSTREQ(slinkname, direntry->d_name, NAMLEN(direntry)))
375 if (direntry != NULL) {
376 fprintf(stderr, "%s: %s/%s will be hidden by mount\n",
377 am_get_progname(), dir_name, direntry->d_name);
378 plog(XLOG_WARNING, "%s/%s will be hidden by mount\n",
379 dir_name, direntry->d_name);
383 /* make sure alternate spool dir exists */
384 if ((errno = mkdirs(alt_spooldir, OPEN_SPOOLMODE))) {
385 fprintf(stderr, "%s: cannot create alternate dir ",
387 perror(alt_spooldir);
388 plog(XLOG_ERROR, "cannot create alternate dir %s: %m",
391 chmod(alt_spooldir, OPEN_SPOOLMODE);
393 /* create failsafe link to alternate spool directory */
394 *(slinkname-1) = '/'; /* unsplit dir_name to include link */
395 if (lstat(dir_name, &stmodes) == 0 &&
396 (stmodes.st_mode & S_IFMT) != S_IFLNK) {
397 fprintf(stderr, "%s: failsafe %s not a symlink\n",
398 am_get_progname(), dir_name);
399 plog(XLOG_WARNING, "failsafe %s not a symlink\n",
404 if (symlink(alt_spooldir, dir_name) < 0) {
406 "%s: cannot create failsafe symlink %s -> ",
407 am_get_progname(), dir_name);
408 perror(alt_spooldir);
410 "cannot create failsafe symlink %s -> %s: %m",
411 dir_name, alt_spooldir);
415 *(slinkname-1) = '\0'; /* resplit dir_name */
416 } /* end of "if (!forcefast) {" */
419 * Register hlfsd as an nfs service with the portmapper.
421 #ifdef HAVE_TRANSPORT_TYPE_TLI
422 ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
423 #else /* not HAVE_TRANSPORT_TYPE_TLI */
424 ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
425 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
427 fatal("cannot create NFS service");
429 #ifdef HAVE_SIGACTION
430 sa.sa_handler = proceed;
432 sigemptyset(&(sa.sa_mask));
433 sigaddset(&(sa.sa_mask), SIGUSR2);
434 sigaction(SIGUSR2, &sa, NULL);
435 #else /* not HAVE_SIGACTION */
436 signal(SIGUSR2, proceed);
437 #endif /* not HAVE_SIGACTION */
439 plog(XLOG_INFO, "Initializing hlfsd...");
440 hlfsd_init(); /* start up child (forking) to run svc_run */
442 #ifdef HAVE_SIGACTION
443 sa.sa_handler = reaper;
445 sigemptyset(&(sa.sa_mask));
446 sigaddset(&(sa.sa_mask), SIGCHLD);
447 sigaction(SIGCHLD, &sa, NULL);
448 #else /* not HAVE_SIGACTION */
449 signal(SIGCHLD, reaper);
450 #endif /* not HAVE_SIGACTION */
453 * In the parent, if -D daemon, we don't need to
454 * set this signal handler.
456 if (!amuDebug(D_DAEMON)) {
458 while (stoplight != SIGUSR2) {
459 plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight);
460 #ifdef HAVE_SIGSUSPEND
464 s = sigsuspend(&mask); /* wait for child to set up */
466 #else /* not HAVE_SIGSUSPEND */
467 s = sigpause(0); /* wait for child to set up */
468 #endif /* not HAVE_SIGSUSPEND */
474 * setup options to mount table (/etc/{mtab,mnttab}) entry
476 xsnprintf(hostpid_fs, sizeof(hostpid_fs),
477 "%s:(pid%d)", hostname, masterpid);
478 memset((char *) &mnt, 0, sizeof(mnt));
479 mnt.mnt_dir = dir_name; /* i.e., "/mail" */
480 mnt.mnt_fsname = hostpid_fs;
482 mnt.mnt_opts = mntopts;
484 xstrlcpy(preopts, default_mntopts, sizeof(preopts));
486 * Turn off all kinds of attribute and symlink caches as
487 * much as possible. Also make sure that mount does not
490 #ifdef MNTTAB_OPT_INTR
491 xstrlcat(preopts, ",", sizeof(preopts));
492 xstrlcat(preopts, MNTTAB_OPT_INTR, sizeof(preopts));
493 #endif /* MNTTAB_OPT_INTR */
494 #ifdef MNTTAB_OPT_IGNORE
495 xstrlcat(preopts, ",", sizeof(preopts));
496 xstrlcat(preopts, MNTTAB_OPT_IGNORE, sizeof(preopts));
497 #endif /* MNTTAB_OPT_IGNORE */
498 #ifdef MNT2_GEN_OPT_CACHE
499 xstrlcat(preopts, ",nocache", sizeof(preopts));
500 #endif /* MNT2_GEN_OPT_CACHE */
501 #ifdef MNT2_NFS_OPT_SYMTTL
502 xstrlcat(preopts, ",symttl=0", sizeof(preopts));
503 #endif /* MNT2_NFS_OPT_SYMTTL */
504 mnt.mnt_opts = preopts;
508 * Make sure that amd's top-level NFS mounts are hidden by default
510 * If they don't appear to support the either the "ignore" mnttab
511 * option entry, or the "auto" one, set the mount type to "nfs".
513 #ifdef HIDE_MOUNT_TYPE
514 mnt.mnt_type = HIDE_MOUNT_TYPE;
515 #else /* not HIDE_MOUNT_TYPE */
516 mnt.mnt_type = "nfs";
517 #endif /* not HIDE_MOUNT_TYPE */
518 /* some systems don't have a mount type, but a mount flag */
520 #ifndef HAVE_TRANSPORT_TYPE_TLI
521 amu_get_myaddress(&localsocket.sin_addr, NULL);
522 localsocket.sin_family = AF_INET;
523 localsocket.sin_port = htons(nfsxprt->xp_port);
524 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
527 * Update hostname field.
528 * Make some name prog:pid (i.e., hlfsd:174) for hostname
530 xsnprintf(progpid_fs, sizeof(progpid_fs),
531 "%s:%d", am_get_progname(), masterpid);
533 /* Most kernels have a name length restriction. */
534 if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN)
535 xstrlcpy(progpid_fs + MAXHOSTNAMELEN - 3, "..",
536 sizeof(progpid_fs) - MAXHOSTNAMELEN + 3);
538 genflags = compute_mount_flags(&mnt);
540 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
544 memmove(&anh.v2, root_fhp, sizeof(*root_fhp));
545 #ifdef HAVE_TRANSPORT_TYPE_TLI
546 compute_nfs_args(&nfs_args,
550 NULL, /* remote host IP addr is set below */
551 NFS_VERSION, /* version 2 */
552 "udp", /* XXX: shouldn't this be "udp"? */
554 progpid_fs, /* host name for kernel */
555 hostpid_fs); /* filesystem name for kernel */
557 * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
558 * be done using the normal mechanism of compute_nfs_args(), because
559 * that one will allocate a new address and use NFS_SA_DREF() to copy
560 * parts to it, while assuming that the ip_addr passed is always
561 * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
562 * because they define a special macro HOST_SELF which is DIFFERENT
563 * than localhost (127.0.0.1)!
565 nfs_args.addr = &nfsxprt->xp_ltaddr;
566 #else /* not HAVE_TRANSPORT_TYPE_TLI */
567 compute_nfs_args(&nfs_args,
572 NFS_VERSION, /* version 2 */
573 "udp", /* XXX: shouldn't this be "udp"? */
575 progpid_fs, /* host name for kernel */
576 hostpid_fs); /* filesystem name for kernel */
577 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
579 /*************************************************************************
580 * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
581 * the toplvl one is not, and so some options must be corrected by hand *
582 * more carefully, *after* compute_nfs_args() runs. *
583 *************************************************************************/
584 compute_automounter_nfs_args(&nfs_args, &mnt);
587 * For some reason, this mount may have to be done in the background, if I am
588 * using -D daemon. I suspect that the actual act of mounting requires
589 * calling to hlfsd itself to invoke one or more of its nfs calls, to stat
590 * /mail. That means that even if you say -D daemon, at least the mount
591 * of hlfsd itself on top of /mail will be done in the background.
592 * The other alternative I have is to run svc_run, but set a special
593 * signal handler to perform the mount in N seconds via some alarm.
596 if (!amuDebug(D_DAEMON)) { /* Normal case */
597 plog(XLOG_INFO, "normal NFS mounting hlfsd service points");
598 if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0)
599 fatal("nfsmount: %m");
600 } else { /* asked for -D daemon */
601 if (fork() == 0) { /* child runs mount */
604 plog(XLOG_INFO, "child NFS mounting hlfsd service points");
605 if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0) {
606 fatal("nfsmount: %m");
608 exit(0); /* all went well */
609 } else { /* fork failed or parent running */
610 plog(XLOG_INFO, "parent waiting 1sec for mount...");
614 #ifdef HAVE_TRANSPORT_TYPE_TLI
616 * XXX: this free_knetconfig() was not done for hlfsd before,
617 * and apparently there was a reason for it, but why? -Erez
619 free_knetconfig(nfs_args.knconf);
621 * local automounter mounts do not allocate a special address, so
622 * no need to XFREE(nfs_args.addr) under TLI.
624 #endif /* HAVE_TRANSPORT_TYPE_TLI */
627 printf("%d\n", masterpid);
629 plog(XLOG_INFO, "hlfsd ready to serve");
631 * If asked not to fork a daemon (-D daemon), then hlfsd_init()
632 * will not run svc_run. We must start svc_run here.
634 if (amuDebug(D_DAEMON)) {
635 plog(XLOG_DEBUG, "starting no-daemon debugging svc_run");
639 cleanup(0); /* should never happen here */
640 return (0); /* everything went fine? */
648 #ifdef HAVE_SIGACTION
650 #endif /* HAVE_SIGACTION */
653 * Initialize file handles.
655 plog(XLOG_INFO, "initializing hlfsd file handles");
656 hlfsd_init_filehandles();
659 * If not -D daemon then we must fork.
661 if (!amuDebug(D_DAEMON))
667 if (child != 0) { /* parent process - save child pid */
669 am_set_mypid(); /* for logging routines */
678 plog(XLOG_INFO, "initializing home directory database");
679 plt_init(); /* initialize database */
680 plog(XLOG_INFO, "home directory database initialized");
682 masterpid = serverpid = am_set_mypid(); /* for logging routines */
685 * SIGALRM/SIGHUP: reload password database if timer expired
686 * or user sent HUP signal.
688 #ifdef HAVE_SIGACTION
689 sa.sa_handler = reload;
691 sigemptyset(&(sa.sa_mask));
692 sigaddset(&(sa.sa_mask), SIGALRM);
693 sigaddset(&(sa.sa_mask), SIGHUP);
694 sigaction(SIGALRM, &sa, NULL);
695 sigaction(SIGHUP, &sa, NULL);
696 #else /* not HAVE_SIGACTION */
697 signal(SIGALRM, reload);
698 signal(SIGHUP, reload);
699 #endif /* not HAVE_SIGACTION */
702 * SIGTERM: cleanup and exit.
704 #ifdef HAVE_SIGACTION
705 sa.sa_handler = cleanup;
707 sigemptyset(&(sa.sa_mask));
708 sigaddset(&(sa.sa_mask), SIGTERM);
709 sigaction(SIGTERM, &sa, NULL);
710 #else /* not HAVE_SIGACTION */
711 signal(SIGTERM, cleanup);
712 #endif /* not HAVE_SIGACTION */
715 * SIGCHLD: interlock synchronization and testing
717 #ifdef HAVE_SIGACTION
718 sa.sa_handler = interlock;
720 sigemptyset(&(sa.sa_mask));
721 sigaddset(&(sa.sa_mask), SIGCHLD);
722 sigaction(SIGCHLD, &sa, NULL);
723 #else /* not HAVE_SIGACTION */
724 signal(SIGCHLD, interlock);
725 #endif /* not HAVE_SIGACTION */
728 * SIGUSR1: dump internal hlfsd maps/cache to file
730 #ifdef HAVE_SIGACTION
731 # if defined(DEBUG) || defined(DEBUG_PRINT)
732 sa.sa_handler = plt_print;
733 # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
734 sa.sa_handler = SIG_IGN;
735 # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
737 sigemptyset(&(sa.sa_mask));
738 sigaddset(&(sa.sa_mask), SIGUSR1);
739 sigaction(SIGUSR1, &sa, NULL);
740 #else /* not HAVE_SIGACTION */
741 # if defined(DEBUG) || defined(DEBUG_PRINT)
742 signal(SIGUSR1, plt_print);
743 # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
744 signal(SIGUSR1, SIG_IGN);
745 # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
746 #endif /* not HAVE_SIGACTION */
748 if (setitimer(ITIMER_REAL, &reloadinterval, (struct itimerval *) 0) < 0)
749 fatal("setitimer: %m");
754 * If not -D daemon, then start serving here in the child,
755 * and the parent will exit. But if -D daemon, then
756 * skip this code and make sure svc_run is entered elsewhere.
758 if (!amuDebug(D_DAEMON)) {
760 * Dissociate from the controlling terminal
762 amu_release_controlling_tty();
765 * signal parent we are ready. parent should
768 if (kill(getppid(), SIGUSR2) < 0)
770 plog(XLOG_INFO, "starting svc_run");
772 cleanup(0); /* should never happen, just in case */
791 if (getpid() != masterpid)
795 * If received a SIGHUP, close and reopen the log file (so that it
798 if (signum == SIGHUP && logfile)
799 switch_to_logfile(logfile, orig_umask, 0);
802 * parent performs the reload, while the child continues to serve
803 * clients accessing the home dir link.
805 if ((child = fork()) > 0) {
806 serverpid = child; /* parent runs here */
811 if (kill(child, SIGKILL) < 0) {
812 plog(XLOG_ERROR, "kill child: %m");
813 } else { /* wait for child to die before continue */
814 if (wait(&status) != child) {
816 * I took out this line because it generates annoying output. It
817 * indicates a very small bug in hlfsd which is totally harmless.
818 * It causes hlfsd to work a bit harder than it should.
819 * Nevertheless, I intend on fixing it in a future release.
820 * -Erez Zadok <ezk@cs.columbia.edu>
822 /* plog(XLOG_ERROR, "unknown child"); */
825 serverpid = masterpid;
826 } else if (child < 0) {
827 plog(XLOG_ERROR, "unable to fork: %m");
829 /* let child handle requests while we reload */
830 serverpid = getpid();
842 if (!amuDebug(D_DAEMON)) {
843 if (getpid() != masterpid)
855 while ((umount_result = UMOUNT_FS(dir_name, mnttab_file_name, 0)) == EBUSY) {
856 dlog("cleanup(): umount delaying for 10 seconds");
859 if (stat(dir_name, &stbuf) == 0 && stbuf.st_ino == ROOTID) {
860 plog(XLOG_ERROR, "unable to unmount %s", dir_name);
861 plog(XLOG_ERROR, "suspending, unmount before terminating");
862 kill(am_mypid, SIGSTOP);
863 continue; /* retry unmount */
868 if (!amuDebug(D_DAEMON)) {
869 plog(XLOG_INFO, "cleanup(): killing processes and terminating");
870 kill(masterpid, SIGKILL);
871 kill(serverpid, SIGKILL);
874 plog(XLOG_INFO, "hlfsd terminating with status 0\n");
884 if (wait(&result) == masterpid) {
891 hlfsd_going_down(int rc)
893 int mypid = getpid(); /* XXX: should this be the global am_mypid */
895 if (mypid == masterpid)
897 else if (mypid == serverpid)
898 kill(masterpid, SIGTERM);
907 if (logfile && !STREQ(logfile, "stderr")) {
911 messlen = strlen(mess);
913 if (!STREQ(&mess[messlen + 1 - sizeof(ERRM)], ERRM))
914 fprintf(stderr, "%s: %s\n", am_get_progname(), mess);
916 xstrlcpy(lessmess, mess, sizeof(lessmess));
917 lessmess[messlen - 4] = '\0';
919 fprintf(stderr, "%s: %s: %s\n",
920 am_get_progname(), lessmess, strerror(errno));
923 plog(XLOG_FATAL, "%s", mess);