Twitter見てたらこんなこと言ってる人がいました。
Unix で実行中の実行ファイルのパスを確実に得る方法はない、というのは FAQ だと思うけど、実際にやりたいことは自分自身を別プロセスで新たに立ち上げたいということなので、メモリにロード済の自分自身から別プロセスを作る手段はないんだろうか
— Yusuke Endoh (@mametter) 2017年10月25日
昔自分もそんなこと考えたなーと思いつつ、Linuxなら /proc/<pid>/exe
が実行ファイルへのリンクになってるんで、
環境によるような気もするけど、自分の実行ファイルのパスは /proc/pid/exe から取れないですかね。
— とみたまさひろ (@tmtms) 2017年10月25日
と言ってみたら、
Linuxならその手が使えますが、現在実行中の実行ファイルでも削除できちゃいますから、パス名を得る完璧な方法は( @mametter さんが書いてる通りで) 存在しませんね。初期化済みのプロセスを待機させておき、pipeかsocketpair経由でfork依頼するのはどうでしょう
— SODA Noriyuki (@n_soda) 2017年10月25日
まあ、たしかにシンボリックリンクだし、実行ファイルが消されちゃったらしょうがないなーと思ったんですよ。
そしたら、こんなリプライがついて、
現在実行中のファイル自体へのアクセスは/proc経由で出来るはずなので、そっちの/procをどこかの一時ファイルにlinkすることでパス名をつくって、そこにexecとかでなんとかならないかな。
— 名前のない恐竜 (@gachacomplete) 2017年10月25日
この緑の怪獣が何者かは知らないんですけど、リンクなんだから実行ファイルが消されちゃったらどうしようもないのに何言ってんの?シロウトなの?
と思ったら実は消されててもアクセスできるんですよ!びっくりさ!
がちゃぴ^H^H^H緑の怪獣さんすごい!
/proc/pid/exe はシンボリックリンクで実ファイルが消えたら (deleted) って出るからもうアクセスできない…と思いきや open したら普通に読めてびっくりだわ。
— とみたまさひろ (@tmtms) 2017年10月25日
試してみます。プログラム作るの面倒なんで、sleep コマンドで。
~% cp /bin/sleep /tmp ~% /tmp/sleep 99999 & [1] 18728 ~% ls -l /proc/18728/exe lrwxrwxrwx 1 tommy tommy 0 10月 25 23:38 /proc/18728/exe -> /tmp/sleep ~% rm /tmp/sleep ~% ls -l /proc/18728/exe lrwxrwxrwx 1 tommy tommy 0 10月 25 23:38 /proc/18728/exe -> /tmp/sleep (deleted) ~% ls -lL /proc/18728/exe -rwxr-xr-x 0 tommy tommy 35000 10月 25 23:38 /proc/18728/exe ~% cmp /proc/18728/exe /bin/sleep ~% /proc/18728/exe --version sleep (GNU coreutils) 8.26 Copyright (C) 2016 Free Software Foundation, Inc. ライセンス GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. 作者 Jim Meyering および Paul Eggert。
exe はリンクファイルなので、実行ファイルが消されたら (deleted)
となって、もう参照できないように思えるんだけど、実体を見ようとしたらちゃんと見えるんですよ。リンクカウント 0 のファイルとして。
それをそのまま読み込むこともできるし、実行だってできる。面白い。
プロセスの実行ファイルだけじゃなくて、プロセスがオープンしているファイルも /proc/<pid>/fd/
配下で見ることができるんですけど、それも同じように実体が消えたとしてもアクセスできます。
UNIX/Linux ではオープン中のファイルがファイルシステム上から削除されても、ディレクトリツリーからは見えなくなるだけで、ディスク上には残ってて、そのファイルをオープンしているプロセスがすべて死んだら、ディスク上の領域からもなくなります。
/proc
はカーネル内の管理領域をファイルシステムとして見せている特殊なファイルシステムだから、こういうこともできるんですかねー。
ところでやっぱりこれは Linux だけでしか通用しないみたいです。
ちなみに NetBSD でも Linuxバイナリ互換用に /proc/$PID/exe はあるんですが(ただし NetBSD では /proc は optional なので、必ずしもマウントされているとは限りません)、削除されてなければ実行できるものの、削除されたらダメでした。
— SODA Noriyuki (@n_soda) 2017年10月25日
おまけ
言い出しっぺの人が全然反応ないなーと思ってたら…。
メモリ上に自分自身の実行バイナリを再構築(してそれを exec)って、Quine じゃん!って言ってほしかっただけとは言えない雰囲気
— Yusuke Endoh (@mametter) 2017年10月25日