Як читати змінні середовища в процесі


Відповіді:


20

/proc/$pid/environоновлює, якщо процес змінює власне середовище. Але багато програм не переймаються зміною власного середовища, оскільки це трохи безглуздо: середовище програми не видно через звичайні канали, лише через /procта ps, і навіть не кожен варіант Unix має таку особливість, тому програми не покладаються на цьому.

Щодо ядра, то середовище відображається лише як аргумент execveсистемного виклику, який запускає програму. Linux відкриває область в пам'яті /proc, а деякі програми оновлюють цю область, а інші -. Зокрема, я не думаю, що жодна оболонка оновлює цю область. Оскільки область має фіксований розмір, неможливо буде додати нові змінні або змінити довжину значення.


Таким чином, фактично немає можливості отримати доступ до процесу '* envp (масив покажчиків до налаштувань середовища). @Gilles, чи можете ви покажіть, чи можна приєднати налагоджувач і прочитати масив покажчиків до налаштувань середовища.
Нікхіл Маллі

2
@Nikhil Звичайно, так і є. Але те, що ви пишете PATH=fooв оболонці, не означає, що оболонка буде змінюватися *envp. У деяких оболонках це лише оновило внутрішню структуру даних, і оновлений код виконання програми оновляється *envp. Подивіться assign_in_envв variables.cв джерелі Баш, наприклад.
Жил "ТАК - перестань бути злим"

9
@Gilles: Ця відповідь у кращому випадку вводить в оману (-1). Середовище в / proc / $$ / оточення зчитується із стеку процесу. Див. Fs / proc / base.c. Це початкове середовище. Він ніколи не оновлюється і насправді бути не може. Середовище, яке використовує libc setenv, виділяється на купу і ініціалізується вмістом середовища в стеку. Якщо процес викликає libc, forkтоді libc робить sys_forkвиклик, використовуючи виділене середовище для купи дочірнього процесу.
Джонатан Бен-Аврахам

7
@ JonathanBen-Avraham Ви праві, що початкове середовище не оновлюється в жодній оболонці. Однак ця область читається не тільки в Linux, я стикався з програмами, які використовують її для повідомлення про свій статус (звіти про стан argvє більш поширеними, але обидва існують).
Жил "ТАК - перестань бути злим"

39

Ви можете прочитати початкове середовище процесу /proc/<pid>/environ.

Якщо процес змінює своє середовище, то для того, щоб прочитати середовище, ви повинні мати таблицю символів для цього процесу та використовувати ptraceсистемний виклик (наприклад, використовуючи gdb) для зчитування середовища з глобальної char **__environзмінної. Не існує жодного іншого способу отримати значення будь-якої змінної з запущеного процесу Linux.

Ось відповідь. Тепер кілька записок.

Вищенаведене передбачає, що процес сумісний з POSIX, що означає, що процес управляє своїм середовищем, використовуючи глобальну змінну, char **__environяк зазначено в Ref Spec .

Початкове середовище для процесу передається процесу в буфері фіксованої довжини на стеку процесу. (Звичайний механізм, який це робить linux//fs/exec.c:do_execve_common(...).) Оскільки обчислювальний розмір буфера не перевищує розмір, необхідний для початкового середовища, ви не можете додавати нові змінні, не видаляючи існуючі змінні або розбиваючи стек. Отже, будь-яка розумна схема дозволу змін у середовищі процесу використовує купу, де пам'ять у довільних розмірах може бути розподілена та звільнена, що саме GNU libc( glibc) робить для вас.

Якщо процес використовує glibc, то він сумісний з POSIX, __environі декларується в glibc//posix/environ.cGlibc ініціалізується __environвказівником на пам'ять, що він знаходиться mallocз кучі процесу, а потім копіює початкове середовище зі стека в цю область купи. Кожен раз, коли процес використовує setenvфункцію, glibcробить a, 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вирішив це для мене.
retrohacker

@retrohacker Це дає більш надійне рішення: askubuntu.com/questions/978711/…
Frank Kusters

20

Він оновлюється як і коли процес набуває / видаляє свої змінні середовища. Чи є у вас посилання, в якій зазначено, що 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вихідному форматі, необхідна обробка тексту (розбір / фільтрація), щоб побачити змінні середовища як список.

Solaris (не запитують, але для довідки я опублікую тут):

/usr/ucb/ps -wwwe <pid>

або

pargs -e <pid> 

EDIT: / proc / pid / Environment не оновлюється! Я стою виправлений. Процес перевірки наведено нижче. Однак діти, від яких процес виходить, успадковують змінну середовища процесу, і це видно у відповідному файлі / proc / self / оточення. (Використовуйте рядки)

З оболонкою: тут 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]$ 

terminal2: на тому ж хості - не запускайте його в тій же оболонці, де була встановлена ​​вищезгадана змінна, запустіть термінал окремо.

[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
Я export foo=barв одному сесії bash (pid xxxx), потім cat /proc/xxxx/environ | tr \\0 \\nв іншому сесії bash, і я не бачу foo.

Я оновив вищевказану відповідь на прикладі перевірки того ж процесу в оболонці.
Nikhil Mulley

Ви праві. Я стою виправлений. Спасибі. Тепер мені потрібно прочитати мої посібники, щоб перевірити змінні середовища іншого процесу в групі процесів користувача.
Нікхіл Маллі

1
І ще одна річ: я спробував перевірити середовище, що приєднує gdb до pid, але все ще немає посилань. Блок змінних середовищ у пам'яті перерозподіляється кожного разу, коли відбувається зміна і не відображається у файлі оточення власного процесу у файловій системі proc, але, однак, дозволяє успадковувати дочірній процес. Це означає, що це може простіше дізнатись внутрішні деталі, коли вилка відбувається, як дочірній процес отримує змінні середовища, скопійовані як є.
Нікхіл Маллі

Я сподіваюся, що @Gilles кине на це трохи свого факела .. :-)
Nikhil Mulley

7

Ну, наступне не пов'язане з реальними намірами автора, але якщо ви дійсно хочете "ЧИТАТИ" те /proc/<pid>/environ, ви можете спробувати

strings /proc/<pid>/environ

що краще за catнього.


1
+1 для strings. Не ускладнювати.
Ед Рандалл

Погодьтеся @EdRandall, це відчуває, як легший підхід проти xargs --null.
Пер Лундберг

"Файл" припиняється до нуля, замінюйте нулі новим рядком і нормальні інструменти знову працюють (із звичайними застереженнями), наприклад:tr '\0' '\n' < /proc/$$/environ | ...
Тор

Поки сама змінна середовище не містить нових рядків. Оболонки типу BASH іноді роблять це для 'експортованих функцій'.
Антоній
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.