Eigene Unix-Shell in C schreiben - Probleme mit PATH und execv
Frage
Ich schreibe meine eigene Shell in C.Es muss in der Lage sein, das aktuelle Verzeichnis des Benutzers anzuzeigen und Befehle basierend auf dem vollständigen Pfad auszuführen (muss execv verwenden) und erlauben Sie dem Benutzer, das Verzeichnis mit cd zu ändern.
Das IST eine Hausaufgabe.Der Lehrer gab uns nur eine grundlegende Einführung in C und einen sehr kurzen Grundriss, wie das Programm funktionieren sollte.Da ich nicht der Typ bin, der so schnell aufgibt, habe ich drei Tage lang recherchiert, wie das geht, aber jetzt bin ich ratlos.
Folgendes habe ich bisher:
- Zeigt den Benutzernamen, den Computernamen und das aktuelle Verzeichnis des Benutzers an (standardmäßig das Home-Verzeichnis).
- Fordert den Benutzer zur Eingabe auf und ruft die Eingabe ab
- Teilt die Benutzereingabe durch „ “ in ein Array von Argumenten auf
- Teilt die Umgebungsvariable PATH nach „:“ in ein Array von Tokens auf
Ich bin mir nicht sicher, wie ich von hier aus fortfahren soll.Ich weiß, dass ich den Befehl execv verwenden muss, aber bei meiner Recherche auf Google habe ich kein Beispiel gefunden, das ich verstehe.Wenn der Befehl beispielsweise bin/ls lautet, woher weiß execv dann, dass alle Dateien/Ordner aus dem Home-Verzeichnis angezeigt werden?Wie teile ich dem System mit, dass ich das Verzeichnis geändert habe?
Ich habe diese Seite oft genutzt, was hilfreich war: http://linuxgazette.net/111/ramankutty.html aber auch hier bin ich ratlos.
Vielen Dank für Ihre Hilfe.Lassen Sie mich wissen, ob ich einen Teil meines vorhandenen Codes veröffentlichen sollte. Ich bin mir allerdings nicht sicher, ob das notwendig ist.
Lösung
Um den cd-Befehl zu implementieren, benötigen Sie lediglich den Systemaufruf chdir
.
#include <unistd.h>
int chdir(
const char *path /* the path name */
);
Sie können also einfach so etwas aufrufen:
int ret1 = chdir("../foo/bar");
Der Rückgabewert von chdir
ist 0, wenn ein Wechsel in dieses Verzeichnis möglich war und -1, wenn ein Fehler aufgetreten ist.Für den Fehler sollten Sie die Manpage konsolidieren.
Das aktuelle Verzeichnis kann von jedem Programm überprüft werden, also wenn Sie es ausführen ls
ohne Argumente, dann prüft ls, in welchem Verzeichnis es läuft und verwendet dieses Verzeichnis als einziges Argument.Dies ist eine Funktion von ls und nicht von the execv
Anruf.
Für den zweiten Teil.
#include <unistd.h>
int execv(
const char *path, /* programm path*/
char *const argv[]/* argument vector*/
);
execv
führt eine ausführbare Datei zum angegebenen Zeitpunkt aus path
und mit den angegebenen Argumenten argv
.Wenn Sie also ausführen möchten /bin/ls ../foo /bar
, Sie brauchen etwas Ähnliches
char *cmd_str = "/bin/ls";
char *argv[] = {cmd_str, "../foo", "/bar", NULL };
if (execv(cmd_str, argv) == -1 ){
/* an error occurred */
}
Der von zurückgegebene Fehler execv
ist -1.Wenn Sie wissen möchten, warum der Befehl nicht ausgeführt wurde, schauen Sie sich die Manpages an.
Der NULL
In char *argv[] = {cmd_str, "../foo", "/bar", NULL };
soll darauf hinweisen, dass es nach dem keine weiteren Argumente gibt NULL
.
Der dritte Teil.Unix-basierte Systeme behandeln Befehle mit einem / darin normalerweise als Befehle, die direkt ausgeführt werden können.Das bedeutet, dass Sie zunächst prüfen, ob die angegebene Befehlszeichenfolge einen Schrägstrich enthält.
int ret_value;
if (strchr(cmd_str, '/')
if (execv(cmd_str, argv) == -1 ){
/* an error occurred */
}
Wenn kein Schrägstrich vorhanden ist, müssen Sie alle Verzeichnisse durchgehen PATH
und prüfen Sie, ob Sie den Befehl ausführen können.Der gegebene Befehl lautet also ls ../foo /bar
und nehmen wir den Wert von an PATH
Ist ".:/sbin:/bin:/usr/bin"
.Wir würden dann versuchen, zuerst auszuführen ./ls ../foo /bar
Dann /usr/bin/ls ../foo /bar
und zuletzt /bin/ls ../foo /bar
.
Hoffe das hilft.
Andere Tipps
Zum Beispiel, wenn der Befehl lautet
bin/ls
, wie funktioniertexecv
Kennen Sie die Anzeige aller Dateien/Ordner aus dem Home-Verzeichnis?Wie teile ich dem System mit, dass ich das Verzeichnis geändert habe?
Jeder Prozess verfügt über ein aktuelles Arbeitsverzeichnis, das mit geändert werden kann chdir
.Untergeordnete Prozesse erben das Arbeitsverzeichnis von ihren übergeordneten Prozessen.Im Allgemeinen verwaltet Ihre Shell also ihr aktuelles Arbeitsverzeichnis als Reaktion darauf cd
Vom Benutzer eingegebene Befehle.Wenn ein Befehl eingegeben wird, der nicht integriert ist, werden Sie Folgendes tun fork
um einen untergeordneten Prozess zu erstellen und dann aufzurufen execv
dort, um die Binärdatei auszuführen.
Wenn Sie das nehmen möchten PATH
Berücksichtigen Sie Programmnamen, die keinen Verzeichnisteil enthalten, dann sollten Sie alle möglichen Kombinationen von a ausprobieren PATH
Element und den Programmnamen.Sie können entweder prüfen, ob die genannte Datei existiert, oder einfach versuchen, sie auszuführen und mit der nächsten fortzufahren, wenn dies fehlschlägt.Ich falle execv
Anrufe scheiterten, Sie müssen anrufen _exit
um den Kindprozess zu beenden.
Beachten Sie, dass die meisten Shells jeden Befehl behandeln, der a enthält /
als ein Pfad, an den übergeben wird execv
direkt.Wenn der Pfad dies nicht tut Start mit einem /
, dann handelt es sich um einen relativen Pfad, und das Betriebssystem löst ihn in Bezug auf das aktuelle Arbeitsverzeichnis auf.Mit anderen Worten, die bin/ls
aus Ihrem Beispiel würde sich auf die beziehen ls
binär in der bin
Verzeichnis, das ein Unterverzeichnis des aktuellen Arbeitsverzeichnisses ist.Nur Befehle, die keine enthalten /
überhaupt werden entweder als eingebauter Befehl interpretiert (wie cd
) oder der Name einer Binärdatei, die sich auf der befindet PATH
.
Das erste Argument dazu execv
ist der Pfad, wie Sie ihn berechnet haben.Das erste Element der argv
Die Liste entspricht traditionell dem Namen, wie er eingegeben wurde, d. h.ohne Zusatz PATH
Verzeichnis.Nach diesem ersten Argument werden alle zusätzlichen Befehlszeilenparameter übergeben, gefolgt von a NULL
um die Liste zu beenden.
Ich denke, das Problem besteht darin, dass Sie glauben, dass die Shell für die Arbeit verantwortlich ist ls
. ls
ist nicht wirklich ein „Teil“ der Shell (zumindest in diesem Fall).die Muschel ausführt ein Programm namens ls
.Die meisten Kommentare scheinen zu erklären, wie man findet ls
, aber ich glaube nicht, dass Sie darüber verwirrt sind.
Sie sollten sorgfältig überlegen, wozu die Shell dient, bevor Sie sie schreiben.Die Kommentare haben indirekt darauf hingewiesen, dass die Shell „einfach“ Programme wie „aufrufen“ muss ls
Und chdir
, ihre Aufgaben nicht erfüllen.
ls
weiß von selbst, dass es, wenn keine Argumente angegeben werden, die Dateien im aktuellen Arbeitsverzeichnis auflisten soll, wie von zurückgegeben getcwd