¿Hay alguna forma de cambiar las variables de entorno de otro proceso en Unix?

105

En Unix, ¿hay alguna forma de que un proceso pueda cambiar las variables de entorno de otro (asumiendo que todas las ejecuta el mismo usuario)? Una solución general sería lo mejor, pero si no, ¿qué pasa con el caso específico en el que uno es hijo del otro?

Editar: ¿Qué tal a través de gdb?

raldi
fuente
Esto me parece más que feo. ¿Cuál es el problema real que desea resolver?
Jens
1
Ejemplo: me gustaría definir una variable de entorno para que cada nueva aplicación, lanzada por la interfaz de usuario, la obtenga. No conozco ningún método excepto definir las variables en uno de los scripts de inicio y RE-LOGIN. Sin embargo, me gustaría no volver a iniciar sesión, sino simplemente definir las variables en la sesión actual para que las nuevas aplicaciones lo obtengan, sin cerrar la sesión de la interfaz de usuario.
AlikElzin-kilaka

Respuestas:

142

A través de gdb:

(gdb) attach process_id

(gdb) call putenv ("env_var_name=env_var_value")

(gdb) detach

Este es un truco bastante desagradable y, por supuesto, solo debe hacerse en el contexto de un escenario de depuración.

Andrés
fuente
8
Entonces, esto parece implicar que, de hecho, puede cambiar el entorno de un proceso si se adjunta al proceso como lo hace GDB y luego se desconecta. Parece que sería posible escribir un programa que solo haga esto.
duelo el
3
"Parece que sería posible escribir un programa que solo haga esto" De hecho ... lo es.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
2
¡Incluso funciona en Windows usando cygwin, para procesos que no se compilan usando cygwin!
Juan Carlos Muñoz
11
Tenga en cuenta que esto solo funciona si el proceso no ha almacenado en caché permanentemente el valor después de una getenv anterior.
An̲̳̳drew
1
ptrace: Operation not permitted
gerrit
22

Probablemente puedas hacerlo técnicamente (ver otras respuestas), pero es posible que no te ayude.

La mayoría de los programas esperarán que las vars env no se puedan cambiar desde el exterior después del inicio, por lo tanto, la mayoría probablemente solo leerán las vars que les interesan al inicio y se inicializarán basándose en eso. Así que cambiarlos después no hará ninguna diferencia, ya que el programa nunca los volverá a leer.

Si publicó esto como un problema concreto, probablemente debería adoptar un enfoque diferente. Si fue solo por curiosidad: Buena pregunta :-).

sleske
fuente
1
El caso de uso más común en el que sería útil es hacer que los procesos secundarios hereden las nuevas variables de entorno, por ejemplo, en un entorno de escritorio donde desea que los nuevos terminales usen las nuevas variables.
Hjulle
13

Básicamente, no. Si tenía suficientes privilegios (root, o algo parecido) y hurgó en / dev / kmem (memoria del kernel), e hizo cambios en el entorno del proceso, y si el proceso realmente volvió a hacer referencia a la variable de entorno después (es decir, el proceso aún no había tomado una copia de env var y no estaba usando solo esa copia), entonces tal vez, si tenía suerte e inteligencia, y el viento soplaba en la dirección correcta, y la fase de la luna era correcta, tal vez, podrías lograr algo.

Jonathan Leffler
fuente
2
No obtuve la respuesta.
AlikElzin-kilaka
@kilaka: La palabra clave es la segunda: no . El resto de la respuesta está diciendo que si tiene privilegios de root o está ejecutando un depurador, entonces tal vez usted puede hacerlo, pero para todos los propósitos prácticos, la respuesta es no .
Jonathan Leffler
Tiene un script de shell ejecutándose; desea cambiar el entorno en el proceso principal de su script de shell ... por lo que el script de shell se inicia gdben el proceso principal y está programado para realizar el cambio, y funciona sin bloquear el proceso principal. Está bien, probablemente puedas hacerlo, pero no es algo que vayas a hacer de forma rutinaria. A efectos prácticos, por lo tanto, la respuesta sigue siendo no . El resto de la respuesta cubre las alternativas teóricamente posibles y algo poco factibles.
Jonathan Leffler
7

Citando a Jerry Peek:

No puedes enseñarle trucos nuevos a un perro viejo.

Lo único que puede hacer es cambiar la variable de entorno del proceso hijo antes de iniciarlo: obtiene la copia del entorno padre, lo siento.

Consulte http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm para obtener más detalles.

Solo un comentario sobre la respuesta sobre el uso de / proc. Bajo linux / proc es compatible, pero no funciona, no puede cambiar el /proc/${pid}/environarchivo, incluso si es root: es absolutamente de solo lectura.

Davide
fuente
Lo que todavía deja la pregunta: ¿dónde se almacenan realmente los valores de env var? ¿Eso lo hace el núcleo? ¿O el shell almacena los valores y / proc / <pid> / environment los obtiene de allí?
Oliver
Este es un detalle de implementación y podría ser una buena pregunta (separada). Creo que cada UNIX usa su propia forma de almacenamiento, pero todos comparten el comportamiento descrito anteriormente, que es parte de las especificaciones.
Davide
7

