Linux /proc/<pid>/environnon 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>/environnon 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/environsi 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 /proce 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 execvechiamata 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=fooin 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_envdentro variables.cnella fonte bash, per esempio.
forkallora libc effettua la sys_forkchiamata usando l'ambiente allocato heap per il processo figlio.
argvsono 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 ptracechiamata di sistema (ad esempio utilizzando gdb) per leggere l'ambiente dalla char **__environvariabile 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 **__environcome 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' __environessere dichiarato in glibc//posix/environ.cGlibc inizializzato __environcon un puntatore alla memoria che mallocproviene dall'heap del processo, quindi copia l'ambiente iniziale dallo stack in questa area dell'heap. Ogni volta che il processo utilizza la setenvfunzione, glibcesegue una reallocregolazione della dimensione dell'area a cui __environpunta 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 forkeditato, senza una successiva execsovrascrittura dello stack, viene eseguita l'argomento e la magia della copia dell'ambiente linux//kernel/fork.c:do_fork(...), in cui vengono copy_processchiamate le routine dup_task_structche 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 __environconvenzione POSIX è una convenzione spazio utente . Non ha alcuna connessione con nulla nel kernel Linux. Puoi scrivere un programma userspace senza usare glibce senza il __environglobale 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_execed è 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 environstamperei le variabili di ambiente in un formato davvero difficile da leggere. cat environ | stringsrisolto questo per me.
Viene aggiornato come e quando il processo acquisisce / elimina le sue variabili di ambiente. Hai un riferimento che indica che il environfile 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 psformato 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/environfile.
[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=barnella sessione di one bash (pid xxxx), poi faccio cat /proc/xxxx/environ | tr \\0 \\nnella 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 catcosì.
strings. Mantienilo semplice.
xargs --null.
tr '\0' '\n' < /proc/$$/environ | ...