Linuxは/proc/<pid>/environ
プロセス環境を更新しません。私が理解したところ、このファイルにはプロセスの初期環境が含まれています。
プロセスをどのように読みますか?現在の環境?
答え1
あなたは読むことができます初期のプロセス環境は/proc/<pid>/environ
。
プロセスなら多様性環境を読み取るには、プロセスのシンボルテーブルが存在し、ptrace
システムコール(たとえばを使用して)を使用してグローバル変数gdb
から環境を読み取る必要がありますchar **__environ
。実行中のLinuxプロセスから変数値を取得する他の方法はありません。
これが答えです。今メモしてみてください。
上記は、プロセスがPOSIXに準拠していると仮定しています。つまり、プロセスはグローバル変数を使用して、次char **__environ
の環境を管理します。参考仕様。
プロセスの初期環境は、プロセススタックの固定長バッファを介してプロセスに渡されます。 (これを行う一般的なメカニズムは次のとおりですlinux//fs/exec.c:do_execve_common(...)
。)計算されたバッファサイズは、初期環境に必要なサイズより大きくないため、既存の変数を消去したりスタックを破壊したりせずに新しい変数を追加することはできません。したがって、プロセス環境の変更を可能にする合理的な方法は、任意のサイズのメモリを割り当てて解放できるヒープを使用することです。これはGNU libc
(glibc
)が行うことです。
プロセスがGlibcで宣言され、プロセスヒープのメモリへのポインタで初期化され、初期環境がスタックからそのヒープ領域にコピーされると、glibc
POSIX互換です。__environ
プロセスがこの関数を使用するたびに、指す領域のサイズは新しい値または変数に合わせて調整されます。 (glibcソースコードをダウンロードできます)。メカニズムを実際に理解するには、Hurdコード(git clone git://git.sv.gnu.org/hurd/hurd.git hurd)も読む必要があります。glibc//posix/environ.c
__environ
malloc
setenv
glibc
realloc
__environ
git clone git://sourceware.org/git/glibc.git glibc
hurd//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.h
alloc_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'