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