Existe-t-il un moyen de modifier les variables d'environnement d'un autre processus sous Unix?

105

Sous Unix, existe-t-il un moyen pour un processus de modifier les variables d'environnement d'un autre (en supposant qu'elles sont toutes exécutées par le même utilisateur)? Une solution générale serait la meilleure, mais sinon, qu'en est-il du cas spécifique où l'un est enfant de l'autre?

Edit: Que diriez-vous via gdb?

Raldi
la source
Cela me semble plus que laid. Quel est le problème réel que vous souhaitez résoudre?
Jens
1
Exemple: je voudrais définir une variable d'environnement afin que chaque nouvelle application - lancée par l'interface utilisateur - l'obtienne. Je ne connais aucune méthode sauf la définition des variables dans l'un des scripts de démarrage et RE-LOGIN. Je voudrais cependant ne pas me reconnecter, mais simplement définir les variables de la session en cours afin que les nouvelles applications l'obtiennent - sans se déconnecter de l'interface utilisateur.
AlikElzin-kilaka

Réponses:

142

Via gdb:

(gdb) attach process_id

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

(gdb) detach

C'est un hack assez méchant et ne devrait être fait que dans le contexte d'un scénario de débogage, bien sûr.

An̲̳̳drew
la source
8
Cela semble donc impliquer que vous pouvez en effet changer l'environnement d'un processus si vous vous attachez au processus comme le fait GDB, puis vous détachez. Il semble qu'il serait possible d'écrire un programme qui ne fasse que cela.
pleurer
3
"Il semble qu'il serait possible d'écrire un programme qui ne fait que cela" En effet .. c'est le cas.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
2
Cela fonctionne même sous Windows avec cygwin, pour les processus qui ne sont pas compilés avec cygwin!
Juan Carlos Muñoz
11
Notez que cela ne fonctionne que si le processus n'a pas mis en cache de manière permanente la valeur après un getenv précédent.
An̲̳̳drew le
1
ptrace: Operation not permitted
gerrit
22

Vous pouvez probablement le faire techniquement (voir les autres réponses), mais cela pourrait ne pas vous aider.

La plupart des programmes s'attendront à ce que les variables d'environnement ne puissent pas être modifiées de l'extérieur après le démarrage, par conséquent, la plupart ne liront probablement que les variables qui les intéressent au démarrage et initialiseront en fonction de cela. Donc, les changer par la suite ne fera aucune différence, puisque le programme ne les relira jamais.

Si vous posez cela comme un problème concret, vous devriez probablement adopter une approche différente. Si c'était juste par curiosité: Belle question :-).

sleske
la source
1
Le cas d'utilisation le plus courant où il serait utile est de faire en sorte que les processus enfants héritent des nouvelles variables d'environnement, par exemple, dans un environnement de bureau où vous souhaitez que les nouveaux terminaux utilisent les nouvelles variables.
Hjulle
13

En gros, non. Si vous aviez des privilèges suffisants (root ou à peu près) et que vous aviez fouillé / dev / kmem (mémoire du noyau), et que vous avez apporté des modifications à l'environnement du processus, et si le processus a effectivement re-référencé la variable d'environnement par la suite (c'est-à-dire, le processus n'avait pas déjà pris une copie du var env et n'utilisait pas seulement cette copie), alors peut-être, si vous étiez chanceux et intelligent, et que le vent soufflait dans la bonne direction, et que la phase de la lune était correcte, peut-être, vous pourriez réaliser quelque chose.

Jonathan Leffler
la source
2
Je n'ai pas eu de réponse.
AlikElzin-kilaka
@kilaka: Le mot clé est le deuxième - Non . Le reste de la réponse dit que si vous avez des privilèges root ou si vous exécutez un débogueur, vous pouvez peut-être le faire, mais à toutes fins pratiques, la réponse est non .
Jonathan Leffler
Vous avez un script shell en cours d'exécution; vous voulez changer l'environnement dans le processus parent de votre script shell ... donc le script shell se lance gdbsur le processus parent et est scripté pour faire le changement, et cela fonctionne sans planter le processus parent. OK - vous pouvez probablement le faire, mais ce n'est pas quelque chose que vous allez faire de façon routinière. Pour des raisons pratiques, la réponse reste donc non . Le reste de la réponse couvre les alternatives off-the-wall théoriquement possibles, quelque peu impraticables.
Jonathan Leffler
7

Citant Jerry Peek:

Vous ne pouvez pas apprendre de nouveaux tours à un vieux chien.

La seule chose que vous pouvez faire est de modifier la variable d'environnement du processus enfant avant démarrer: il obtient la copie de l'environnement parent, désolé.

Voir http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm pour plus de détails.

Juste un commentaire sur la réponse à propos de l'utilisation de / proc. Sous linux / proc est pris en charge mais, cela ne fonctionne pas, vous ne pouvez pas modifier le /proc/${pid}/environfichier, même si vous êtes root: c'est absolument en lecture seule.

Davide
la source
Ce qui laisse encore la question: où sont réellement stockées les valeurs d'env var? Est-ce fait par le noyau? Ou est-ce que le shell stocke les valeurs et / proc / <pid> / environ les obtient à partir de là?
oliver
Ceci est un détail de mise en œuvre, et cela pourrait être une bonne question (distincte). Je pense que chaque UNIX utilise sa propre méthode pour le stockage, mais tous partagent le comportement décrit ci-dessus, qui fait partie des spécifications.
Davide
7

Je pourrais penser à la manière plutôt artificielle de le faire, et cela ne fonctionnera pas pour des processus arbitraires.

Supposons que vous écriviez votre propre bibliothèque partagée qui implémente 'char * getenv'. Ensuite, vous configurez l'environnement 'LD_PRELOAD' ou 'LD_LIBRARY_PATH'. vars afin que vos deux processus soient exécutés avec votre bibliothèque partagée préchargée.

De cette façon, vous aurez essentiellement un contrôle sur le code de la fonction 'getenv'. Ensuite, vous pourriez faire toutes sortes de vilains tours. Votre 'getenv' pourrait consulter le fichier de configuration externe ou le segment SHM pour des valeurs alternatives de vars env. Ou vous pouvez effectuer une recherche / remplacement de regexp sur les valeurs demandées. Ou ...

Je ne peux pas penser à un moyen facile de le faire pour les processus en cours d'exécution arbitraires (même si vous êtes root), à moins de réécrire l'éditeur de liens dynamique (ld-linux.so).

Expert
la source
Cela devrait être faisable. Vous pourriez avoir une petite base de données gdbm pour les paires var = valeur. J'ai quelque chose de similaire pour malloc à stromberg.dnsalias.org/~strombrg/malloc-wrapper
dstromberg
Je pense que cette méthode nécessite une réflexion préalable. Vous devrez également faire attention à ne pas l'appliquer accidentellement à trop de processus.
dstromberg
3

Ou demandez à votre processus de mettre à jour un fichier de configuration pour le nouveau processus, puis soit:

  • effectuer un kill -HUP sur le nouveau processus pour relire le fichier de configuration mis à jour, ou
  • demandez au processus de vérifier le fichier de configuration pour les mises à jour de temps en temps. Si des modifications sont trouvées, relisez le fichier de configuration.
Rob Wells
la source
2

Pas pour autant que je sache. En réalité, vous essayez de communiquer d'un processus à un autre qui fait appel à l'une des méthodes IPC (mémoire partagée, sémaphores, sockets, etc.). Après avoir reçu des données par l'une de ces méthodes, vous pouvez ensuite définir des variables d'environnement ou effectuer d'autres actions plus directement.

Stephen Darlington
la source
1

Si votre unix prend en charge le système de fichiers / proc, alors il est trivial de LIRE l'environnement - vous pouvez lire l'environnement, la ligne de commande et de nombreux autres attributs de tout processus que vous possédez de cette façon. Le changer ... Eh bien, je peux penser à un moyen, mais c'est une mauvaise idée.

Le cas plus général ... Je ne sais pas, mais je doute qu'il y ait une réponse portable.

(Modifié: ma réponse originale supposait que l'OP voulait LIRE l'environnement, pas le changer)

Mike G.
la source
Oups, j'ai édité ma réponse - je supposais qu'il voulait lire l'environnement, pas le changer.
Mike G.
1
Ne me laisse pas pendre. Quelle est votre mauvaise idée?
raldi
Sur Linux, je crois que vous POURREZ être capable d'ouvrir / proc / <pid> / mem en lecture-écriture pour d'autres processus que vous possédez ... Je ne suis pas sûr, cependant. Essayer, et en fait jouer avec l'environnement, serait définitivement une mauvaise idée. Donc je ne vous suggère pas de l'essayer ...
Mike G.
1

UNIX regorge de communications inter-processus. Vérifiez si votre instance cible en possède. Dbus est en train de devenir un standard de l'IPC «de bureau».

Je change les variables d'environnement dans le gestionnaire de fenêtres Awesome en utilisant awesome-client avec un "expéditeur" Dbus de code lua.

DVD
la source
1

Pas une réponse directe mais ... Raymond Chen avait une justification [basée sur Windows] à ce sujet seulement l'autre jour : -

... Bien qu'il y ait certainement des façons non prises en charge de le faire ou des méthodes qui fonctionnent avec l'aide d'un débogueur, il n'y a rien qui soit pris en charge pour l'accès par programme à la ligne de commande d'un autre processus, du moins rien fourni par le noyau. ...

Le fait qu'il n'y en ait pas est une conséquence du principe de ne pas conserver les informations dont vous n'avez pas besoin. Le noyau n'a pas besoin d'obtenir la ligne de commande d'un autre processus. Il prend la ligne de commande passée à la CreateProcessfonction et la copie dans l'espace d'adressage du processus en cours de lancement, à un emplacement où leGetCommandLine fonction peut la récupérer. Une fois que le processus peut accéder à sa propre ligne de commande, les responsabilités du noyau sont terminées.

Puisque la ligne de commande est copiée dans l'espace d'adressage du processus, le processus peut même écrire dans la mémoire qui contient la ligne de commande et la modifier. Si cela se produit, la ligne de commande d'origine est perdue à jamais; la seule copie connue a été écrasée.

En d'autres termes, de telles installations du noyau seraient

  • difficile à mettre en œuvre
  • potentiellement un problème de sécurité

Cependant, la raison la plus probable est simplement qu'il existe des cas d'utilisation limités pour une telle installation.

Ruben Bartelink
la source
1

Il semble que putenv ne fonctionne pas maintenant, mais setenv le fait. Je testais la réponse acceptée en essayant de définir la variable dans le shell actuel sans succès

$] 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=

et la variante comment cela fonctionne:

$] 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
Kakash1hatake
la source