/* 17May24: Das Ziel ist es ein Programm zu schreiben, welches einen * Befehl doppelt auffuhrt. Hier sehen wie wir man exec+fork+waitpid * einsetzt. */ #include #include #include #include /* Hier ein Beispiel für Module: Wir definieren unsere eigene Variante * von execvp in der Datei execvp.c und holen hier die Schnittstelle * aus execvp.h. */ #include "execvp.h" int main(int argc, char *argv[]) { /* Mit den fork()-Systemaufruf erstellen wir eine Kopie des * Prozesses. Man hat danach ein Kind- und Elternprozess, welche * beide unabhängig voneinander arbeiten. */ fork(); /* TODO: Fehlerbehandlung */ /* Wenn wir fork() zweimal ausführen, dann haben wir nun vier * Prozesse. Ob wir im Kind- oder Elternprozess sind können wir * anhand von dem Rückgabewert ausmachen: Kind-Prozesse bekommen * immer den Rückgabewert 0 zurück, Eltern-Prozesse bekommen die * PID (Prozess ID Number) des Kinds: */ pid_t pid = fork(); switch (pid) { /* Natürlich kann das fehlschlagen, weil der Speicher * ausgeht. Das muss man entsprechend Behandeln. */ case -1: perror("fork"); exit(EXIT_FAILURE); break; /* Weil fork() im Kind-Prozess das gleiche Programm ab der * stelle wo man fork() aufgerufen hat ausführt, brauchen * wir ein anderes Mittel um ein Programm auszuführen: Die * exec-Funktionen ersetzen in einem Prozess ein Programm, * was dann im gleichen Prozess ausgeführt wird. */ case 0: /* child */ _execvp(argv[1], argv + 1); /* Weil exec das Programm ersetzt, und wir danach nicht mehr * zurückkehren, kann exec nur zurückkehren, wenn es * fehlschlägt. */ perror("execvp"); exit(EXIT_FAILURE); /* Im Eltern-Prozess warten wir darauf, dass unser * Kind-Prozess sich beendet hat. Dazu benutzt man waitpid, * hier im einfachen Modus wo wir nur über eine int-Variable * den Status auslesen und damit die Prozess-Daten * aufräumen. */ default: { /* parent */ int status; if (-1 == waitpid(pid, &status, 0)) { perror("waitpid"); exit(EXIT_FAILURE); } /* status kann man mit WIFEXITED, WEXITSTATUS, ... proben */ } } return EXIT_SUCCESS; }