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

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

Linuxは/proc/<pid>/environプロセス環境を更新しません。私が理解したところ、このファイルにはプロセスの初期環境が含まれています。

プロセスをどのように読みますか?現在の環境?

答え1

あなたは読むことができます初期のプロセス環境は/proc/<pid>/environ

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

これが答えです。今メモしてみてください。

上記は、プロセスがPOSIXに準拠していると仮定しています。つまり、プロセスはグローバル変数を使用して、次char **__environの環境を管理します。参考仕様

プロセスの初期環境は、プロセススタックの固定長バッファを介してプロセスに渡されます。 (これを行う一般的なメカニズムは次のとおりですlinux//fs/exec.c:do_execve_common(...)。)計算されたバッファサイズは、初期環境に必要なサイズより大きくないため、既存の変数を消去したりスタックを破壊したりせずに新しい変数を追加することはできません。したがって、プロセス環境の変更を可能にする合理的な方法は、任意のサイズのメモリを割り当てて解放できるヒープを使用することです。これはGNU libcglibc)が行うことです。

プロセスがGlibcで宣言され、プロセスヒープのメモリへのポインタで初期化され、初期環境がスタックからそのヒープ領域にコピーされると、glibcPOSIX互換です。__environプロセスがこの関数を使用するたびに、指す領域のサイズは新しい値または変数に合わせて調整されます。 (glibcソースコードをダウンロードできます)。メカニズムを実際に理解するには、Hurdコード(git clone git://git.sv.gnu.org/hurd/hurd.git hurd)も読む必要があります。glibc//posix/environ.c__environmallocsetenvglibcrealloc__environgit clone git://sourceware.org/git/glibc.git glibchurd//init/init.c:frob_kernel_process()

forkその後、スタックを上書きせずにexec新しいプロセスが作成されると()を呼び出して、新しいプロセスのスタックを割り当てるルーチン呼び出しでlinux//kernel/fork.c:do_fork(...)引数copy_processと環境コピーマジックが実行されます。次に、次をdup_task_struct使用して新しいプロセスにスタックをalloc_thread_info_node割り当てます。呼ぶsetup_thread_stack()。linux//include/linux/sched.halloc_thread_info_node

最後に、POSIX__environルールは次のようになります。ユーザースペース習慣。これはLinuxカーネルのどれにも関係ありません。グローバル変数を使用せずにglibcユーザー空間プログラムを作成し、必要に応じて__environ環境変数を管理できます。このようにしても誰もあなたを逮捕しません。しかし、あなたは自分の環境管理関数(setenv/ getenv)とあなた自身のラッパーを書く必要があり、sys_execおそらくあなたが環境の変更をどこに置いたかを推測することはできません。

答え2

プロセスが環境変数を取得または削除すると更新されます。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ファイルに反映されます。

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

端末/セッションが環境変数を設定するシェルの子プロセス以外のセッションで確認してください。

同じホストの他の端末/セッションで確認してください。

ターミナル1::printenv は分岐して bash の子プロセスなので、独自の環境ファイルを読み込みます。

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

ターミナル2:同じホストで - 上記の変数を設定した同じシェルで起動しないで、端末を別々に起動してください。

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

答え3

/proc/$pid/environプロセスが独自の環境を変更すると、更新されます。しかし、多くのプログラムは、自分の環境を変えることには気にしません。なぜなら少し無意味だからです。プログラムの環境は通常のチャンネルでは見ることができず、そしてを通してしか見ることができず、/procすべてpsのUnixバリアントにもこの機能があるわけではないので、アプリケーションに依存しないでください。その上に。

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

答え4

私は一時的にgdbプログラムにセッションを接続し、getenvそこから呼び出すことにしました。には適用されない場合がありますみんなこれは手続きであり、コストはかなり高いですが、通常は次のように動作します。

echo 'p (char *) getenv("PWD")' | \
     gdb --quiet -p $(pidof emacs) | \
     sed -n 's/.*"\(.*\)"$/\1/p'

関連情報