4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1989 Jan-Simon Pendry
6 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1989 The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * File: am-utils/hlfsd/hlfsd.c
44 * HLFSD was written at Columbia University Computer Science Department, by
45 * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
46 * It is being distributed under the same terms and conditions as amd does.
51 #endif /* HAVE_CONFIG_H */
58 static RETSIGTYPE
proceed(int);
59 static RETSIGTYPE
reaper(int);
60 static RETSIGTYPE
reload(int);
61 static char *hlfs_group
= DEFAULT_HLFS_GROUP
;
62 static char default_dir_name
[] = DEFAULT_DIRNAME
;
63 static char *dir_name
= default_dir_name
;
64 static int printpid
= 0;
65 static int stoplight
= 0;
66 static void hlfsd_init(void);
67 static void usage(void);
69 static struct itimerval reloadinterval
= {
70 {DEFAULT_INTERVAL
, 0},
75 * default mount options.
77 static char default_mntopts
[] = "ro,noac";
83 char *alt_spooldir
= ALT_SPOOLDIR
;
84 char *home_subdir
= HOME_SUBDIR
;
85 char *logfile
= DEFAULT_LOGFILE
;
86 char *passwdfile
= NULL
; /* alternate passwd file to use */
87 char *slinkname
= NULL
;
88 char hostname
[MAXHOSTNAMELEN
+ 1] = "localhost";
89 u_int cache_interval
= DEFAULT_CACHE_INTERVAL
;
90 gid_t hlfs_gid
= (gid_t
) INVALIDID
;
98 /* symbol must be available always */
99 #ifdef MNTTAB_FILE_NAME
100 char *mnttab_file_name
= MNTTAB_FILE_NAME
;
101 #else /* not MNTTAB_FILE_NAME */
102 char *mnttab_file_name
= NULL
;
103 #endif /* not MNTTAB_FILE_NAME */
105 /* forward declarations */
106 void hlfsd_going_down(int rc
);
107 void fatalerror(char *str
);
114 "Usage: %s [-Cfhnpv] [-a altdir] [-c cache-interval] [-g group]\n",
116 fprintf(stderr
, "\t[-i interval] [-l logfile] [-o mntopts] [-P passwdfile]\n");
117 show_opts('x', xlog_opt
);
119 show_opts('D', dbg_opt
);
121 fprintf(stderr
, "\t[dir_name [subdir]]\n");
127 fatalerror(char *str
)
130 size_t l
= strlen(str
) + sizeof(ERRM
) - 1;
131 char *tmp
= strnsave(str
, l
);
132 xstrlcat(tmp
, ERRM
, l
);
138 main(int argc
, char *argv
[])
141 char *mntopts
= (char *) NULL
;
142 char hostpid_fs
[MAXHOSTNAMELEN
+ 1 + 16]; /* room for ":(pid###)" */
143 char progpid_fs
[PROGNAMESZ
+ 1 + 11]; /* room for ":pid" */
152 int soNFS
; /* NFS socket */
157 struct dirent
*direntry
;
161 MTYPE_TYPE type
= MOUNT_TYPE_NFS
;
163 #ifdef HAVE_SIGACTION
165 #endif /* not HAVE_SIGACTION */
167 #ifndef HAVE_TRANSPORT_TYPE_TLI
168 struct sockaddr_in localsocket
;
169 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
172 /* get program name and truncate so we don't overflow progpid_fs */
174 if ((progname
= strrchr(argv
[0], '/')) != NULL
)
178 if ((int) strlen(progname
) > PROGNAMESZ
) /* truncate to reasonable size */
179 progname
[PROGNAMESZ
] = '\0';
180 am_set_progname(progname
);
182 while ((opt
= getopt(argc
, argv
, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1)
186 if (!optarg
|| optarg
[0] != '/') {
187 printf("%s: invalid directory for -a: %s\n",
188 am_get_progname(), optarg
);
191 alt_spooldir
= optarg
;
196 printf("%s: invalid interval for -c: %s\n",
197 am_get_progname(), optarg
);
200 cache_interval
= atoi(optarg
);
217 printf("%s: invalid interval for -i: %s\n",
218 am_get_progname(), optarg
);
221 reloadinterval
.it_interval
.tv_sec
= atoi(optarg
);
222 reloadinterval
.it_value
.tv_sec
= atoi(optarg
);
246 fprintf(stderr
, "%s\n", HLFSD_VERSION
);
250 opterrs
+= switch_option(optarg
);
255 opterrs
+= debug_option(optarg
);
256 #else /* not DEBUG */
257 fprintf(stderr
, "%s: not compiled with DEBUG -- sorry.\n", am_get_progname());
258 #endif /* not DEBUG */
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 nodaemon, 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 nodaemon), 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 -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
*) NULL
) < 0)
749 fatal("setitimer: %m");
754 * If -D daemon, then start serving here in the child,
755 * and the parent will exit. But if -D nodaemon, then
756 * skip this code and make sure svc_run is entered elsewhere.
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
);