I have always wanted to know what goes into writing a daemon for Linux so I decided it was about time to figure it out. I attribute most of what I have learned to Devin Watson’s article here.
What is a Daemon?
A daemon is essentially a program that runs in the background instead
of the foreground and isn’t associated with any tty. It often runs
continuously and starts when the OS boots up but doesn’t have to. What
do I mean by background vs. foreground? Well, if you start a script
or program at the command line you will see the output in the console
until the program finishes or you terminate the process. This is
running in the “foreground”. You can also run a program in the
background from the command line by appending an &
to the end of the
script or program.
So I just have to append an ampersand to a command to make a service? No. That just runs a program in the background. See the discussion about a poor man’s daemon using nohup. Ok. Now that we established what a Daemon is… How do we write one?
Writing a Daemon
According to https://en.wikipedia.org/wiki/Daemon the creation of a Daemon involves:
- Dissociating from the controlling tty
- Becoming a session leader.
- Becoming a process group leader.
- Executing as a background task by forking and exiting (once or twice). This is required sometimes for the process to become a session leader. It also allows the parent process to continue its normal execution.
- Setting the root directory (/) as the current working directory so that the process does not keep any directory in use that may be on a mounted file system (allowing it to be unmounted).
- Changing the umask to 0 to allow open(), creat(), and other operating system calls to provide their own permission masks and not to depend on the umask of the caller
- Closing all inherited files at the time of execution that are left open by the parent process, including file descriptors 0, 1 and 2 for the standard streams (stdin, stdout and stderr). Required files will be opened later.
- Using a logfile, the console, or /dev/null as stdin, stdout, and stderr
Lets take a look at some basic C daemon code and see how it aligns
with the Wikipedia formula. The first thing we do is create a child
process by calling fork()
and exit the parent process by calling
exit()
. This:
- disassociates from the controlling tty
- executes as a background task by forking and exiting
Change the current directory so we don’t hold references to any mounted directories allowing them to be unmounted.
Next we change the umask to 0. As mentioned previously, this will allow open(), creat(), and other operating system calls to provide their own permission masks and not to depend on the umask of the caller.
Become the session leader and process group leader:
Closing all inherited files at the time of execution:
Use a log file:
Altogether we get:
Trial Run
So what happens if we compile and run it?
We can see that our program is not holding on to the terminal window but is indeed running in the background based upon looking at the process list and the log entry that has been written.