Add daemonising routines
This commit is contained in:
parent
529c50212b
commit
f2f2baa129
|
@ -11,6 +11,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <dirent.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
/* daemonitor/src/daemonitor/103_daemon.c
|
||||||
|
*
|
||||||
|
* (c)2007, Laurence Withers, <l@lwithers.me.uk>.
|
||||||
|
* 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
|
||||||
|
*/
|
Loading…
Reference in New Issue