Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Linux-UNIX-Programmierung von Jürgen Wolf
Das umfassende Handbuch – 2., aktualisierte und erweiterte Auflage 2006
Buch: Linux-UNIX-Programmierung

Linux-UNIX-Programmierung
1216 S., mit CD, 49,90 Euro
Rheinwerk Computing
ISBN 3-89842-749-8
gp Kapitel 7 Dämonen, Zombies und Prozesse
  gp 7.1 Was ist ein Prozess?
  gp 7.2 Prozesskomponente
    gp 7.2.1 Prozessnummer (PID)
    gp 7.2.2 Prozessnummer des Vaterprozesses (PPID)
    gp 7.2.3 Benutzer- und Gruppennummer eines Prozesses (UID, EUID, GID, EGID)
    gp 7.2.4 Prozessstatus
    gp 7.2.5 Prozesspriorität
    gp 7.2.6 Timesharing-Prozesse
    gp 7.2.7 Prozessauslagerung
    gp 7.2.8 Steuerterminal
  gp 7.3 Prozesse überwachen – ps, top, kpm
  gp 7.4 Lebenszyklus eines Prozesses
  gp 7.5 Umgebungsvariablen eines Prozesses
    gp 7.5.1 Einzelne Umgebungsvariablen abfragen
    gp 7.5.2 Umgebungsvariable verändern oder hinzufügen – putenv() und setenv()
    gp 7.5.3 Löschen von Umgebungsvariablen – unsetenv() und clearenv()
  gp 7.6 Ressourcenlimits eines Prozesses
    gp 7.6.1 Mehr Sicherheit mit Ressourcenlimits
  gp 7.7 Prozesserkennung
  gp 7.8 Erzeugung von Prozessen – fork()
    gp 7.8.1 Pufferung
    gp 7.8.2 Was wird vererbt und was nicht?
    gp 7.8.3 Einen Prozess mit veränderter Priorität erzeugen
  gp 7.9 Warten auf einen Prozess
  gp 7.10 Die exec-Familie
    gp 7.10.1 execl()
    gp 7.10.2 execve()
    gp 7.10.3 execv()
    gp 7.10.4 execle()
    gp 7.10.5 execlp()
    gp 7.10.6 execvp()
    gp 7.10.7 Kindprozesse mit exec-Aufruf überlagern
  gp 7.11 Kommandoaufrufe aus dem Programm – system()
  gp 7.12 Dämonprozesse
    gp 7.12.1 Wie ein Prozess zum Dämon wird ...
    gp 7.12.2 Dämon, sprich mit uns ...
    gp 7.12.3 Protokollieren von Dämonen – syslog()
    gp 7.12.4 syslog() in der Praxis
    gp 7.12.5 Den Dämon, den ich rief ...
  gp 7.13 Rund um die Ausführung von Prozessen
    gp 7.13.1 Einen Dämon beim Booten mit einem init-Skript starten
    gp 7.13.2 Hintergrundprozesse und Jobkontrolle
    gp 7.13.3 Prozesse zeitgesteuert ausführen (cron-Jobs)
  gp 7.14 Zusammenfassung und Ausblick


Rheinwerk Computing

7.10 Die exec-Familie  downtop

Die Funktionen der exec-Familie wurden in diesem Kapitel schon des Öfteren erwähnt. Häufig finden Sie diese Anwendung, indem mit fork() ein neuer Kindprozess erzeugt und, mit Aufruf einer exec-Funktion durch das neue angegebene Programm, komplett ersetzt wird. Außerdem bewirkt ein exec-Aufruf auch keine Änderung der PID, da ja kein neuer Prozess erzeugt wird, sondern eben nur die Segmente des aktuellen Prozesses durch die Segmente des neuen Prozesses überschrieben werden. Es gibt sechs verschiedene exec-Funktionen, die sich nur geringfügig anhand der Parameter voneinander unterscheiden. Allerdings basieren alle exec-Funktionen auf der Funktion execve(), die einen Systemaufruf darstellt. Hierzu die Syntax der vorhandenen exec-Funktionen:

