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.5 Umgebungsvariablen eines Prozesses  downtop

Jeder Prozess besitzt seine eigene Umgebung mit vordefinierten Variablen. Diese Variablen werden meistens bei der Anmeldung der Shell vorbelegt. Die bash durchläuft dabei beim Start (Startup-Routine) die Dateien /etc/bash.bashrc, /etc/bash.bashrc.local, vielleicht auch welche aus /etc/profile.d/, ~/.bash_profile und ~/.bash_rc (~ = Home-Verzeichnis). Einige dieser Variablen können vom Anwender geändert und den eigenen Bedürfnissen angepasst werden. Auf andere wiederum können Sie nur lesend zugreifen. Einen Überblick zu den gesetzten Variablen Ihrer aktuellen Umgebung (z. B. der Shell) können Sie sich mit den Kommandos env oder printenv auflisten lassen. In dieser Umgebung steht beschrieben, wo das aktuelle Heimverzeichnis liegt (HOME), der Terminaltyp (TERM), der Suchpfad für Kommandos (PATH), welche Shell verwendet wird (SHELL), den Loginnamen des aktuellen Benutzers (LOGNAME) und noch eine Menge mehr. Die Bedeutung der einzelnen Umgebungsvariablen hier aufzuzählen wäre etwas zu umfangreich und hängt zum Teil auch vom System und Anwender ab. Für mehr Informationen sollten Sie unter info env nachblättern.

Wollen Sie jetzt die Umgebungsvariablen Ihres neu erstellten Prozesses ausgeben lassen, dann können Sie dazu einen Zeiger auf die Umgebungsvariablenliste namens environ verwenden. Dabei handelt es sich um eine globale Variable, die wie die Argumentenliste argv der main-Funktion verwendet werden kann. In dieser Liste befinden sich Strings, die mit \0 abgeschlossen sind. Hierzu das Beispiel, das die gesamte Umgebung des eigenen Prozesses ausgibt:

/* environ1.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd. h.>
/* Wird in keiner (modernen) Headerdatei portabel */
/* definiert, daher manuelle Einbindung           */
extern char **environ;
int main(void) {
   int i=0;
   while(environ[i]!= NULL) {
      printf("%s\n", environ[i++]);
   }
  return EXIT_SUCCESS;
}

Oder alternativ:

/* environ2.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd. h.>
int main(int argc, char **argv, char **envp) {
    while(*envp != NULL) {
        printf("%s\n", *envp++);
    }
    return EXIT_SUCCESS;
}

Und so kann es aussehen:

$ gcc -o environ environ.c
$ ./environ
LESSKEY=/etc/lesskey.bin
NNTPSERVER=news
INFODIR=/usr/local/info:/usr/share/info:/usr/info
MANPATH=/usr/local/man:/usr/share/man:/usr/X11R6/ 
KDE_MULTIHEAD=false
HOSTNAME=linux 
XKEYSYMDB=/usr/X11R6/lib/X11/XKeysymDB
HOST=linux
TERM=xterm
SHELL=/bin/bash 
...

Rheinwerk Computing

7.5.1 Einzelne Umgebungsvariablen abfragen  downtop

Wollen Sie einzelne Umgebungsvariablen der Liste abfragen, dann können Sie die Funktion getenv() verwenden. getenv() wird auch recht häufig in der CGI-Programmierung mit C verwendet (mehr dazu finden Sie im Buch »C von A bis Z« im Handel oder auf der Buch-CD).

#include <stdlib.h>
char *getenv(const char *name);

Diese Funktion gibt einen Zeiger auf den zu name gehörenden Wert zurück oder im Falle, dass es die Variable nicht gibt, NULL. Hierzu ein Beispiel, wie Sie einzelne Umgebungsvariablen einer Anwendung erfragen können:

/* get_env.c */
#include <stdio.h>
#include <stdlib.h>
#define MAX 255
 int main (void) {
  char name[MAX];
  printf("Umgebungsvariable: ");
  scanf("%254s",name);  
  printf("Wert      : %s\n", getenv(name));
  return EXIT_SUCCESS;
}

Das Programm bei der Ausführung:

