Apakah ada cara untuk mengubah variabel lingkungan dari proses lain di Unix?

105

Di Unix, adakah cara agar satu proses dapat mengubah variabel lingkungan lain (dengan asumsi semuanya dijalankan oleh pengguna yang sama)? Solusi umum adalah yang terbaik, tetapi jika tidak, bagaimana dengan kasus spesifik di mana yang satu adalah anak dari yang lain?

Edit: Bagaimana kalau via gdb?

raldi
sumber
Bagi saya ini lebih dari jelek. Apa masalah sebenarnya yang ingin Anda selesaikan?
Jens
1
Contoh: Saya ingin mendefinisikan variabel lingkungan sehingga setiap aplikasi baru - yang diluncurkan oleh UI - akan mendapatkannya. Saya tidak tahu metode apa pun kecuali menentukan variabel di salah satu skrip startup dan RE-LOGIN. Namun saya tidak ingin masuk kembali, tetapi hanya menentukan variabel dalam sesi saat ini sehingga aplikasi baru akan mendapatkannya - tanpa keluar dari UI.
AlikElzin-kilaka

Jawaban:

142

Melalui gdb:

(gdb) attach process_id

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

(gdb) detach

Ini adalah peretasan yang cukup buruk dan seharusnya hanya dilakukan dalam konteks skenario debugging, tentunya.

An̲̳̳drew
sumber
8
Jadi ini tampaknya menyiratkan bahwa Anda memang dapat mengubah lingkungan proses jika Anda melampirkan ke proses seperti yang dilakukan GDB, lalu melepaskannya. Tampaknya dimungkinkan untuk menulis program yang hanya melakukan ini.
berduka pada
3
"Tampaknya akan mungkin untuk menulis program yang hanya melakukan ini" Memang .. itu.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
2
Ia bahkan bekerja di Windows menggunakan cygwin, untuk proses yang tidak dikompilasi menggunakan cygwin!
Juan Carlos Muñoz
11
Perhatikan bahwa ini hanya berfungsi jika proses tidak secara permanen menyimpan nilai setelah getenv sebelumnya.
An̲̳̳drew
1
ptrace: Operation not permitted
gerrit
22

Anda mungkin bisa melakukannya secara teknis (lihat jawaban lain), tetapi mungkin tidak membantu Anda.

Sebagian besar program akan mengharapkan bahwa env vars tidak dapat diubah dari luar setelah startup, oleh karena itu kemungkinan besar hanya akan membaca vars yang mereka minati saat startup dan menginisialisasi berdasarkan itu. Jadi mengubahnya setelah itu tidak akan membuat perbedaan, karena program tidak akan pernah membacanya kembali.

Jika Anda memposting ini sebagai masalah konkret, Anda mungkin harus mengambil pendekatan yang berbeda. Jika hanya ingin tahu: Pertanyaan bagus :-).

sleske
sumber
1
Kasus penggunaan paling umum yang akan berguna adalah membuat proses turunan mewarisi variabel lingkungan baru, misalnya, dalam lingkungan desktop tempat Anda ingin terminal baru menggunakan variabel baru.
Hjulle
13

Secara substansial, tidak. Jika Anda memiliki cukup hak (root, atau sekitarnya) dan melihat-lihat / dev / kmem (memori kernel), dan Anda membuat perubahan pada lingkungan proses, dan jika proses benar-benar mereferensikan variabel lingkungan sesudahnya (yaitu, proses belum mengambil salinan env var dan tidak hanya menggunakan salinan itu), maka mungkin, jika Anda beruntung dan pintar, dan angin bertiup ke arah yang benar, dan fase bulan benar, mungkin, Anda mungkin mencapai sesuatu.

