Sie können die Initiale lesen Umgebung eines Prozesses aus /proc/<pid>/environ
.
Wenn sich ein Prozess ändert seine Umgebung, dann müssen Sie, um die Umgebung zu lesen, die Symboltabelle für den Prozess haben und den ptrace
verwenden Systemaufruf (zum Beispiel mit gdb
), um die Umgebung aus dem globalen char **__environ
zu lesen Variable. Es gibt keine andere Möglichkeit, den Wert einer Variablen von einem laufenden Linux-Prozess abzurufen.
Das ist die Antwort. Nun zu einigen Anmerkungen.
Das Obige geht davon aus, dass der Prozess POSIX-kompatibel ist, was bedeutet, dass der Prozess seine Umgebung mit einer globalen Variable char **__environ
verwaltet wie in der Ref Spec angegeben.
Die anfängliche Umgebung für einen Prozess wird dem Prozess in einem Puffer fester Länge auf dem Stack des Prozesses übergeben. (Der übliche Mechanismus, der dies tut, ist linux//fs/exec.c:do_execve_common(...)
.) Da die Größe des Puffers so berechnet wird, dass sie nicht größer ist als die für die anfängliche Umgebung erforderliche Größe, können Sie keine neuen Variablen hinzufügen, ohne vorhandene Variablen zu löschen oder den Stapel zu zerstören. Daher würde jedes vernünftige Schema, um Änderungen in der Umgebung eines Prozesses zuzulassen, den Heap verwenden, wo Speicher in beliebiger Größe zugewiesen und freigegeben werden kann, was genau das ist, was GNU libc
tut (glibc
) für Sie erledigt.
Wenn der Prozess glibc
verwendet , dann ist es POSIX-kompatibel, mit __environ
in glibc//posix/environ.c
deklariert werden Glibc initialisiert __environ
mit einem Zeiger auf den Speicher, der malloc
ist s vom Heap des Prozesses und kopiert dann die anfängliche Umgebung vom Stack in diesen Heap-Bereich. Jedes Mal, wenn der Prozess den setenv
verwendet Funktion, glibc
macht einen realloc
um die Größe des Bereichs anzupassen, der __environ
zeigt auf, um den neuen Wert oder die neue Variable aufzunehmen. (Sie können den Glibc-Quellcode mit git clone git://sourceware.org/git/glibc.git glibc
herunterladen ). Um den Mechanismus wirklich zu verstehen, müssen Sie auch den Hurd-Code in hurd//init/init.c:frob_kernel_process()
lesen (git-Klon git://git.sv.gnu.org/hurd/hurd.git hurd).
Wenn der neue Prozess jetzt nur fork
ist ed, ohne ein nachfolgendes exec
Überschreiben des Stacks, dann wird das Kopieren von Argumenten und Umgebungen in linux//kernel/fork.c:do_fork(...)
durchgeführt , wobei copy_process
Routine ruft dup_task_struct
auf das den Stack des neuen Prozesses allokiert, indem es alloc_thread_info_node
aufruft , die setup_thread_stack
aufruft (linux//include/linux/sched.h
) für den neuen Prozess mit alloc_thread_info_node
.
Schließlich der POSIX __environ
Konvention ist ein Benutzerbereich Konvention. Es hat keine Verbindung mit irgendetwas im Linux-Kernel. Sie können ein Userspace-Programm schreiben, ohne glibc
zu verwenden und ohne __environ
global und verwalten Sie dann die Umgebungsvariablen nach Belieben. Niemand wird Sie dafür verhaften, aber Sie müssen Ihre eigenen Umgebungsverwaltungsfunktionen schreiben (setenv
/getenv
) und eigene Wrapper für sys_exec
und es ist wahrscheinlich, dass niemand erraten kann, wo Sie die Änderungen an Ihrer Umgebung vorgenommen haben.
/proc/$pid/environ
wird aktualisiert, wenn der Prozess seine eigene Umgebung ändert. Aber viele Programme machen sich nicht die Mühe, ihre eigene Umgebung zu ändern, weil es ein bisschen sinnlos ist:Die Umgebung eines Programms ist nicht durch normale Kanäle sichtbar, nur durch /proc
und ps
, und sogar nicht jede Unix-Variante hat diese Art von Feature, also verlassen sich Anwendungen nicht darauf.
Was den Kernel betrifft, erscheint die Umgebung nur als Argument von execve
Systemaufruf, der das Programm startet. Linux legt einen Bereich im Speicher durch /proc
offen , und einige Programme aktualisieren diesen Bereich, während andere dies nicht tun. Insbesondere glaube ich nicht, dass eine Shell diesen Bereich aktualisiert. Da der Bereich eine feste Größe hat, wäre es unmöglich, neue Variablen hinzuzufügen oder die Länge eines Werts zu ändern.
Sie wird aktualisiert, sobald der Prozess seine Umgebungsvariablen erfasst/löscht. Haben Sie eine Referenz, die den environ
angibt Datei wird für den Prozess in ihrem Prozessverzeichnis unter /proc filesystem nicht aktualisiert?
xargs --null --max-args=1 echo < /proc/self/environ
oder
xargs --null --max-args=1 echo < /proc/<pid>/environ
oder
ps e -p <pid>
Das obige gibt die Umgebungsvariablen des Prozesses in ps
aus Ausgabeformat, Textverarbeitung (Parsen/Filtern) ist erforderlich, um die Umgebungsvariablen als Liste anzuzeigen.
Solaris (nicht gefragt, aber als Referenz werde ich hier posten):
/usr/ucb/ps -wwwe <pid>
oder
pargs -e <pid>
BEARBEITEN: /proc/pid/environ wird nicht aktualisiert! Ich stehe korrigiert. Der Überprüfungsprozess ist unten. Die untergeordneten Elemente, von denen der Prozess geforkt wird, erben jedoch die Prozessumgebungsvariable und sie ist in ihrer jeweiligen /proc/self/environ-Datei sichtbar. (Strings verwenden)
Mit in der Shell:Hier ist xargs ein untergeordneter Prozess und erbt daher die Umgebungsvariable und spiegelt sich auch in ihrem /proc/self/environ
wider Datei.
[[email protected] t]$ printenv | grep MASK
[[email protected] t]$ export MASK=NIKHIL
[[email protected] t]$ printenv | grep MASK
MASK=NIKHIL
[[email protected] t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
MASK=NIKHIL
[[email protected] t]$ unset MASK
[[email protected] t]$ printenv | grep MASK
[[email protected] t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
[[email protected] t]$
Überprüfung von einer anderen Sitzung aus, wo das Terminal/die Sitzung nicht der untergeordnete Prozess der Shell ist, in der die Umgebungsvariable gesetzt ist.
Überprüfung von einem anderen Terminal/einer anderen Sitzung auf demselben Host:
terminal1: :Beachten Sie, dass printenv gegabelt wird und ein untergeordneter Prozess von bash ist und daher seine eigene Umgebungsdatei liest.
[[email protected] t]$ echo $$
2610
[[email protected] t]$ export SPIDEY=NIKHIL
[[email protected] t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[[email protected] t]$
terminal2: auf demselben Host – starten Sie es nicht in derselben Shell, in der die obige Variable gesetzt wurde, starten Sie das Terminal separat.
[[email protected] ~]$ echo $$
4436
[[email protected] ~]$ xargs --null --max-args=1 echo < /proc/self/environ | grep -i spidey
[[email protected] ~]$ strings -f /proc/2610/environ | grep -i spidey
[[email protected] ~]$ xargs --null --max-args=1 echo < /proc/2610/environ | grep -i spidey
[[email protected] ~]$