Umgebungsvariablen und exec

Content

Der POSIX-Standard sieht folgende Varianten für exec vor:

int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
int execle(const char *path, const char *arg0, ... /*,
       (char *)0, char *const envp[]*/);
int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);
int execv(const char *path, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execvp(const char *file, char *const argv[]);
int fexecve(int fd, char *const argv[], char *const envp[]);

Normalerweise werden nur die Argumente übergeben, aber die Varianten execle, execve und fexecve sehen auch die Übergabe der Umgebungsparameter vor. Wenn die Umgebungsparameter nicht mit angegeben werden, wird stattdessen implizit environ übergeben, das bei Bedarf so selbst deklariert werden kann:

extern char **environ;

Die Zeigerliste environ wird mit einem Nullzeiger terminiert und die einzelnen Elemente zeigen auf nullbyte-terminierte Zeichenketten, die jeweils mindestens ein '=' enthalten. Der Teil vor dem ersten '=' ist der Name der jeweiligen Umgebungsvariablen, der Teil danach ist der Wert. Die Umgebungsvariablen sind nicht nur über environ zugänglich, sondern können auch bei main über den dritten Parameter bezogen werden. Folgendes Programm gibt sämtliche Umgebungsparameter aus:

#include <stdio.h>

int main(int argc, char** argv, char** env) {
   for (char** ep = env; *ep; ++ep) {
      puts(*ep);
   }
}

Die Umgebungsvariablen von environ können mit Hilfe der Funktionen getenv und setenv aus #include <stdlib.h> abgefragt und verändert werden:

char *getenv(const char *name);
int setenv(const char *envname, const char *envval, int overwrite);
int unsetenv(const char *name);

Hierbei verändert setenv eine bereits vorhandene Umgebungsvariable nur, wenn overwrite ungleich 0 ist. Die Shell selbst bietet die Möglichkeit an, Umgebungsvariablen zu setzen. Und mit dem Werkzeug env lassen sich nicht nur Umgebungsvariablen zusätzlich setzen, sondern auch mit der Option „-i“ alle Umgebungsvariablen zuvor entfernen:

theon$ gcc -Wall -o printenv printenv.c
theon$ env -i foo=bar hello=world ./printenv
hello=world
foo=bar
theon$ 

Aufgabe

Entwickeln Sie environ.c als einfache Variante von env, die grundsätzlich nur die Umgebungsvariablen an das aufzurufende Kommando übermittelt, die auf der Kommandozeile angegeben sind (also analog zu env mit impliziter Option „-i“). Die Argumente von environ bestehen somit aus beliebig vielen Umgebungsvariablen (zu erkennen am „=“) und dem eigentlichen Kommando.

Die Umgebungsvariablenliste können Sie mit strlist aus der Vorlesungsbibliothek aufbauen: http://www.mathematik.uni-ulm.de/numerik/soft2/ss19/afblib/strlist.html

Zu wünschen wäre eine Funktion execvpe, die sowohl die Umgebungsparameter entgegennimmt als auch PATH unterstützt. Diese ist aber nicht Teil des POSIX-Standards (wird aber von Linux unterstützt). Verwenden Sie daher zunächst execve und akzeptieren Sie, dass Sie die den vollständigen Pfad des Kommandos angeben müssen.