Gibt es eine Möglichkeit, die Umgebungsvariablen eines anderen Prozesses in Unix zu ändern?


104

Gibt es unter Unix eine Möglichkeit, dass ein Prozess die Umgebungsvariablen eines anderen ändert (vorausgesetzt, sie werden alle von demselben Benutzer ausgeführt)? Eine allgemeine Lösung wäre am besten, aber wenn nicht, was ist mit dem speziellen Fall, in dem einer ein Kind des anderen ist?

Edit: Wie wäre es über gdb?


Das kommt mir mehr als hässlich vor. Was ist das eigentliche Problem, das Sie lösen möchten?
Jens

1
Beispiel: Ich möchte eine Umgebungsvariable definieren, damit jede neue App, die von der Benutzeroberfläche gestartet wird, diese erhält. Ich kenne keine Methode außer der Definition der Variablen in einem der Startskripte und RE-LOGIN. Ich möchte mich jedoch nicht erneut anmelden, sondern nur die Variablen in der aktuellen Sitzung definieren, damit neue Apps sie erhalten - ohne sich von der Benutzeroberfläche abzumelden.
AlikElzin-Kilaka

Antworten:


141

Über gdb:

(gdb) attach process_id

(gdb) call putenv ("env_var_name=env_var_value")

(gdb) detach

Dies ist ein ziemlich böser Hack und sollte natürlich nur im Rahmen eines Debugging-Szenarios durchgeführt werden.


8
Dies scheint also zu implizieren, dass Sie die Umgebung eines Prozesses tatsächlich ändern können, wenn Sie wie GDB an den Prozess anhängen und ihn dann trennen. Es scheint möglich zu sein, ein Programm zu schreiben, das nur dies tut.
Trauer

3
"Es scheint möglich zu sein, ein Programm zu schreiben, das nur dies tut."
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

2
Es funktioniert sogar unter Windows mit Cygwin für Prozesse, die nicht mit Cygwin kompiliert wurden!
Juan Carlos Muñoz

11
Beachten Sie, dass dies nur funktioniert, wenn der Prozess den Wert nach einem vorherigen Abruf nicht dauerhaft zwischengespeichert hat.
Andrew

1
ptrace: Operation not permitted
Gerrit

22

Sie können es wahrscheinlich technisch tun (siehe andere Antworten), aber es hilft Ihnen möglicherweise nicht.

Die meisten Programme erwarten, dass env-Variablen nach dem Start nicht von außen geändert werden können. Daher lesen die meisten wahrscheinlich nur die Variablen, an denen sie beim Start interessiert sind, und initialisieren sie basierend darauf. Ein späteres Ändern macht also keinen Unterschied, da das Programm sie nie wieder liest.

Wenn Sie dies als konkretes Problem angegeben haben, sollten Sie wahrscheinlich einen anderen Ansatz wählen. Wenn es nur aus Neugier war: Schöne Frage :-).


1
Der häufigste Anwendungsfall, bei dem es nützlich wäre, untergeordnete Prozesse dazu zu bringen, die neuen Umgebungsvariablen zu erben, z. B. in einer Desktop-Umgebung, in der neue Terminals die neuen Variablen verwenden sollen.
Hjulle

13

Im Wesentlichen nein. Wenn Sie über ausreichende Berechtigungen (root oder so ungefähr) verfügten und in / dev / kmem (Kernelspeicher) stöberten und Änderungen an der Umgebung des Prozesses vorgenommen haben und wenn der Prozess die Umgebungsvariable danach tatsächlich neu referenziert hat (d. H. Den Prozess) hatte noch nicht eine Kopie der env var genommen und benutzte nicht nur diese Kopie), dann vielleicht, wenn Sie Glück hatten und klug waren und der Wind in die richtige Richtung wehte und die Mondphase vielleicht richtig war, vielleicht Sie könnten etwas erreichen.


2
Ich habe die Antwort nicht bekommen.
AlikElzin-Kilaka

@ Kilaka: Das Schlüsselwort ist das zweite - Nein . Der Rest der Antwort lautet: Wenn Sie über Root-Rechte verfügen oder einen Debugger ausführen, können Sie dies möglicherweise tun, aber für alle praktischen Zwecke lautet die Antwort Nein .
Jonathan Leffler

