use POSIX; sub daemonize { fork and exit; POSIX::setsid(); fork and exit; umask 0; chdir '/'; close STDIN; close STDOUT; close STDERR; }If the daemon has code that relies on STDIO, you can reopen the system file descriptors on /dev/null
sub daemonize { fork and exit; POSIX::setsid(); fork and exit; umask 0; chdir '/'; open STDIN , '<', '/dev/null'; open STDOUT, '>', '/dev/null'; open STDERR, '>', '/dev/null';If you want to spawn some other program, add an exec call. Leave the system file descriptors open for the exec'd program.
sub daemonize { fork and exit; POSIX::setsid(); fork and exit; umask 0; chdir '/'; exec 'my-daemon'; }If you want the parent to continue execution, do a return instead of exit
sub daemonize { fork and return; POSIX::setsid(); fork and exit; umask 0; chdir '/'; exec 'my-daemon';For production code, add error checking
use POSIX; sub Fork { my $pid = fork; defined $pid or die "Can't fork: $!\n"; $pid } sub daemonize { Fork and return; POSIX::setsid(); Fork and exit; umask 0; chdir '/' or die "Can't chdir to /: $!\n"; exec 'my-daemon' die "Can't exec my-daemon: $!\n"; }
After the second fork, the child is not the session leader (the parent is the session leader) and only a session leader can acquire a controlling terminal. Of course, the child could become a session leader by executing setsid again, but presumably anyone who does that knows what they are doing.
Some Perl modules dup STDERR. You can close STDERR, but the dup'd descriptor will remain open on the terminal. One way to avoid this is to close STDERR in a BEGIN block, before the modules load
BEGIN { close STDERR; }If that isn't convenient, you can hunt down the dup'd descriptors and close them with code like
my $fd2 = "/proc/$$/fd/2"; my $stderr = readlink $fd2 or die "Can't readlink $fd2: $!\n"; for my $link (</proc/$$/fd/*>) { my($fd) = $link =~ /(\d+)$/; $fd > $^F or next; readlink($link) eq $stderr and POSIX::close($fd); }
Here is some context.
A particular problem is SIGHUP. HUP is short for Hang UP; the terminology dates back to the days when people connected physical terminals to computers using modems and phone lines.
Many programmers will recognize SIGHUP as the signal that you send to a daemon to tell it to re-read its configuration files. However, the original use of SIGHUP was to tell a processes that the phone connection to its terminal had been broken: that it literally no longer had a controlling terminal. The default action for a process that receives SIGHUP is to terminate (see signal(7)).
The modern equivalent of a physical terminal is a pseudo-terminal, of the sort provided by XTerm or PuTTY. When a pseudo-terminal exits (for example, because the user closes the window on their screen) the OS sends SIGHUP to processes that were controlled by that terminal. (See setpgid(2) for details.) If your daemon still has a controlling terminal, it is liable to exit when this happens. So you want your daemon to not have a controlling terminal.
A daemon that is properly started with no controlling terminal will never receive SIGHUP from the OS. Thus, it is convenient to repurpose SIGHUP to tell the daemon to read its configuration files.
% cat > foothen you want STDIN, Ctl-D, and Ctl-C to be directed to the cat, not to your shell.
If you do
% cat foo | sort | morethen you want to be able to use STDIN to control the more, and you want Ctl-C to kill off the entire pipeline, which means that it has to be delivered to all three processes.
If you do
% sort foo > bar & % more bazthen you want the sort to run quietly in the background while you use the terminal to view baz.
To manage all this, Unix provides some addition structures for processes
+-session 1 ----------------+ | | | +-process group 1-----+ | | | | | | | process 1 | | | | process 2 | | | | | | | +---------------------+ | | | | +-process group 3-----+ | | | | | | | process 3 | | | | process 4 | | | | process 5 | | | | | | | +---------------------+ | | | +---------------------------+Generally, a session corresponds to a terminal session: a shell and all the processes that the shell runs on behalf of the user. When you start a new terminal, the OS creates a new session for you, and the shell becomes the session leader.
The shell typically creates a new process group for each pipeline that it runs (even if there is only one process in the pipeline).
Any process in the session can write to the terminal. That is why you sometimes see output from background processes in the middle of something else.
One process group is designated foreground; all other process groups are in background. Processes in the foreground group can read from the terminal; processes in the background will block if they try to read from STDIN. If a signal is generated by the terminal (e.g. Ctl-C), then that signal is delivered to each process in the foreground process group.
This system allows shells to manage processes in the way that users want, and to make input, output, and signals work the way that users expect.
A process that wants to get out of the system—to not be in the same session as the shell—calls setsid(). It then becomes the session leader of a new session, and that session has no controlling terminal.