2012-12-04 13 views
5

Im Moment schreibe ich ein C-Programm, das einen Kindprozess ausführen muss. Ich mache nicht mehrere Kindprozesse gleichzeitig oder irgendetwas, also ist das ziemlich einfach. Ich führe die eingebauten Shell-Programme (d. H. Dinge wie cat und echo) erfolgreich aus, aber ich muss auch in der Lage sein zu erkennen, wenn eines dieser Programme nicht erfolgreich ausgeführt werden kann. Ich versuche, dies mit dem folgenden vereinfachten Code:execvp/fork - Wie erhalte ich erfolglose Ausführungen?

int returnStatus; // The return status of the child process. 
pid_t pid = fork(); 

if (pid == -1) // error with forking. 
{ 
    // Not really important for this question. 
} 
else if (pid == 0) // We're in the child process. 
{ 
    execvp(programName, programNameAndCommandsArray); // vars declared above fork(). 

    // If this code executes the execution has failed. 
    exit(127); // This exit code was taken from a exec tutorial -- why 127? 
} 
else // We're in the parent process. 
{ 
    wait(&returnStatus); // Wait for the child process to exit. 

    if (returnStatus == -1) // The child process execution failed. 
    { 
     // Log an error of execution. 
    } 
} 

So zum Beispiel, wenn ich versuche, rm fileThatDoesntExist.txt auszuführen, würde Ich mag zu bedenken, dass ein Fehler, da die Datei nicht existierte. Wie kann ich das erreichen? Während dieser Aufruf von execvp() integrierte Shell-Programme erfolgreich ausführt, führt er auch keine Programme im aktuellen Verzeichnis der ausführbaren Datei aus (d. H. Das Programm, in dem dieser Code läuft); Muss ich noch etwas anderes tun, um Programme im aktuellen Verzeichnis ausführen zu lassen?

Danke!

+0

Mögliches Duplikat von [Wie behebt man execvp (...) Fehler nach fork()?] (Https: // stackoverflow.com/questions/1584956/how-to-handle-execvp-Fehler-nach-fork) – Ruslan

Antwort

13

Dies ist ein klassisches Problem mit einer sehr eleganten Lösung. Vor dem Verzweigen, erstellen Sie eine pipe im übergeordneten. Nach fork sollte das übergeordnete Element das Schreibende der Pipe schließen und den Versuch blockieren, vom Leseende bis read zu gehen. Das untergeordnete Element sollte das Leseende schließen und das Close-on-Exec-Flag für das Schreibende mit fcntl festlegen. Jetzt

, wenn das Kind execvp erfolgreich aufruft, wird das Schreibende des Rohres ohne Daten geschlossen werden, und read im Elternteil 0 zurück Wenn execvp in dem Kind nicht, schreiben Sie den Fehlercode an das Rohr, und read in der Eltern wird nicht Null zurückgeben, nachdem der Fehlercode für die Eltern zu behandeln gelesen.

+0

Danke für den Kommentar, es hat mich definitiv auf den richtigen Weg gebracht. Nach einigen Recherchen wurde mir klar, dass es mir nur sehr wichtig ist, die stderr-Ausgabe des Kindprozesses zu erfassen. Ich denke, ich überprüfe nur, ob der stderr leer ist und das reicht aus, um festzustellen, welches Problem mit der Ausführung aufgetreten ist. Allerdings habe ich Probleme, diese Idee in Code umzuwandeln. Würde es überhaupt einen Aufruf von dup() geben? –

0

In Bezug auf die Fehlererkennung, wenn eine exec() - Funktion den aktuellen Prozess durch einen neuen ersetzt, dann ist der aktuelle Prozess weg; Es spielt keine Rolle, ob das ausgeführte Programm entscheidet, dass es ein Erfolg oder Misserfolg ist. Der Elternprozess vor der Verzweigung kann jedoch den Beendigungscode des Kindes erkennen, der wahrscheinlich die Befehlserfolgs-/Fehlerinformation hätte.

In Bezug auf die Suche nach ausführbaren Dateien dupliziert execvp() die Aktion der Shell und sucht den aktuellen Pfad. Wenn keine ausführbaren Dateien im Arbeitsverzeichnis gefunden werden, befindet sich das Verzeichnis wahrscheinlich nicht im Suchpfad (oder die Dateien sind nicht ausführbar). Sie können versuchen, sie mit einem vollständigen Pfadnamen anzugeben.

Wenn Sie einfach einen Befehl ausführen und auf das Ergebnis warten möchten, können Sie die system() - Funktion verwenden, die dies für Sie erledigt, anstatt sie selbst mit fork/exec zu erstellen.

+0

Gute Info, aber es ist nicht ausreichend für den Elternteil zu unterscheiden zwischen 'execvp' fehlgeschlagen und das externe Programm mit Nicht-Null-Exit-Status beenden. –

+0

@R - Bei Verwendung von execvp() kann der ursprüngliche Prozess nur dann ausgeführt werden, wenn execvp fehlschlägt. Sie können dann den übergeordneten Benutzer informieren. Wenn Sie system() verwenden, kann eine Untersuchung erforderlich sein, um herauszufinden, wie die Fehler zu unterscheiden sind. –

+0

Das Informieren der Eltern ist der schwierige Teil. Meine Antwort geht darauf ein, wie das geht. –

3

wait(2) gibt Ihnen mehr als nur den Exit-Status des untergeordneten Prozesses. Um den echten Exit-Status zu erhalten, müssen Sie das Makro WIFEXITED() verwenden, um zu testen, ob das Kind normal (im Gegensatz zu abnormal über ein Signal usw.) ausgetreten ist, und dann das WEXITSTATUS() Makro zu verwenden, um den echten Exit-Status zu erhalten:

wait(&status); 
if(WIFEXITED(status)) 
{ 
    if(WEXITSTATUS(status) == 0) 
    { 
     // Program succeeded 
    } 
    else 
    { 
     // Program failed but exited normally 
    } 
} 
else 
{ 
    // Program exited abnormally 
} 

Damit execvp(3) ein Programm im aktuellen Verzeichnis ausführen können, müssen Sie entweder das aktuelle Verzeichnis in Ihrer $PATH Umgebung (in der Regel keine gute Idee) hinzuzufügen, oder es den vollständigen Pfad passieren, zB Verwenden Sie ./myprogram anstatt nur myprogram.

+2

Diese Information ist korrekt, aber es kann Ihnen nicht sagen, ob 'execvp' erfolgreich war. –