Linux /proc/<pid>/environ
no se actualiza (según tengo entendido, el archivo contiene el entorno inicial del proceso).
¿Cómo puedo leer el entorno actual de un proceso ?
Linux /proc/<pid>/environ
no se actualiza (según tengo entendido, el archivo contiene el entorno inicial del proceso).
¿Cómo puedo leer el entorno actual de un proceso ?
Respuestas:
/proc/$pid/environ
se actualiza si el proceso cambia su propio entorno. Pero muchos programas no se molestan en cambiar su propio entorno, porque es un poco inútil: el entorno de un programa no es visible a través de los canales normales, solo a través de /proc
e ps
, e incluso no todas las variantes de Unix tienen este tipo de característica, por lo que las aplicaciones no dependen en eso.
En lo que respecta al núcleo, el entorno solo aparece como el argumento de la execve
llamada al sistema que inicia el programa. Linux expone un área en la memoria /proc
, y algunos programas actualizan esta área mientras que otros no. En particular, no creo que ningún shell actualice esta área. Como el área tiene un tamaño fijo, sería imposible agregar nuevas variables o cambiar la longitud de un valor.
PATH=foo
en un shell no significa que el shell se va a modificar *envp
. En algunos shells, eso solo actualizó una estructura de datos interna, y es el código de ejecución del programa externo el que se actualiza *envp
. Mira assign_in_env
en variables.c
la fuente de fiesta, por ejemplo.
fork
libc realiza la sys_fork
llamada utilizando el entorno de montón asignado para el proceso secundario.
argv
son más comunes pero ambos existen).
Puede leer el entorno inicial de un proceso desde /proc/<pid>/environ
.
Si un proceso cambia su entorno, entonces para leer el entorno debe tener la tabla de símbolos para el proceso y usar la ptrace
llamada al sistema (por ejemplo, usando gdb
) para leer el entorno de la char **__environ
variable global . No hay otra forma de obtener el valor de ninguna variable de un proceso Linux en ejecución.
Esa es la respuesta. Ahora para algunas notas.
Lo anterior supone que el proceso es compatible con POSIX, lo que significa que el proceso gestiona su entorno utilizando una variable global char **__environ
como se especifica en la Especificación de referencia .
El entorno inicial para un proceso se pasa al proceso en un búfer de longitud fija en la pila del proceso. (El mecanismo habitual que hace esto es linux//fs/exec.c:do_execve_common(...)
.) Dado que el tamaño de la memoria intermedia se calcula a no ser más que el tamaño requerido para el medio ambiente inicial, no se puede agregar nuevas variables sin borrar las variables existentes o rompiendo la pila. Por lo tanto, cualquier esquema razonable para permitir cambios en el entorno de un proceso usaría el montón, donde se puede asignar y liberar memoria en tamaños arbitrarios, que es exactamente lo que GNU libc
( glibc
) hace por usted.
Si el proceso usa glibc
, entonces es compatible con POSIX, y __environ
al declararse en glibc//posix/environ.c
Glibc se inicializa __environ
con un puntero a la memoria que malloc
proviene del montón del proceso, luego copia el entorno inicial de la pila en esta área del montón. Cada vez que el proceso usa la setenv
función, glibc
hace una realloc
para ajustar el tamaño del área que __environ
apunta para acomodar el nuevo valor o variable. (Puede descargar el código fuente de glibc con git clone git://sourceware.org/git/glibc.git glibc
). Para comprender realmente el mecanismo, también deberá leer el código Hurd en hurd//init/init.c:frob_kernel_process()
(git clone git: //git.sv.gnu.org/hurd/hurd.git hurd).
Ahora, si el nuevo proceso solo se fork
edita, sin una posterior exec
sobrescritura de la pila, entonces el argumento y la magia de copia del entorno se realiza en linux//kernel/fork.c:do_fork(...)
, donde la copy_process
rutina llama dup_task_struct
que asigna la pila del nuevo proceso llamando alloc_thread_info_node
, que llama setup_thread_stack
( linux//include/linux/sched.h
) para el nuevo proceso usando alloc_thread_info_node
.
Finalmente, la __environ
convención POSIX es una convención de espacio de usuario . No tiene conexión con nada en el kernel de Linux. Puede escribir un programa de espacio de usuario sin usar glibc
y sin el __environ
global y luego administrar las variables de entorno como desee. Nadie lo arrestará por hacer esto, pero tendrá que escribir sus propias funciones de administración del entorno ( setenv
/ getenv
) y sus propios contenedores sys_exec
y es probable que nadie pueda adivinar dónde coloca los cambios en su entorno.
/proc/[pid]/
parecen tener una codificación extraña (alguien más puede saber qué y por qué). Para mí, simplemente cat environ
imprimiría las variables de entorno en un formato realmente difícil de leer. cat environ | strings
Resuelto esto por mí.
Se actualiza a medida que el proceso adquiere / elimina sus variables de entorno. ¿Tiene una referencia que indique que el environ
archivo no está actualizado para el proceso en su directorio de proceso en / 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>
Lo anterior imprimirá las variables de entorno del proceso en el ps
formato de salida, se requiere procesamiento de texto (análisis / filtrado) para ver las variables de entorno como una lista.
Solaris (no preguntado, pero para referencia lo publicaré aquí):
/usr/ucb/ps -wwwe <pid>
o
pargs -e <pid>
EDITAR: / proc / pid / environment no se actualiza! Estoy corregido. El proceso de verificación está abajo. Sin embargo, los hijos de los que se bifurca el proceso heredan la variable de entorno del proceso y es visible en su respectivo / proc / self / environment. (Use cadenas)
Con en el shell: aquí xargs es un proceso hijo y, por lo tanto, hereda la variable de entorno y también se refleja en su /proc/self/environ
archivo.
[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]$
Verificándolo desde otra sesión, donde el terminal / sesión no es el proceso hijo del shell donde se establece la variable de entorno.
Verificación desde otra terminal / sesión en el mismo host:
terminal1:: Tenga en cuenta que printenv está bifurcado y es un proceso secundario de bash y, por lo tanto, lee su propio archivo de entorno.
[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$
terminal2: en el mismo host: no lo inicie con el mismo shell donde se configuró la variable anterior, inicie el terminal por separado.
[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
en la sesión de un bash (pid xxxx), luego lo hago cat /proc/xxxx/environ | tr \\0 \\n
en la sesión de otro bash y no veo foo
.
gdb
al pid, pero aún no hay referencia allí. El bloque de variables de entorno en la memoria se reasigna cada vez que hay un cambio y no se refleja en el archivo de entorno de su propio proceso en el sistema de archivos proc, pero permite que el proceso secundario lo herede. Eso significa que esto podría ser más fácil de conocer detalles intrínsecos cuando ocurre la bifurcación, cómo el proceso secundario obtiene las variables de entorno copiadas tal como están.
Bueno, lo siguiente no está relacionado con las intenciones reales del autor, pero si realmente quieres "LEER" el /proc/<pid>/environ
, puedes intentar
strings /proc/<pid>/environ
que es mejor que cat
eso
strings
. Mantenlo simple.
xargs --null
.
tr '\0' '\n' < /proc/$$/environ | ...