What Is the Reason for Performing a Double Fork When Creating a Daemon

What is the reason for performing a double fork when creating a daemon?

Looking at the code referenced in the question, the justification is:

Fork a second child and exit immediately to prevent zombies. This
causes the second child process to be orphaned, making the init
process responsible for its cleanup. And, since the first child is
a session leader without a controlling terminal, it's possible for
it to acquire one by opening a terminal in the future (System V-
based systems). This second fork guarantees that the child is no
longer a session leader, preventing the daemon from ever acquiring
a controlling terminal.

So it is to ensure that the daemon is re-parented onto init (just in case the process kicking off the daemon is long lived), and removes any chance of the daemon reacquiring a controlling tty. So if neither of these cases apply, then one fork should be sufficient. "Unix Network Programming - Stevens" has a good section on this.

Why fork() twice while daemonizing?

The first call to fork(2) ensures that the process is not a group leader, so that it is possible for that process to create a new session and become a session leader. There are other reasons for the first fork(2): if the daemon was started as a shell command, having the process fork and the parent exit makes the shell go back to its prompt and wait for more commands.

The second fork(2) is there to ensure that the new process is not a session leader, so it won't be able to (accidentally) allocate a controlling terminal, since daemons are not supposed to ever have a controlling terminal. About the 2nd fork, here's a quote from Advanced Programming in the UNIX Environment, Chapter 13 (Daemon Processes):

Under System V-based systems, some people recommend calling fork again
at this point, terminating the parent, and continuing the daemon in
the child. This guarantees that the daemon is not a session leader,
which prevents it from acquiring a controlling terminal under the
System V rules. Alternatively, to avoid acquiring a controlling
terminal, be sure to specify O_NOCTTY whenever opening a terminal
device.

Section 13.3 of that book describes a lot more rules and patterns that are used when daemonizing a process, it is well worth the time to read it, if you can.

Why fork() twice

In Linux, a daemon is typically created by forking twice with the intermediate process exiting after forking the grandchild. This has the effect of orphaning the grandchild process. As a result, it becomes the responsibility of the OS to clean up after it if it terminates. The reason has to do with what are known as zombie processes which continue to live and consume resources after exiting because their parent, who'd normally be responsible for the cleaning up, has also died.

Why do daemons fork?

I think daemons fork for several reasons:

  1. One reason is to detach process from any shell that starts it. Some shells (Bash, for instance) kill children upon exit, unless special, shell-specific precautions are made. Forking is a generic way to evade this.

  2. Another reason is to report that the daemon was successfully started.

    Assume it doesn't fork. How would you know that the daemon has been started successfully? You can't just read and parse daemon output, because daemon management programs should do it in a generic way. So the only way is to get return code of the program.

    Indeed, if a daemon failed to start (for example, it couldn't find config file), you would know that immediately. But hey, if a daemon has been started successfully, it may never return! So your daemon manager can't know whether daemon is still trying to start, or has been started, and is working. Fork would solve the problem, and the forking program would return success if a fork worked well.

  3. As for privileges, dropping them after execve is much less secure than doing so before execve. Here's another reason why fork is handy.

Is forking in a daemon still necessary when using systemd?

You are correct. The forking is now 100% handled by the systemd environment so there is really no need to do anything in that arena. It even saves the PID which you can access in the StopExec=... as $MAINPID:

StopExec=/bin/kill "$MAINPID"

If your daemon has a forking capability, you can use it with the forking type:

[Service]
type=forking

But if you don't have any forking mechanism in your daemon, don't implement it. It's useless.

Note that from the command line, you can always use the & to start it in the background. That's explicit. People can clearly understand how that works.

Another point, many people would use a PID file to save that identifier and use it to kill the process on a stop. That PID file was also useful to prevent the administrator from starting a second instance of the same service. Again, systemd takes care of that. You can have at most one instance of any service.

Create a daemon with double-fork in Ruby

According to Stevens's Advanced Programming in the UNIX Environment chapter 13, this is the procedure to make a well-behaved Unix daemon:

  1. Fork and have the parent exit. This makes the shell or boot script think the command is done. Also, the child process is guaranteed not to be a process group leader (a prerequisite for setsid next)
  2. Call setsid to create a new session. This does three things:

    1. The process becomes a session leader of a new session
    2. The process becomes the process group leader of a new process group
    3. The process has no controlling terminal
  3. Optionally fork again and have the parent exit. This guarantes that the daemon is not a session leader nor can it acquire a controlling terminal (under SVR4)
  4. Change the current working directory to / to avoid interfering with mounting and unmounting
  5. Set file mode creation mask to 000 to allow creation of files with any required permission later.
  6. Close unneeded file descriptors inherited from the parent (there is no controlling terminal anyway): stdout, stderr, and stdin.

Nowadays there is a file to track the PID which is used heavily by Linux distribution boot scripts. Be sure to write out the PID of the grandchild, either the return value of the second fork (step 3) or the value of getpid() after step 3.

Here is a Ruby implementation, mostly translated from the book, but with the double-fork and writing out the daemon PID.

# Example double-forking Unix daemon initializer.

raise 'Must run as root' if Process.euid != 0

raise 'First fork failed' if (pid = fork) == -1
exit unless pid.nil?

Process.setsid
raise 'Second fork failed' if (pid = fork) == -1
exit unless pid.nil?
puts "Daemon pid: #{Process.pid}" # Or save it somewhere, etc.

Dir.chdir '/'
File.umask 0000

STDIN.reopen '/dev/null'
STDOUT.reopen '/dev/null', 'a'
STDERR.reopen STDOUT

Understanding Python code for creating daemon process

A process being part of same session means when bash receives SIGHUP when you disconnect over ssh, it terminates all the processes in the session. Default SIGHUP handler also terminates process. To avoid this you want to create a new session.

Additionally, TTY is a somewhat old concept, which through the years has picked up a huge history and loads of corner cases intended for interactivity, but are counterproductive when running daemons, because you do not want the kernel to send random signals to your non-interactive daemon process when something TTY related happens.


So ... you do not want to be a member of TTY session and you do not want to be a session leader, because those get signalled.

That's why you start a daemon: you run python1, this process forks, you get python1 and python2. Python2 starts new session and forks, so you get python3.

Setsid in python2 ensures python3 is not connected to python1 session, and fork in python2 is needed because python2 is still a session leader.

Python3 will then not receive any TTY related signals and won't be killed by SIGHUP when you disconnect or whatever TTY related stuff happens on the box.



Related Topics



Leave a reply



Submit