Sie haben ein Shell-Skript ausgeführt. Sie möchten die Umgebung im übergeordneten Prozess Ihres Shell-Skripts ändern. Das Shell-Skript wird also im übergeordneten Prozess gestartet gdbund mit einem Skript versehen, um die Änderung vorzunehmen. Es funktioniert, ohne den übergeordneten Prozess zum Absturz zu bringen. OK - Sie können es wahrscheinlich tun, aber Sie werden es nicht routinemäßig tun. Aus praktischen Gründen bleibt die Antwort daher Nein . Der Rest der Antwort behandelt die theoretisch möglichen, etwas unpraktisch machbaren Alternativen.
Jonathan Leffler

7

Zitat Jerry Peek:

Sie können einem alten Hund keine neuen Tricks beibringen.

Das einzige, was Sie tun können, ist, die Umgebungsvariable des untergeordneten Prozesses zu ändern, bevor Sie ihn starten: Es wird leider die Kopie der übergeordneten Umgebung abgerufen.

Weitere Informationen finden Sie unter http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm .

Nur ein Kommentar zur Antwort über die Verwendung von / proc. Unter Linux wird / proc unterstützt, aber es funktioniert nicht, Sie können die /proc/${pid}/environDatei nicht ändern , auch wenn Sie root sind: Es ist absolut schreibgeschützt.


Was noch die Frage offen lässt: Wo werden env var-Werte tatsächlich gespeichert? Wird das vom Kernel gemacht? Oder speichert die Shell die Werte und / proc / <pid> / environ ruft sie von dort ab?
Oliver

Dies ist ein Implementierungsdetail, und es könnte eine (separate) gute Frage sein. Ich denke, jeder UNIX verwendet seinen eigenen Weg für den Speicher, aber alle teilen das oben beschriebene Verhalten, das Teil der Spezifikationen ist.
Davide

7

Ich könnte mir den ziemlich erfundenen Weg vorstellen, das zu tun, und es wird nicht für willkürliche Prozesse funktionieren.

Angenommen, Sie schreiben Ihre eigene gemeinsam genutzte Bibliothek, die 'char * getenv' implementiert. Anschließend richten Sie 'LD_PRELOAD' oder 'LD_LIBRARY_PATH' env ein. vars, sodass beide Prozesse mit vorinstallierter gemeinsam genutzter Bibliothek ausgeführt werden.

Auf diese Weise haben Sie im Wesentlichen die Kontrolle über den Code der Funktion 'getenv'. Dann könnten Sie alle möglichen bösen Tricks machen. Ihr 'getenv' könnte eine externe Konfigurationsdatei oder ein SHM-Segment für alternative Werte von env vars konsultieren. Oder Sie können die angeforderten Werte erneut suchen / ersetzen. Oder ...

Ich kann mir keinen einfachen Weg vorstellen, dies für beliebig laufende Prozesse zu tun (selbst wenn Sie root sind), ohne den dynamischen Linker (ld-linux.so) neu zu schreiben.


Dies sollte machbar sein. Sie könnten eine kleine GDBM-Datenbank für die var = value-Paare haben. Ich habe etwas ähnliches für malloc unter stromberg.dnsalias.org/~strombrg/malloc-wrapper
dstromberg

Ich denke, diese Methode erfordert jedoch Voraussicht. Sie müssen auch darauf achten, dass Sie es nicht versehentlich auf zu viele Prozesse anwenden.
Dstromberg

3

Oder veranlassen Sie Ihren Prozess, eine Konfigurationsdatei für den neuen Prozess zu aktualisieren, und dann entweder:

  • Führen Sie ein kill -HUP für den neuen Prozess aus, um die aktualisierte Konfigurationsdatei erneut zu lesen, oder
  • Lassen Sie den Prozess von Zeit zu Zeit die Konfigurationsdatei auf Aktualisierungen überprüfen. Wenn Änderungen gefunden werden, lesen Sie die Konfigurationsdatei erneut.

2

