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


Відповіді:


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.