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.
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++.
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
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.
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
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.
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.
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
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.
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.
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.
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.
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.
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.
29th Oct 2013
@Reva whats your compile command?
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]
}
^
6th Sep 2014
Are you sure you are using the c++ compiler? g++?
Hello Shahmir.
This tutorial is very simply and well done, but I'm not a very well programmer.
So I don't understand those:
- Where I have to place my compiled and executable file.
- What's its name?
- When I make init.d file I have to put it in etc/init.d directory? what name I have to give it?
- how does my process to bind the two files?(init.d and program)?
- If my daemon have to write and read a file like myprog.ini I also have to make
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
- my you make an example where explain the command shell side?
thank you. bye.
13th Mar 2015
- You can place it where ever you like, most common place is /usr/local/bin. You just have to reference the location it is in to run it.
- Whatever you like but the convention is <name>d where the d stands for daemon so if my program was called mycoolprogram I would call it mycoolprogramd
- Yes you do have to put it into /etc/init.d. Again the convention of the name states `mycoolprogramd` from above
- init.d calls your program
- your deamon can write to files like any other program, the convention to put configuration files has always been in /etc/ directory. If you have many configuration files create a folder inside /etc/ but if you only have one
I am not a 100% on your last question. Can you rephrase
11th Oct 2015
@Julian, you can use a signal handler to manage kill signals to the process. http://www.yolinux.com/TUTORIALS/C++Signals.html
This is the most common way of doing clean up when a program is told to die.
4th Jan 2016
You are absolutely correct, usually a program like this should have signal handlers that turn a flag `running` to false once SIGINT is sent and then the while loop can be written. Adding this will however increase complexity to the simple factor
while (running) {
// do things
}
However in this case fortunately the man page of openlog says (http://linux.die.net/man/3/openlog):
> closelog() closes the descriptor being used to write to the system logger. The use of closelog() is optional.
Nice spot. Hope this clarifies things.
1st Jun 2017
Part II is linked at the bottom of the blog or http://shahmirj.com/blog/the-initd-script