• Top
  • Comment
  • Reply

Beginners Guide to creating a daemon in Linux

Before reading this please note this is a beginners guide and does not go in detail about the content. However if this is the first time you are creating a daemon in linux you have come to the right place.

What do you need to know.

A basic understanding of C++ and some bare know how about using linux, and by linux we mean knowing how to start a process and kill a process. Using eclipse in Linux with C++.

What am i using

I'm currently running Fedora 13 with eclipse installed. You can however program the below in Ubuntu and test your deamon out in both platforms.

Now that we have discussed the requirements lets breeze through some local knowledge

Understanding how Linux handles services

To run any daemon you have to create a init script. this scripts control the start stop and restart functionality of the process. Init scripts control the services Start and Stops, And they also don't let a service start when it is already running. I will talk more about init scripts in part 2 of this tutorial.

Lets Begin - Two Birds, One Stone

I've learned before creating daemons its always good to get the process part of it working. So first lets set-up a test program. For this example we are going to write to the syslog daemon. The reason why I do this is because there is a lot of code that goes above and below in our main file to setup a daemon. So i leave my processing to be done in another function.

Daemon and Programs are fairly similar to each other, however daemons don't output their outward code to the console. So its a good idea to get into grips with logging your outputs rather than using cout or printf. Below we are going to add a syslog entry into our process function.

#include <syslog .h>

void process(){

    syslog(LOG_NOTICE, "Writing to my Syslog");
}     

int main (int argc, char *argv[]) {

    setlogmask (LOG_UPTO (LOG_NOTICE));
    openlog ("testd", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);

    process();

    closelog();
    return(EXIT_SUCCESS);
}

What have we done above. Well simply put we have opened a connection to syslog (openlog()) then we wrote to syslog using (syslog()) and finally we close the connection (closelog()). You might mention what is setlogmask and all the input parameters such as LOG_INFO, LOG_NOTICE. Well a lets go through with the basics. setlogmask() lets us choose what to log and what not to log even if the syslog() function is called. This is handy as we leave alot of messages when debugging but we want to turn off the messages when we go live with our daemon. Therefore instead of going through your code and commenting out all the notice entries, we just change the log mask.

If you have never worked with syslog in C++, its a good idea to familiarize yourself with it. You can find more about syslog commands Here if you are interested.

Ok so now you have logged your messages where to find them. In Ubuntu or Fedora logs are located under /var/logs/messages so once you have compiled your program and ran it try this command(Last 100 lines of the file message).

tail -n 100 /var/log/messages

The Daemon

We have established our process and managed our logging, now we want to add some daemon code. The best place to start is by looking at our daemon code below.

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>

using namespace std;

#define DAEMON_NAME "vdaemon"

void process(){

    syslog (LOG_NOTICE, "Writing to my Syslog");
}   

int main(int argc, char *argv[]) {

    //Set our Logging Mask and open the Log
    setlogmask(LOG_UPTO(LOG_NOTICE));
    openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);

    syslog(LOG_INFO, "Entering Daemon");

    pid_t pid, sid;

   //Fork the Parent Process
    pid = fork();

    if (pid < 0) { exit(EXIT_FAILURE); }

    //We got a good pid, Close the Parent Process
    if (pid > 0) { exit(EXIT_SUCCESS); }

    //Change File Mask
    umask(0);

    //Create a new Signature Id for our child
    sid = setsid();
    if (sid < 0) { exit(EXIT_FAILURE); }

    //Change Directory
    //If we cant find the directory we exit with failure.
    if ((chdir("/")) < 0) { exit(EXIT_FAILURE); }

    //Close Standard File Descriptors
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    //----------------
    //Main Process
    //----------------
    while(true){
        process();    //Run our Process
        sleep(60);    //Sleep for 60 seconds
    }

    //Close the log
    closelog ();
}

Looks like alot of code but lets look at some key factors. If you note that our actual daemon code is only three lines long. Basically an infinite loop with our process function, and a sleep command. Where as the rest of the code is preparing our application to run as a daemon. Lets walk through some of the commands in brief.

fork

Forking is a method of creating a child process. When we run the command fork() we are actually creating a child clone of our program. From our above code we try to fork our parent process. If the return value is less than 0 then something went wrong. Therefore we exit our program, otherwise we exit our parent and continue on with our child process. This can get confusing, For more information refer to the reference in the bottom of the tutorial.

umask

When ever you create a new file in linux, you need premissions to read or write them. The umask command specifies this processes permissions. This is a complicated one to dig into. You can read more in the reference page.

setsid

setsid is otherwise short for Set Session Id. Because we have fork-ed our process we need to give our new process its own unique process-id, therefore we run this function to determine a new process-id.

chdir

This command changes the current working directory. In linux an equivilent to this function will be cd /. This will be the working directory of the process. The reason we choose / or root as a working directory is because, it is the one directory that globally exists throughout all linux types. You can however change the directory to your suiting.

close

Because daemon is a background process we want to close all Input and Output. So if you look at the close function we have closed all standard file descriptors.

sleep

The sleep command sends the process to sleep for the defined number of seconds. Think about this number whenever you are designing your daemon. A small number will require more processing power as your CPU, is dealing with more processes in a short space of time.

Fin

Im sure before you get to this part. you have already tested your daemon, so I leave you with some final words of advice.

Learn more, Use the Devon Watson Guide to writing a Daemon, to fill in some black holes that I may have left out. Also not a bad idea to try the Peter Lambardo example to understanding how to handle signals and making sure your daemon always shuts down cleanly.

Whenever creating your process function: be defensive, be defensive and be more defensive; and when you have secured it try going back and be very very defensive. And Enjoy

Hope the above helps in some way of understanding about daemons in Linux based operating system. However this doesn't end here. Part 2 explains how to create a init.d script to control the starting and stopping of this daemon.

Resources

By

19th Nov 2010
© 2011 Shahmir Javaid - http://shahmirj.com/blog/9

Danilo Carvalho

6th Feb 2012

Hi, Shahmir, very nice guide. Any chance the Part 2 explaining about the init.d scripts is coming out soon? Haven't been able to find a decent guide on it. Either way, thanks for this one.

Shahmir Javaid

14th Feb 2012

I can do that, give me the weekend. Il muster an easy init.d script which you can transfer easily to your daemon.

luis

8th Nov 2012

excellent guide

Reva Yoga Pradana

28th Oct 2013

I'm using ubuntu 12.04. when I compile this, I got messages : fatal error : syslog.h : no such file or directory
what must I do to solve this?
thanks

Shahmir Javaid

29th Oct 2013

@Reva whats your compile command?

곽철현

6th Sep 2014

I am using Ubuntu 14.04 and have updated my gcc compiler to 4.8.2.
When I copy&paste the full code and then compile it the following errors come up

a4.c:11:1: error: unknown type name ‘using’
using namespace std;
^
a4.c:11:17: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘std’
using namespace std;
^
a4.c: In function ‘main’:
a4.c:57:11: error: ‘true’ undeclared (first use in this function)
while(true){
^
a4.c:57:11: note: each undeclared identifier is reported only once for each function it appears in
a4.c:64:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^

Shahmir Javaid

6th Sep 2014

Are you sure you are using the c++ compiler? g++?



Back to Top
All content is © copyrighted, unless stated otherwise.
Subscribe, @shahmirj, Shahmir Javaid+