Linux /proc/<pid>/environ
не обновляется (насколько я понимаю, файл содержит исходную среду процесса).
Как я могу прочитать текущую среду процесса ?
Linux /proc/<pid>/environ
не обновляется (насколько я понимаю, файл содержит исходную среду процесса).
Как я могу прочитать текущую среду процесса ?
Ответы:
/proc/$pid/environ
обновляется, если процесс изменяет свою собственную среду. Но многие программы не беспокоятся об изменении собственной среды, потому что это немного бессмысленно: среда программы не видна через обычные каналы, только через /proc
и ps
, и даже не в каждом варианте Unix есть такая функция, поэтому приложения не полагаются в теме.
Что касается ядра, окружение появляется только в качестве аргумента execve
системного вызова, запускающего программу. Linux раскрывает область в памяти /proc
, и некоторые программы обновляют эту область, а другие - нет. В частности, я не думаю, что какая-либо оболочка обновляет эту область. Поскольку область имеет фиксированный размер, было бы невозможно добавить новые переменные или изменить длину значения.
PATH=foo
в оболочке, не означает, что оболочка будет изменена *envp
. В некоторых оболочках обновляется только внутренняя структура данных, и обновляется код выполнения внешней программы *envp
. Посмотрите assign_in_env
в variables.c
в источнике Баш, например.
fork
то libc выполняет sys_fork
вызов, используя выделенную кучу среду для дочернего процесса.
argv
более распространены, но оба существуют).
Вы можете прочитать исходную среду процесса из /proc/<pid>/environ
.
Если процесс изменяет свою среду, то для чтения среды необходимо иметь таблицу символов для процесса и использовать ptrace
системный вызов (например, с помощью gdb
) для чтения среды из глобальной char **__environ
переменной. Нет другого способа получить значение любой переменной из запущенного процесса Linux.
Это ответ. Теперь о некоторых заметках.
Выше предполагается, что процесс совместим с POSIX, что означает, что процесс управляет своей средой, используя глобальную переменную, char **__environ
как указано в Ссылочной спецификации .
Начальная среда для процесса передается процессу в буфере фиксированной длины в стеке процесса. (Обычный механизм, который делает это linux//fs/exec.c:do_execve_common(...)
.) Поскольку размер буфера рассчитывается не больше, чем размер, необходимый для начальной среды, вы не можете добавить новые переменные, не удалив существующие переменные или не разрушив стек. Таким образом, любая разумная схема, позволяющая вносить изменения в среду процесса, будет использовать кучу, в которой можно выделять и освобождать память произвольных размеров, что в точности делает для вас GNU libc
( glibc
).
Если процесс использует glibc
, то он является POSIX-совместимым, __environ
поскольку объявление в glibc//posix/environ.c
Glibc инициализируется __environ
указателем на память malloc
из кучи процесса, а затем копирует исходную среду из стека в эту область кучи. Каждый раз, когда процесс использует setenv
функцию, glibc
выполняет realloc
настройку размера области, на которую __environ
указывает новое значение или переменная. (Вы можете скачать исходный код glibc с помощью git clone git://sourceware.org/git/glibc.git glibc
). Чтобы по-настоящему понять механизм, вам также нужно прочитать код Hurd в hurd//init/init.c:frob_kernel_process()
(git clone git: //git.sv.gnu.org/hurd/hurd.git hurd).
Теперь, если новый процесс редактируется только fork
без последующей exec
перезаписи стека, тогда происходит волшебство копирования аргумента и среды linux//kernel/fork.c:do_fork(...)
, когда copy_process
подпрограммы вызывают dup_task_struct
выделение стека нового процесса путем вызова alloc_thread_info_node
, который вызывает setup_thread_stack
( linux//include/linux/sched.h
) для нового процесса, использующего alloc_thread_info_node
.
Наконец, __environ
соглашение POSIX является соглашением пространства пользователя . Он не имеет ничего общего с ядром Linux. Вы можете написать программу пользовательского пространства без использования glibc
и без __environ
глобальных параметров, а затем управлять переменными среды по своему усмотрению. Никто не арестует вас за это, но вам придется написать свои собственные функции управления средой ( setenv
/ getenv
) и свои собственные оболочки, sys_exec
и, вероятно, никто не сможет угадать, куда вы вносите изменения в вашу среду.
/proc/[pid]/
имеют странную кодировку (кто-то другой может знать, что и почему). Для меня просто cat environ
вывести переменные окружения в действительно трудном для чтения формате. cat environ | strings
решил это для меня.
Он обновляется по мере того, как и когда процесс получает / удаляет свои переменные окружения. У вас есть ссылка, в которой говорится, что environ
файл не обновляется для процесса в его каталоге процессов в / proc файловой системы?
xargs --null --max-args=1 echo < /proc/self/environ
или
xargs --null --max-args=1 echo < /proc/<pid>/environ
или
ps e -p <pid>
Выше будет печатать переменные среды процесса в ps
выходном формате, обработка текста (анализ / фильтрация) требуется, чтобы увидеть переменные среды в виде списка.
Солярис (не спрашивал, но для справки выложу здесь):
/usr/ucb/ps -wwwe <pid>
или
pargs -e <pid>
РЕДАКТИРОВАТЬ: / proc / pid / environment не обновляется! Я стою исправлено. Процесс проверки ниже. Однако потомки, от которых процесс является fork, наследуют переменную среды процесса, и это видно в их соответствующем файле / proc / self / environment. (Используйте строки)
В оболочке: здесь xargs является дочерним процессом и, следовательно, наследует переменную окружения, а также отражается в его /proc/self/environ
файле.
[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]$
Проверка его из другого сеанса, где терминал / сеанс не является дочерним процессом оболочки, в которой установлена переменная среды.
Проверка из другого терминала / сеанса на том же хосте:
Terminal1:: Обратите внимание, что printenv является fork'd и является дочерним процессом bash, и, следовательно, он читает свой собственный файл окружения.
[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$
терминал2: на том же хосте - не запускайте его в той же оболочке, где была установлена вышеуказанная переменная, запускайте терминал отдельно.
[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
в одном сеансе bash (pid xxxx), затем делаю cat /proc/xxxx/environ | tr \\0 \\n
в другом сеансе bash, и я не вижу foo
.
gdb
к pid, но там до сих пор нет ссылок. Блок переменных среды в памяти перераспределяется всякий раз, когда происходит изменение, и не отражается в файле окружения своего собственного процесса в файловой системе proc, но, тем не менее, позволяет наследоваться дочерним процессом. Это означает, что это может быть легче узнать внутренние детали, когда происходит разветвление, как дочерний процесс получает переменные среды, скопированные как есть.
Что ж, следующее не связано с реальными намерениями автора, но если вы действительно хотите «ПРОЧИТАТЬ» /proc/<pid>/environ
, вы можете попробовать
strings /proc/<pid>/environ
что лучше, чем cat
это.
strings
. Будь проще.
xargs --null
.
tr '\0' '\n' < /proc/$$/environ | ...