Linux /proc/<pid>/environ
tidak memperbarui (seperti yang saya mengerti, file tersebut mengandung lingkungan awal dari proses).
Bagaimana saya bisa membaca lingkungan proses saat ini ?
Linux /proc/<pid>/environ
tidak memperbarui (seperti yang saya mengerti, file tersebut mengandung lingkungan awal dari proses).
Bagaimana saya bisa membaca lingkungan proses saat ini ?
Jawaban:
/proc/$pid/environ
tidak memperbarui jika proses mengubah lingkungannya sendiri. Tetapi banyak program tidak perlu repot mengubah lingkungannya sendiri, karena ini sedikit tidak berguna: lingkungan program tidak terlihat melalui saluran normal, hanya melalui /proc
dan ps
, dan bahkan tidak setiap varian unix memiliki fitur semacam ini, sehingga aplikasi tidak bergantung di atasnya.
Sejauh menyangkut kernel, lingkungan hanya muncul sebagai argumen dari execve
panggilan sistem yang memulai program. Linux mengekspos area dalam memori melalui /proc
, dan beberapa program memperbarui area ini sementara yang lain tidak. Secara khusus, saya tidak berpikir shell memperbarui area ini. Karena area memiliki ukuran tetap, tidak mungkin untuk menambahkan variabel baru atau mengubah panjang nilai.
PATH=foo
di shell tidak berarti shell akan dimodifikasi *envp
. Dalam beberapa shell, yang hanya memperbarui struktur data internal, dan kode eksekusi program eksternal yang diperbarui *envp
. Lihat di assign_in_env
dalam variables.c
sumber bash, misalnya.
fork
maka libc membuat sys_fork
panggilan menggunakan lingkungan heap yang dialokasikan untuk proses anak.
argv
lebih umum tetapi keduanya ada).
Anda dapat membaca lingkungan awal suatu proses dari /proc/<pid>/environ
.
Jika suatu proses mengubah lingkungannya, maka untuk membaca lingkungan Anda harus memiliki tabel simbol untuk proses dan menggunakan ptrace
panggilan sistem (misalnya dengan menggunakan gdb
) untuk membaca lingkungan dari char **__environ
variabel global . Tidak ada cara lain untuk mendapatkan nilai variabel apa pun dari proses Linux yang sedang berjalan.
Itulah jawabannya. Sekarang untuk beberapa catatan.
Di atas mengasumsikan bahwa prosesnya adalah POSIX compliant, yang berarti bahwa proses mengelola lingkungannya menggunakan variabel global char **__environ
seperti yang ditentukan dalam Referensi Ref .
Lingkungan awal untuk suatu proses dilewatkan ke proses dalam buffer dengan panjang tetap pada tumpukan proses. (Mekanisme biasa yang melakukan ini adalah linux//fs/exec.c:do_execve_common(...)
.) Karena ukuran buffer dihitung tidak lebih dari ukuran yang diperlukan untuk lingkungan awal, Anda tidak dapat menambahkan variabel baru tanpa menghapus variabel yang ada atau menghancurkan tumpukan. Jadi, setiap skema yang masuk akal untuk memungkinkan perubahan dalam lingkungan proses akan menggunakan heap, di mana memori dalam ukuran sewenang-wenang dapat dialokasikan dan dibebaskan, yang persis seperti yang dilakukan GNU libc
( glibc
) untuk Anda.
Jika proses menggunakan glibc
, maka itu adalah POSIX compliant, dengan __environ
dideklarasikan di glibc//posix/environ.c
Glibc menginisialisasi __environ
dengan pointer ke memori yang malloc
berasal dari tumpukan proses, kemudian menyalin lingkungan awal dari tumpukan ke area tumpukan ini. Setiap kali proses menggunakan setenv
fungsi, glibc
lakukan realloc
untuk menyesuaikan ukuran area yang __environ
menunjuk untuk mengakomodasi nilai atau variabel baru. (Anda dapat mengunduh kode sumber glibc dengan git clone git://sourceware.org/git/glibc.git glibc
). Untuk benar-benar memahami mekanisme ini, Anda juga harus membaca kode Hurd di hurd//init/init.c:frob_kernel_process()
(git clone git: //git.sv.gnu.org/hurd/hurd.git hurd).
Sekarang jika proses baru hanya fork
diedit, tanpa exec
menimpa tumpukan berikutnya , maka argumen dan sihir penyalinan lingkungan dilakukan linux//kernel/fork.c:do_fork(...)
, di mana copy_process
panggilan rutin dup_task_struct
yang mengalokasikan tumpukan proses baru dengan memanggil alloc_thread_info_node
, yang memanggil setup_thread_stack
( linux//include/linux/sched.h
) untuk proses baru menggunakan alloc_thread_info_node
.
Akhirnya, __environ
konvensi POSIX adalah konvensi ruang pengguna . Tidak memiliki koneksi dengan apa pun di kernel Linux. Anda dapat menulis program userspace tanpa menggunakan glibc
dan tanpa __environ
global dan kemudian mengelola variabel lingkungan sesuka Anda. Tidak ada yang akan menahan Anda untuk melakukan ini tetapi Anda harus menulis fungsi manajemen lingkungan Anda sendiri ( setenv
/ getenv
) dan pembungkus Anda sendiri untuk sys_exec
dan kemungkinan tidak ada yang akan bisa menebak di mana Anda menempatkan perubahan pada lingkungan Anda.
/proc/[pid]/
tampaknya memiliki penyandian aneh (orang lain mungkin tahu apa dan mengapa). Bagi saya, cukup cat environ
mencetak variabel lingkungan dalam format yang sangat sulit dibaca. cat environ | strings
memecahkan ini untukku.
Ini diperbarui ketika dan ketika proses memperoleh / menghapus variabel lingkungannya. Apakah Anda memiliki referensi yang menyatakan environ
file tidak diperbarui untuk proses dalam direktori prosesnya di bawah / proc filesystem?
xargs --null --max-args=1 echo < /proc/self/environ
atau
xargs --null --max-args=1 echo < /proc/<pid>/environ
atau
ps e -p <pid>
Di atas akan mencetak variabel lingkungan dari proses dalam ps
format output, pemrosesan teks (parsing / filtering) diperlukan untuk melihat variabel lingkungan sebagai daftar.
Solaris (tidak ditanyakan, tetapi untuk referensi saya akan posting di sini):
/usr/ucb/ps -wwwe <pid>
atau
pargs -e <pid>
EDIT: / proc / pid /viron tidak diperbarui! Saya berdiri dikoreksi. Proses verifikasi di bawah. Namun, anak-anak dari mana proses tersebut diwariskan mewarisi variabel lingkungan proses dan terlihat di file / proc / self / environment masing-masing. (Gunakan string)
Dengan di dalam shell: di sini xargs adalah proses anak dan karenanya mewarisi variabel lingkungan dan juga tercermin dalam /proc/self/environ
file -nya .
[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]$
Memeriksa dari sesi lain, di mana terminal / sesi bukanlah proses anak dari shell di mana variabel lingkungan diatur.
Memverifikasi dari terminal / sesi lain pada host yang sama:
terminal1:: Perhatikan bahwa printenv adalah fork'd dan merupakan proses anak dari bash dan karenanya ia membaca file environmentnya sendiri.
[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$
terminal2: pada host yang sama - jangan memulai dengan shell yang sama di mana variabel di atas diatur, luncurkan terminal secara terpisah.
[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 ~]$
export foo=bar
di sesi satu bash (pid xxxx), kemudian lakukan cat /proc/xxxx/environ | tr \\0 \\n
di sesi bash lain dan saya tidak melihat foo
.
gdb
pada pid, tetapi masih tidak ada referensi di sana. Blok variabel lingkungan dalam memori akan dialokasikan kembali setiap kali ada perubahan dan tidak mencerminkan dalam file lingkungan prosesnya sendiri dalam sistem file proc, tetapi bagaimanapun memungkinkan untuk diwarisi oleh proses anak. Itu berarti ini bisa menjadi lebih mudah untuk mengetahui detail intrinsik ketika garpu terjadi, bagaimana proses anak mendapat variabel lingkungan seperti apa adanya.
Nah berikut ini tidak terkait dengan niat sebenarnya penulis, tetapi jika Anda benar-benar ingin "BACA" /proc/<pid>/environ
, Anda dapat mencoba
strings /proc/<pid>/environ
mana yang lebih baik dari cat
itu.
strings
. Tetap sederhana.
xargs --null
.
tr '\0' '\n' < /proc/$$/environ | ...