Linux /proc/<pid>/environ
non si aggiorna (a quanto ho capito, il file contiene l'ambiente iniziale del processo).
Come posso leggere l' ambiente corrente di un processo ?
Linux /proc/<pid>/environ
non si aggiorna (a quanto ho capito, il file contiene l'ambiente iniziale del processo).
Come posso leggere l' ambiente corrente di un processo ?
Risposte:
/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 canali normali, solo attraverso /proc
e ps
, e persino non tutte le varianti unix hanno questo tipo di funzionalità, quindi le applicazioni non fanno affidamento su di esso.
Per quanto riguarda il kernel, l'ambiente appare solo come argomento della execve
chiamata di sistema che avvia il programma. Linux espone un'area in memoria /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.
PATH=foo
in una shell non significa che la shell cambierà *envp
. In alcune shell, questo ha aggiornato solo una struttura di dati interna ed è il codice di esecuzione del programma esterno che aggiorna *envp
. Guarda assign_in_env
dentro variables.c
nella fonte bash, per esempio.
fork
allora libc effettua la sys_fork
chiamata usando l'ambiente allocato heap per il processo figlio.
argv
sono più comuni ma entrambi esistono).
È possibile leggere l' ambiente iniziale di un processo da /proc/<pid>/environ
.
Se un processo cambia il suo ambiente, per poter leggere l'ambiente è necessario disporre della tabella dei simboli per il processo e utilizzare la ptrace
chiamata di sistema (ad esempio utilizzando gdb
) per leggere l'ambiente dalla char **__environ
variabile globale . Non esiste 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 è conforme a POSIX, il che significa che il processo gestisce suo ambiente utilizzando una variabile globale char **__environ
come specificato nel Rif Spec .
L'ambiente iniziale per un processo viene passato al processo in un buffer a lunghezza fissa nello stack del processo. (Il solito meccanismo che lo fa è linux//fs/exec.c:do_execve_common(...)
.) Poiché la dimensione del buffer non è 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 in 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 l' __environ
essere dichiarato in glibc//posix/environ.c
Glibc inizializzato __environ
con un puntatore alla memoria che malloc
proviene dall'heap del processo, quindi copia l'ambiente iniziale dallo stack in questa area dell'heap. Ogni volta che il processo utilizza la setenv
funzione, glibc
esegue una realloc
regolazione della dimensione dell'area a cui __environ
punta 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 viene solo fork
editato, senza una successiva exec
sovrascrittura dello stack, viene eseguita l'argomento e la magia della copia dell'ambiente linux//kernel/fork.c:do_fork(...)
, in cui vengono copy_process
chiamate le routine dup_task_struct
che allocano 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, la __environ
convenzione POSIX è una convenzione spazio utente . Non ha alcuna connessione con nulla nel kernel Linux. Puoi scrivere un programma userspace senza usare glibc
e senza il __environ
globale e quindi gestire le variabili d'ambiente come preferisci. Nessuno ti arresterà per farlo, 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 apporti le modifiche al tuo ambiente.
/proc/[pid]/
sembrano avere una strana codifica (qualcun altro potrebbe sapere cosa e perché). Per me, semplicemente cat environ
stamperei le variabili di ambiente in un formato davvero difficile da leggere. cat environ | strings
risolto questo per me.
Viene aggiornato come e quando il processo acquisisce / elimina le sue variabili di ambiente. Hai un riferimento che indica che il environ
file non è aggiornato per il processo nella sua directory di processo nel filesystem / proc?
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 di ambiente del processo nel ps
formato di output, l'elaborazione del testo (analisi / filtro) è necessaria per visualizzare le variabili di ambiente come un elenco.
Solaris (non richiesto, ma per riferimento posterò qui):
/usr/ucb/ps -wwwe <pid>
o
pargs -e <pid>
EDIT: / proc / pid / environment non è aggiornato! Sono corretto. Il processo di verifica è di seguito. Tuttavia, i figli da cui viene eseguito il fork ereditano la variabile di ambiente di processo ed è visibile nel rispettivo file / proc / self / environment. (Usa le stringhe)
Con nella shell: qui xargs è un processo figlio e quindi eredita la variabile di ambiente e si riflette anche nel suo /proc/self/environ
file.
[centos@centos t]$ printenv | grep MASK
[centos@centos t]$ export MASK=NIKHIL
[centos@centos t]$ printenv | grep MASK
MASK=NIKHIL
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
MASK=NIKHIL
[centos@centos t]$ unset MASK
[centos@centos t]$ printenv | grep MASK
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
[centos@centos t]$
Controllandolo da un'altra sessione, in cui il terminale / sessione non è il processo figlio della shell in cui è impostata la variabile di ambiente.
Verifica da un altro terminale / sessione sullo stesso host:
terminal1:: Notare che printenv è fork ed è un processo figlio di bash e quindi legge il proprio file environment.
[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$
terminal2: sullo stesso host - non avviarlo con la stessa shell in cui è stata impostata la variabile sopra, avviare il terminale separatamente.
[centos@centos ~]$ echo $$
4436
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/self/environ | grep -i spidey
[centos@centos ~]$ strings -f /proc/2610/environ | grep -i spidey
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/2610/environ | grep -i spidey
[centos@centos ~]$
export foo=bar
nella sessione di one bash (pid xxxx), poi faccio cat /proc/xxxx/environ | tr \\0 \\n
nella sessione di altri bash e non vedo foo
.
gdb
al pid, ma ancora nessun riferimento lì. Il blocco delle variabili di ambiente nella memoria viene riallocato ogni volta che si verifica una modifica e non si riflette nel file di ambiente del proprio processo nel filesystem proc, ma consente comunque di essere ereditato dal processo figlio. Ciò significa che potrebbe essere più semplice conoscere i dettagli intrinseci quando si verifica il fork, in che modo il processo figlio ottiene le variabili di ambiente così come sono.
Bene, quanto segue non è correlato alle reali intenzioni dell'autore, ma se vuoi davvero "LEGGERE" il /proc/<pid>/environ
, puoi provare
strings /proc/<pid>/environ
che è meglio di cat
così.
strings
. Mantienilo semplice.
xargs --null
.
tr '\0' '\n' < /proc/$$/environ | ...