]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/doc/daemon.txt
Merge branch 'master' into dev-opt
[libucw.git] / ucw / doc / daemon.txt
index a5a23dc4ecedfae9474b101b9539dbbda0abc170..6077e6032e345bb7ef985c19919c4018a34465a2 100644 (file)
@@ -1,6 +1,93 @@
-Daemonization helper
-====================
+Daemon helpers
+==============
 
 
-FIXME: Add general description
+Daemonization
+-------------
+
+When programs run as daemons, they frequently forget to detach themselves
+from the parent environment. LibUCW therefore offers a simple daemonization
+helper which performs the necessary actions. Namely:
+
+* Establishing a new session via a call to `setsid()`.
+* Switching the user and group ID if needed. The user and group can be specified
+  by either a name or `#uid`. If only the user is given, the relevant groups are
+  set according to `/etc/passwd` and `/etc/group`.
+* Redirecting standard input and output from `/dev/null`. Standard error
+  output is left open, so that error messages can be printed before you
+  set up proper <<log:,logging>>.
+* Setting the `umask()` to a fixed value (022).
+* Switching from the current directory to `/`, so that it is not kept busy.
+* Writing a PID file. While the daemon is running, the PID file is kept locked
+  by `flock()`, so we can easily detect stale PID files.
+
+Example
+-------
+
+       #include <ucw/lib.h>
+       #include <ucw/daemon.h>
+
+       void daemon_body(struct daemon_params *dp)
+       {
+               // ... daemon's code ...
+               // When we are done, release the PID file and exit:
+               daemon_exit(dp);
+       }
+
+       int main(int argc, char **argv)
+       {
+               struct daemon_params dp = { .pid_file = "/var/run/example.pid" };
+               // ... parse arguments ...
+               daemon_init(&dp);
+               // ... initialize everything ...
+               // Let us fork off the daemon:
+               daemon_run(daemon_body);
+               // Here continues the parent process
+               return 0;
+       }
+
+Daemon control
+--------------
+
+Daemons using the LibUCW helpers can be controlled by traditional mechanisms present
+in most UNIX-like operating systems. These are usually based on PID files, but they
+are inherently racy, since they do not perform any locking. For example, attempts to
+start the daemon, while another process is trying to stop it often lead to undefined
+states. Also, detection of running daemons fails when the daemon dies and its PID
+is recycled. Checking of process name and similar tricks do not avoid the problem,
+since there can be multiple instances of the daemon running simultaneously.
+
+We therefore recommend the following daemon control protocol, which prevents all such
+race conditions. Its implementation is available in form of the daemon_control() library
+function or the `ucw-daemon-control` stand-alone utility.
+
+* There exist two files:
+** PID file (usually `/var/run/daemon.pid`), which contains the PID of the daemon
+   process and when the daemon runs, it keeps the file locked by `flock()`.
+** Guard file (usually `/var/run/daemon.lock`), which is locked (again by `flock()`)
+   whenever we want to perform an action on the daemon.
+* When we want to start the daemon:
+** Lock the guard file, creating it if it did not exist.
+** Try to lock the PID file. If it fails, the daemon is already running, so we are done.
+** Unlock the PID file.
+** Run the daemon. The daemon locks the PID file and when it has everything initialized,
+   it forks and the parent process writes the child's PID and exits.
+** Unlock the guard file.
+* When we want to stop it:
+** Lock the guard file, creating it if it did not exist.
+** Try to lock the PID file. If it succeeds, the daemon is not running, so we are done.
+** Read the PID from the PID file.
+** Send a signal to the process. [This is the only place when we can race. The daemon could
+   have exited in the meantime and its PID could have been recycled. Hopefully, the time window
+   between checking the lock and sending the signal will be short enough. Using 32-bit PIDs
+   is advisable anyway.]
+** Lock the PID file. This will wait until the daemon finishes and releases the lock.
+** Unlock the guard file.
+* When we want to query the daemon's status:
+** Lock the guard file, creating it if it did not exist.
+** Try to lock the PID file. If it succeeds, the daemon was not running.
+** Unlock everything.
+
+ucw/daemon.h
+------------
 
 !!ucw/daemon.h
 
 !!ucw/daemon.h