From f2f2baa129eaf02937d7c600ef0e82f91f303847 Mon Sep 17 00:00:00 2001 From: Laurence Withers Date: Sat, 26 Jul 2008 16:40:24 +0000 Subject: [PATCH] Add daemonising routines --- src/daemonitor/000_TopSource.c | 1 + src/daemonitor/103_daemon.c | 158 +++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 src/daemonitor/103_daemon.c diff --git a/src/daemonitor/000_TopSource.c b/src/daemonitor/000_TopSource.c index 1174719..782395c 100644 --- a/src/daemonitor/000_TopSource.c +++ b/src/daemonitor/000_TopSource.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/src/daemonitor/103_daemon.c b/src/daemonitor/103_daemon.c new file mode 100644 index 0000000..f8a5b98 --- /dev/null +++ b/src/daemonitor/103_daemon.c @@ -0,0 +1,158 @@ +/* daemonitor/src/daemonitor/103_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)."); + 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 +*/