Auf Unix- und Linux-artigen Systemen laufen immer einige sogenannte Daemon-Prozesse. Diese laufen im Hintergrund, haben also keine Verbindung mit einem Terminal.
Beim Start kann man eine sogenannte Daemonisierung verwenden. Man startet von dem interaktiv gestarteten Prozess einen Child-Prozess. Dieser hat noch Verbindung zum ersten und damit zum Terminal. Nun startet man von diesem den eigentlichen Daemon-Prozess und beendet den Child-Prozess. Nun ist die Verbindung zum Parent-Prozess gekappt und der Daemon-Prozess wird damit zum Child-Prozess des Init-Prozesses. Wenn sich der Daemon beendet, wird durch init regelmäßig wait() aufgerufen und damit verhindert, dass dieser als Zombie-Prozess noch lange im System unterwegs ist. Nun muss der Daemon-Prozess aber informiert werden, wann der Child-Prozess beendet ist.
Dies kann wie folgt erfolgen:
/* (C) IT Sky Consulting GmbH 2014 * http://www.it-sky-consulting.com/ * Author: Karl Brodowsky * Date: 2014-02-27 * License: GPL v2 (See https://de.wikipedia.org/wiki/GNU_General_Public_License ) */ #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <signal.h> int daemonized = 0; void signal_handler(int signo) { daemonized = 1; } int main(int argc, char *argv[]) { int fork_result; int ret_code; int status; int pid = getpid(); /* set pgid to pid */ setpgid(pid, pid); signal(SIGUSR1, signal_handler); /* first fork() to create child */ fork_result = fork(); if (fork_result == 0) { printf("In child\n"); /* second fork to create grand child */ fork_result = fork(); if (fork_result != 0) { /* exit child, make grand child a daemon */ printf("exiting child\n"); exit(0); } /* in daemon (grand child) */ pid = getpid(); while (! daemonized) { pause(); } printf("daemon has pid=%d pgid=%d ppid=%d\n", pid, getpgid(pid), getppid()); /* do daemon stuff */ sleep(30); printf("done with daemon\n"); exit(0); } printf("parent waiting for child\n"); wait(&status); printf("child terminated\n"); kill(-getpid(), SIGUSR1); printf("parent done\n"); }
Durch das Setzen einer Prozessgruppen-ID ist es möglich, den Parent-Prozess, den Child-Prozess und den Daemonprozess auch über diese gemeinsame Gruppen-Id anzusprechen, ohne die eigentliche pid zu kennen. Negative Werte als Funktionsparameter für Funktionenen, die dort eine Prozess-Id (pid) erwarten, werden oft als pgid (Prozessgruppen-ID) interpretiert. Wenn der Child-Prozess beendet ist, wird das wait im Parent-Prozess beendet und dieser schickt ein Signal an den Daemon-Prozess, das von diesem ignoriert wird, aber zur Beendigung des Wait-Prozesses führt.
Für ein kleines Beispiel mag es noch akzeptabel sein, nach stdout zu schreiben, aber die Ausgaben eines Daemons sollten natürlich am Ende in einer Log-Datei landen. Das kann durch Ausgabeumleitung oder noch schöner durch Verwendung von syslog geschehen, ist aber ein Thema für sich.