Linux Exec-Systemaufruf

Linux Exec System Call

Der exec-Systemaufruf wird verwendet, um eine Datei auszuführen, die sich in einem aktiven Prozess befindet. Beim Aufruf von exec wird die vorherige ausführbare Datei ersetzt und die neue Datei ausgeführt.

Genauer gesagt können wir sagen, dass die Verwendung des exec-Systemaufrufs die alte Datei oder das Programm aus dem Prozess durch eine neue Datei oder ein neues Programm ersetzt. Der gesamte Inhalt des Prozesses wird durch ein neues Programm ersetzt.



Das Benutzerdatensegment, das den Systemaufruf exec() ausführt, wird durch die Datendatei ersetzt, deren Name beim Aufruf von exec() im Argument angegeben wird.



Das neue Programm wird in denselben Prozessraum geladen. Der aktuelle Prozess wird nur in einen neuen Prozess umgewandelt und daher wird die Prozess-ID-PID nicht geändert, da wir keinen neuen Prozess erstellen, sondern nur einen Prozess durch einen anderen Prozess in exec ersetzen.



Enthält der aktuell laufende Prozess mehr als einen Thread, werden alle Threads beendet und das neue Prozessabbild geladen und anschließend ausgeführt. Es gibt keine Destruktorfunktionen, die Threads des aktuellen Prozesses beenden.

Die PID des Prozesses wird nicht geändert, aber die Daten, der Code, der Stapel, der Heap usw. des Prozesses werden geändert und durch die des neu geladenen Prozesses ersetzt. Der neue Prozess wird vom Einstiegspunkt aus ausgeführt.

Der Systemaufruf Exec ist eine Sammlung von Funktionen und in der Programmiersprache C lauten die Standardnamen für diese Funktionen wie folgt:



  1. ausschließen
  2. ausführen
  3. execlp
  4. leitender Angestellter
  5. ausführen
  6. execvp


Dabei ist zu beachten, dass diese Funktionen die gleiche Basis haben ausführender gefolgt von einem oder mehreren Buchstaben. Diese werden im Folgenden erläutert:

Und: Es ist ein Array von Zeigern, das auf Umgebungsvariablen zeigt und explizit an den neu geladenen Prozess übergeben wird.

das: l ist für die Befehlszeilenargumente, die eine Liste an die Funktion übergeben

P: p ist die Pfadumgebungsvariable, die hilft, die als Argument übergebene Datei zu finden, die in den Prozess geladen werden soll.

v: v steht für die Befehlszeilenargumente. Diese werden als Array von Zeigern an die Funktion übergeben.

Warum wird exec verwendet?

exec wird verwendet, wenn der Benutzer eine neue Datei oder ein neues Programm im selben Prozess starten möchte.

Innere Arbeitsweise von exec

Beachten Sie die folgenden Punkte, um die Funktionsweise von exec zu verstehen:

  1. Das aktuelle Prozessabbild wird mit einem neuen Prozessabbild überschrieben.
  2. Das neue Prozessabbild ist dasjenige, das Sie als exec-Argument übergeben haben
  3. Der aktuell laufende Prozess wird beendet
  4. Neues Prozessabbild hat gleiche Prozess-ID, gleiche Umgebung und gleichen Dateideskriptor (weil Prozess nicht ersetzt wird Prozessabbild wird ersetzt)
  5. Der CPU-Status und der virtuelle Speicher sind betroffen. Das virtuelle Speichermapping des aktuellen Prozessabbilds wird durch den virtuellen Speicher des neuen Prozessabbilds ersetzt.

Syntaxen von Exec-Familienfunktionen:

Im Folgenden sind die Syntaxen für jede Funktion von exec aufgeführt:

int execl(const char* Pfad, const char* arg, …)
int execlp(const char* Datei, const char* arg, …)
int execle(const char* path, const char* arg, …, char* const envp[])
int execv(const char* path, const char* argv[])
int execvp(const char* Datei, const char* argv[])
int execvpe(const char* file, const char* argv[], char *const envp[])

