diff --git a/src/daemonitor/200_log.c b/src/daemonitor/200_log.c index b82ecea..f337b48 100644 --- a/src/daemonitor/200_log.c +++ b/src/daemonitor/200_log.c @@ -1,9 +1,9 @@ /* daemonitor/src/daemonitor/200_log.c * - * (c)2007, Laurence Withers, . - * Released under the GNU GPLv3. See file COPYING or - * http://www.gnu.org/copyleft/gpl.html for details. -*/ + * Copyright: ©2007–2012, Laurence Withers. + * Author: Laurence Withers + * License: GPLv3 + */ @@ -170,16 +170,25 @@ void log_func_syslog(int level, const char* fmt, ...) /* log_destination_set() * Set `log_func' function pointer. */ -void log_destination_set(enum log_destination_t dest) +void +log_destination_set(enum log_destination_t dest) { switch(dest) { case log_destination_stdout: - log_func_fd = STDOUT_FILENO; + log_func_fd = dup(STDOUT_FILENO); + if(log_func_fd == -1) { + printf("dup() failed: %m."); + exit(1); + } log_func = log_func_file; break; case log_destination_stderr: - log_func_fd = STDERR_FILENO; + log_func_fd = dup(STDERR_FILENO); + if(log_func_fd == -1) { + fprintf(stderr, "dup() failed: %m."); + exit(1); + } log_func = log_func_file; break; @@ -210,6 +219,5 @@ int log_destination_set_file(const char* filename) /* options for text editors -kate: replace-trailing-space-save true; space-indent true; tab-width 4; vim: expandtab:ts=4:sw=4 */ diff --git a/src/daemonitor/400_daemon.c b/src/daemonitor/400_daemon.c deleted file mode 100644 index 7d9540d..0000000 --- a/src/daemonitor/400_daemon.c +++ /dev/null @@ -1,160 +0,0 @@ -/* daemonitor/src/daemonitor/400_daemon.c - * - * (c)2007, Laurence Withers, . - * Released under the GNU GPLv3. See file COPYING or - * http://www.gnu.org/copyleft/gpl.html for details. -*/ - - - -/* DAEMON ROUTINES ******************************************************************************** - * - * This file provides the daemonise() routine, which makes the process a daemon (fork() + setsid() - * so that the process lives in the background, also opens /dev/console). It also provides the - * close_file_descriptors() routine, which clears all file descriptors but 0, 1 and 2. - */ - - - -/* PUBLIC API ************************************************************************************/ - - - -/* daemonise() - * Performs a fork() and setsid() so that the process lives in the background. It closes stdin, - * stdout and stderr and opens /dev/null and/or /dev/console instead, as appropriate. On error, - * this function exits the program. - */ -void daemonise(void); - - - -/* close_file_descriptors() - * Closes all file descriptors but stdin, stdout and stderr. Should be called whether we are - * daemonising or not. - */ -void close_file_descriptors(void); - - - -/* IMPLEMENTATION ********************************************************************************/ - - - -void daemonise(void) -{ - int fd; - pid_t pid; - - /* close stdin and reopen it as /dev/null */ - TEMP_FAILURE_RETRY( close(STDIN_FILENO) ); - fd = open("/dev/null", O_RDONLY); - switch(fd) { - case -1: - LOG(LOG_CRIT, "Could not open `/dev/null' (%m)."); - exit(1); - - case STDIN_FILENO: - break; - - default: - LOG(LOG_CRIT, "Opened `/dev/null' for stdin, but got file descriptor %d instead.", fd); - exit(1); - } - - /* close stdout and reopen it as /dev/console if possible, or /dev/null if not */ - TEMP_FAILURE_RETRY( close(STDOUT_FILENO) ); - fd = open("/dev/console", O_WRONLY | O_NOCTTY); - if(fd == -1) { - LOG(LOG_WARNING, "Could not open `/dev/console' for stdout (%m)."); - fd = open("/dev/null", O_WRONLY); - } - switch(fd) { - case -1: - LOG(LOG_CRIT, "Could not open `/dev/null' (%m)."); - exit(1); - - case STDOUT_FILENO: - break; - - default: - LOG(LOG_CRIT, "Opened `/dev/null' for stdout, but got file descriptor %d instead.", fd); - exit(1); - } - - /* close stderr and reopen it as /dev/console if possible, or /dev/null if not */ - TEMP_FAILURE_RETRY( close(STDERR_FILENO) ); - fd = open("/dev/console", O_WRONLY | O_NOCTTY); - if(fd == -1) { - LOG(LOG_WARNING, "Could not open `/dev/console' for stderr (%m)."); - /* force fd closed again, in case glibc kindly connected it to syslog for us */ - TEMP_FAILURE_RETRY( close(STDERR_FILENO) ); - fd = open("/dev/null", O_WRONLY); - } - switch(fd) { - case -1: - LOG(LOG_CRIT, "Could not open `/dev/null' (%m)."); - exit(1); - - case STDERR_FILENO: - break; - - default: - LOG(LOG_CRIT, "Opened `/dev/null' for stderr, but got file descriptor %d instead.", fd); - exit(1); - } - - /* daemonise */ - pid = fork(); - if(pid == (pid_t)-1) { - LOG(LOG_CRIT, "Could not fork daemonised process (%m)."); - exit(1); - } - - if(pid) { - /* parent */ - _exit(0); /* don't call atexit() et al. in parent */ - } - - - setsid(); - LOG(LOG_NOTICE, "Daemonised, PID %lu.", (unsigned long)getpid()); -} - - - -/* close_file_descriptors() - * Adapted from libgslutil (GPL-3). - */ -void close_file_descriptors(void) -{ - DIR* d; - struct dirent* de; - int i, end, dfd; - - d = opendir("/proc/self/fd"); - if(!d) { - /* backup method */ - for(i = STDERR_FILENO + 1, end = getdtablesize(); i < end; ++i) { - close(i); - } - return; - } - dfd = dirfd(d); - - while( (de = readdir(d)) ) { - if(de->d_name[0] == '.') continue; - i = strtol(de->d_name, 0, 10); - if(i == dfd) continue; /* skip file descriptor associated with `DIR* d' */ - if(i <= STDERR_FILENO) continue; /* leave stdin, stdout, stderr alone */ - TEMP_FAILURE_RETRY( close(i) ); - } - closedir(d); -} - - - -/* options for text editors -kate: replace-trailing-space-save true; space-indent true; tab-width 4; -vim: expandtab:ts=4:sw=4 -*/ diff --git a/src/daemonitor/600_run_program.c b/src/daemonitor/600_run_program.c index 638eaf1..a85720c 100644 --- a/src/daemonitor/600_run_program.c +++ b/src/daemonitor/600_run_program.c @@ -1,9 +1,9 @@ /* daemonitor/src/daemonitor/600_run_program.c * - * (c)2007, Laurence Withers, . - * Released under the GNU GPLv3. See file COPYING or - * http://www.gnu.org/copyleft/gpl.html for details. -*/ + * Copyright: ©2007–2012, Laurence Withers. + * Author: Laurence Withers + * License: GPLv3 + */ @@ -45,8 +45,8 @@ volatile int sigterm_received = 0; /* close_file_descriptors() - * Closes all file descriptors but stdin, stdout and stderr. Should be called whether we are - * daemonising or not. + * Closes all file descriptors but stdin, stdout and stderr (which it leaves + * unchanged). */ void close_file_descriptors(void); @@ -56,6 +56,38 @@ void close_file_descriptors(void); +/* close_file_descriptors() + * Adapted from libgslutil (GPL-3). + */ +void +close_file_descriptors(void) +{ + DIR* d; + struct dirent* de; + int i, end, dfd; + + d = opendir("/proc/self/fd"); + if(!d) { + /* backup method */ + for(i = STDERR_FILENO + 1, end = getdtablesize(); i < end; ++i) { + close(i); + } + return; + } + dfd = dirfd(d); + + while( (de = readdir(d)) ) { + if(de->d_name[0] == '.') continue; + i = strtol(de->d_name, 0, 10); + if(i == dfd) continue; /* skip file descriptor associated with `DIR* d' */ + if(i <= STDERR_FILENO) continue; /* leave stdin, stdout, stderr alone */ + TEMP_FAILURE_RETRY( close(i) ); + } + closedir(d); +} + + + /* crash() * Crash the program. This is better than just calling exit() because it doesn't clean up. We * should leave our PID file lying around to look like we crashed. This function is paranoid. @@ -113,6 +145,8 @@ void run_program(const char* exe_path, char** argv) /* child -- execute new process */ if(pid == 0) { + close_file_descriptors(); + /* clear the child's signal mask */ sigemptyset(&ss); sigprocmask(SIG_SETMASK, &ss, 0); @@ -203,6 +237,5 @@ void run_program(const char* exe_path, char** argv) /* options for text editors -kate: replace-trailing-space-save true; space-indent true; tab-width 4; vim: expandtab:ts=4:sw=4 */ diff --git a/src/daemonitor/999_main.c b/src/daemonitor/999_main.c index b4819b2..98e46f7 100644 --- a/src/daemonitor/999_main.c +++ b/src/daemonitor/999_main.c @@ -79,7 +79,7 @@ int main(int argc, char* argv[]) { char* endp; const char* log_argument = 0, * pidfile_argument = 0, * restart_argument = 0; - int daemon = 0, restart_interval = DEFAULT_RESTART_INTERVAL; + int do_daemon = 0, restart_interval = DEFAULT_RESTART_INTERVAL; /* safety */ close_file_descriptors(); /* leaves stdout etc. open */ @@ -91,7 +91,7 @@ int main(int argc, char* argv[]) case '?': LOG_ANYWHERE("Invalid commandline options."); return 1; case 'h': usage(); return 1; case 'V': fputs("daemonitor " VERSION "\n", stderr); return 1; - case 'd': ++daemon; break; + case 'd': ++do_daemon; break; case 'l': log_argument = optarg; break; case 'p': pidfile_argument = optarg; break; case 'R': restart_argument = optarg; break; @@ -136,7 +136,12 @@ int main(int argc, char* argv[]) if(load_child_environ()) return 1; /* daemonise? */ - if(daemon) daemonise(); + if(do_daemon) { + if(daemon(0, 0)) { + LOG(LOG_CRIT, "daemon() failed: %m."); + return 1; + } + } /* write a PID file */ if(pidfile_argument) {