A Simple Daemon in C

(Before diving into creating your own daemon, you might want to take a look at the Fat Controller which is a program which can daemonise anything. If you need to daemonise something, run something repeatedly or parallelise something, then it may well be worth taking a look.)

A daemon is a process which runs in the background of your computer, periodically carrying out a specific task. The following is an example of a simple daemon written in C. It works by forking to create a child process, the parent then terminates but the child carries on in the background – entering a continuous loop of doing a task and then sleeping. The child process is of course an identical copy of the parent so care must be taken to close all file descriptors, thus detaching the child completely from the calling process. The deamonised process is controlled by sending it signals which it can catch and take action accordingly. In the example below, the process is terminated by sending SIGINT or SIGTERM, but you can of course add in your own handling – for example to re-read config data on SIGHUP.


#define DAEMON_NAME "simpledaemon"

    void daemonShutdown();
    void signal_handler(int sig);
    void daemonize(char *rundir, char *pidfile);

    int pidFilehandle;

    void signal_handler(int sig)
            case SIGHUP:
                syslog(LOG_WARNING, "Received SIGHUP signal.");
            case SIGINT:
            case SIGTERM:
                syslog(LOG_INFO, "Daemon exiting");
                syslog(LOG_WARNING, "Unhandled signal %s", strsignal(sig));
    void daemonShutdown()

    void daemonize(char *rundir, char *pidfile)
        int pid, sid, i;
        char str[10];
        struct sigaction newSigAction;
        sigset_t newSigSet;
        /* Check if parent process id is set */
        if (getppid() == 1)
            /* PPID exists, therefore we are already a daemon */

        /* Set signal mask - signals we want to block */
        sigaddset(&newSigSet, SIGCHLD);  /* ignore child - i.e. we don't need to wait for it */
        sigaddset(&newSigSet, SIGTSTP);  /* ignore Tty stop signals */
        sigaddset(&newSigSet, SIGTTOU);  /* ignore Tty background writes */
        sigaddset(&newSigSet, SIGTTIN);  /* ignore Tty background reads */
        sigprocmask(SIG_BLOCK, &newSigSet, NULL);   /* Block the above specified signals */
        /* Set up a signal handler */
        newSigAction.sa_handler = signal_handler;
        newSigAction.sa_flags = 0;
            /* Signals to handle */
            sigaction(SIGHUP, &newSigAction, NULL);     /* catch hangup signal */
            sigaction(SIGTERM, &newSigAction, NULL);    /* catch term signal */
            sigaction(SIGINT, &newSigAction, NULL);     /* catch interrupt signal */

        /* Fork*/
        pid = fork();
        if (pid < 0)
            /* Could not fork */
        if (pid > 0)
            /* Child created ok, so exit parent process */
            printf("Child process created: %d\n", pid);
        /* Child continues */
        umask(027); /* Set file permissions 750 */
        /* Get a new process group */
        sid = setsid();
        if (sid < 0)
        /* close all descriptors */
        for (i = getdtablesize(); i >= 0; --i)
        /* Route I/O connections */

        /* Open STDIN */
        i = open("/dev/null", O_RDWR);

        /* STDOUT */

        /* STDERR */
        chdir(rundir); /* change running directory */
        /* Ensure only one copy */
        pidFilehandle = open(pidfile, O_RDWR|O_CREAT, 0600);
        if (pidFilehandle == -1 )
            /* Couldn't open lock file */
            syslog(LOG_INFO, "Could not open PID lock file %s, exiting", pidfile);
        /* Try to lock file */
        if (lockf(pidFilehandle,F_TLOCK,0) == -1)
            /* Couldn't get lock on lock file */
            syslog(LOG_INFO, "Could not lock PID lock file %s, exiting", pidfile);

        /* Get and format PID */
        /* write pid to lockfile */
        write(pidFilehandle, str, strlen(str));
    int main()
        /* Debug logging
        openlog(DAEMON_NAME, LOG_CONS, LOG_USER);
        /* Logging */
        syslog(LOG_INFO, "Daemon starting up");

        /* Deamonize */
        daemonize("/tmp/", "/tmp/daemon.pid");
        syslog(LOG_INFO, "Daemon running");
        while (1)
            syslog(LOG_INFO, "daemon says hello");

The above example is only simple but it serves as a good starting point to create your own daemon. In my next article I will demonstrate how it can be extended to periodically call a PHP script.

If I find enough time I will also demonstrate how it can be extended from being a single-threaded daemon to a multi-threaded daemon, maintaining a continuous pool of x threads, each doing a given task.

This entry was posted in C and tagged , , , , , , , , . Bookmark the permalink.

11 Responses to A Simple Daemon in C

  1. nikitha says:

    how 2 execute it in ubuntu??

  2. Nick says:

    1. Save the code into a file, let’s say daemon.c
    2. Now you need to compile it: gcc daemon.c -odaemon
    3. Next, add executable permissions to the compiled source: chmod +x daemon
    4. Run: ./daemon

    If you’re looking to daemonise something, you might want to have a look at my project The Fat Controller:


    It can basically daemonise anything (PHP scripts, Python, Java, etc) as well as provide some other useful features such as parallel execution and repeated execution.

  3. Sean Palmer says:

    Is it enough to just close the pidfile, or should you also delete it?

  4. Nick says:

    To be honest, I’m not sure. I had a look and according to this Stackoverflow post, you should delete the PID file afterwards:


    Also, I just tested Apache HTTP server and MySQL – both delete their PID files when they’re shut down.

  5. I’d like to ask about the bit where STDIN, STDOUT, STDERR are closed. Isn’t that going to lead to “undefined behaviour” if the program ever writes to STDOUT/STDERR? See:

    So would it be better to keep them open, but redirected to /dev/null or something like that?

  6. Nick says:

    Hello. Thanks for pointing that out – you’re absoluteley right. Instead, as you suggest, we should redirect the standard file descriptors to a harmless I/O device such as /dev/null:

    /* Open STDIN */
    i = open(“/dev/null”, O_RDWR);

    /* STDOUT */

    /* STDERR */

    I’ve updated the code accordingly.

  7. Robert Graham says:

    For a more solid written code, I would loop on a global volatile variable that you change the value of on exit. I would also close the syslog before the program returns.

  8. Robert Graham says:

    And remove the PIDFILE before exiting in the signal handler.

  9. Nick says:

    Hi Robert, thanks for your comments! Can you explain your idea with the global, volatile variable, please? I’m not quite sure I get what you mean – thanks!

  10. kamal raghav says:

    kamal raghav :
    Hi Robert,
    Wont the global volatile variable be limited to the scope the daemon lifetime. So effectively whatever you write at the exit would vanish due to exit of context. Also the compiler would do the optimization of creating the variable on heap and in very rare case can it be recovered by another app, i.e. if called successively. It would be best to write the status to the pidfile in the next line, if that is what you are suggesting.

  11. Jacek says:

    I know it’s been quite some time since you wrote this, but as it came up high in Google results I decided to add my two cents here, as a warning for the people who may read this.

    You should be very careful with what you use in signal handler – there’s only a limited set of functions you may call in signal handler and, unfortunately, syslog() is not one of them – it can even be exploited (see e.g.: https://cwe.mitre.org/data/definitions/828.html). Also, simple exit() seems not to be on the safe list (http://man7.org/linux/man-pages/man7/signal.7.html).

    Typically, the safest approach would be to (atomically) set a flag in the signal handler function that could be checked inside the main loop to break it and do the cleanup and exit. And use no logging in signal handler (regardless of how much it’s tempting to add it there :) ), at least in release version.

Leave a Reply

Your email address will not be published. Required fields are marked *