Beschreibung:

Der Rückgabetyp dieser Funktionen ist Int. Wenn das Prozessabbild erfolgreich ersetzt wurde, wird nichts an die aufrufende Funktion zurückgegeben, da der Prozess, der sie aufgerufen hat, nicht mehr ausgeführt wird. Wenn jedoch ein Fehler auftritt, wird -1 zurückgegeben. Wenn ein Fehler aufgetreten ist und Fehler eingestellt ist.

In der Syntax:

  1. Weg wird verwendet, um den vollständigen Pfadnamen der auszuführenden Datei anzugeben.
  1. verärgert ist das übergebene Argument. Es ist eigentlich der Name der Datei, die dabei ausgeführt wird. Meistens ist der Wert von arg und path gleich.
  1. const char* arg in den Funktionen wird execl(), execlp() und execle() als arg0, arg1, arg2, …, argn betrachtet. Es ist im Grunde eine Liste von Zeigern auf nullterminierte Strings. Hier zeigt das erste Argument auf den Dateinamen, der wie in Punkt 2 beschrieben ausgeführt wird.
  1. envp ist ein Array, das Zeiger enthält, die auf die Umgebungsvariablen zeigen.
  1. Datei wird verwendet, um den Pfadnamen anzugeben, der den Pfad der neuen Prozessabbilddatei identifiziert.
  1. Die Funktionen von exec-Aufrufen, die mit enden Und werden verwendet, um die Umgebung für das neue Prozessabbild zu ändern. Diese Funktionen übergeben die Liste der Umgebungseinstellungen mit dem Argument envp . Dieses Argument ist ein Array von Zeichen, das auf einen nullterminierten String zeigt und eine Umgebungsvariable definiert.

Um die Funktionen der exec-Familie zu verwenden, müssen Sie die folgende Header-Datei in Ihr C-Programm einbinden:

#enthalten

Beispiel 1: Verwendung des exec-Systemaufrufs in einem C-Programm

Betrachten Sie das folgende Beispiel, in dem wir den exec-Systemaufruf in der C-Programmierung in Linux, Ubuntu verwendet haben: Wir haben hier zwei C-Dateien example.c und hello.c:

beispiel.c

CODE:

#enthalten
#enthalten
#enthalten
inthauptsächlich(intargc, verkohlen *argv[])
{
druckenf ('PID von Beispiel.c = %d ',getpid());
verkohlen *args[] = {'Hallo', 'C', 'Programmierung',NULL};
leitender Angestellter('./Hallo',args);
druckenf ('Zurück zu Beispiel.c');
Rückkehr 0;
}

Hallo c

CODE:

#enthalten
#enthalten
#enthalten
inthauptsächlich(intargc, verkohlen *argv[])
{
druckenf ('Wir sind in Hello.c ');
druckenf ('PID von hello.c = %d ',getpid());
Rückkehr 0;
}

AUSGANG:

PID von example.c = 4733
Wir sind in Hello.c
PID von hello.c = 4733

Im obigen Beispiel haben wir eine example.c-Datei und eine hello.c-Datei. In der Beispiel-.c-Datei haben wir zunächst die ID des aktuellen Prozesses ausgegeben (Datei example.c läuft im aktuellen Prozess). Dann haben wir in der nächsten Zeile ein Array von Zeichenzeigern erstellt. Das letzte Element dieses Arrays sollte als Endpunkt NULL sein.

Dann haben wir die Funktion execv() verwendet, die den Dateinamen und das Zeichenzeiger-Array als Argument verwendet. Es sollte hier beachtet werden, dass wir ./ mit dem Dateinamen verwendet haben, es gibt den Pfad der Datei an. Da sich die Datei in dem Ordner befindet, in dem sich example.c befindet, ist es nicht erforderlich, den vollständigen Pfad anzugeben.

Wenn die Funktion execv() aufgerufen wird, wird unser Prozessabbild ersetzt, jetzt ist die Datei example.c nicht im Prozess, aber die Datei hello.c ist im Prozess. Es ist zu erkennen, dass die Prozess-ID gleich ist, egal ob hello.c Prozessabbild oder example.c Prozessabbild ist, da Prozess gleich ist und Prozessabbild nur ersetzt wird.

