How to Create a Daemon in C

How to create a c-style process daemon
How to create a c-style process daemon
Summary:

Daemons are programs on Unix-like operating systems that work in the background. They usually handle important recurring tasks without the user’s knowledge.

Daemons are programs on Unix-like operating systems that work in the background and don’t belong to a TTY. That’s why stdout/stderr can’t be used the normal way. Usually a syslog daemon (syslogd) is used for logging messages to files (debug, error,…). They usually handle important recurring tasks without the user’s knowledge.

There are a few required steps to daemonize a process

  • fork off the parent process & let it terminate if forking was successful. -> Because the parent process has terminated, the child process now runs in the background.
  • setsid – Create a new session. The calling process becomes the leader of the new session and the process group leader of the new process group. The process is now detached from its controlling terminal (CTTY).
  • catch signals – Ignore and/or handle signals.
  • fork again & let the parent process terminate to ensure that you get rid of the session leading process. (Only session leaders may get a TTY again.)
  • chdir – Change the working directory of the daemon.
  • umask – Change the file mode mask according to the needs of the daemon.
  • close – Close all open file descriptors that may be inherited from the parent process.

Source Code – Basic skeleton of an old school process daemon

The source code of the daemon is also available on Github:
Creating a process daemon in C

/*
* daemonize.c
* This example daemonizes a process, writes a few log messages,
* sleeps 20 seconds and terminates afterwards.
* This is an answer to the stackoverflow question:
* https://stackoverflow.com/questions/17954432/creating-a-daemon-in-linux/17955149#17955149
* Fork this code: https://github.com/pasce/daemon-skeleton-linux-c
*/
    
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
   
static void skeleton_daemon()
{
    pid_t pid;
    
    /* Fork off the parent process */
    pid = fork();
    
    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);
    
     /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);
    
    /* On success: The child process becomes session leader */
    if (setsid() < 0)
        exit(EXIT_FAILURE);
    
    /* Catch, ignore and handle signals */
    /*TODO: Implement a working signal handler */
    signal(SIGCHLD, SIG_IGN);
    signal(SIGHUP, SIG_IGN);
    
    /* Fork off for the second time*/
    pid = fork();
    
    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);
    
    /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);
    
    /* Set new file permissions */
    umask(0);
    
    /* Change the working directory to the root directory */
    /* or another appropriated directory */
    chdir("/");
    
    /* Close all open file descriptors */
    int x;
    for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
    {
        close (x);
    }
    
    /* Open the log file */
    openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
}
int main()
{
    skeleton_daemon();
    
    while (1)
    {
        //TODO: Insert daemon code here.
        syslog (LOG_NOTICE, "First daemon started.");
        sleep (20);
        break;
    }
   
    syslog (LOG_NOTICE, "First daemon terminated.");
    closelog();
    
    return EXIT_SUCCESS;
}

Compiling and Running the Code

  • Compile the code: gcc -o firstdaemon daemonize.c
  • Start the daemon: ./firstdaemon
  • Check if everything is working properly: ps -xj | grep firstdaemon

Interpreting the Output

The output should be similar to what is shown below:

+------+------+------+------+-----+-------+------+------+------+-----+
| PPID | PID  | PGID | SID  | TTY | TPGID | STAT | UID  | TIME | CMD |
+------+------+------+------+-----+-------+------+------+------+-----+
|    1 | 3387 | 3386 | 3386 | ?   |    -1 | S    | 1000 | 0:00 | ./  |
+------+------+------+------+-----+-------+------+------+------+-----+

What we see here is…

  • The daemon has no controlling terminal (TTY = ?)
  • The parent process ID (PPID) is 1 (The init process)
  • The PID != SID which means that our process is NOT the session leader
    (because of the second fork())
  • Because PID != SID the process can’t take control over a TTY again

Reading the syslog

  • Locate your syslog file. In Ubuntu it is probably here: /var/log/syslog
  • Type in a terminal: grep firstdaemon /var/log/syslog
  • The output should be similar to this one:
firstdaemon[3387]: First daemon started.
firstdaemon[3387]: First daemon terminated.

A note: Usually you would also want to implement a signal handler and set up the logging properly (Files, log levels…).

Pascal Werkl
Written by
Pascal Werkl
Join the discussion

Pascal Werkl

Pascal Werkl

Pascal is a computer scientist/software engineer and digital marketer by profession with over 15 years of experience in the industry. He is skilled in data science, statistical data exploration and data visualization.

At the moment, he is trying to exhaust the limits of augmented reality in marketing using Google's ARCore and Unity's 3D Engine.