Jonathan Leffler
sumber
2
Saya tidak mendapatkan jawabannya.
AlikElzin-kilaka
@kilaka: Kata kuncinya adalah yang kedua - Tidak . Sisa jawabannya mengatakan bahwa jika Anda memiliki hak akses root atau menjalankan debugger, maka mungkin Anda dapat melakukannya, tetapi untuk semua tujuan praktis, jawabannya adalah Tidak .
Jonathan Leffler
Anda menjalankan skrip shell; Anda ingin mengubah lingkungan dalam proses induk skrip shell Anda ... sehingga skrip shell diluncurkan gdbpada proses induk dan diberi skrip untuk melakukan perubahan, dan berfungsi tanpa merusak proses induk. Oke - Anda mungkin bisa melakukannya, tetapi itu bukanlah sesuatu yang akan Anda lakukan secara rutin. Oleh karena itu, untuk tujuan praktis, jawabannya tetap Tidak . Sisa jawaban mencakup alternatif yang tidak mungkin secara teoritis mungkin, alternatif yang agak tidak praktis.
Jonathan Leffler
7

Mengutip Jerry Peek:

Anda tidak bisa mengajari anjing tua trik baru.

Satu-satunya hal yang dapat Anda lakukan adalah mengubah variabel lingkungan dari proses anak sebelum memulainya: ia mendapat salinan lingkungan induk, maaf.

Lihat http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm untuk detailnya.

Sekedar komentar untuk jawaban tentang penggunaan / proc. Di bawah linux / proc didukung tetapi, itu tidak berfungsi, Anda tidak dapat mengubah /proc/${pid}/environfile, bahkan jika Anda root: itu benar - benar hanya-baca.

Davide
sumber
Yang masih menyisakan pertanyaan: di mana sebenarnya nilai env var disimpan? Apakah itu dilakukan oleh kernel? Atau apakah shell menyimpan nilai, dan / proc / <pid> / environment mendapatkannya dari sana?
oliver
Ini adalah detail implementasi, dan mungkin ini merupakan pertanyaan (terpisah) yang bagus. Saya pikir setiap UNIX menggunakan caranya sendiri untuk penyimpanan, tetapi semuanya berbagi perilaku yang dijelaskan di atas, yang merupakan bagian dari spesifikasinya.
Davide
7

Saya bisa memikirkan cara yang agak dibuat-buat untuk melakukan itu, dan itu tidak akan berhasil untuk proses yang sewenang-wenang.

Misalkan Anda menulis perpustakaan bersama Anda sendiri yang mengimplementasikan 'char * getenv'. Kemudian, Anda menyiapkan 'LD_PRELOAD' atau 'LD_LIBRARY_PATH' env. vars sehingga kedua proses Anda dijalankan dengan pustaka bersama yang dimuat sebelumnya.

Dengan cara ini, Anda pada dasarnya akan memiliki kendali atas kode fungsi 'getenv'. Kemudian, Anda bisa melakukan segala macam trik jahat. 'Getenv' Anda dapat melihat file konfigurasi eksternal atau segmen SHM untuk nilai alternatif env vars. Atau Anda bisa melakukan pencarian / ganti regexp pada nilai yang diminta. Atau ...

Saya tidak dapat memikirkan cara mudah untuk melakukannya untuk proses yang berjalan sewenang-wenang (bahkan jika Anda root), singkatnya menulis ulang dynamic linker (ld-linux.so).

Mahir
sumber
Ini harus bisa dilakukan. Anda dapat memiliki database gdbm kecil untuk pasangan var = nilai. Saya memiliki sesuatu yang serupa untuk malloc di stromberg.dnsalias.org/~strombrg/malloc-wrapper
dstromberg
Saya pikir metode ini membutuhkan pemikiran sebelumnya. Anda juga harus berhati-hati agar tidak menerapkannya secara tidak sengaja ke terlalu banyak proses.
dstromberg
3

Atau dapatkan proses Anda untuk memperbarui file konfigurasi untuk proses baru dan kemudian:

  • melakukan kill -HUP pada proses baru untuk membaca ulang file konfigurasi yang diperbarui, atau
  • mintalah proses memeriksa file konfigurasi untuk pembaruan sesekali. Jika perubahan ditemukan, baca ulang file konfigurasi.
