Vous pouvez lire l'initiale environnement d'un processus de /proc/<pid>/environ
.
Si un processus change son environnement, alors pour lire l'environnement vous devez avoir la table des symboles du processus et utiliser le ptrace
appel système (par exemple en utilisant gdb
) pour lire l'environnement à partir du char **__environ
global variable. Il n'y a pas d'autre moyen d'obtenir la valeur d'une variable à partir d'un processus Linux en cours d'exécution.
C'est la réponse. Maintenant quelques notes.
Ce qui précède suppose que le processus est conforme à POSIX, ce qui signifie que le processus gère son environnement à l'aide d'une variable globale char **__environ
comme spécifié dans la réf.
L'environnement initial d'un processus est transmis au processus dans un tampon de longueur fixe sur la pile du processus. (Le mécanisme habituel qui fait cela est linux//fs/exec.c:do_execve_common(...)
.) Étant donné que la taille du tampon est calculée pour ne pas dépasser la taille requise pour l'environnement initial, vous ne pouvez pas ajouter de nouvelles variables sans effacer les variables existantes ou briser la pile. Ainsi, tout schéma raisonnable permettant des modifications dans l'environnement d'un processus utiliserait le tas, où la mémoire de tailles arbitraires peut être allouée et libérée, ce qui est exactement ce que GNU libc
(glibc
) fait pour vous.
Si le processus utilise glibc
, alors il est compatible POSIX, avec __environ
étant déclaré en glibc//posix/environ.c
Glibc initialise __environ
avec un pointeur vers la mémoire qu'il malloc
s du tas du processus, puis copie l'environnement initial de la pile dans cette zone de tas. Chaque fois que le processus utilise le setenv
fonction, glibc
fait un realloc
pour ajuster la taille de la zone __environ
pointe vers pour accueillir la nouvelle valeur ou variable. (Vous pouvez télécharger le code source de la glibc avec git clone git://sourceware.org/git/glibc.git glibc
). Pour bien comprendre le mécanisme vous devrez également lire le code Hurd en hurd//init/init.c:frob_kernel_process()
(git clone git://git.sv.gnu.org/hurd/hurd.git hurd).
Maintenant, si le nouveau processus est seulement fork
ed, sans un exec
suivant écraser la pile, puis la magie de copie des arguments et de l'environnement se fait dans linux//kernel/fork.c:do_fork(...)
, où le copy_process
appels de routine dup_task_struct
qui alloue la pile du nouveau processus en appelant alloc_thread_info_node
, qui appelle setup_thread_stack
(linux//include/linux/sched.h
) pour le nouveau processus utilisant alloc_thread_info_node
.
Enfin, le POSIX __environ
convention est un espace utilisateur convention. Il n'a aucun lien avec quoi que ce soit dans le noyau Linux. Vous pouvez écrire un programme en espace utilisateur sans utiliser glibc
et sans le __environ
global, puis gérez les variables d'environnement comme bon vous semble. Personne ne vous arrêtera pour cela mais vous devrez écrire vos propres fonctions de gestion de l'environnement (setenv
/getenv
) et vos propres wrappers pour sys_exec
et il est probable que personne ne pourra deviner où vous placez les changements dans votre environnement.
/proc/$pid/environ
se met à jour si le processus modifie son propre environnement. Mais de nombreux programmes ne prennent pas la peine de changer leur propre environnement, car c'est un peu inutile :l'environnement d'un programme n'est pas visible via les canaux normaux, uniquement via /proc
et ps
, et même toutes les variantes d'Unix ne disposent pas de ce type de fonctionnalité, les applications n'en dépendent donc pas.
En ce qui concerne le noyau, l'environnement n'apparaît que comme argument du execve
appel système qui lance le programme. Linux expose une zone en mémoire via /proc
, et certains programmes mettent à jour cette zone tandis que d'autres ne le font pas. En particulier, je ne pense pas qu'un shell mette à jour ce domaine. Comme la zone a une taille fixe, il serait impossible d'ajouter de nouvelles variables ou de modifier la longueur d'une valeur.
Il est mis à jour au fur et à mesure que le processus acquiert/supprime ses variables d'environnement. Avez-vous une référence qui indique le environ
le fichier n'est pas mis à jour pour le processus dans son répertoire de processus sous /proc filesystem ?
xargs --null --max-args=1 echo < /proc/self/environ
ou
xargs --null --max-args=1 echo < /proc/<pid>/environ
ou
ps e -p <pid>
Ce qui précède imprimera les variables d'environnement du processus dans le ps
format de sortie, le traitement de texte (analyse/filtrage) est nécessaire pour voir les variables d'environnement sous forme de liste.
Solaris (pas demandé, mais pour référence, je posterai ici):
/usr/ucb/ps -wwwe <pid>
ou
pargs -e <pid>
MODIF : /proc/pid/environ n'est pas mis à jour ! Je me suis trompé. Le processus de vérification est ci-dessous. Cependant, les enfants à partir desquels le processus est dérivé héritent de la variable d'environnement de processus et celle-ci est visible dans leur fichier /proc/self/environ respectif. (Utilisez des chaînes)
Avec dans le shell :ici xargs est un processus enfant et hérite donc de la variable d'environnement et se reflète également dans son /proc/self/environ
fichier.
[[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]$
Vérification depuis une autre session, où le terminal/session n'est pas le processus enfant du shell où la variable d'environnement est définie.
Vérification depuis un autre terminal/session sur le même hôte :
terminal1 : :Notez que printenv est fork'd et est un processus enfant de bash et donc il lit son propre fichier environ.
[[email protected] t]$ echo $$
2610
[[email protected] t]$ export SPIDEY=NIKHIL
[[email protected] t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[[email protected] t]$
terminal2 : sur le même hôte - ne le lancez pas dans le même shell où la variable ci-dessus a été définie, lancez le terminal séparément.
[[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] ~]$