X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=daemon.c;h=8f39e86cfe48f18b1c9ed0e86a0039e26258f00f;hb=33cddbff323efcbae1503e91e6e65b2733da80c7;hp=b08f31e97a765891d70b1cb00be2b110dbadd22f;hpb=538023278d853b2f310954e0b220be25ccea6330;p=~andy%2Ffetchmail diff --git a/daemon.c b/daemon.c index b08f31e9..8f39e86c 100644 --- a/daemon.c +++ b/daemon.c @@ -1,105 +1,88 @@ -/* Copyright 1993-95 by Carl Harris, Jr. Copyright 1996 by Eric S. Raymond - * All rights reserved. +/* + * daemon.c -- turn a process into a daemon under POSIX, SYSV, BSD. + * * For license terms, see the file COPYING in this directory. */ - -/*********************************************************************** - module: daemon - project: popclient - programmer: Carl Harris, ceharris@mal.com - description: This module contains all of the code needed to - turn a process into a daemon for POSIX, SysV, and - BSD systems. - - ***********************************************************************/ - - -#include +#include "config.h" #include -#include -#include +#include #include +#include +#include +#include #include +#include /* get umask(2) prototyped */ -#if defined(HAVE_SYS_WAIT_H) -# include -#endif +#include -#if defined(HAVE_UNISTD_H) -# include -#endif +#include -#if defined(QNX) -# include -#endif +#include /* for TIOCNOTTY under Linux */ /* BSD portability hack */ -#if !defined(SIGCLD) && defined(SIGCHLD) -#define SIGCLD SIGCHLD +#if !defined(SIGCHLD) && defined(SIGCLD) +#define SIGCHLD SIGCLD #endif -#include "popclient.h" - -/****************************************************************** - function: sigchld_handler - description: Process the SIGCHLD (a.k.a SIGCLD) signal by calling - a wait() variant to obtain the exit code of the - terminating process. - arguments: none. - ret. value: none (or undefined if REGSIGTYPE is int). - globals: none. - calls: none. - *****************************************************************/ - -RETSIGTYPE -sigchld_handler () -{ - pid_t pid; - -#if defined(HAVE_UNION_WAIT) - union wait status; -#else - int status; -#endif +#include "fetchmail.h" +#include "tunable.h" -#if defined(HAVE_WAIT3) - while ((pid = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0) - ; /* swallow 'em up. */ -#elif defined(HAVE_WAITPID) - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) - ; /* swallow 'em up. */ -#else /* Zooks! Nothing to do but wait(), and hope we don't block... */ - wait(&status); -#endif +static void +sigchld_handler (int sig) +/* process SIGCHLD to obtain the exit code of the terminating process */ +{ + int status; + while (waitpid(-1, &status, WNOHANG) > 0) + continue; /* swallow 'em up. */ + 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 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). + */ +{ + SIGHANDLERTYPE rethandler; + struct sigaction sa_new, sa_old; + + memset (&sa_new, 0, sizeof sa_new); + sigemptyset (&sa_new.sa_mask); + 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) + if (sig == SIGCHLD) + sigaction(SIGPWR, &sa_new, NULL); +#endif + return rethandler; +} -/****************************************************************** - function: daemonize - description: become a daemon process; i.e. detach from the - control terminal, don't reacquire a control terminal, - become process group leader of our own process group, - and set up to catch child process termination signals. - arguments: - logfile file to direct stdout and stderr to, if non-NULL. - - ret. value: none. - globals: termhook, sigchld_handler(). - calls: none. - *****************************************************************/ +void deal_with_sigchld(void) +{ + set_signal_handler(SIGCHLD, sigchld_handler); +} int -daemonize (logfile, termhook) -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; - RETSIGTYPE sigchld_handler(); /* if we are started by init (process 1) via /etc/inittab we needn't bother to detach from our process group context */ @@ -109,13 +92,13 @@ void (*termhook)(int); /* Ignore BSD terminal stop signals */ #ifdef SIGTTOU - signal(SIGTTOU, SIG_IGN); + set_signal_handler(SIGTTOU, SIG_IGN); #endif #ifdef SIGTTIN - signal(SIGTTIN, SIG_IGN); + set_signal_handler(SIGTTIN, SIG_IGN); #endif #ifdef SIGTSTP - signal(SIGTSTP, SIG_IGN); + set_signal_handler(SIGTSTP, SIG_IGN); #endif /* In case we were not started in the background, fork and let @@ -123,7 +106,7 @@ void (*termhook)(int); group leader */ if ((childpid = fork()) < 0) { - perror("fork"); + report(stderr, "fork (%s)\n", strerror(errno)); return(PS_IOERR); } else if (childpid > 0) @@ -133,70 +116,55 @@ 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) { - perror("setsid"); + report(stderr, "setsid (%s)\n", strerror(errno)); return(PS_IOERR); } -#elif defined(SIGTSTP) /* BSD */ - /* change process group */ - setpgrp(0, getpid()); - - /* lose controlling tty */ - if ((fd = open("/dev/tty", O_RDWR)) >= 0) { - ioctl(fd, TIOCNOTTY, (char *) 0); - close(fd); - } -#else /* SVR3 and older */ - /* change process group */ - setpgrp(); - - /* lose controlling tty */ - signal(SIGHUP, SIG_IGN); - if ((childpid = fork) < 0) { - perror("fork"); + +nottyDetach: + + (void)close(0); + + /* Reopen stdin descriptor on /dev/null */ + if (open("/dev/null", O_RDWR) < 0) { /* stdin */ + report(stderr, "cannot open /dev/null: %s\n", strerror(errno)); return(PS_IOERR); } - else if (childpid > 0) { - exit(0); /* parent */ - } -#endif -nottyDetach: + if (logfile) + { + 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) - for (fd = getdtablesize()-1; fd >= 0; fd--) + fd = getdtablesize() - 1; #elif defined(NOFILE) - for (fd = NOFILE-1; fd >= 0; fd--) + fd = NOFILE - 1; #else /* make an educated guess */ - for (fd = 19; fd >= 0; fd--) + fd = 1023; #endif - { - close(fd); - } - - /* Reopen stdin descriptor on /dev/null */ - if ((fd = open("/dev/null", O_RDWR)) < 0) { /* stdin */ - perror("open: /dev/null"); - return(PS_IOERR); + while (fd >= 1) { + if (fd != logfd) + close(fd); /* not checking this should be safe, no writes */ + -- fd; } - if (logfile) - fd = open(logfile, O_CREAT|O_WRONLY, 0777); /* stdout */ - else - if (dup(fd) < 0) { /* stdout */ - perror("dup"); + 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 */ - perror("dup"); - 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) @@ -205,9 +173,26 @@ nottyDetach: umask(022); #endif - /* set up to catch child process termination signals */ - signal(SIGCLD, sigchld_handler); -#if defined(QNX) - signal(SIGPWR, sigchld_handler); -#endif + deal_with_sigchld(); + + return(0); +} + +flag is_a_file(int fd) +/* is the given fd attached to a file? (used to control logging) */ +{ + struct stat stbuf; + + /* + * We'd like just to return 1 on (S_IFREG | S_IFBLK), + * but weirdly enough, Linux ptys seem to have S_IFBLK + * so this test would fail when run on an xterm. + */ + if (isatty(fd) || fstat(fd, &stbuf)) + return(0); + else if (stbuf.st_mode & (S_IFREG)) + return(1); + return(0); } + +/* daemon.c ends here */