#include <unistd. h.>
extern char **environ;
/* Bibliotheksfunktionen */
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg , ...,
            char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
/* Systemaufruf */
int execve(const char *filename, char *const argv [],
           char *const envp[]);

Alle Funktionen geben im Falle eines Fehlers -1 zurück, ansonsten gibt es bei Ausführung keine Rückkehr mehr zum aufrufenden Programm. Es ist daher überflüssig, den Rückgabewert zu überprüfen; man kann gleich mit der Fehlerroutine weitermachen. Die einzelnen Funktionen unterscheiden sich anhand der Endungen, wobei jeder der vier Buchstaben folgende Bedeutung hat:


Tabelle 7.9    Bedeutung der Endungen von exec-Funktionen

Buchstabe Bedeutung
e Es wird eine Environmentliste (Umgebungsvariablen) als Vektor erwartet.
l Es werden die Kommandozeilenargumente in Form einer Liste erwartet.
v Es werden die Kommandozeilenargumente in Form eines Vektors erwartet.
p Es wird ein Dateiname und nicht ein Pfadname als Argument zum Aufruf des Programms erwartet.

Damit es bei den vielen verschiedenen Versionen einfacher fällt, will ich Ihnen zu jeder dieser Funktionen einen kurzen Codeausschnitt zu deren Anwendung geben.


Rheinwerk Computing

7.10.1 execl()  downtop

Das folgende Listing soll den Inhalt des aktuellen Arbeitsverzeichnisses mit »ls -l /home/user« ausgeben.

/* exec1.c */
#include <stdio.h>
#include <unistd. h.>
#include <dirent.h>
#define MAX 255
int main (void) {
   char wd[MAX];
   wd[MAX - 1] = '\0';
   if(getcwd(wd, MAX - 1) == NULL)
      printf ("Konnte Arbeitsverzeichnis nicht"
              " ermitteln\n");
   else
      return execl ("/bin/ls", "ls", "-l", wd, NULL);
}

Das zweite Argument wird in der Prozesstabelle als Prozessname ausgegeben. Würden Sie also z. B. Folgendes angeben:

execl ("/bin/ls", "whoami", "-l", wd, NULL);

würde trotzdem das Arbeitsverzeichnis aufgelistet werden und nicht das Programm whoami, weil es whoami im aktuellen Verzeichnis nicht gibt. Als Prozessname, mit ps bzw. ps x, würden Sie hier allerdings den Namen whoami aufgelistet bekommen.


Rheinwerk Computing

7.10.2 execve()  downtop

Das folgende Listing ruft die Anwendung printenv auf und verändert die Umgebungsvariablen von diesem Prozess.

/* exec2.c */
#include <stdio.h>
#include <unistd. h.>
int main (void) {
    char *args[] = {"printenv", NULL};
    char *env[] =  {
       "SHELL=/bin/bash",
       "LOGNAME=a_username",
       "OSTYPE=L1NuX", NULL
    };
    return execve("/usr/bin/printenv", args, env);
}

Rheinwerk Computing

7.10.3 execv()  downtop

/* exec3.c */
#include <stdio.h>
#include <unistd. h.>
int main (void) {
   char *argumente[4] = { "ls", "-l", "/usr/bin", NULL };    
   return execv ("/bin/ls", argumente);
}

Was hier geschieht, sollte eigentlich ersichtlich sein. Das Beispiel ist ähnlich wie mit execve(), nur dass hier keine Environmentvariablen mitgegeben werden. Stattdessen wird das aktuelle Environment übergeben.


Rheinwerk Computing

7.10.4 execle()  downtop

Diese exec-Funktion ist ähnlich wie execve(), nur dass die Argumente in Listenform getrennt mit NULL gefolgt von den Umgebungsvariablen in Vektorform erfolgen.

/* exec4.c */
#include <stdio.h>
#include <unistd. h.>
int main (void) {
   char *environment[4];
   environment[0] = "SHELL=/bin/csh";
   environment[1] = "LOGNAME=heino";
   environment[2] = "OSTYPE=LiNuX";
   environment[3] = NULL;
   return execle("/usr/bin/ls", "ls", "-d", "/proc",
                 "/", NULL, environment);
}

