GNU/Linux >> Linux Esercitazione >  >> Linux

Come leggere le variabili d'ambiente di un processo

Puoi leggere l'iniziale ambiente di un processo da /proc/<pid>/environ .

Se un processo cambia suo ambiente, quindi per leggere l'ambiente devi avere la tabella dei simboli per il processo e usare il ptrace chiamata di sistema (ad esempio utilizzando gdb ) per leggere l'ambiente dal char **__environ globale variabile. Non c'è altro modo per ottenere il valore di qualsiasi variabile da un processo Linux in esecuzione.

Questa è la risposta. Ora per alcune note.

Quanto sopra presuppone che il processo sia conforme a POSIX, il che significa che il processo gestisce il proprio ambiente utilizzando una variabile globale char **__environ come specificato nelle specifiche di riferimento.

L'ambiente iniziale per un processo viene passato al processo in un buffer di lunghezza fissa nello stack del processo. (Il solito meccanismo che fa questo è linux//fs/exec.c:do_execve_common(...) .) Poiché la dimensione del buffer è calcolata per non essere superiore alla dimensione richiesta per l'ambiente iniziale, non è possibile aggiungere nuove variabili senza cancellare le variabili esistenti o distruggere lo stack. Quindi, qualsiasi schema ragionevole per consentire cambiamenti nell'ambiente di un processo userebbe l'heap, dove la memoria di dimensioni arbitrarie può essere allocata e liberata, che è esattamente ciò che GNU libc (glibc ) fa per te.

Se il processo utilizza glibc , allora è conforme a POSIX, con __environ dichiarato in glibc//posix/environ.c Glibc inizializza __environ con un puntatore alla memoria che è malloc s dall'heap del processo, quindi copia l'ambiente iniziale dallo stack in questa area dell'heap. Ogni volta che il processo utilizza il setenv funzione, glibc fa un realloc per regolare la dimensione dell'area che __environ punta a per accogliere il nuovo valore o variabile. (Puoi scaricare il codice sorgente di glibc con git clone git://sourceware.org/git/glibc.git glibc ). Per capire veramente il meccanismo dovrai anche leggere il codice Hurd in hurd//init/init.c:frob_kernel_process() (git clone git://git.sv.gnu.org/hurd/hurd.git hurd).

Ora se il nuovo processo è solo fork ed, senza un successivo exec sovrascrivendo lo stack, allora la magia di copia dell'argomento e dell'ambiente viene eseguita in linux//kernel/fork.c:do_fork(...) , dove copy_process chiamate di routine dup_task_struct che alloca lo stack del nuovo processo chiamando alloc_thread_info_node , che chiama setup_thread_stack (linux//include/linux/sched.h ) per il nuovo processo utilizzando alloc_thread_info_node .

Infine, il POSIX __environ convenzione è uno spazio utente convenzione. Non ha alcuna connessione con nulla nel kernel Linux. Puoi scrivere un programma in spazio utente senza usare glibc e senza __environ global e poi gestisci le variabili d'ambiente come preferisci. Nessuno ti arresterà per averlo fatto, ma dovrai scrivere le tue funzioni di gestione dell'ambiente (setenv /getenv ) e i tuoi wrapper per sys_exec ed è probabile che nessuno sarà in grado di indovinare dove hai apportato le modifiche al tuo ambiente.


/proc/$pid/environ si aggiorna se il processo cambia il proprio ambiente. Ma molti programmi non si preoccupano di cambiare il proprio ambiente, perché è un po' inutile:l'ambiente di un programma non è visibile attraverso i normali canali, solo attraverso /proc e ps e anche non tutte le varianti unix hanno questo tipo di funzionalità, quindi le applicazioni non fanno affidamento su di essa.

Per quanto riguarda il kernel, l'ambiente appare solo come argomento del execve chiamata di sistema che avvia il programma. Linux espone un'area in memoria tramite /proc e alcuni programmi aggiornano quest'area mentre altri no. In particolare, non credo che nessuna shell aggiorni quest'area. Poiché l'area ha una dimensione fissa, sarebbe impossibile aggiungere nuove variabili o modificare la lunghezza di un valore.


Viene aggiornato man mano che il processo acquisisce/cancella le sue variabili d'ambiente. Hai un riferimento che indica il environ file non è aggiornato per il processo nella sua directory di processo sotto /proc filesystem?

xargs --null --max-args=1 echo < /proc/self/environ

o

xargs --null --max-args=1 echo < /proc/<pid>/environ

o

ps e -p <pid>

Quanto sopra stamperà le variabili d'ambiente del processo nel ps formato di output, è necessaria l'elaborazione del testo (analisi/filtro) per vedere le variabili d'ambiente come un elenco.

Solaris (non richiesto, ma per riferimento posterò qui):

/usr/ucb/ps -wwwe <pid>

o

pargs -e <pid> 

MODIFICA: /proc/pid/environ non è aggiornato! mi correggo. Il processo di verifica è riportato di seguito. Tuttavia, i figli da cui viene eseguito il fork del processo ereditano la variabile di ambiente del processo ed è visibile nel rispettivo file /proc/self/environ. (Usa stringhe)

With nella shell:qui xargs è un processo figlio e quindi eredita la variabile d'ambiente e si riflette anche nel suo /proc/self/environ file.

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

Controllandolo da un'altra sessione, dove il terminale/sessione non è il processo figlio della shell in cui è impostata la variabile d'ambiente.

Verifica da un altro terminale/sessione sullo stesso host:

terminale1: :Nota che printenv è fork'd ed è un processo figlio di bash e quindi legge il proprio file environ.

[[email protected] t]$ echo $$
2610
[[email protected] t]$ export SPIDEY=NIKHIL
[[email protected] t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[[email protected] t]$ 

terminale2: sullo stesso host:non avviarlo nella stessa shell in cui è stata impostata la variabile precedente, avvia il terminale separatamente.

[[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] ~]$ 

Linux
  1. Come impostare/creare variabili di ambiente e shell in Linux

  2. Come impostare, elencare e rimuovere variabili d'ambiente in Linux

  3. Come posso fare in modo che R legga le mie variabili ambientali?

  4. Come impostare le variabili di ambiente Linux con Ansible

  5. Come stampare variabili d'ambiente apparentemente nascoste?

Come impostare la variabile d'ambiente in Windows

Come impostare le variabili d'ambiente in MacOS

Come impostare ed elencare le variabili di ambiente in Linux

Come impostare ed elencare variabili ambientali in Linux

Come impostare e annullare l'impostazione delle variabili di ambiente su Linux

Variabili d'ambiente Linux