Чи є спосіб зміни змінних оточення іншого процесу в Unix?


105

У Unix, чи є спосіб, що один процес може змінити змінні середовища іншого (якщо припустити, що ними керує той самий користувач)? Загальне рішення було б найкращим, але якщо ні, то про конкретний випадок, коли один є дитиною іншого?

Редагувати: як щодо gdb?


Це вражає мене як більш ніж потворне. Яку актуальну проблему ви хочете вирішити?
Єнс

1
Приклад. Я хотів би визначити змінну середовища, щоб кожна нова програма - запущена користувальницьким інтерфейсом - отримала її. Я не знаю жодного методу, крім визначення змінних в одному зі сценаріїв запуску та RE-LOGIN. Однак я хотів би не повторно входити в систему, а просто визначити змінні в поточному сеансі, щоб нові програми отримували його - не виходячи з інтерфейсу користувача.
AlikElzin-kilaka

Відповіді:


142

Через gdb:

(gdb) attach process_id

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

(gdb) detach

Це досить неприємний злом, і його слід робити, звичайно, лише в сценарії налагодження.


8
Таким чином, це, мабуть, означає, що ви дійсно можете змінити середовище процесу, якщо ви приєднаєтесь до процесу, як це робить GDB, а потім від'єднатися. Здається, можна було б написати програму, яка займається лише цим.
скорботи

3
"Здається, можна було б написати програму, яка робить це лише" Дійсно .. так.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

2
Він навіть працює в Windows за допомогою cygwin, для процесів, які не компілюються за допомогою cygwin!
Хуан Карлос Муньоз

11
Зауважте, що це працює лише в тому випадку, якщо процес не зміг кешувати значення постійно після попереднього гетен.
An̲̳̳drew

1
ptrace: Operation not permitted
Геррі

22

Напевно, ви можете це зробити технічно (див. Інші відповіді), але це може вам не допомогти.

Більшість програм очікують, що навколишнє середовище не може бути змінено ззовні після запуску, отже, більшість, ймовірно, просто прочитають вари, які їх цікавлять при запуску, та ініціалізувати на основі цього. Тож зміна їх після цього не матиме значення, оскільки програма ніколи їх не перечитає.

Якщо ви опублікували це як конкретну проблему, ви, ймовірно, повинні скористатися іншим підходом. Якби це було просто з цікавості: Приємне запитання :-).


1
Найбільш поширений випадок використання, коли було б корисно - змусити дочірні процеси успадкувати нові змінні середовища, наприклад, у середовищі робочого столу, де потрібно, щоб нові термінали використовували нові змінні.
Hjulle

13

