exec (Unix)

exec*() ist eine Gruppe von Systemcalls unter Unix und unixähnlichen Betriebssystemen. Ihnen allen ist gemeinsam, einen neuen Prozess in dem Environment eines bestehenden Prozesses zu starten und damit diesen zu ersetzen. (Dieser Vorgang wird auch Overlay genannt.) Im POSIX-Standard werden dazu folgende Funktionsprototypen in der Headerdatei unistd.h definiert:

 int execl(char const *path, char const *arg0, ...);
 int execle(char const *path, char const *arg0, ..., char const *envp[]);
 int execlp(char const *file, char const *arg0, ...);
 int execv(char const *path, char const *argv[]);
 int execve(char const *path, char const *argv[], char const *envp[]);
 int execvp(char const *file, char const *argv[]);

Dabei bedeuten:

arg0
das erste (eigentlich: nullte, weil implizit gesetzte) Argument auf der Kommandozeile und konventionell der Name des ausgeführten Executables. Schlecht programmierte Software verlässt sich unter Umständen auf diese Angabe, um den exakten Ort in Filesystem festzustellen, von dem das laufende Programm geladen wurde. Dies ist allerdings nicht nur nicht durch den Standard garantiert, sondern auch nicht plattformübergreifend konsistent geregelt.
envp[]
ein Array von Pointern, die auf Strings von der Form Variable=Wert zeigen und das Environment des Prozesses darstellen
path
der Pfadname der Datei, die ausgeführt werden soll. (Dieser sollte anstatt arg0 für diese Information genutzt werden.)
argv[]
ein Array von Pointern, die auf die übergebenen Kommandozeilenargumente zeigen.

Beide beteiligten Arrays, envp[] und argv[] enthalten Pointer auf nullterminierte Strings. Das letzte Element des Arrays ist konventionell ein Nullpointer, womit das Ende des Arrays angezeigt wird.

Seiteneffekte

Offene File Descriptors des aufrufenden Prozesses bleiben auch in dem neuen Prozess geöffnet. Das Environment bleibt ebenfalls grundsätzlich erhalten. Hingegen werden (private) Daten und Code des aufrufenden Prozesses durch das Overlay zerstört und mit den Daten und dem Code des Overlays ersetzt. Shared Memory wird zum Unterschied zu exklusiv genutztem nicht berührt.

Der Return Code eines erfolgreich durchgeführten exec*()-Calls kann vom aufrufenden Prozess nicht abgefragt werden, da dieser ja durch den Aufruf ersetzt wurde. Einen Prozess durch einen exec*()-Aufruf zu ersetzen stellt keine Beendigung des Prozesses dar, der ja (lediglich in geändertem Zustand) weiter existiert. Im Falle eines fehlgeschlagenen Aufrufs (in diesem Fall läuft der zu ersetzende Prozess ja noch) wird −1 zurückgegeben und errno auf einen der folgenden Werte (siehe errno.h) gesetzt:

E2BIGDie Argumentliste ist größer als das diesbezügliche System-Limit es zulässt.
EACCESDer Zugriff auf das Executable wurde verweigert. (Mögliche Gründe können sein: File gelockt, fehlende Rechte, ....)
ENOENTDas zu startende Executable wurde nicht gefunden.
ENOMEMEs steht nicht genug Memory zur Verfügung um das Programm zu starten.

Geschichte, heutige Verwendung

Das ursprüngliche Unix konnte die Funktionalität starte aus einem bestehenden einen neuen, anderen Prozess nicht in einem Schritt durchführen. Stattdessen wurde mit fork() eine Kopie des bestehenden Prozesses erzeugt und dann eine der exec*()-Funktionen genutzt, um die erzeugte Kopie mit einem (anderen) Overlay zu versehen. Dadurch kam dieser Gruppe von System-Calls eine große Bedeutung zu.

POSIX hat mittlerweile eine Gruppe von System-Calls posix_spawn*() als (optionale) Erweiterung definiert, mit denen die Abfolge fork()-exec*() vermieden werden kann, allerdings unter Verlust eines Teils der Flexibilität, die dieser Mechanismus bietet.

exec als Shell-Befehl

Viele gängige Unix-Shells implementieren ebenfalls einen Befehl exec, der im Grunde Analoges zum System-Call leistet: der laufende Prozess (bzw. das laufende Script) wird durch eine Instanz des angegebenen neuen Executables ersetzt. Im angeführten Beispiel verwendet man diesen Mechanismus, um ein X11-Startscript nach Aufruf des Window-Managers zu verlassen:

 #!/bin/ksh
 xclock &
 xsetroot -solid black
 exec mwm -multiscreen -xrm "ShowFeedback: -quit"

Weblinks