X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=daemon.c;h=8f39e86cfe48f18b1c9ed0e86a0039e26258f00f;hb=98cfcef26048bba06975e68a1aad05a8bac0d65d;hp=220d0d0c1d1ba9f4b954614c4f917dfb164bfd50;hpb=d988048914d0f54c06c3bf86ab97a4c14b9e78fe;p=~andy%2Ffetchmail diff --git a/daemon.c b/daemon.c index 220d0d0c..8f39e86c 100644 --- a/daemon.c +++ b/daemon.c @@ -11,39 +11,15 @@ #include #include #include -#ifdef HAVE_SYS_WAIT_H #include -#endif -#ifdef HAVE_FCNTL_H #include -#else /* !HAVE_FCNTL_H */ -#ifdef HAVE_SYS_FCNTL_H -#include -#endif /* HAVE_SYS_FCNTL_H */ -#endif /* !HAVE_FCNTL_H */ #include /* get umask(2) prototyped */ -#if defined(HAVE_UNISTD_H) #include -#endif -#if defined(STDC_HEADERS) #include -#endif - -#if defined(QNX) -#include -#endif - -#if !defined(HAVE_SETSID) && defined(SIGTSTP) -#if defined(HAVE_TERMIOS_H) -# include /* for TIOCNOTTY under Linux */ -#endif -#if !defined(TIOCNOTTY) && defined(HAVE_SGTTY_H) -# include /* for TIOCNOTTY under NEXTSTEP */ -#endif -#endif /* !defined(HAVE_SETSID) && defined(SIGTSTP) */ +#include /* for TIOCNOTTY under Linux */ /* BSD portability hack */ #if !defined(SIGCHLD) && defined(SIGCLD) @@ -53,76 +29,60 @@ #include "fetchmail.h" #include "tunable.h" -RETSIGTYPE +static void sigchld_handler (int sig) /* process SIGCHLD to obtain the exit code of the terminating process */ { - extern volatile int lastsig; /* last signal received */ - pid_t pid; - -#if defined(HAVE_WAITPID) /* the POSIX way */ - int status; - - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) - continue; /* swallow 'em up. */ -#elif defined(HAVE_WAIT3) /* the BSD way */ -#if defined(HAVE_UNION_WAIT) && !defined(__FreeBSD__) - union wait status; -#else int status; -#endif - while ((pid = wait3(&status, WNOHANG, 0)) > 0) + while (waitpid(-1, &status, WNOHANG) > 0) continue; /* swallow 'em up. */ -#else /* Zooks! Nothing to do but wait(), and hope we don't block... */ - int status; - - wait(&status); -#endif lastsig = SIGCHLD; + (void)sig; } +void null_signal_handler(int sig) { (void)sig; } + +SIGHANDLERTYPE set_signal_handler(int sig, SIGHANDLERTYPE handler) /* * This function is called by other parts of the program to - * setup the sigchld handler after a change to the signal context. + * setup the signal handler after a change to the signal context. * This is done to improve robustness of the signal handling code. + * It has the same prototype as signal(2). */ -void deal_with_sigchld(void) { - RETSIGTYPE sigchld_handler(int); -#ifdef HAVE_SIGACTION - struct sigaction sa_new; + SIGHANDLERTYPE rethandler; + struct sigaction sa_new, sa_old; memset (&sa_new, 0, sizeof sa_new); sigemptyset (&sa_new.sa_mask); - /* sa_new.sa_handler = SIG_IGN; pointless */ - - /* set up to catch child process termination signals */ - sa_new.sa_handler = sigchld_handler; -#ifdef SA_RESTART /* SunOS 4.1 portability hack */ - sa_new.sa_flags = SA_RESTART | SA_NOCLDSTOP; -#endif - sigaction (SIGCHLD, &sa_new, NULL); -#if defined(SIGPWR) - sigaction (SIGPWR, &sa_new, NULL); -#endif -#else /* HAVE_SIGACTION */ - signal(SIGCHLD, sigchld_handler); + sa_new.sa_handler = handler; + sa_new.sa_flags = 0; + /* system call should restart on all signals except SIGALRM */ + if (sig != SIGALRM) + sa_new.sa_flags |= SA_RESTART; + if (sig == SIGCHLD) + sa_new.sa_flags |= SA_NOCLDSTOP; + sigaction(sig, &sa_new, &sa_old); + rethandler = sa_old.sa_handler; #if defined(SIGPWR) - signal(SIGPWR, sigchld_handler); + if (sig == SIGCHLD) + sigaction(SIGPWR, &sa_new, NULL); #endif -#endif /* HAVE_SIGACTION */ + return rethandler; +} + +void deal_with_sigchld(void) +{ + set_signal_handler(SIGCHLD, sigchld_handler); } int -daemonize (const char *logfile, void (*termhook)(int)) +daemonize (const char *logfile) /* detach from control TTY, become process group leader, catch SIGCHLD */ { - int fd; + int fd, logfd; pid_t childpid; -#ifdef HAVE_SIGACTION - struct sigaction sa_new; -#endif /* HAVE_SIGACTION */ /* if we are started by init (process 1) via /etc/inittab we needn't bother to detach from our process group context */ @@ -131,34 +91,14 @@ daemonize (const char *logfile, void (*termhook)(int)) goto nottyDetach; /* Ignore BSD terminal stop signals */ -#ifdef HAVE_SIGACTION - memset (&sa_new, 0, sizeof sa_new); - sigemptyset (&sa_new.sa_mask); - sa_new.sa_handler = SIG_IGN; -#ifdef SA_RESTART /* SunOS 4.1 portability hack */ - sa_new.sa_flags = SA_RESTART; -#endif -#endif /* HAVE_SIGACTION */ #ifdef SIGTTOU -#ifndef HAVE_SIGACTION - signal(SIGTTOU, SIG_IGN); -#else - sigaction (SIGTTOU, &sa_new, NULL); -#endif /* HAVE_SIGACTION */ + set_signal_handler(SIGTTOU, SIG_IGN); #endif #ifdef SIGTTIN -#ifndef HAVE_SIGACTION - signal(SIGTTIN, SIG_IGN); -#else - sigaction (SIGTTIN, &sa_new, NULL); -#endif /* HAVE_SIGACTION */ + set_signal_handler(SIGTTIN, SIG_IGN); #endif #ifdef SIGTSTP -#ifndef HAVE_SIGACTION - signal(SIGTSTP, SIG_IGN); -#else - sigaction (SIGTSTP, &sa_new, NULL); -#endif /* HAVE_SIGACTION */ + set_signal_handler(SIGTSTP, SIG_IGN); #endif /* In case we were not started in the background, fork and let @@ -176,84 +116,55 @@ daemonize (const char *logfile, void (*termhook)(int)) /* Make ourselves the leader of a new process group with no controlling terminal */ -#if defined(HAVE_SETSID) /* POSIX */ /* POSIX makes this soooo easy to do */ if (setsid() < 0) { report(stderr, "setsid (%s)\n", strerror(errno)); return(PS_IOERR); } -#elif defined(SIGTSTP) /* BSD */ - /* change process group */ -#ifndef __EMX__ - setpgrp(0, getpid()); -#endif - /* lose controlling tty */ - if ((fd = open("/dev/tty", O_RDWR)) >= 0) { - ioctl(fd, TIOCNOTTY, (char *) 0); - close(fd); /* not checking should be safe, there were no writes */ - } -#else /* SVR3 and older */ - /* change process group */ -#ifndef __EMX__ - setpgrp(); -#endif - - /* lose controlling tty */ -#ifndef HAVE_SIGACTION - signal(SIGHUP, SIG_IGN); -#else - sigaction (SIGHUP, &sa_new, NULL); -#endif /* HAVE_SIGACTION */ - if ((childpid = fork()) < 0) { - report(stderr, "fork (%s)\n", strerror(errno)); - return(PS_IOERR); - } - else if (childpid > 0) { - exit(0); /* parent */ - } -#endif nottyDetach: - /* Close any/all open file descriptors */ -#if defined(HAVE_GETDTABLESIZE) - for (fd = getdtablesize()-1; fd >= 0; fd--) -#elif defined(NOFILE) - for (fd = NOFILE-1; fd >= 0; fd--) -#else /* make an educated guess */ - for (fd = 19; fd >= 0; fd--) -#endif - { - close(fd); /* not checking this should be safe, no writes */ - } + (void)close(0); /* Reopen stdin descriptor on /dev/null */ - if ((fd = open("/dev/null", O_RDWR)) < 0) { /* stdin */ - report(stderr, "open: /dev/null (%s)\n", strerror(errno)); + if (open("/dev/null", O_RDWR) < 0) { /* stdin */ + report(stderr, "cannot open /dev/null: %s\n", strerror(errno)); return(PS_IOERR); } if (logfile) { - if ((fd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0666)) < 0) { /* stdout */ - report(stderr, "open %s (%s)\n", logfile, strerror(errno)); - return(PS_IOERR); - } + if ((logfd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0666)) < 0) { /* stdout */ + report(stderr, "cannot open %s: %s\n", logfile, strerror(errno)); + return PS_IOERR; + } + } else + logfd = 0; /* else use /dev/null */ + + /* Close any/all open file descriptors */ +#if defined(HAVE_GETDTABLESIZE) + fd = getdtablesize() - 1; +#elif defined(NOFILE) + fd = NOFILE - 1; +#else /* make an educated guess */ + fd = 1023; +#endif + while (fd >= 1) { + if (fd != logfd) + close(fd); /* not checking this should be safe, no writes */ + -- fd; } - else - { - if (dup(fd) < 0) { /* stdout */ + + if (dup(logfd) < 0 /* stdout */ + || ((logfd == 0 || logfd >= 3) && dup(logfd) < 0)) { /* stderr */ report(stderr, "dup (%s)\n", strerror(errno)); return(PS_IOERR); - } - } - if (dup(fd) < 0) { /* stderr */ - report(stderr, "dup (%s)\n", strerror(errno)); - return(PS_IOERR); } +#ifdef HAVE_GETCWD /* move to root directory, so we don't prevent filesystem unmounts */ chdir("/"); +#endif /* set our umask to something reasonable (we hope) */ #if defined(DEF_UMASK) @@ -267,7 +178,7 @@ nottyDetach: return(0); } -flag isafile(int fd) +flag is_a_file(int fd) /* is the given fd attached to a file? (used to control logging) */ { struct stat stbuf;