Есть ли способ изменить переменные среды другого процесса в Unix?

105

Есть ли в Unix способ, которым один процесс может изменить переменные среды другого (при условии, что все они запускаются одним и тем же пользователем)? Общее решение было бы лучше всего, но если нет, как насчет конкретного случая, когда один из них является потомком другого?

Изменить: как насчет через GDB?

ралди
источник
Мне это кажется более чем уродливым. Какую актуальную проблему вы хотите решить?
Йенс
1
Пример: я хотел бы определить переменную среды, чтобы каждое новое приложение, запускаемое пользовательским интерфейсом, получало ее. Я не знаю ни одного метода, кроме определения переменных в одном из сценариев запуска и RE-LOGIN. Однако я бы хотел не повторно входить в систему, а просто определить переменные в текущем сеансе, чтобы новые приложения получали их - без выхода из пользовательского интерфейса.
AlikElzin-kilaka

Ответы:

143

Через 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!
Хуан Карлос Муньос
12
Обратите внимание, что это работает только в том случае, если процесс не кэшировал значение на постоянной основе после предыдущего getenv.
An̲̳̳drew
2
В некоторых системах gdb может выдать следующую ошибку 'putenv' has unknown return type; cast the call to its declared return type:; в этих случаях вам следует изменить putenvзвонок на это:call (int) putenv ("env_var_name=env_var_value")
Эмир Унер
22

Вы, вероятно, можете сделать это технически (см. Другие ответы), но это может вам не помочь.

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

Если вы разместили это как конкретную проблему, вам, вероятно, следует использовать другой подход. Если бы это было просто из любопытства: Хороший вопрос :-).

Sleske
источник
1
Наиболее распространенный вариант использования, в котором было бы полезно, - заставить дочерние процессы наследовать новые переменные среды, например, в среде рабочего стола, где вы хотите, чтобы новые терминалы использовали новые переменные.
Hjulle
13

По сути, нет. Если у вас были достаточные привилегии (root или около того) и вы копались в / dev / kmem (память ядра), и вы внесли изменения в среду процесса, и если процесс действительно впоследствии повторно ссылался на переменную среды (то есть процесс еще не сделал копию env var и не использовал только эту копию), тогда, возможно, если вам повезло и умен, и ветер дул в правильном направлении, и фаза луны была правильной, возможно, вы могли бы чего-то добиться.

Джонатан Леффлер
источник
2
Я не получил ответа.
AlikElzin-kilaka
@kilaka: Ключевое слово - второе - Нет . Остальная часть ответа говорит о том, что если у вас есть привилегии root или вы используете отладчик, то, возможно, вы сможете это сделать, но для всех практических целей ответ - нет .
Jonathan Leffler
У вас запущен сценарий оболочки; вы хотите изменить среду в родительском процессе вашего сценария оболочки ... поэтому сценарий оболочки запускается 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. vars, чтобы оба процесса запускались с предварительно загруженной общей библиотекой.

Таким образом, у вас будет практически полный контроль над кодом функции getenv. Тогда вы сможете проделывать всевозможные неприятные трюки. Ваш 'getenv' может обращаться к внешнему файлу конфигурации или сегменту SHM для получения альтернативных значений переменных env. Или вы можете выполнить поиск / замену регулярного выражения для запрошенных значений. Или ...

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

ADEpt
источник
Это должно быть выполнимо. У вас может быть небольшая база данных gdbm для пар var = value. У меня есть нечто подобное для malloc на stromberg.dnsalias.org/~strombrg/malloc-wrapper
dstromberg
Я думаю, что этот метод требует предусмотрительности. Вы также должны быть осторожны, чтобы случайно не применить его ко многим процессам.
dstromberg
3

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

  • выполнить kill -HUP для нового процесса, чтобы перечитать обновленный файл конфигурации, или
  • пусть процесс время от времени проверяет файл конфигурации на наличие обновлений. Если изменения обнаружены, то перечитайте файл конфигурации.
Роб Уэллс
источник
2

Насколько я знаю, нет. На самом деле вы пытаетесь взаимодействовать от одного процесса к другому, который вызывает один из методов IPC (общая память, семафоры, сокеты и т. Д.). Получив данные одним из этих методов, вы можете затем установить переменные среды или выполнить другие действия более напрямую.

Стивен Дарлингтон
источник
2

Кажется, что 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
Какаш1хатаке
источник
1

Если ваш unix поддерживает файловую систему / proc, то ПРОЧИТАТЬ env тривиально - таким образом вы можете читать среду, командную строку и многие другие атрибуты любого процесса, которым вы владеете. Изменить это ... Ну, я могу придумать способ, но это ПЛОХАЯ идея.

Более общий случай ... Я не знаю, но сомневаюсь, что есть переносимый ответ.

(Отредактировано: мой первоначальный ответ предполагал, что OP хочет ПРОЧИТАТЬ env, а не изменять его)

Майк Г.
источник
Ой, отредактировал свой ответ - я предполагал, что он хочет прочитать env, а не изменять его.
Майк Г.
1
Не оставляй меня висеть. Какая у тебя плохая идея?
raldi
Я считаю, что в Linux вы МОЖЕТЕ открыть / proc / <pid> / mem для чтения и записи для другого процесса, которым вы владеете ... Я не уверен. Пытаться и фактически возиться с окружающей средой ОПРЕДЕЛЕННО будет плохой идеей. Так что я не предлагаю вам попробовать ...
Майк Дж.
1

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

Я меняю переменные окружения внутри оконного менеджера Awesome, используя awesome-client с Dbus "отправителем" кода lua.

DVD
источник
1

Не прямой ответ, но ... Рэймонд Чен только на днях обосновал это [на основе Windows] : -

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

То, что нет, является следствием принципа отказа от отслеживания информации, которая вам не нужна. Ядру нет необходимости получать командную строку другого процесса. Он берет командную строку, переданную CreateProcessфункции, и копирует ее в адресное пространство запускаемого процесса в место, откуда GetCommandLineфункция может ее получить. Как только процесс получает доступ к собственной командной строке, все обязанности ядра выполняются.

Поскольку командная строка копируется в адресное пространство процесса, процесс может даже записывать в память, содержащую командную строку, и изменять ее. Если это произойдет, исходная командная строка будет потеряна навсегда; единственная известная копия была перезаписана.

Другими словами, любые такие средства ядра будут

  • сложно реализовать
  • потенциально проблема безопасности

Однако наиболее вероятная причина просто в том, что существует ограниченное количество вариантов использования такого средства.

Рубен Бартелинк
источник