Cómo leer las variables de entorno de un proceso


Respuestas:


20

/proc/$pid/environse 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 /proce 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 execvellamada 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.


por lo tanto, efectivamente no hay forma de acceder al proceso '* envp (matriz de punteros a la configuración del entorno). @Gilles, ¿puede mostrar si es posible adjuntar el depurador y leer la matriz de punteros a la configuración del entorno?
Nikhil Mulley

2
@Nikhil Claro, lo es. Pero el hecho de que escriba PATH=fooen 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_enven variables.cla fuente de fiesta, por ejemplo.
Gilles 'SO- deja de ser malvado'

99
@Gilles: esta respuesta es, en el mejor de los casos, engañosa (-1). El entorno en / proc / $$ / environment se lee desde la pila del proceso. Ver fs / proc / base.c. Este es el entorno inicial. Nunca se actualiza y, de hecho, no se puede. El entorno que utiliza libc setenv se asigna en el montón y se inicializa con el contenido del entorno en la pila. Si el proceso llama a libc, forklibc realiza la sys_forkllamada utilizando el entorno de montón asignado para el proceso secundario.
Jonathan Ben-Avraham

77
@ JonathanBen-Avraham Tienes razón en que el entorno inicial no se actualiza en ningún shell. Sin embargo, esa área no se lee solo en Linux, he encontrado programas que la usan para informar su estado (los informes de estado argvson más comunes pero ambos existen).
Gilles 'SO- deja de ser malvado'

39

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 ptracellamada al sistema (por ejemplo, usando gdb) para leer el entorno de la char **__environvariable 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 **__environcomo 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 __environal declararse en glibc//posix/environ.cGlibc se inicializa __environcon un puntero a la memoria que mallocproviene 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 setenvfunción, glibchace una reallocpara ajustar el tamaño del área que __environapunta 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 forkedita, sin una posterior execsobrescritura 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_processrutina llama dup_task_structque 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 __environconvenció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 glibcy sin el __environglobal 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_execy es probable que nadie pueda adivinar dónde coloca los cambios en su entorno.


Muchos de los archivos /proc/[pid]/parecen tener una codificación extraña (alguien más puede saber qué y por qué). Para mí, simplemente cat environimprimiría las variables de entorno en un formato realmente difícil de leer. cat environ | stringsResuelto esto por mí.
retrohacker

@retrohacker Esto ofrece una solución más robusta: askubuntu.com/questions/978711/…
Frank Kusters

20

Se actualiza a medida que el proceso adquiere / elimina sus variables de entorno. ¿Tiene una referencia que indique que el environarchivo 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 psformato 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/environarchivo.

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

1
Lo hago export foo=baren la sesión de un bash (pid xxxx), luego lo hago cat /proc/xxxx/environ | tr \\0 \\nen la sesión de otro bash y no veo foo.

Actualicé la respuesta anterior con un ejemplo que verifica el mismo proceso dentro de Shell.
Nikhil Mulley

Estás en lo correcto. Estoy corregido. Gracias. Ahora tengo que ir a leer mis manuales para verificar las variables de entorno de un proceso diferente en el grupo de procesos del usuario.
Nikhil Mulley

1
Una cosa más: intenté verificar el entorno adjunto 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.
Nikhil Mulley

Espero que @Gilles arroje algo de su antorcha sobre esto ... :-)
Nikhil Mulley

7

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 cateso


1
+1 para strings. Mantenlo simple.
Ed Randall el

De acuerdo @EdRandall, esto se siente como el enfoque más fácil vs xargs --null.
Según Lundberg el

El "archivo" es nulo terminado, reemplace los nulos con herramientas de nueva línea y las normales funcionan de nuevo (con las advertencias habituales), por ejemplo:tr '\0' '\n' < /proc/$$/environ | ...
Thor

Siempre que la variable de entorno en sí no contenga nuevas líneas. Los shells como BASH a veces lo hacen para 'funciones exportadas'.
Anthony
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.