Steuern Sie den Daemon-Prozess von einem anderen Prozess in C

Jinku Hu 12 Oktober 2023
  1. Verwenden Sie die Funktionen fork und setsid, um einen Daemon-Prozess zu erstellen
  2. Verwenden Sie die Funktion daemon, um einen Daemon-Prozess zu erstellen
Steuern Sie den Daemon-Prozess von einem anderen Prozess in C

In diesem Artikel werden verschiedene Methoden zum Steuern des Daemon-Prozesses von einem anderen Prozess in C aus vorgestellt.

Verwenden Sie die Funktionen fork und setsid, um einen Daemon-Prozess zu erstellen

Daemon-Prozesse weisen mehrere Merkmale auf, z. B., dass es sich um Prozesse mit langer Laufzeit handelt, und Daemons können beim Systemstart gestartet werden. Der Daemon-Prozess kann über die Benutzerbefehle gesteuert werden, die ihn zwingen, beim Start zu beenden, anzuhalten oder sogar zu deaktivieren. Das übliche Szenario würde jedoch dazu führen, dass ein Dämon beim Herunterfahren des Systems mithilfe einiger systemspezifischer Skripts beendet wird. Daemons werden im Allgemeinen ohne steuerndes Terminal im Hintergrund ausgeführt, und die Programme, die solche Funktionen verwenden, sollten verschiedene Signalhandler implementieren, um externe Interrupts zu verarbeiten.

Es gibt mehrere Methoden, um einen Dämonprozess zu erstellen und zu überwachen. In diesem Beispiel wird jedoch die Erstellungsphase demonstriert, in der wir eine fork-Funktion aufrufen, um einen untergeordneten Prozess zu erstellen. Dann wird der übergeordnete Prozess beendet und das untergeordnete Element setzt die Ausführung fort, da es das untergeordnete Element des init-Prozesses wird (auf Linux-Systemen ist der init-Prozess der erste Prozess beim Start). Der untergeordnete Prozess ruft die Funktion setsid auf, um eine neue Sitzung zu starten und den Prozess vom steuernden Terminal zu entfernen. Schließlich rufen wir noch einmal fork auf und verlassen den übergeordneten Prozess, um sicherzustellen, dass unser Daemon kein steuerndes Terminal erhält. Jetzt führen wir den Daemon-Prozess aus. Es ist wichtig, einen SIGTERM-Signal-Handler zu registrieren, um eine Bereinigung der Ressourcen und einen ordnungsgemäßen Exit durchzuführen, wenn das System oder der Benutzer den entsprechenden Interrupt liefert.

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define errExit(msg)    \
  do {                  \
    perror(msg);        \
    exit(EXIT_FAILURE); \
  } while (0)

void cleanupRoutine(int signal_number) {
  write(STDERR_FILENO, "hello", 5);
  _exit(EXIT_SUCCESS);
}

int main(int argc, char *argv[]) {
  fprintf(stderr, "[pid - %d] running...\n", getpid());

  switch (fork()) {
    case -1:
      errExit("fork");
    case 0:
      break;
    default:
      _exit(EXIT_SUCCESS);
  }
  fprintf(stderr, "[pid - %d] running...\n", getpid());

  if (setsid() == -1) errExit("setsid");

  switch (fork()) {
    case -1:
      errExit("fork");
    case 0:
      break;
    default:
      _exit(EXIT_SUCCESS);
  }
  fprintf(stderr, "[pid - %d] running...\n", getpid());

  struct sigaction sigterm_action;

  memset(&sigterm_action, 0, sizeof(sigterm_action));
  sigterm_action.sa_handler = &cleanupRoutine;
  sigterm_action.sa_flags = 0;

  // Mask other signals from interrupting SIGTERM handler
  if (sigfillset(&sigterm_action.sa_mask) != 0) {
    perror("sigfillset");
    exit(EXIT_FAILURE);
  }
  // Register SIGTERM handler
  if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
    perror("sigaction SIGTERM");
    exit(EXIT_FAILURE);
  }

  while (1) {
    getpid();
  }

  exit(EXIT_SUCCESS);
}

Verwenden Sie die Funktion daemon, um einen Daemon-Prozess zu erstellen

Obwohl das vorherige Beispiel scheinbar korrekten Code zeigt, fehlen die Schritte, um sicherzustellen, dass alle vom übergeordneten Element geerbten offenen Dateideskriptoren geschlossen sind. Das Arbeitsverzeichnis wurde geändert, die Standardeingabe nach /dev/null umgeleitet und so weiter. Diese Schritte garantieren, dass bestimmte Funktionen nicht fehlschlagen, wenn der Dämon sie aufruft, und dass auch ein seltsames Verhalten nicht beobachtet wird.

Wenn Sie beispielsweise das vorherige Programm über das Terminalfenster gestartet und dann das Signal SIGTERM an den Daemon-Prozess gesendet haben, wird die Funktion write vom Signalhandler cleanupRoutine auch nach der neuen Eingabeaufforderung auf demselben Terminal gedruckt angezeigt. Somit wird die Funktion daemon von der GNU C-Bibliothek bereitgestellt. Die oben genannten Schritte werden automatisch ausgeführt, um einen sauberen Kontext für den neu erstellten Daemon-Prozess sicherzustellen. Die Funktion daemon akzeptiert zwei ganzzahlige Argumente: das erste (wenn gleich Null), das angibt, ob das aktuelle Arbeitsverzeichnis in das Stammverzeichnis geändert werden soll. Die zweite Ganzzahl (falls gleich Null) gibt an, ob die Standard-E/A-Streams nach /dev/null umgeleitet werden sollen.

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define errExit(msg)    \
  do {                  \
    perror(msg);        \
    exit(EXIT_FAILURE); \
  } while (0)

void cleanupRoutine(int signal_number) {
  write(STDERR_FILENO, "hello", 5);
  _exit(EXIT_SUCCESS);
}

int main(int argc, char *argv[]) {
  fprintf(stderr, "[pid - %d] running...\n", getpid());

  if (daemon(0, 0) == -1) errExit("daemon");

  fprintf(stderr, "[pid - %d] running...\n", getpid());

  struct sigaction sigterm_action;

  memset(&sigterm_action, 0, sizeof(sigterm_action));
  sigterm_action.sa_handler = &cleanupRoutine;
  sigterm_action.sa_flags = 0;

  // Mask other signals from interrupting SIGTERM handler
  if (sigfillset(&sigterm_action.sa_mask) != 0) errExit("sigfillset");

  // Register SIGTERM handler
  if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) errExit("sigaction");

  while (1) {
    getpid();
  }

  exit(EXIT_SUCCESS);
}
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Verwandter Artikel - C Process