O Linux /proc/<pid>/environ
não é atualizado (como eu o entendo, o arquivo contém o ambiente inicial do processo).
Como posso ler o ambiente atual de um processo ?
O Linux /proc/<pid>/environ
não é atualizado (como eu o entendo, o arquivo contém o ambiente inicial do processo).
Como posso ler o ambiente atual de um processo ?
Respostas:
/proc/$pid/environ
atualiza se o processo alterar seu próprio ambiente. Mas muitos programas não se incomodam em mudar seu próprio ambiente, porque é um pouco inútil: o ambiente de um programa não é visível através dos canais normais, apenas através /proc
e ps
, e nem todas as variantes unix possuem esse tipo de recurso, portanto, os aplicativos não dependem nele.
No que diz respeito ao kernel, o ambiente aparece apenas como o argumento da execve
chamada do sistema que inicia o programa. O Linux expõe uma área na memória /proc
e alguns programas atualizam essa área, enquanto outros não. Em particular, acho que nenhum shell atualiza essa área. Como a área tem um tamanho fixo, seria impossível adicionar novas variáveis ou alterar o tamanho de um valor.
PATH=foo
em um shell não significa que ele será modificado *envp
. Em alguns shells, isso atualizou apenas uma estrutura de dados interna e é o código de execução do programa externo que é atualizado *envp
. Olhe assign_in_env
em variables.c
na fonte bash, por exemplo.
fork
libc fará a sys_fork
chamada usando o ambiente alocado para heap para o processo filho.
argv
são mais comuns, mas ambos existem).
Você pode ler o ambiente inicial de um processo em /proc/<pid>/environ
.
Se um processo alterar seu ambiente, para ler o ambiente, você deve ter a tabela de símbolos para o processo e usar a ptrace
chamada do sistema (por exemplo, usando gdb
) para ler o ambiente a partir da char **__environ
variável global . Não há outra maneira de obter o valor de qualquer variável de um processo Linux em execução.
Essa é a resposta. Agora, para algumas anotações.
O exposto acima pressupõe que o processo seja compatível com POSIX, o que significa que o processo gerencia seu ambiente usando uma variável global char **__environ
conforme especificado nas especificações de referência .
O ambiente inicial de um processo é passado para o processo em um buffer de tamanho fixo na pilha do processo. (O mecanismo usual que faz isso é linux//fs/exec.c:do_execve_common(...)
.) Como o tamanho do buffer é calculado para não exceder o tamanho necessário para o ambiente inicial, você não pode adicionar novas variáveis sem apagar as variáveis existentes ou esmagar a pilha. Portanto, qualquer esquema razoável para permitir mudanças no ambiente de um processo usaria o heap, onde a memória em tamanhos arbitrários pode ser alocada e liberada, o que é exatamente o que o GNU libc
( glibc
) faz por você.
Se o processo for utilizado glibc
, ele será compatível com POSIX, __environ
sendo declarado no glibc//posix/environ.c
Glibc inicializado __environ
com um ponteiro para a memória que é malloc
do heap do processo e copia o ambiente inicial da pilha para essa área de heap. Cada vez que o processo usa a setenv
função, glibc
faz um realloc
para ajustar o tamanho da área que __environ
aponta para acomodar o novo valor ou variável. (Você pode baixar o código-fonte da glibc com git clone git://sourceware.org/git/glibc.git glibc
). Para realmente entender o mecanismo, você também precisará ler o código Hurd hurd//init/init.c:frob_kernel_process()
(git clone git: //git.sv.gnu.org/hurd/hurd.git hurd).
Agora, se o novo processo for fork
editado apenas , sem uma exec
substituição subsequente da pilha, a magia de cópia de argumento e ambiente será concluída linux//kernel/fork.c:do_fork(...)
, onde as copy_process
chamadas de rotina dup_task_struct
que alocam a pilha do novo processo chamando alloc_thread_info_node
, chama setup_thread_stack
( linux//include/linux/sched.h
) para o novo processo usando alloc_thread_info_node
.
Finalmente, a __environ
convenção POSIX é uma convenção de espaço do usuário . Não tem conexão com nada no kernel do Linux. Você pode escrever um programa de espaço do usuário sem usar glibc
e sem o __environ
global e, em seguida, gerenciar as variáveis de ambiente da maneira que desejar. Ninguém o prenderá por fazer isso, mas você terá que escrever suas próprias funções de gerenciamento de ambiente ( setenv
/ getenv
) e seus próprios wrappers, sys_exec
e é provável que ninguém seja capaz de adivinhar onde você colocou as alterações em seu ambiente.
/proc/[pid]/
parecem ter uma codificação estranha (alguém pode saber o que e por quê). Para mim, simplesmente cat environ
imprimiria as variáveis de ambiente em um formato realmente difícil de ler. cat environ | strings
resolveu isso para mim.
Ele é atualizado à medida que o processo adquire / exclui suas variáveis de ambiente. Você tem uma referência informando que o environ
arquivo não foi atualizado para o processo em seu diretório de processo em / proc filesystem?
xargs --null --max-args=1 echo < /proc/self/environ
ou
xargs --null --max-args=1 echo < /proc/<pid>/environ
ou
ps e -p <pid>
O ps
texto acima imprimirá as variáveis de ambiente do processo no formato de saída, o processamento de texto (análise / filtragem) é necessário para ver as variáveis de ambiente como uma lista.
Solaris (não solicitado, mas para referência vou postar aqui):
/usr/ucb/ps -wwwe <pid>
ou
pargs -e <pid>
EDIT: / proc / pid / environ não é atualizado! Eu estou corrigido. O processo de verificação está abaixo. No entanto, os filhos dos quais o processo é submetido à bifurcação herdam a variável de ambiente do processo e ela é visível em seu respectivo arquivo / proc / self / environment. (Use strings)
Com no shell: aqui xargs é um processo filho e, portanto, herda a variável de ambiente e também reflete em seu /proc/self/environ
arquivo.
[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]$
Verificando-o de outra sessão, em que o terminal / sessão não é o processo filho do shell em que a variável de ambiente está definida.
Verificando de outro terminal / sessão no mesmo host:
terminal1:: Observe que printenv é fork e é um processo filho do bash e, portanto, lê seu próprio arquivo environment.
[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$
terminal2: no mesmo host - não o inicie no mesmo shell em que a variável acima foi definida, inicie o terminal separadamente.
[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
na sessão de uma festa (pid xxxx), depois faço cat /proc/xxxx/environ | tr \\0 \\n
na sessão de outra festa e não vejo foo
.
gdb
o pid, mas ainda não há referência lá. O bloco de variáveis de ambiente na memória é realocado sempre que há uma alteração e não está refletindo no arquivo de ambiente de seu próprio processo no sistema de arquivos proc, mas, no entanto, permite ser herdado pelo processo filho. Isso significa que é mais fácil saber detalhes intrínsecos quando o fork ocorre, como o processo filho obtém as variáveis de ambiente copiadas como estão.
Bem, o seguinte não está relacionado às reais intenções do autor, mas se você realmente deseja "LER" /proc/<pid>/environ
, pode tentar
strings /proc/<pid>/environ
o que é melhor que cat
isso.
strings
. Mantenha simples.
xargs --null
.
tr '\0' '\n' < /proc/$$/environ | ...