Version 13 of daemon

Updated 2007-02-07 02:27:37

Unix people generally understand "daemon" to be a long-running process, disconnected from any TTY, perhaps with signal management configured in a particular way. This corresponds closely to services under Microsoft Windows NT.

[... start ...]

Tom Poindexter posted [L1 ] this example implementation:

 package require Tclx
 proc shutdown {} {
   # whatever cleanup you need to do
   exit
 }

 proc dispatcher {} {
   # do your work here!  this sample just opens a log file and writes to it.
   while 1 {
     set fd [open /tmp/daemon2.log w]
     puts $fd "daemon2.tcl last ran at [clock format [clock seconds]]" 
     close $fd
     sleep 5
   }
 }
 proc daemonize {} {
   close stdin
   close stdout
   close stderr
   if {[fork]} {exit 0}
   id process group set
   # why this second fork?
   #if {[fork]} {exit 0}
   set fd [open /dev/null r]
   set fd [open /dev/null w]
   set fd [open /dev/null w]
   cd /
   umask 022
   return [id process]
 }
 daemonize
 signal ignore  SIGHUP
 signal unblock {QUIT TERM}
 signal trap    {QUIT TERM} shutdown
 dispatcher

Tom wrote this as a Tcl (or, more properly, TclX) translation of a C-coded example which appeared in W. Richard Stevens' Unix Network Programming. Tom notes that Expect also has enough of the POSIX API "to dissociated from the tty, set umask, become a new process group leader, etc." In fact, BOOK Exploring Expect devotes an entire chapter to "Background Processing".

[Tom might work on setsid() access (by way of a patch) at some point.]

TP - changed the 'after 5000' to 'sleep 5', which should work better. I noticed some problems with signals and after. TclX's 'sleep' sets a traditional Unix alarm(2) system call. [Tom, are the problems something the after maintainer should fix?]


[Explanation of the open /dev/null ...s:]

In Unix, a successful open() call traditionally returns the smallest currently-unused file descriptor. So if you close file descriptors 0, 1, and 2 (standard input, standard output, resp. standard error), the next three files you open will be assigned FDs 0, 1, and 2. This is the traditional way to reassign standard input, etc. (The modern way is to use dup2(), BTW.)

Tcl's channel system contains some black magic that emulates this behaviour for the channels stdin, stdout, and stderr; see Tcl_StandardChannels(3) [L2 ] for details.

The daemonize proc closes stdin, stdout, and stderr in order to detach from the inherited standard file descriptors, then opens /dev/null three times so that it will get a new stdin, stdout, and stderr.


    nohup tclsh my_daemon .... &

Is generally useful for "putting a process in the background" while suppressing SIGHUPs to my_daemon.

And it's even more useful if you redirect stderr/stdout to a file that is named mnemonically...


dzach: I'm trying to write a simple daemon for SuSE Linux 9.3 based on the above.

  • So far I managed to get the daemon started. But when trying to stop the daemon, nothing happens, but the panel shows daemon has stoped.
  • How can I set the runlevels for the daemon? There is nothing showing on the Yast panel.
  • How can I write a description for the daemon so that it shows up in the Yast2 panel?

Any ideas please?


AMG: I recommend against having a process daemonize itself. It's simpler overall if it instead relies on the shell to fork it into the background. This allows the shell to redirect its output to a log file or logger process, among other things. It centralizes the "daemonization" code in the parent shell, which is a better design than having every potential daemon process contain a (possibly buggy) copy.

Here's a bash example:

 $ server.tcl &

The ampersand makes bash (or whatever shell) fork a child process to run server.tcl.

If you simply must have the process appear to daemonize itself, perhaps because your Linux distribution demands this, wrap it with a one-line shell script similar to the above example. This shell script can also set resource limits, redirect stdin/stdout/stderr, record PIDs, change UIDs, and contain configuration in the form of command-line arguments passed to the child.

See daemontools [L3 ] for a very robust implementation of this concept.


[ Category Example ]