Dann müssen wir hier noch etwas beachten, nämlich die printf()-Anweisung, nachdem execv() nicht ausgeführt wurde. Dies liegt daran, dass die Kontrolle nie wieder an das alte Prozessabbild zurückgegeben wird, wenn es durch ein neues Prozessabbild ersetzt wird. Die Steuerung kehrt erst dann zum Funktionsaufruf zurück, wenn das Ersetzen des Prozessabbilds nicht erfolgreich ist. (Der Rückgabewert ist in diesem Fall -1).

Unterschied zwischen fork() und exec() Systemaufrufen:

Der Systemaufruf fork() wird verwendet, um eine exakte Kopie eines laufenden Prozesses zu erstellen, und die erstellte Kopie ist der Kindprozess und der laufende Prozess ist der Elternprozess. Der Systemaufruf exec() hingegen wird verwendet, um ein Prozessabbild durch ein neues Prozessabbild zu ersetzen. Daher gibt es beim exec()-Systemaufruf kein Konzept von Eltern- und Kindprozessen.

Beim Systemaufruf fork() werden Eltern- und Kindprozess gleichzeitig ausgeführt. Bei einem exec()-Systemaufruf kehrt die Steuerung jedoch, wenn das Ersetzen des Prozessabbilds erfolgreich ist, nicht dorthin zurück, wo die exec-Funktion aufgerufen wurde, sondern führt den neuen Prozess aus. Die Steuerung wird nur im Fehlerfall zurückübertragen.

Beispiel 2: Kombination von fork()- und exec()-Systemaufrufen

Betrachten Sie das folgende Beispiel, in dem wir sowohl fork()- als auch exec()-Systemaufrufe im selben Programm verwendet haben:

beispiel.c

CODE:

#enthalten
#enthalten
#enthalten
inthauptsächlich(intargc, verkohlen *argv[])
{
druckenf ('PID von Beispiel.c = %d ',getpid());
pid_t p;
P=Gabel();
wenn(P== -1)
{
druckenf ('Beim Aufrufen von fork() ist ein Fehler aufgetreten');
}
wenn(P==0)
{
druckenf („Wir sind im Kinderprozess“ ');
druckenf ('Aufruf von hello.c aus untergeordnetem Prozess ');
verkohlen *args[] = {'Hallo', 'C', 'Programmierung',NULL};
leitender Angestellter('./Hallo',args);
}
anders
{
druckenf („Wir befinden uns im Elternprozess“);
}
Rückkehr 0;
}

Hallo c:

CODE:

#enthalten
#enthalten
#enthalten
inthauptsächlich(intargc, verkohlen *argv[])
{
druckenf ('Wir sind in Hello.c ');
druckenf ('PID von hello.c = %d ',getpid());
Rückkehr 0;
}

AUSGANG:

PID von example.c = 4790
Wir befinden uns im Elternprozess
Wir befinden uns im Kinderprozess
Aufruf von hello.c aus untergeordnetem Prozess
Wir sind in hello.c
PID von hello.c = 4791

In diesem Beispiel haben wir den Systemaufruf fork() verwendet. Wenn der untergeordnete Prozess erstellt wird, wird p 0 zugewiesen und dann werden wir zum untergeordneten Prozess übergehen. Nun wird der Anweisungsblock mit if(p==0) ausgeführt. Eine Meldung wird angezeigt und wir haben den execv()-Systemaufruf verwendet und das aktuelle untergeordnete Prozessabbild, das example.c ist, wird durch hello.c ersetzt. Vor dem Aufruf von execv() waren Child- und Parent-Prozesse gleich.

Es ist zu sehen, dass die PID von example.c und hello.c jetzt unterschiedlich ist. Dies liegt daran, dass example.c das übergeordnete Prozessabbild und hello.c das untergeordnete Prozessabbild ist.