2011-01-07 5 views
3

Ich arbeite an der Implementierung einer Unix-Shell in C und ich bin derzeit mit dem Problem der relativen Pfade beschäftigt. Besonders beim Eingeben von Befehlen. Für den Moment muss ich immer den vollen Pfad der ausführbaren Datei eingeben, wenn ich lieber "ls" oder "cat" setzen würde.Implementieren einer Unix-Shell in C: überprüfen, ob die Datei ausführbar ist

Ich habe es geschafft, die Variable $ PATH env zu bekommen. Meine Idee ist, die Variable auf das Zeichen ":" aufzuteilen, dann jede neue Zeichenfolge an den Befehlsnamen anzufügen und zu prüfen, ob die Datei existiert und ausführbar ist. Wenn mein PATH beispielsweise "/ bin:/usr/bin" ist und ich "ls" eingabe, möchte ich, dass das Programm zuerst prüft, ob "/ bin/ls" existiert und ausführbar ist, wenn nicht gehe zu "/ usr/bin /".

Zwei Fragen:

1) Ist es ein guter Weg, es zu tun? (Muss es nicht unbedingt das Beste sein. Ich möchte nur sicherstellen, dass es funktioniert.

2) Noch wichtiger, Wie kann ich in C einchecken, wenn eine Datei existiert und ausführbar ist?

Ich hoffe, ich bin klar genug, und ... na ja danke :)

Antwort

8

Nicht. Diese Überprüfung ist falsch. es unterliegt inhärent einer Wettlaufsituation. Stattdessen versuchen Sie mit dem entsprechenden exec-Familienruf ausführen. Wenn es nicht ausführbar ist, erhalten Sie einen Fehler.

Beachten Sie auch, dass Sie die PATH nicht selbst suchen müssen; execvp kann dies für Sie tun.

+3

Das ist genau richtig. Vielleicht könnte es nützlich sein, diese Überprüfung als eine Form der Vorvalidierung durchzuführen, aber die Realität ist, dass nichts weniger als der Versuch, sie auszuführen, Ihnen sagen wird, ob sie ausgeführt werden kann. –

+0

Das Problem ist, wenn Sie versuchen, eines von zwei Programmen zu erkennen, von denen jedes 30 Sekunden zum Starten benötigt. –

4

Verwenden Sie die stat Funktion: http://linux.die.net/man/2/stat

zB:

struct stat sb; 
if(!stat(path, &sb)) 
{ 
    if(IS_REG(sb.st_mode) && sb.st_mode & 0111) 
    printf("%s is executable\n", path); 
} 
4

Anruf stat auf die volle Pfadname, und wenn es 0 zurückgibt (Erfolg), existiert das Ziel. In diesem Fall Fall können Sie das Feld st_mode in der zurückgegebenen Struktur verwenden, um zu testen, ob das Ziel ein Verzeichnis, Gerät, Named Pipe oder normale Datei ist. Wenn es sich um eine Datei handelt, enthält st_mode auch die Berechtigungsbits. (Wenn es ein Verzeichnis ist, könnten einige „ausführbar“ Bits eingestellt werden, aber das würde bedeuten, „durchsuchbar“ und nicht als „ausführbar“.)

Edit: Wie andere bereits erwähnt haben, ist dies Gegenstand einer Race-Bedingung und es gibt bessere Wege, um das zu erreichen, was Sie in dieser speziellen Situation tun möchten.

4

stat? PSH. Viel mehr als du brauchst.

Überprüfen Sie die access() syscall.

if (access(filename, F_OK|X_OK) == 0) 
{ 
    /* You can execute this file. */ 
} 

Beachten Sie, dass jede Prüfung für den Dateizugriff oder Vorhandensein einer Datei ein inhärenten Race-Bedingung in sich hat. Sie können bei Ihrem Anruf bei execve nicht garantieren, dass jemand das ausführbare Bit nicht entfernt, die Eigentümerschaft der Datei geändert, die Datei usw. in der Zeit seit der Überprüfung gelöscht hat. Denken Sie daran, wenn Sie Ihren Code schreiben und entscheiden, wie Fehlerbedingungen behandelt werden.

+0

+1 für die Erinnerung an den Race-Zustand. Lösungen wie diese können nicht davon ausgehen, dass sich zwischen dem Prüfen und Handeln auf externe Ressourcen (nicht innerhalb des Programms) nichts geändert hat. –

+0

Nein, 'X_OK' ist nicht ausreichend. Sie müssten immer noch stat (2) aufrufen, um zu sehen, ob es sich um eine Datei handelt, und dann versuchen, sie auszuführen, um zu sehen, ob es wirklich in Ordnung ist. Aus dem feinen Handbuch: "X_OK for execute/search permission" und sogar "Access() ist eine potentielle Sicherheitslücke und sollte niemals benutzt werden". –

+0

@mu ist zu kurz - Es sieht so aus, als hätte ich 'F_OK' für Dateiexistenz verpasst. Aber ich bin verwirrt darüber, was 'X_OK' tut, wenn ich das Bit nicht überprüfe. Interessant. Was das "potentielle Sicherheitsloch" betrifft, ist dies sehr vage. Sie könnten sich auf den Race-Condition-Teil beziehen. – asveikau

0

Wie erstellen Sie den Prozess?

Verwenden Sie execlp oder execvp.

+0

execvp hat das für mich gemacht. Was ist der Unterschied zu execlp? – rahmu

+2

Der Unterschied ergibt sich aus der Dokumentation! (Und wenn Sie Google haben, haben Sie Dokumentation.) Wenn Sie so etwas tun, möchten Sie wirklich die Dokumentation als eine normale Sache betrachten. Vielleicht lernst du sogar etwas, das du nicht erwartet hast. – davep

0

Die access() Antwort ist die einzig sinnvolle. Wenn Sie stat verwenden, müssen Sie/etc/group analysieren, um alle Gruppen in BESIDEgetgid() herauszufinden und sie zusammen mit dem ausführbaren Gruppenbit zu testen.

Verwandte Themen