$ gcc -o get_env get_env.c
$ ./getenv
Umgebungsvariable: LOGNAME
Wert             : tot
$ ./get_env
Umgebungsvariable: HOME
Wert             : /home/tot
$ ./get_env
Umgebungsvariable: SHELL
Wert             : /bin/bash
$ ./get_env
Umgebungsvariable: Irgendwas
Wert             : (null)

Rheinwerk Computing

7.5.2 Umgebungsvariable verändern oder hinzufügen – putenv() und setenv()  downtop

Wollen Sie eine neue Umgebungsvariable für den laufenden Prozess setzen oder eine bereits existierende verändern, können Sie die Funktionen putenv() und setenv() dazu verwenden. Zuerst die Syntax von putenv():

#include <stdlib.h>
int putenv( char *name_wert );

Mit putenv() wird der String name_wert, der die Form name=wert haben muss, in die Liste der Umgebungsvariablen eingetragen. Ein bereits existierender String name_wert wird zuvor noch aus der Liste entfernt und durch den neuen ersetzt. Bei Erfolg gibt diese Funktion 0, ansonsten ungleich 0 zurück. Als Beispiel wird unsere Anwendung von zuvor erweitert. Eine bereits existierende Umgebungsvariable in der Liste wird durch den neuen Wert ersetzt, und eine neue Umgebungsvariable wird neu in die Liste hinzugefügt.

/* put_env.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
 static int put_env( const char *name, const char *wert) {
   static char buffer[MAX+MAX];
   strcpy( buffer, name );
   strcat( buffer, "=");
   strcat( buffer, wert);
   return putenv( strdup(buffer) );
}   
int main(void) {
  char name[MAX], neu_wert[MAX];
  printf("Umgebungsvariable: ");
  scanf("%254s",name);
  printf("Wert          : %s\n", getenv(name));   
   
  printf("Wert ändern/setzen durch : ");
  scanf("%254s",neu_wert);
  if( put_env( name, neu_wert ) != 0 )
     printf("Konnte neuen Wert nicht setzen\n");
   
  printf("Neuer Wert (%s): %s\n", name, getenv(name));
  return EXIT_SUCCESS;
}

Das Programm bei der Ausführung:

$ gcc -o put_env put_env.c
$ ./put_env
Umgebungsvariable: HOME
Wert             : /home/tot
Wert ändern/setzen durch : /home/tot/test_dir
Neuer Wert (HOME): /home/tot/test_dir
$ echo $HOME
/home/tot
$ ./put_env
Umgebungsvariable: NEUE_VAR
Wert             : Unbekannt
Wert ändern/setzen durch : mein_wert
Neuer Wert (NEUE_VAR)    : mein_wert

Mit der Ausgabe von echo $HOME wurde nur demonstriert, dass sich die Veränderung der aktuellen Umgebungsvariablen allein auf den aktuell laufenden Prozess (und Unterprozesse) bezieht. In diesem Beispiel wäre dies der Prozess put_env. Bei Beendigung und erneutem Starten des Prozesses sind wieder die »alten« Umgebungsvariablen gesetzt.

Sicherlich fällt Ihnen in diesem Beispiel die Verwendung von strdup() in der Funktion put_env() auf. Dass dies nötig ist, liegt an der Eigenheit von putenv(), wie mir mein Fachgutachter mit folgendem Listing bewiesen hat:

/* put_env2.c */
#include <stdio.h>
#include <stdlib.h>
int main (void) {
   char buf[] = "key=value";
   putenv(buf);
   printf("buf=%p, getenv=%p (%s)\n",
      buf, getenv("key"), getenv("key"));
   printf("heap  test: %p\n", malloc(1));
   printf("stack test: %p\n", &buf);
   return EXIT_SUCCESS;
}

Das Listing wurde gleich mit mehreren C-Bibliotheken auf verschiedenen Betriebssystemen getestet.


Tabelle 7.4    Ergebnis von putenv() mit mehreren Bibliotheken

  glibc 2.3.3 msvcrt.dll btcpp/tiny
buf 0xbfffeff0 0x73fdf0 0xffec
getenv 0xbfffeff4 0x8608d4 0x1c60
heap test 0x804a158 0x8609c0 0x1c6a
stack test 0xbfffeff0 0x73fdf0 0xffec

