はじめに
※言わずもがな、お約束の自己責任でお願いします
かの有名なFork爆弾。Bashなら以下です。
:(){ :|: & };:
この原理が今一つピンとこなかったので、今さらながら **動作確認がてら(!)**解析してみました。
順番通り(悪く言えばダラダラと)記載していますので、単に読み物(ポエム)としてお読みいただければありがたいです。
本編
読みやすく改変して投下
:
の代わりに、関数名としてbomb
を使います。
bomb() { bomb | bomb & }; bomb
投下で見事に炸裂、再起動が必要となりました。まずは成功?です!
フォアグラウンドで実行してみる
いちいち再起動するのは面倒なので、フォアグラウンドにしてみましょう。
bomb() { bomb | bomb ; }; bomb
こちらも同様に炸裂していますが、Ctrl+C、もしくはターミナルを閉じると何とか復帰できるようです。
解析のため、このフォアグラウンド実行は継続します。
スリープしてみる
同じく解析に手間取りそうなので、10秒くらい待ってみます。
bomb() { sleep 10 ; bomb | bomb ; }; bomb
別のターミナルで確認すると、ゆっくり破滅に向かっていくことが確認できます。
(以下の-bash
とsleep 10
が時間とともにわらわら増えていく)
user@user-VirtualBox:~$ ps -f -u user | grep pts/2
user 25428 25363 0 15:54 ? 00:00:00 sshd: user@pts/2
user 25429 25428 0 15:54 pts/2 00:00:00 -bash
user 26605 25429 0 15:56 pts/2 00:00:00 -bash
user 26606 25429 0 15:56 pts/2 00:00:00 -bash
user 26607 26606 0 15:56 pts/2 00:00:00 sleep 10
user 26608 26605 0 15:56 pts/2 00:00:00 sleep 10
user 26612 25777 0 15:56 pts/3 00:00:00 grep --color=auto pts/2
ログを仕込む
foo
というファイルにログを出すようにしてみます。
まだワンライナーで読めますね。
bomb() { sleep 10 ; echo `date +%H:%M:%S.%3N`: Throw 2 bombs... >> foo ; bomb | bomb ; }; bomb
別ターミナルでのログの確認結果:
user@user-VirtualBox:~$ tail -f foo
16:15:14.374: Throw 2 bombs...
16:15:24.378: Throw 2 bombs...
16:15:24.379: Throw 2 bombs...
16:15:34.384: Throw 2 bombs...
16:15:34.385: Throw 2 bombs...
16:15:34.388: Throw 2 bombs...
16:15:34.389: Throw 2 bombs...
何とも素晴らしいログ(自画自賛)!
- 16:15:14に2個投下
- 16:15:24に2 + 2 = 4個投下
- 16:15:34に2 + 2 + 2 + 2 = 8個投下
よって、倍々ゲームで爆弾(プロセス)が増えていることが明確になりました!
10秒スリープしていなかったらと思うと恐ろしいですね!笑
1個にしてみる
誰しも疑問に思うであろう(ですよね?)、1個ならどうなの?です。
bomb() { sleep 10 ; echo `date +%H:%M:%S.%3N`: Throw a bomb... >> foo ; bomb ; }; bomb
ログは当然の結果:
user@user-VirtualBox:~$ tail -f foo
16:28:09.661: Throw a bomb...
16:28:19.664: Throw a bomb...
16:28:29.668: Throw a bomb...
プロセスの確認結果は以下(適当に間隔を空けて確認しています):
user@user-VirtualBox:~$ ps -f -u user | grep pts/2
user 25428 25363 0 15:54 ? 00:00:00 sshd: user@pts/2
user 25429 25428 0 15:54 pts/2 00:00:00 -bash
user 26743 25429 0 16:28 pts/2 00:00:00 sleep 10
user 26746 25777 0 16:28 pts/3 00:00:00 grep --color=auto pts/2
user@user-VirtualBox:~$ ps -f -u user | grep pts/2
user 25428 25363 0 15:54 ? 00:00:00 sshd: user@pts/2
user 25429 25428 0 15:54 pts/2 00:00:00 -bash
user 26748 25429 0 16:28 pts/2 00:00:00 sleep 10
user 26750 25777 0 16:28 pts/3 00:00:00 grep --color=auto pts/2
user@user-VirtualBox:~$ ps -f -u user | grep pts/2
user 25428 25363 0 15:54 ? 00:00:00 sshd: user@pts/2
user 25429 25428 0 15:54 pts/2 00:00:00 -bash
user 26754 25429 0 16:28 pts/2 00:00:00 sleep 10
user 26756 25777 0 16:28 pts/3 00:00:00 grep --color=auto pts/2
user@user-VirtualBox:~$
大元の-bash
プロセスはずっと生きていて、sleep 10
プロセスが別個に起動していることがわかります(26743
→26748
→26754
)。
すなわち、新しいプロセスは起動しているが、都度前のプロセスが終わっているので、増殖しないということかと。
平たく言ってしまえば、単にbombを繰り返す無限ループですね。
パイプからセミコロンにしてみる
では2つの爆弾の間を、|
でなく;
にしたらどうなるでしょうか。
bomb() { sleep 10 ; echo `date +%H:%M:%S.%3N`: Throw 1st bomb... >> foo ; bomb ; echo `date +%H:%M:%S.%3N`: Throw 2nd bomb... >> foo ; bomb ; }; bomb
user@user-VirtualBox:~$ tail -f foo
16:42:05.384: Throw 1st bomb...
16:42:15.387: Throw 1st bomb...
16:42:25.390: Throw 1st bomb...
2nd bomb
まで到達していませんね。これは1st bomb
をひたすら繰り返しているためで、実体は爆弾1個の場合と同じです。
おわりに
感想(ポエム)
百聞は一見にしかず。愚直な方法ではありましたが、また一つ賢くなりました。笑
確認環境
- Ubuntu 18.04 LTS(をVMで)