/proc/pid/environでは任意のプロセスの全ての環境変数を取得できない?

投稿者: | ↻ : 2019年1月28日

はじめに

ネット上には、プロセスIDからプロセスの環境変数を得る方法として以下の例があります。

(strings部分はsedだったり、trだったり色々だけど、そこは関係ないのです)

$ strings /proc/$pid/environ

好奇心から自分自身の環境変数を取得しようとしたら、設定したはずの環境変数が見当たりません。

$ export rabbit=peter
$ env | grep ^rabbit
rabbit=peter
$ strings /proc/$$/environ | grep ^rabbit
# (TωT)出てこない

自分自身の環境変数ならばenv(cshならsetenv)取れるので支障はありません。

問題は、これが自分自身だから駄目だったのか、根本的に/proc/$pid/environから得られるものの認識を間違っているのかが分からないと、/proc/$pid/environの情報を有効に扱えないことです。

これを調べて、ほぼコレという理由を見つけたので、まとめます。

検証環境

CentOS 7.4.1708上のbash

理由

この方法では、そのプロセスで設定された環境変数は取得できません。

/proc/$pid/environで見る事ができるのは、プロセスの初期環境だからです。

新しく環境変数を設定してもプロセスの初期環境を変更しません。なので、/proc/$$/environのように自分自身のプロセスIDに対して読み出すと、新しく設定した環境変数を見つけることはできません。

子プロセスを生成する際に子プロセスの初期環境として、自身の初期環境と、新しく設定した環境変数(優先)が引き継がれます。

上記の理由から、プロセスIDから任意のプロセスの全ての環境変数を得る方法はありません。

検証手順

#環境変数を設定する
$ export rabbit=peter

#確認する => 見つからない
$ strings /proc/$$/environ | grep ^rabbit

#子プロセス(サブシェル)を生成する
$ bash

#確認する => 親プロセスで設定された値
$ strings /proc/$$/environ | grep ^rabbit
rabbit=peter

#引き継いだ環境変数を変更する
export rabbit=sekine

#確認する => 親プロセスで設定された値のまま
$ strings /proc/$$/environ | grep ^rabbit
rabbit=peter

#孫プロセス(サブシェル)生成する
bash

#確認する => 子プロセスで設定された値
$ strings /proc/$$/environ | grep ^rabbit
rabbit=sekine

#プロセスの階層を確認
$ ps x --forest
  PID TTY      STAT   TIME COMMAND
 5466 ?        S      0:00 sshd: vagrant@pts/0
 5467 pts/0    Ss     0:00  \_ -bash
 5543 pts/0    S      0:00      \_ bash
 5565 pts/0    S      0:00          \_ bash
 5584 pts/0    R+     0:00              \_ ps x --forest
 
#それぞれのプロセスIDを指定して環境変数を取得する
# 親プロセス = 出力なし
$ strings /proc/5467/environ | grep ^rabbit

# 子プロセス = 親プロセスで設定された値
$ strings /proc/5543/environ | grep ^rabbit
rabbit=peter

# 孫プロセス = 子プロセスで設定された値
$ strings /proc/5565/environ | grep ^rabbit
rabbit=sekine

例外

調べたいプロセスが、環境を引き継ぐ条件で生成した子プロセスを持っているならば、/proc/子プロセスのpid/environにより、引き継いだ初期環境を得られます。

子プロセスが引き継いだ初期環境が親プロセスの環境なので、条件付きならば任意のプロセスの環境変数を取得できます。

まとめ

任意のプロセスIDの環境変数を取得するために/proc/$pid/environを参照する場合、その内容は初期環境なので注意が必要ということです。

今回の内容は、unix.stackexchange.comのHow to read environment variables of a processで、Toby Speightさんの回答から理由が分かりました。回答には実装についての説明まであるので、時間を取って実装確認するべきか・・・