Podría pensar en una forma bastante artificial de hacer eso, y no funcionará para procesos arbitrarios.

Suponga que escribe su propia biblioteca compartida que implementa 'char * getenv'. Luego, configura el entorno 'LD_PRELOAD' o 'LD_LIBRARY_PATH'. vars para que ambos procesos se ejecuten con su biblioteca compartida precargada.

De esta manera, esencialmente tendrá un control sobre el código de la función 'getenv'. Entonces, podrías hacer todo tipo de trucos desagradables. Su 'getenv' podría consultar el archivo de configuración externo o el segmento SHM para obtener valores alternativos de env vars. O puede hacer una búsqueda / reemplazo de expresiones regulares en los valores solicitados. O ...

No puedo pensar en una manera fácil de hacerlo para procesos en ejecución arbitrarios (incluso si eres root), salvo reescribir el enlazador dinámico (ld-linux.so).

Adepto
fuente
Esto debería ser factible. Podría tener una pequeña base de datos gdbm para los pares var = value. Tengo algo similar para malloc en stromberg.dnsalias.org/~strombrg/malloc-wrapper
dstromberg
Sin embargo, creo que este método requiere previsión. También debería tener cuidado de no aplicarlo accidentalmente a demasiados procesos.
dstromberg
3

O obtenga su proceso para actualizar un archivo de configuración para el nuevo proceso y luego:

  • realizar un kill -HUP en el nuevo proceso para volver a leer el archivo de configuración actualizado, o
  • Haga que el proceso revise el archivo de configuración para ver si hay actualizaciones de vez en cuando. Si se encuentran cambios, vuelva a leer el archivo de configuración.
Rob Wells
fuente
2

No tan lejos como sé. Realmente está tratando de comunicarse de un proceso a otro que requiere uno de los métodos IPC (memoria compartida, semáforos, sockets, etc.). Después de haber recibido datos mediante uno de estos métodos, puede establecer variables de entorno o realizar otras acciones de forma más directa.

Stephen Darlington
fuente
1

Si su unix admite el sistema de archivos / proc, entonces es trivial LEER el entorno: puede leer el entorno, la línea de comandos y muchos otros atributos de cualquier proceso que posea de esa manera. Cambiarlo ... Bueno, se me ocurre una manera, pero es una MALA idea.

El caso más general ... No lo sé, pero dudo que haya una respuesta portátil.

(Editado: mi respuesta original asumió que el OP quería LEER el env, no cambiarlo)

Mike G.
fuente
Vaya, edité mi respuesta, asumí que quería leer el env, no cambiarlo.
Mike G.
1
No me dejes colgado. ¿Cuál es tu mala idea?
raldi
En Linux, creo que PODRÍA ser capaz de abrir / proc / <pid> / mem read-write para otro proceso de su propiedad ... aunque no estoy seguro. Probar, y realmente jugar con el medio ambiente, DEFINITIVAMENTE sería una mala idea. Así que no te sugiero que lo pruebes ...
Mike G.
1

UNIX está lleno de comunicación entre procesos. Compruebe si su instancia de destino tiene algunos. Dbus se está convirtiendo en un estándar en IPC de "escritorio".

Cambio las variables de entorno dentro del administrador de ventanas Awesome usando awesome-client con un "remitente" de Dbus de código lua.

DVD
fuente
1

No es una respuesta directa, pero ... Raymond Chen tenía un fundamento [basado en Windows] en torno a esto solo el otro día : -

... Aunque ciertamente hay formas no admitidas de hacerlo o formas que funcionan con la ayuda de un depurador, no hay nada que sea compatible para el acceso programático a la línea de comando de otro proceso, al menos nada proporcionado por el kernel. ...

Que no lo haya es una consecuencia del principio de no realizar un seguimiento de la información que no necesita. El kernel no necesita obtener la línea de comandos de otro proceso. Toma la línea de comando pasada a la CreateProcessfunción y la copia en el espacio de direcciones del proceso que se está lanzando, en una ubicación donde la GetCommandLinefunción puede recuperarla. Una vez que el proceso puede acceder a su propia línea de comandos, las responsabilidades del kernel están terminadas.

Dado que la línea de comando se copia en el espacio de direcciones del proceso, el proceso puede incluso escribir en la memoria que contiene la línea de comando y modificarla. Si eso sucede, la línea de comando original se pierde para siempre; se sobrescribió la única copia conocida.

En otras palabras, cualquiera de estas instalaciones del kernel sería

  • difícil de implementar
  • potencialmente una preocupación de seguridad

Sin embargo, la razón más probable es simplemente que hay casos de uso limitados para dicha instalación.

Ruben Bartelink
fuente
1

Parece que putenv no funciona ahora, pero setenv sí. Estaba probando la respuesta aceptada mientras intentaba establecer la variable en el shell actual sin éxito

$] sudo gdb -p $$
(gdb) call putenv("TEST=1234")
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x0
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=

y la variante de cómo funciona:

$] sudo gdb -p $$
(gdb) call (int) setenv("TEST", "1234", 1)
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x55f19ff5edc0 "1234"
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=1234
Kakash1hatake
fuente