Durchsuchen von PATH
Da die Funktion execvpe nicht Bestandteil von POSIX ist, wäre es reizvoll, diese selbst zu implementieren. So sieht unter Linux die Schnittstelle hierfür aus:
int execvpe(const char *file, char *const argv[], char *const envp[]);
Wie könnte diese realisiert werden?
-
Falls file irgendeinen „/“ enthält, sollte execvpe äquivalent zu execve sein.
-
Der Inhalt der PATH-Umgebungsvariablen lässt sich mit getenv("PATH") abrufen. Die einzelnen Verzeichnisse sind dabei durch Doppelpunkte voneinander getrennt. Eine Möglichkeit, die einzelnen Verzeichnisse zu durchlaufen, bieten die Funktionen strtok bzw. strtok_r aus #include <string.h>. Beispiel:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { const char* path = getenv("PATH"); char* mypath = strdup(path); char* lasts; char* dir = strtok_r(mypath, ":", &lasts); while (dir) { puts(dir); dir = strtok_r(0, ":", &lasts); } free(mypath); }
theon$ gcc -Wall -o path path.c theon$ echo $PATH .:/home/borchert/bin:/opt/ulm/dublin/cmd:/opt/ulm/dublin/bin:/opt/schily/bin:/usr/bin:/usr/perl5/5.12/bin:/opt/developerstudio12.5/bin:/opt/ulm/admin/bin:/usr/sbin:/usr/proc/bin:/boot/solaris/bin:/opt/bacula/bin:/usr/openwin/bin theon$ ./path . /home/borchert/bin /opt/ulm/dublin/cmd /opt/ulm/dublin/bin /opt/schily/bin /usr/bin /usr/perl5/5.12/bin /opt/developerstudio12.5/bin /opt/ulm/admin/bin /usr/sbin /usr/proc/bin /boot/solaris/bin /opt/bacula/bin /usr/openwin/bin theon$
Warum wurde hier strdup verwendet?
-
Bei jedem Verzeichnis aus dem Pfad wäre nun zu testen, ob es das Kommando in diesem Pfad gibt. Dies könnte erfolgen, indem ein zusammengesetzter Pfadname gebaut wird. Es geht aber auch ohne:
-
Sie können das Verzeichnis eröffnen mit folgender Variante von open:
int dirfd = open(dir, O_DIRECTORY|O_SEARCH);
O_DIRECTORY stellt sicher, dass das es ein Verzeichnis sein muss und O_SEARCH gibt an, dass wir das Verzeichnis nur durchsuchen können möchten. Beide Flags sind in #include <fcntl.h> definiert.
-
Mit dem Systemaufruf openat können Sie das Verzeichnis, zu dem relativ ein Pfad interpretiert wird, als Dateideskriptor angeben:
int openat(int fd, const char *path, int oflag, ...);
Wenn Sie die Datei nur ausführen können möchten, genügt als Flag hier O_EXEC.
-
Eine Datei, die Sie mit O_EXEC eröffnet haben, können Sie direkt bei dem Systemaufruf fexecve angeben:
int fexecve(int fd, char *const argv[], char *const envp[]);
-
Aufgabe
Implementieren Sie die Funktion execvpe wie beschrieben und verwenden Sie diese in Ihrer bisherigen Lösung.