По суті, ні. Якщо у вас було достатньо привілеїв (root або thereabouts), ви накручували / dev / kmem (пам'ять ядра), і ви вносили зміни в середовище процесу, і якщо процес насправді перенаправляв змінну середовища після цього (тобто процес ви вже не взяли копію env var і не використовували саме цю копію), то, можливо, якщо вам пощастило і розумно, і вітер дме в потрібному напрямку, і фаза місяця була правильною, можливо, ви можете чогось досягти.


2
Я не отримав відповіді.
AlikElzin-kilaka

@kilaka: Ключове слово друге - Ні . Решта відповіді говорить про те, що якщо у вас є root права або ви працюєте з налагоджувачем, можливо, ви можете це зробити, але для всіх практичних цілей відповідь - ні .
Джонатан Леффлер

У вас запущений сценарій оболонки; ви хочете змінити середовище в батьківському процесі скрипта оболонки ... так що скрипт оболонки запускається gdbна батьківський процес і сценарій виконує внесення змін, і він працює без збоїв батьківського процесу. Гаразд - ти, мабуть, можеш це зробити, але це не те, що ти збираєшся робити щоденно. Тому в практичних цілях відповідь залишається « Ні» . Решта відповіді стосується теоретично можливих, непредметних, альтернативних варіантів зовнішніх стін.
Джонатан Леффлер

7

Цитуючи Джеррі Піка:

Ви не можете навчити старого собаку нових хитрощів.

Єдине, що ви можете зробити - це змінити змінну середовища дочірнього процесу перед його запуском: вона отримує копію батьківського середовища, вибачте.

Детальніше див. На http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm .

Просто коментар до відповіді про використання / proc. Під linux / proc підтримується, але він не працює, ви не можете змінити /proc/${pid}/environфайл, навіть якщо ви root: він абсолютно лише для читання.


Що ще залишає питання: де насправді зберігаються значення env var? Це зробило ядро? Або оболонка зберігає значення, і / proc / <pid> / Environment отримує їх звідти?
Олівер

Це деталізація щодо впровадження, і це може бути (окремим) хорошим питанням. Я думаю, що кожен UNIX використовує свій спосіб зберігання, але всі вони поділяють описану вище поведінку, яка є частиною специфікацій.
Девіде

7

Я міг би придумати досить надуманий спосіб зробити це, і це не спрацює для довільних процесів.

Припустимо, ви пишете власну спільну бібліотеку, яка реалізує "char * getenv". Потім ви встановлюєте "LD_PRELOAD" або "LD_LIBRARY_PATH" env. вар, так що обидва ваші процеси запускаються з попередньо завантаженою спільною бібліотекою.

Таким чином, ви по суті матимете контроль над кодом функції 'getenv'. Тоді ви могли робити всілякі неприємні хитрощі. Ваш "getenv" може звернутися до зовнішнього файлу конфігурації або сегменту SHM щодо альтернативних значень env vars. Або ви можете виконати пошук / заміну regexp за запитуваними значеннями. Або ...

Я не можу придумати простий спосіб зробити це для довільних запущених процесів (навіть якщо ви root), окрім переписування динамічного лінкера (ld-linux.so).


Це повинно бути виконано. Ви можете мати трохи бази даних gdbm для пар var = value. У мене є щось схоже на malloc на stromberg.dnsalias.org/~strombrg/malloc-wrapper
dstromberg

Я думаю, що цей метод вимагає продуманості. Вам також слід бути обережними, щоб випадково не застосувати його до занадто багатьох процесів.
дстромберг

3

Або змусити ваш процес оновити конфігураційний файл для нового процесу, а потім:

  • виконати kill -HUP у новому процесі, щоб перечитати оновлений конфігураційний файл, або
  • попросіть процес перевіряти конфігураційний файл на оновлення раз у раз. Якщо зміни знайдені, перечитайте конфігураційний файл.

2

Не наскільки я знаю. Дійсно, ви намагаєтеся спілкуватися з одного процесу в інший, який вимагає одного з методів IPC (спільна пам'ять, семафори, сокети тощо). Отримавши дані одним із цих методів, ви могли потім встановити змінні середовища або виконати інші дії більш безпосередньо.


1

Якщо ваш unix підтримує файлову систему / proc, то НЕОБХІДНО читати env - ви можете прочитати середовище, командний рядок та багато інших атрибутів будь-якого процесу, яким ви володієте. Змінивши це ... Ну, я можу придумати спосіб, але це ідея БАД.

Більш загальний випадок ... Я не знаю, але сумніваюся, що є портативна відповідь.

(Відредаговано: моя оригінальна відповідь припускала, що ОП хотів ЧИТАТИ оточення, а не змінювати його)


Ооопс, відредагував мою відповідь - я припускав, що він хоче прочитати оточення, а не змінити його.
Майк Г.

1
Не залишай мене вішати. Яка ваша погана ідея?
raldi

В Linux я вважаю, що ви ВІДМОВИТИ зможете відкрити / proc / <pid> / mem read / write для іншого вашого процесу ... Хоча я не впевнений. Спроба, і насправді возитися з навколишнім середовищем, БЕЗПЕЧНО було б поганою ідеєю. Тож я не пропоную вам спробувати це ...
Майк Г.

1

UNIX сповнений міжпроцесорного спілкування. Перевірте, чи є ваш цільовий примірник. Dbus стає стандартом у «настільних» IPC.

Я змінюю змінні середовища всередині диспетчера вікон Awesome, використовуючи awesome-client з Dbus "відправника" коду lua.


1

Не пряма відповідь, але ... Реймонд Чен був обгрунтованим [Windows] на цьому лише на днях : -

... Хоча, безумовно, є непідтримувані способи цього чи способи, що працюють за допомогою налагоджувача, нічого не підтримується для програмного доступу до командного рядка іншого процесу, принаймні нічого, що надається ядром. ...

Те, що немає, є наслідком принципу не відстежувати інформацію, яка вам не потрібна. Ядро не потребує отримання командного рядка іншого процесу. Він бере командний рядок, переданий CreateProcessфункції, і копіює її в адресний простір запущеного процесу, в місце, де GetCommandLineфункція може його отримати. Як тільки процес може отримати доступ до власного командного рядка, виконуються обов'язки ядра.

Оскільки командний рядок скопійовано в адресний простір процесу, процес може навіть записати в пам'ять, що містить командний рядок, і змінити його. Якщо це трапиться, тоді початковий командний рядок втрачається назавжди; єдину відому копію перезаписали.

Іншими словами, будь-які подібні засоби ядра були б

  • важко здійснити
  • потенційно питання безпеки

Однак найімовірнішою причиною є просто те, що для такої установи є обмежені випадки використання.


1

Здається, putenv зараз не працює, але setenv робить. Я тестував прийняту відповідь, намагаючись встановити змінну в поточній оболонці без успіху

$] 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=

і варіант, як це працює:

$] 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.