Soweit ich weiß, nicht. Sie versuchen wirklich, von einem Prozess zum anderen zu kommunizieren, was eine der IPC-Methoden erfordert (gemeinsamer Speicher, Semaphoren, Sockets usw.). Nachdem Sie Daten mit einer dieser Methoden empfangen haben, können Sie Umgebungsvariablen festlegen oder andere Aktionen direkter ausführen.


1

Wenn Ihr Unix das Dateisystem / proc unterstützt, ist es trivial, die Umgebung zu LESEN. Sie können die Umgebung, die Befehlszeile und viele andere Attribute jedes Prozesses, den Sie besitzen, auf diese Weise lesen. Ändern ... Nun, ich kann mir einen Weg vorstellen, aber es ist eine schlechte Idee.

Der allgemeinere Fall ... Ich weiß es nicht, aber ich bezweifle, dass es eine tragbare Antwort gibt.

(Bearbeitet: Meine ursprüngliche Antwort ging davon aus, dass das OP die Umgebung LESEN und nicht ändern wollte.)


Hoppla, habe meine Antwort bearbeitet - ich ging davon aus, dass er die Umgebung lesen und nicht ändern wollte.
Mike G.

1
Lass mich nicht hängen. Was ist deine schlechte Idee?
Raldi

Ich glaube, dass Sie unter Linux möglicherweise / proc / <pid> / mem read-write für andere Prozesse öffnen können, die Sie besitzen ... Ich bin mir jedoch nicht sicher. Es wäre definitiv eine schlechte Idee, es zu versuchen und tatsächlich mit der Umwelt zu spielen. Also schlage ich nicht vor, dass Sie es versuchen ...
Mike G.

1

UNIX ist voll von prozessübergreifender Kommunikation. Überprüfen Sie, ob Ihre Zielinstanz welche hat. Dbus wird zum Standard im "Desktop" -IPC.

Ich ändere Umgebungsvariablen innerhalb von Awesome Window Manager mit awesome-client mit einem Dbus "Absender" von Lua-Code.


1

Keine direkte Antwort, aber ... Raymond Chen hatte erst neulich eine [Windows-basierte] Begründung : -

... Obwohl es sicherlich nicht unterstützte Methoden gibt oder Möglichkeiten, die mit Hilfe eines Debuggers funktionieren, wird für den programmgesteuerten Zugriff auf die Befehlszeile eines anderen Prozesses nichts unterstützt, zumindest nichts, was vom Kernel bereitgestellt wird. ...

Dass dies nicht der Fall ist, ist eine Folge des Prinzips, Informationen, die Sie nicht benötigen, nicht im Auge zu behalten. Der Kernel muss nicht die Befehlszeile eines anderen Prozesses abrufen. Es nimmt die an die CreateProcessFunktion übergebene Befehlszeile und kopiert sie in den Adressraum des zu startenden Prozesses an einem Ort, an dem die GetCommandLineFunktion sie abrufen kann. Sobald der Prozess auf seine eigene Befehlszeile zugreifen kann, sind die Verantwortlichkeiten des Kernels erledigt.

Da die Befehlszeile in den Adressraum des Prozesses kopiert wird, schreibt der Prozess möglicherweise sogar in den Speicher, in dem sich die Befehlszeile befindet, und ändert sie. In diesem Fall geht die ursprüngliche Befehlszeile für immer verloren. Die einzige bekannte Kopie wurde überschrieben.

Mit anderen Worten, solche Kernel-Einrichtungen wären

  • schwer umzusetzen
  • möglicherweise ein Sicherheitsrisiko

Der wahrscheinlichste Grund ist jedoch einfach, dass es für eine solche Einrichtung nur begrenzte Anwendungsfälle gibt.


1

Es scheint, dass putenv jetzt nicht funktioniert, aber setenv . Ich habe die akzeptierte Antwort getestet, während ich versucht habe, die Variable in der aktuellen Shell ohne Erfolg festzulegen

$] sudo gdb -p $$
(gdb) call putenv("TEST=1234")
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x0
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=

und die Variante, wie es funktioniert:

$] sudo gdb -p $$
(gdb) call (int) setenv("TEST", "1234", 1)
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x55f19ff5edc0 "1234"
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=1234
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.