X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=daemon.c;h=5ae73ed69565c6bd0d299b85e503494d0d448100;hb=53293ee30678d3db753e51820cc554c0b2b1bd97;hp=89ccdcd66cb6a2396a45cc39a2eb4187d6a05ef9;hpb=edacc32d007ba8dd0cb61f0c3daea81622a8b350;p=~andy%2Ffetchmail diff --git a/daemon.c b/daemon.c index 89ccdcd6..5ae73ed6 100644 --- a/daemon.c +++ b/daemon.c @@ -1,120 +1,158 @@ -/* 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 +#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_SYS_WAIT_H) -# include +#if defined(HAVE_UNISTD_H) +#include #endif -#if defined(HAVE_UNISTD_H) -# include +#if defined(STDC_HEADERS) +#include #endif +#if defined(QNX) +#include +#endif -#include "popclient.h" +#if !defined(HAVE_SETSID) && defined(SIGTSTP) +#if defined(HAVE_TERMIOS_H) +# include /* for TIOCNOTTY under Linux */ +#endif -static void (*my_termhook)(int); +#if !defined(TIOCNOTTY) && defined(HAVE_SGTTY_H) +# include /* for TIOCNOTTY under NEXTSTEP */ +#endif +#endif /* !defined(HAVE_SETSID) && defined(SIGTSTP) */ -/****************************************************************** - 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. - *****************************************************************/ +/* BSD portability hack */ +#if !defined(SIGCHLD) && defined(SIGCLD) +#define SIGCHLD SIGCLD +#endif -RETSIGTYPE -sigchld_handler () -{ - pid_t pid; +#include "fetchmail.h" +#include "tunable.h" -#if defined(HAVE_UNION_WAIT) - union wait status; +static RETSIGTYPE +sigchld_handler (int sig) +/* process SIGCHLD to obtain the exit code of the terminating process */ +{ +#if defined(HAVE_WAITPID) /* the POSIX way */ + int status; + + while (waitpid(-1, &status, WNOHANG) > 0) + continue; /* swallow 'em up. */ +#elif defined(HAVE_WAIT3) /* the BSD way */ + pid_t pid; +#if defined(HAVE_UNION_WAIT) && !defined(__FreeBSD__) + union wait status; #else - int status; + int status; #endif - if (my_termhook) - (*my_termhook)(SIGCHLD); - -#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. */ + while ((pid = wait3(&status, WNOHANG, 0)) > 0) + continue; /* swallow 'em up. */ #else /* Zooks! Nothing to do but wait(), and hope we don't block... */ - wait(&status); -#endif + int status; + wait(&status); +#endif + lastsig = SIGCHLD; + (void)sig; } +RETSIGTYPE 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; +#ifdef HAVE_SIGACTION + 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; +#ifdef SA_RESTART /* SunOS 4.1 portability hack */ + /* system call should restart on all signals except SIGALRM */ + if (sig != SIGALRM) + sa_new.sa_flags |= SA_RESTART; +#endif +#ifdef SA_NOCLDSTOP /* SunOS 4.1 portability hack */ + if (sig == SIGCHLD) + sa_new.sa_flags |= SA_NOCLDSTOP; +#endif + sigaction(sig, &sa_new, &sa_old); + rethandler = sa_old.sa_handler; +#if defined(SIGPWR) + if (sig == SIGCHLD) + sigaction(SIGPWR, &sa_new, NULL); +#endif +#else /* HAVE_SIGACTION */ + rethandler = signal(sig, handler); +#if defined(SIGPWR) + if (sig == SIGCHLD) + signal(SIGPWR, handler); +#endif + /* system call should restart on all signals except SIGALRM */ + siginterrupt(sig, sig == SIGALRM); +#endif /* HAVE_SIGACTION */ + 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 */ - my_termhook = termhook; - if (getppid() == 1) goto nottyDetach; /* 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 @@ -122,7 +160,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) @@ -135,26 +173,29 @@ void (*termhook)(int); #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 */ +#ifndef __EMX__ setpgrp(0, getpid()); - +#endif /* lose controlling tty */ if ((fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, (char *) 0); - close(fd); + 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 */ - signal(SIGHUP, SIG_IGN); - if ((childpid = fork) < 0) { - perror("fork"); + set_signal_handler(SIGHUP, SIG_IGN); + if ((childpid = fork()) < 0) { + report(stderr, "fork (%s)\n", strerror(errno)); return(PS_IOERR); } else if (childpid > 0) { @@ -164,38 +205,47 @@ void (*termhook)(int); 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); + } + + 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); + while (fd >= 1) { + if (fd != logfd) + close(fd); /* not checking this should be safe, no writes */ + -- fd; } - /* Reopen stdin descriptor on /dev/null */ - if ((fd = open("/dev/null", O_RDWR)) < 0) { /* stdin */ - perror("open: /dev/null"); - return(PS_IOERR); - } - - 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) @@ -204,7 +254,26 @@ nottyDetach: umask(022); #endif - /* set up to catch child process termination signals */ - signal(SIGCLD, sigchld_handler); + 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 */