Rob Wells
sumber
2

Tidak sejauh yang saya tahu. Sungguh Anda mencoba berkomunikasi dari satu proses ke proses lainnya yang memanggil salah satu metode IPC (memori bersama, semaphore, soket, dll.). Setelah menerima data dengan salah satu metode ini, Anda kemudian dapat menetapkan variabel lingkungan atau melakukan tindakan lain secara lebih langsung.

Stephen Darlington
sumber
1

Jika unix Anda mendukung filesystem / proc, maka mudah untuk MEMBACA env - Anda dapat membaca lingkungan, commandline, dan banyak atribut lain dari proses apa pun yang Anda miliki dengan cara itu. Mengubahnya ... Yah, saya bisa memikirkan cara, tapi itu ide yang BURUK.

Kasus yang lebih umum ... Saya tidak tahu, tapi saya ragu ada jawaban yang bisa dibawa-bawa.

(Diedit: jawaban asli saya mengasumsikan OP ingin MEMBACA env, bukan mengubahnya)

Mike G.
sumber
Ups, mengedit jawaban saya - saya berasumsi dia ingin membaca env, bukan mengubahnya.
Mike G.
1
Jangan biarkan aku menggantung. Apa ide buruk Anda?
raldi
Di Linux, saya yakin Anda BISA membuka / proc / <pid> / mem read-write untuk proses lain yang Anda miliki ... Namun, saya tidak yakin. Mencoba, dan benar-benar mengotak-atik lingkungan, PASTI akan menjadi ide yang buruk. Jadi saya tidak menyarankan Anda mencobanya ...
Mike G.
1

UNIX penuh dengan komunikasi antar-proses. Periksa apakah instance target Anda memiliki beberapa. Dbus menjadi standar di "desktop" IPC.

Saya mengubah variabel lingkungan di dalam window manager Awesome menggunakan awesome-client dengan adalah "pengirim" kode lua Dbus.

DVD
sumber
1

Bukan jawaban langsung tapi ... Raymond Chen memiliki alasan [berbasis Windows] seputar ini hanya beberapa hari yang lalu : -

... Meskipun ada cara yang pasti tidak didukung untuk melakukannya atau cara yang bekerja dengan bantuan debugger, tidak ada yang didukung untuk akses programatik ke baris perintah proses lain, setidaknya tidak ada yang disediakan oleh kernel. ...

Bahwa tidak ada konsekuensi dari prinsip tidak melacak informasi yang tidak Anda butuhkan. Kernel tidak perlu mendapatkan baris perintah dari proses lain. Ini mengambil baris perintah yang diteruskan ke CreateProcessfungsi dan menyalinnya ke ruang alamat dari proses yang diluncurkan, di lokasi tempat GetCommandLinefungsi dapat mengambilnya. Setelah proses dapat mengakses baris perintahnya sendiri, tanggung jawab kernel selesai.

Karena baris perintah disalin ke dalam ruang alamat proses, proses tersebut bahkan mungkin menulis ke memori yang menyimpan baris perintah dan memodifikasinya. Jika itu terjadi, maka baris perintah asli akan hilang selamanya; satu-satunya salinan yang diketahui ditimpa.

Dengan kata lain, fasilitas kernel seperti itu adalah

  • sulit untuk diterapkan
  • berpotensi menjadi masalah keamanan

Namun alasan yang paling mungkin hanyalah bahwa ada kasus penggunaan yang terbatas untuk fasilitas semacam itu.

Ruben Bartelink
sumber
1

Tampaknya putenv tidak berfungsi sekarang, tetapi setenv berfungsi . Saya sedang menguji jawaban yang diterima sambil mencoba mengatur variabel di shell saat ini tanpa hasil

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

dan varian cara kerjanya:

$] 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
Kakash1hatake
sumber