web-dev-qa-db-ja.com

プロセスの環境変数を読み取る方法

Linuxの/proc/<pid>/environは更新されません(私が理解しているように、ファイルにはプロセスの初期環境が含まれています)。

プロセスのcurrent環境を読み取るにはどうすればよいですか?

45
user14284

/proc/$pid/environは、プロセスが独自の環境を変更すると更新されます。しかし、多くのプログラムは独自の環境を変更する必要がありません。それは少し無意味だからです。プログラムの環境は、通常のチャネルからは見えず、/procpsからしか見えません。この種の機能なので、アプリケーションはそれに依存しません。

カーネルに関する限り、環境はプログラムを起動する execve システムコールの引数としてのみ表示されます。 Linuxは/procを介してメモリ内の領域を公開し、一部のプログラムはこの領域を更新しますが、他のプログラムは更新しません。特に、シェルがこの領域を更新することはないと思います。領域のサイズは固定されているため、新しい変数を追加したり、値の長さを変更したりすることはできません。

プロセスのinitial環境は_/proc/<pid>/environ_から読み取ることができます。

プロセスchangesその環境の場合、環境を読み取るには、プロセスのシンボルテーブルがあり、ptraceシステムコールを使用して(たとえば、gdbを使用して)グローバルから環境を読み取る必要があります。 _char **__environ_変数。実行中のLinuxプロセスから変数の値を取得する方法は他にありません。

それが答えです。次に、いくつかの注意事項について説明します。

上記は、プロセスがPOSIX準拠であることを前提としています。つまり、プロセスは Ref Spec で指定されているグローバル変数_char **__environ_を使用して環境を管理します。

プロセスの初期環境は、プロセスのスタック上の固定長バッファーでプロセスに渡されます。 (これを行う通常のメカニズムはlinux//fs/exec.c:do_execve_common(...)です。)バッファーのサイズは初期環境に必要なサイズ以下になるように計算されるため、既存の変数を消去せずに新しい変数を追加したり、スタックを壊します。したがって、プロセスの環境での変更を許可するための適切なスキームはヒープを使用します。ここで、任意のサイズのメモリを割り当てて解放できます。これは、GNU libcglibc)が行うこととまったく同じです。

プロセスがglibcを使用する場合、それはPOSIXに準拠しており、___environ_は_glibc//posix/environ.c_で宣言されています。Glibcは、プロセスのヒープからmallocsを指すメモリへのポインタで___environ_を初期化し、初期スタックからこのヒープ領域への環境。プロセスがsetenv関数を使用するたびに、glibcreallocを実行して、___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)。

次に、新しいプロセスがforkedのみで、後続の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_規約はuser-space規約です。 Linuxカーネルには何の関係もありません。 glibcを使用せず、___environ_グローバルを使用せずにユーザー空間プログラムを作成し、環境変数を好きなように管理できます。これを行ったことで誰もあなたを逮捕することはありませんが、独自の環境管理関数(setenv/getenv)と_sys_exec_の独自のラッパーを作成する必要があり、どこにどこに置くか推測できない可能性があります環境の変化。

41

プロセスがその環境変数を取得/削除したときに更新されます。/procファイルシステムの下のプロセスディレクトリで、プロセスのenvironファイルが更新されていないことを示すリファレンスがありますか?

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ファイルにも反映されます。

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

ターミナル/セッションが環境変数が設定されているシェルの子プロセスではない他のセッションからそれをチェックします。

同じホスト上の別の端末/セッションから確認する:

terminal1::printenvはforkされ、bashの子プロセスであるため、独自の環境ファイルを読み取ることに注意してください。

[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$ 

terminal2:同じホストで-上記の変数が設定された同じシェルで起動しないでください。ターミナルを個別に起動します。

[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 ~]$ 
22
Nikhil Mulley

さて、以下は作者の本当の意図とは関係ありませんが、本当に「読みたい」場合は/proc/<pid>/environ、お試しください

strings /proc/<pid>/environ

catより良いです。

8
fibonacci