Rheinwerk Computing

7.10.5 execlp()  downtop

Besonderheit von lp ist, dass das erste Argument zu execlp() nicht ein absoluter Dateiname sein muss, wie dies bei der Listenform von execle() der Fall ist.

/* exec5.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd. h.>
int main (void) {
   return execlp("/bin/ls","ls","-l",getenv("HOME"),NULL);
}

Rheinwerk Computing

7.10.6 execvp()  downtop

Ähnlich wie eben execlp(), nur werden die Argumente als Vektor übergeben.

/* exec6.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd. h.>
int main (void) {
   char *argumente[4];
   argumente[0] = "ls";
   argumente[1] = "-l";
   argumente[2] = getenv("HOME");
   argumente[3] = NULL;
   
   return execvp ("/bin/ls", argumente);
}

Rheinwerk Computing

7.10.7 Kindprozesse mit exec-Aufruf überlagern  toptop

Jetzt will ich Ihnen das Beispiel zeigen, wie Sie einen neuen Prozess erzeugen und diesen mittels eines exec-Aufrufs zu einem vom Elternprozess unabhängigen Prozess machen können. Dazu soll als Beispiel nicht wieder irgendein Kommando gestartet werden, sondern ein von Ihnen selbst geschriebenes Programm. Hierzu verwenden Sie folgendes Beispiel:

/* my_programm.c */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
   int i;
   printf("Progammname : %s\n", argv[0]);   
   for( i=1; i < argc; i++)
      printf("Argumente %d : %s\n", i, argv[i]);   
   return EXIT_SUCCESS;
}

So weit dürfte das Listing nichts Neues mehr für Sie sein. Übersetzen Sie das Beispiel mit:

$ gcc -o my_programm my_programm.c

Jetzt zum Listing, wo die Segmente eines neu erzeugten Prozesses, von dem eben erstellten Programm my_programm, überschrieben werden.

/* exec_child.c */
#include <unistd. h.>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
/* Pfad zum Programm ggf. anpassen */
#define  PROGRAMM "./my_programm"
int main (void) {
   pid_t pid;
   switch (pid = fork ()) {
   case -1:
      perror("fork()");
      return EXIT_FAILURE;
   case 0:
       execlp (PROGRAMM, PROGRAMM, "Hallo", "Welt", NULL);
       printf("Wird niemals mehr erreicht ...\n");
       break;      
   default:
       if (waitpid (pid, NULL, 0) != pid) {
          perror ("waitpid()");
          return EXIT_FAILURE;
       }
   }
   return EXIT_SUCCESS;
}

Passen Sie die Konstante PROGRAMM bitte Ihrem Pfadnamen an. Jetzt können Sie auch dieses Listing übersetzen und starten:

$ gcc -o exec_child exec_child.c
$ ./exec_child
Progammname : /home/tot/my_programm
Argumente 1 : Hallo
Argumente 2 : Welt

Hiermit wurde im Kindprozess der komplette Prozess von dem Programm my_programm überschrieben und als Prozess ohne Wiederkehr ausgeführt. Der Programmname hier ist natürlich nicht verbindlich und entspricht nur dem Namen, der als Prozesseintrag verwendet wird. Würden Sie den exec-Aufruf folgendermaßen realisieren:

execlp (PROGRAMM, "wasistdas", "Hallo", "Welt", NULL);

würde der Programmname "wasistdas" lauten. Sie können diese Art von exec-Aufrufen jetzt gerne mit den anderen exec-Funktion testen und ausprobieren.

 << zurück
  
  Zum Rheinwerk-Shop
Neuauflage: Linux-UNIX-Programmierung
Neuauflage:
Linux-UNIX-
Programmierung

bestellen
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: Linux-Server






 Linux-Server


Zum Rheinwerk-Shop: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Rheinwerk-Shop: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Rheinwerk-Shop: Shell-Programmierung






 Shell-
 Programmierung


Zum Rheinwerk-Shop: Linux Handbuch






 Linux Handbuch


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
Info





Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern