Fork off and die

From LQWiki
Jump to navigation Jump to search

A process is said to "fork off and dies" when a parent process forks, to give a child process, but the parent dies, leaving only the child process running. It is the basic principle underlying how daemons are started and run.

For example, if we create a background process from the shell, such as:

yes > /dev/null &

Using ps, you can verify that it is being run as a child of the shell, by comparing the current PID and parent PID (PPID).

ps -fu

UID        PID  PPID  C STIME TTY          TIME CMD
...
XXXXXX    4538  4536  0 11:31 pts/13   00:00:00 bash
XXXXXX    4575  4538 52 11:36 pts/13   00:00:03 yes
...

If we were now to exit the shell, this means that the parent process (bash) that created the child process (yes) has died. Under what process is the yes process being run? (What is yes's parent?)

Open a new shell and repeat the ps.

UID        PID  PPID  C STIME TTY          TIME CMD
...
XXXXXX    4575     1 48 11:36 ?        00:01:01 yes
...

The PPID for the process is now 1, meaning that the process is now running under init. Care must be taken with processes running under init, as init handles child processes more "brutally".

If we were to write a daemon application in C, for example, we could proceed as follows

#include <sys/types.h>
#include <unistd.h>

int 
main(void)
{
   int pid = fork();
   if(pid < 0) 
   {
      fprintf(stderr, "Can't fork.");
      exit(1);
   }
   else if(pid == 0) // we are the child
   {
      setsid(); // "release" from the parent
      int pid2 = fork();
      if (pid2 < 0) fprintf(stderr, "Can't fork after releasing.\n");
      else if (pid2 > 0) exit(0); // we are the parent
      else {
         // We are now completely free and running under init.
         // We have to close the inherited stream descriptors to avoid deadlocks and the like.
         close(0); // stdin
         close(1); // stdout
         close(2); // stderr
         umask(0); // we don't know which umask we might've inherited
         chdir("/"); // (or any other dir) make sure we're not locking a directory
      }
   }
   else //we are the parent
   {
      exit(0);
   }
}

The parents only executes exit(0);, which means then the parent has exited and died, whilst the child process can still be running and do whatever it needs to do.