イニシャルを読むことができます /proc/<pid>/environ
からのプロセスの環境 .
プロセスが変更された場合 その環境を読み取るには、プロセスのシンボル テーブルを取得し、ptrace
を使用する必要があります。 システムコール (たとえば gdb
を使用) ) グローバル char **__environ
から環境を読み取る 変数。実行中の Linux プロセスから変数の値を取得する方法は他にありません。
それが答えです。では、いくつかメモを取りましょう。
上記は、プロセスが POSIX 準拠であることを前提としています。つまり、プロセスはグローバル変数 char **__environ
を使用して環境を管理します。 参照仕様で指定されているとおり。
プロセスの初期環境は、プロセスのスタック上の固定長バッファーでプロセスに渡されます。 (これを行う通常のメカニズムは linux//fs/exec.c:do_execve_common(...)
です .) バッファーのサイズは、初期環境に必要なサイズを超えないように計算されるため、既存の変数を消去するか、スタックを壊さない限り、新しい変数を追加することはできません。したがって、プロセスの環境の変更を許可する合理的なスキームは、任意のサイズのメモリを割り当てて解放できるヒープを使用します。これは、GNU libc
とまったく同じです。 (glibc
) はあなたのために行います。
プロセスが glibc
を使用する場合 の場合、__environ
で POSIX に準拠しています。 glibc//posix/environ.c
で宣言されている glibc は __environ
を初期化します malloc
であるメモリへのポインタ プロセスのヒープから、初期環境をスタックからこのヒープ領域にコピーします。プロセスが setenv
を使用するたびに 関数、glibc
realloc
を実行します __environ
の領域のサイズを調整するには 新しい値または変数を格納するために を指します。 (git clone git://sourceware.org/git/glibc.git glibc
で glibc のソース コードをダウンロードできます。 )。メカニズムを本当に理解するには、hurd//init/init.c:frob_kernel_process()
の Hurd コードも読む必要があります。 (git clone git://git.sv.gnu.org/hurd/hurd.git hurd).
新しいプロセスが fork
のみの場合 ed、後続の 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
を使用した新しいプロセス .
最後に、POSIX __environ
規約はユーザー空間です 大会。 Linux カーネルとは何の関係もありません。 glibc
を使用せずにユーザー空間プログラムを作成できます __environ
なし グローバルで、環境変数を好きなように管理します。これを行ったとして誰もあなたを逮捕することはありませんが、独自の環境管理機能を作成する必要があります (setenv
/getenv
) と sys_exec
の独自のラッパー また、環境のどこに変更を加えたかを誰も推測できない可能性があります。
/proc/$pid/environ
プロセスが独自の環境を変更した場合、更新されます。しかし、多くのプログラムは自分自身の環境をわざわざ変更することはありません。それは少し無意味だからです:プログラムの環境は通常のチャンネルでは見えず、/proc
を通してしか見えません。 と ps
であり、すべての UNIX バリアントにこの種の機能があるわけではないため、アプリケーションはそれに依存しません。
カーネルに関する限り、環境は execve
の引数としてのみ表示されます プログラムを起動するシステムコール。 Linux は /proc
を介してメモリ内の領域を公開します 、一部のプログラムはこの領域を更新しますが、他のプログラムは更新しません。特に、この領域を更新するシェルはないと思います。領域は固定サイズであるため、新しい変数を追加したり、値の長さを変更したりすることはできません。
プロセスがその環境変数を取得/削除すると更新されます。 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>
編集: /proc/pid/environ が更新されていません!私は訂正します。検証プロセスは以下のとおりです。ただし、プロセスがフォークされた子はプロセス環境変数を継承し、それぞれの /proc/self/environ ファイルに表示されます。 (文字列を使用)
シェル内:ここで xargs は子プロセスであるため、環境変数を継承し、その /proc/self/environ
にも反映されます ファイル。
[[email protected] t]$ printenv | grep MASK
[[email protected] t]$ export MASK=NIKHIL
[[email protected] t]$ printenv | grep MASK
MASK=NIKHIL
[[email protected] t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
MASK=NIKHIL
[[email protected] t]$ unset MASK
[[email protected] t]$ printenv | grep MASK
[[email protected] t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
[[email protected] t]$
端末/セッションが、環境変数が設定されているシェルの子プロセスではない、他のセッションからチェックしています。
同じホスト上の別の端末/セッションから検証:
ターミナル1: :printenv は fork され、bash の子プロセスであるため、独自の環境ファイルを読み取ることに注意してください。
[[email protected] t]$ echo $$
2610
[[email protected] t]$ export SPIDEY=NIKHIL
[[email protected] t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[[email protected] t]$
ターミナル2: 同じホスト上で -- 上記の変数が設定されたのと同じシェルで起動しないでください。ターミナルを個別に起動してください。
[[email protected] ~]$ echo $$
4436
[[email protected] ~]$ xargs --null --max-args=1 echo < /proc/self/environ | grep -i spidey
[[email protected] ~]$ strings -f /proc/2610/environ | grep -i spidey
[[email protected] ~]$ xargs --null --max-args=1 echo < /proc/2610/environ | grep -i spidey
[[email protected] ~]$