What is a Daemon?
A daemon is a program that runs in the background. A daemon will usually be started at system startup and end at system shutdown. The exceptions to this rule are programs like the Bluetooth SDP daemon, which is activated when a new Bluetooth HCI is found,, and ends when it is removed. Daemons run transparently and do not normally interact with the user directly.
Daemons start as ordinary processes but they eventually ‘fork and die’ to start running in the background. Some daemons do only the ‘fork and die’ step but ignore other important steps. Here is a list of what a daemon should do:
- Fork to create a child, and exit the parent process.
- Change the umask so that we aren’t relying on the one set in the parent.
- Open logs to write to in the case of an error.
- Create a new session id and detach from the current session.
- Change the working directory to somewhere that won’t get unmounted.
- Close STDIN, STDOUT and STDERR.
These steps ensure that our association with the calling environment is destroyed and our daemon is now free to run as a completely separate process.
Lastly before writing the daemon you should make sure the code is written securely and in a way that fails gracefully. If your daemon crashes it will not be able to prompt the user about what action to take. The user may not even notice until it is too late.
Forking a child process
In Unix fork() is the only system call with two return values. When you call fork a child process is created which is a near copy of its parent (some things will be different in the child eg. process id). The fork command then returns a 0 in the child and the childs process id in the parent, on failure a -1 is sent to the parent. Generally a program will then check whether it is the child or parent by these return values (just like in movies when a cloned character will check to see if he has a belly button and hence is the original). Here is a snippet of code to do this:
pid_t pid;
/* Clone ourselves to make a child */
pid = fork();
/* If the pid is less than zero,
something went wrong when forking */
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If the pid we got back was greater
than zero, then the clone was
successful and we are the parent. */
if (pid > 0) {
exit(EXIT_SUCCESS);
}
/* If execution reaches this point we are the child */
Changing the umask
Because we are a clone of our parent we’ve inherited its umask. This means the child doesn’t know what permissions files will end up with when it tries to create them. We do this by simply calling umask like this:
/* Set the umask to zero */ umask(0);
Open logs to write to
This part can be done in several different ways. You could open text files, log to a database or use syslog. The method I’m going to demonstrate here is to log using syslog. Syslog sends your log messages to a system wide logger, where they can be configured to be written to a file, send to a network server or filtered away entirely.
/* Open a connection to the syslog server */ openlog(argv[0],LOG_NOWAIT|LOG_PID,LOG_USER); /* Sends a message to the syslog daemon */ syslog(LOG_NOTICE, "Successfully started daemon\n"); /* this is optional and only needs to be done when your daemon exits */ closelog();
Create a new session id
Each process on a Unix system is a member of a process group (or session). The id of each group is the process id of its owner. When we forked from our parent earlier we will have inherited its process group, and our process group leader will still be its parent process. We want to create our own process group and become our own process leader otherwise we will look like an orphan. We can do this easily as follows:
pid_t sid;
/* Try to create our own process group */
sid = setsid();
if (sid < 0) {
syslog(LOG_ERR, "Could not create process group\n");
exit(EXIT_FAILURE);
}
Changing the working directory
At the moment we have the working directory we inherited from our parent. This working directory could be a network mount, a removable drive or somewhere the administrator may want to unmount at some point. To unmount any of these the system will have to kill any processes still using them, which would be unfortunate for our daemon. For this reason we set our working directory to the root directory, which we are sure will always exist and can’t be unmounted.
/* Change the current working directory */
if ((chdir("/")) < 0) {
syslog(LOG_ERR, "Could not change working directory to /\n");
exit(EXIT_FAILURE);
}
Closing the standard file descriptors
A daemon doesn’t interact with the user directly it has no use for STDIN, STDOUT and STDERR and we really have no idea where these are connected or where anything we write to them will end up. As these file descriptors are not required and effectively useless we should close them to save some system resources and prevent any related security problems. We close these descriptors like this:
/* Close the standard file descriptors */ close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO);
Writing the payload
Now you have a C program that is capable of becoming a daemon, but its a pretty useless daemon if it exits immediately. Payload code is really up to you to design. I’ll offer you a few tips on designing your payload.
- Put your payload in a loop. Generally in a daemon you want to perform the same action over and over again until you’re killed. If you have to cleanup (such as closing syslog) when the daemon is about to be killed you should add an exit clause that will be activated by a SIGTERM signal handler.
- Make your code as fast an efficient as possible. This is something you should do with any program, but with daemons it is important that you do not hamper the performance of the rest of the system. This is especially true if you’re going to be running this daemon on desktop systems.
- Be aware that your code may be preempted very often. As your daemon is going to be running for the amount of time the system is up, it is likely that its execution will be preempted.
- Be paranoid about security. Daemons are common attack vectors and can be used to gain privileged access to a system. You should consider dropping any privileges that you don’t require.
Conclusion
So if we take all the code I’ve mentioned in this post and put it all together you have a simple daemon. You can download the source from the link here: daemon.c.
If your daemon is only going to be run on Linux and not on a System V style system such as Solaris you can use the daemon function to do a lot of this work for you.
References
Linux Daemon Writing HOWTO in C
Linux Daemon writing in C++
Random Thought: It appears the devil uses a Unix based OS, probably OSX.
Thank you for the post. It was helpful.
Very neatly captured with detailed explanation. I have been doing couple of things said here without knowing the reason behind, this post clears it. Thanks a lot.
This code just goes in pid>0 and exit. How to force fork() to return zero…to be a child. Please respond.
When the fork call returns a value greater than zero it is returning the process id of the child which it has created. This process will continue until it completes. Inside the child process however the process starts as an exact copy of the parent at the point fork was called, except here the return value from fork is zero.
Here is some code that demonstrates this effect:
#include <unistd.h> #include <stdio.h> int main(int argc, char *argv[]) { pid_t pid; printf("Preparing to fork\n"); pid = fork(); printf("Fork complete\n"); printf("Forked pid was: %d\n", pid); if (pid > 0) { printf("I am the parent\n"); } else { printf("I am the child\n"); } }Which on my machine produced the following output:
Can you see how, once the fork is executed everything happens twice (try running under strace or truss)? This is because there are now two processes running the same code. When trying to become a daemon we don’t care about the parent so we exit it (we should probably store the pid somewhere actually) and continue execution on the child.
Thank you for your respond. I’m usually java programer so this is a new thing for me… I understand it now. It’s quite interesting. Tnx
[...] Write a Linux Daemon – Part I Let’s Write a Linux Daemon – Part II Linux Network Daemons Writing a Daemon in C How To Create A Daemon In [...]
Nice write up. BTW there is a single convenience function called daemon() that handles all this.
I did mention this in the last paragraph. Its not part of POSIX, but it is on 4.4BSD+, Solaris and Linux. So fairly portable.
Thanks for your post!
It’s really helpful!