Es zeigt ganz grob, welche Werte sich wo befinden (Heap/Stack), und man kann eindeutig erkennen, dass mit der GNU libc keine eigenständige Kopie gemacht wird.

Würden Sie daher dort kein strdup() (oder auch eine eigenständige Kopieoperation) verwenden, könnten die Folgen fatal sein, wenn Sie mit einer Funktion fertig wären! Denn putenv() nimmt einfach den Parameter und fügt ihn hinzu. Diesen Flaw gibt es bei setenv() (in der GNU libc) nicht. Also am besten: putenv(strdup(puffer)) oder setenv() verwenden.

Den Aufwand mit der Funktion put_env() eben im Listing hätten Sie sich auch sparen können, indem Sie gleich auf die Funktion setenv() zurückgreifen (BSD4.3):

#include <stdlib.h>
int setenv (const char *name,
            const char *wert,
            int schreibschutz);

Damit setzen Sie die Umgebungsvariable name mit dem wert. Das Zusammenbasteln der beiden Strings und dem '='-Zeichen dazwischen entfällt somit. Ob ein existierender Name überschrieben werden soll, können Sie mit schreibschutz festlegen. Setzen Sie den Wert auf 1, wird eine bereits existierende Umgebungsvariable durch die neue ersetzt. Geben Sie schreibschutz hingegen den Wert 0, bleibt die alte Definition in der Liste erhalten. Der Rückgabewert der Funktion ist auch hier bei einem Fehler ungleich 0 und wenn alles glatt verlief 0. Hierzu setenv() im Einsatz:

/* set_env.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
/* Vorhandene Variable nicht überschreiben */
#define PROTECT_ON  0
/* überschreiben ... */  
#define PROTECT_OFF 1
int main (void) {
  char name[MAX], neu_wert[MAX];
  printf("Umgebungsvariable: ");
  scanf("%254s",name);
  printf("Wert       : %s\n", getenv(name));   
   
  printf("Wert ändern/setzen durch : ");
  scanf("%254s",neu_wert);
  if( setenv( name, neu_wert, PROTECT_OFF ) != 0 )
     printf("Konnte neuen Wert nicht setzen\n");
   
  printf("Neuer Wert (%s) : %s\n", name, getenv(name));
  return EXIT_SUCCESS;
}

Die Ausführung des Programms entspricht exakt der im Beispiel zuvor (put_env.c).


Rheinwerk Computing

7.5.3 Löschen von Umgebungsvariablen – unsetenv() und clearenv()  toptop

Wollen Sie einen Namen aus der Liste der Umgebungsvariablen entfernen, können Sie unsetenv() verwenden.

#include <stdlib.h>
void unsetenv( const char *name );

Ein nicht existierendes name wird nicht als Fehler bewertet und ignoriert. Ein Beispiel zu unsetenv():

/* unset_env.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
int main (void) {
  char name[MAX];
  printf("Umgebungsvariable: ");
  scanf("%254s",name);
  printf("Wert     : %s\n", getenv(name));
  unsetenv(name);   
  printf("Neuer Wert (%s) : %s\n", name, getenv(name));
  return EXIT_SUCCESS;
}

Das Programm bei der Ausführung:

$ gcc -o unset_env unset_env.c
$ ./unsetenv
Umgebungsvariable: HOME
Wert             : /home/tot
Neuer Wert (HOME): (null)

Wollen Sie die komplette Liste mit den Umgebungsvariablen eines Prozesses löschen, dann ist die Funktion clearenv() dafür gedacht. Nachträglich können Sie später wieder neue Umgebungsvariablen mit den Funktionen putenv() und setenv() eintragen. Hier die Syntax zu clearenv():

#include <stdlib.h>
int clearenv( void );

Bei Erfolg gibt auch diese Funktion 0, ansonsten bei einem Fehler ungleich 0 zurück, wobei fraglich ist, was denn ein möglicher Fehler sein könnte, da Glibc in jedem Falle 0 zurückgibt.


Hinweis   Früher (und heute zum Teil immer noch) wurden die Umgebungsvariablen zur Interprozesskommunikation zwischen den Prozessen derselben Familie verwendet. Da ja ein mit fork() neu erzeugter Prozess dieselben Umgebungsvariablen von seinem Elternprozess erbt, ist dies ohne weiteres möglich.


 << 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