-
-
Save tspspi/900bbd379cc2c024380bb58e3a5321ca to your computer and use it in GitHub Desktop.
Basic daemon skeleton
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Compilation: clang -o basicdaemon -Wall -ansi -std=c99 -Werror -pedantic ./basicdaemon.c -lutil | |
*/ | |
#include <unistd.h> | |
#include <libutil.h> | |
#include <errno.h> | |
#include <signal.h> | |
#include <fcntl.h> | |
/* Used for perror and (f)printf: */ | |
#include <stdio.h> | |
/* | |
Currently we employ a simple signal handelr that | |
sets a flag that will get checked periodically by | |
the daemon. If SIGTERM is received we will terminate | |
our wait loop. | |
*/ | |
static int termSignaled = 0; | |
static void signalHandlerSIGTERM(int sigio) { | |
termSignaled = 1; | |
} | |
/* Main entry point */ | |
int main(int argc, char* argv[]) { | |
struct pidfh *pidFileHandle; | |
struct sigaction sAction; | |
pid_t otherDaemonPid; | |
pid_t pidChildProcess; | |
pid_t pidLeader; | |
int fileNull; | |
/* | |
Note that we start with fork. Maybe one wants to | |
do some CLI processing or reading of configuration | |
files before that to allwo modification of startup | |
behaviour, configuration of PIDs and GIDs to be | |
used, etc. These will be configured as static constants | |
in this example. | |
This code would belong here ... | |
*/ | |
/* open pidfile */ | |
pidFileHandle = pidfile_open(NULL, 0600, &otherDaemonPid); | |
if(pidFileHandle == NULL) { | |
if(errno == EEXIST) { | |
fprintf(stderr, "Daemon already running, pid: %jd.", (intmax_t)otherDaemonPid); | |
return -1; | |
} | |
perror("Failed to open PID-file"); | |
return -1; | |
} | |
/* Now its time for the first fork (moving to background) */ | |
pidChildProcess = fork(); | |
if(pidChildProcess < 0) { | |
/* The fork failed */ | |
perror("Forking failed\n"); | |
return -1; | |
} else if(pidChildProcess > 0) { | |
/* We are the parent. We'll terminate silently */ | |
return 0; | |
} | |
#ifdef DEBUG | |
printf("%s:%u Moved to background\n", __FILE__, __LINE__); | |
#endif | |
/* | |
At this point we are the child that has moved | |
to the background but is still attached to | |
the original process group. | |
Now detach from the session ... | |
*/ | |
pidLeader = setsid(); | |
if(pidLeader < 0) { | |
perror("Failed to become session leader\n"); | |
/* | |
This will happen if the calling | |
process is already a process group | |
leader or the process group ID of | |
another process other than the | |
calling process matches the process ID | |
of the calling process. | |
*/ | |
return -1; | |
} | |
#ifdef DEBUG | |
/* | |
Note that debug output still works and shows | |
up in the original terminal since we inherited | |
the stdin and stdout pipes from our parents ... | |
*/ | |
printf("%s:%u Moved to new process group\n", __FILE__, __LINE__); | |
#endif | |
/* | |
Now we will ensure detachment from the previous | |
process leader by forking one last time ... | |
*/ | |
pidChildProcess = fork(); | |
if(pidChildProcess < 0) { | |
perror("Forking failed\n"); | |
return -1; | |
} else if(pidChildProcess > 0) { | |
/* We are the parent and will terminate silently again */ | |
return 0; | |
} | |
/* | |
Register signal handler for SIGTERM | |
*/ | |
sAction.sa_sigaction = NULL; | |
sAction.sa_handler = &signalHandlerSIGTERM; | |
sAction.sa_flags = SA_RESTART; /* Restart any interrupted operations like file I/O */ | |
sigfillset(&sAction.sa_mask); /* Mask all signals during our signal handler */ | |
if(sigaction(SIGTERM, &sAction, NULL) < 0) { | |
/* We failed to register our handler ... */ | |
perror("Failed to register SIGTERM handler\n"); | |
pidfile_close(pidFileHandle); | |
return -1; | |
} | |
/* | |
Write our PID into the PID-file | |
*/ | |
pidfile_write(pidFileHandle); | |
/* | |
At this point we are the child process that | |
has moved into background and has detached from | |
the original process group | |
*/ | |
#ifdef DEBUG | |
/* Still works, we've inherited stdin, stdout and stderr ... */ | |
printf("%s:%u Greetings from background detached process\n", __FILE__, __LINE__); | |
#endif | |
/* | |
Now we should | |
* close our standard I/O handles of our parent process | |
(or do that after the following operations just in | |
case we want to provide direct error output) | |
* Do some mandatory access control manipulation if required | |
* Jail if we want to | |
* setgid, setuid | |
* chroot | |
*/ | |
/* close stdin,stdout and stderr. Now printf won't work any more ... */ | |
close(STDOUT_FILENO); | |
close(STDERR_FILENO); | |
close(STDIN_FILENO); | |
/* Open /dev/null as target for stdout and stderr as well as source for stdin */ | |
fileNull = open("/dev/null", 0); | |
dup2(fileNull, STDOUT_FILENO); | |
dup2(fileNull, STDERR_FILENO); | |
dup2(fileNull, STDIN_FILENO); | |
/* | |
Main daemon code goes here ... | |
*/ | |
/* Now remove our PID-file */ | |
pidfile_remove(pidFileHandle); | |
/* And terminate process ... */ | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment