サイズ: 3887
コメント:
|
← 2015-05-09 03:02:26時点のリビジョン5 ⇥
サイズ: 3968
コメント:
|
削除された箇所はこのように表示されます。 | 追加された箇所はこのように表示されます。 |
行 6: | 行 6: |
と怒られて、/bin/shでジョブコントロールが切られた状態で/bin/shが起動する。このままだと{{{^}}}C(SIGINT)とか{{{^}}}Z(SIGTSTP)とかができないために、pingコマンドなど、無限ループするようなプログラムを起動してしまうと、シグナルをプログラムに送ることができないため、Ctrl-Alt-Delで再起動するしかなくなる。これはttyコマンドを叩いてみるとわかるが、制御端末が/dev/consoleに設定されているため。/dev/consoleはLinuxがカーネルが起動時にメッセージなどを出力するための端末で、「本物」の制御端末ではない。これはLinuxカーネルのソース上でブートするときのプロセスなどをシグナルによって止めるられることを防御するためにそのような設計になっているよう。ちなみに/dev/console以外にも制御端末としてなれないのは/dev/consoleだけでなく | と怒られて、/bin/shでジョブコントロールが切られた状態で/bin/shが起動する。このままだと{{{^}}}C(SIGINT)とか{{{^}}}Z(SIGTSTP)とかができないために、pingコマンドなど、無限ループするようなプログラムを誤って起動してしまうと、シグナルをプログラムに送ることができないため、Ctrl-Alt-Delで再起動するしか道がなくなる。これはttyコマンドを叩いてみるとわかるが、制御端末が/dev/consoleに設定されているために怒られる。/dev/consoleはLinuxがカーネルが起動時にメッセージなどを出力するための端末で、「本物」の制御端末ではない。これはLinuxカーネルのソース上でブートするときのプロセスなどをシグナルによって止めるられることを防御するためにそのような設計になっているよう。ちなみに/dev/console以外にも制御端末としてなれないのは/dev/consoleだけでなく |
行 25: | 行 25: |
setsidはプログラム名を引数にとって新しいセッションを開いてプログラムを実行するコマンド。内部でfork()した子プロセスが、setsid()システムコールによって新しいセッションを開く。親プロセスは子プロセスがsetsid()システムコールを発行する前に終了してしまうため、setsid(2)のマニュアルにも書いてあるとおり、子プロセスが新しく開いたセッションのオーナーとなる。更に、開いたセッションでは子プロセスのみが存在しているため子プロセスがプロセスグループのリーダーとなる。この状況で、execvp()システムコールで指定されたコマンドを実行することでsetsidコマンドで指定されたコマンドがセッションオーナーかつプロセスグループリーダーとなるようになっている。 | setsidはプログラム名を引数にとって新しいセッションを開いてプログラムを実行するコマンド。内部でfork()した子プロセスが、setsid()システムコールによって新しいセッションを開く。親プロセスは子プロセスがsetsid()システムコールを発行する前に終了してしまうため、setsid(2)のマニュアルにも書いてあるとおり、子プロセスが新しく開いたセッションのオーナーとなる。更に、開いたセッションでは子プロセスのみが存在しているため子プロセスがプロセスグループのリーダーとなる。この状況で、execvp()システムコールで指定されたコマンドを実行することでsetsidコマンドで指定されたコマンドがセッションオーナーかつプロセスグループリーダーとなるようになっている。以上でsetsidコマンドによって1番目の条件が満たされる。 |
行 27: | 行 27: |
setsidコマンドによって1番目の条件が満たされるため、/bin/shがジョブコントロールできるようになる。 | 以上の手順を踏むことで起動した/bin/shでジョブコントロールができるようになる。 |
initramfsで/bin/shのジョブコントロール
initramfsのシェル環境でそのまま/bin/shを起動すると、
/bin/sh: can't access tty; job control turned off
と怒られて、/bin/shでジョブコントロールが切られた状態で/bin/shが起動する。このままだと^C(SIGINT)とか^Z(SIGTSTP)とかができないために、pingコマンドなど、無限ループするようなプログラムを誤って起動してしまうと、シグナルをプログラムに送ることができないため、Ctrl-Alt-Delで再起動するしか道がなくなる。これはttyコマンドを叩いてみるとわかるが、制御端末が/dev/consoleに設定されているために怒られる。/dev/consoleはLinuxがカーネルが起動時にメッセージなどを出力するための端末で、「本物」の制御端末ではない。これはLinuxカーネルのソース上でブートするときのプロセスなどをシグナルによって止めるられることを防御するためにそのような設計になっているよう。ちなみに/dev/console以外にも制御端末としてなれないのは/dev/consoleだけでなく
- /dev/tty0
- /dev/tty
- PTYのマスター側
の3つがある。
さて、ジョブコントロールを行うためには「本物」の制御端末でなければならない。これを探してくれるのがcttyhackコマンド。このコマンドは「本物」の制御端末を探してその端末を現在の端末に設定してくれるコマンド。このコマンドを使うことで「本物」の端末を制御してくれる。
しかし、cttyhackを行っても依然としてcan't access ttyと怒られてジョブコントロールを切られた状態で/bin/shが起動してしまう。これはttyを制御端末にするために満たすべき次の条件のうち、cttyhackが2番めの条件のみを解決するため。
- セッションオーナーかつプロセスグループリーダーである
- 現在の端末が「本物」の制御端末であること
^Cや^Zなどが入力できる
- 標準入力のttyを制御端末にすることができる
2番目の条件は満たされているが、1番目の条件が満たされていないので、/bin/shはジョブコントロールを制御できない。つまり、/bin/shをセッションオーナーかつプロセスグループリーダーにすればこの問題は解決する。
/bin/shをセッションオーナーかつプロセスグループリーダーにするにはsetsid(1)を次のように実行すればプログラムをセッションオーナーかつプロセスグループリーダーに変更することができる。
1 setsid cttyhack /bin/sh
setsidはプログラム名を引数にとって新しいセッションを開いてプログラムを実行するコマンド。内部でfork()した子プロセスが、setsid()システムコールによって新しいセッションを開く。親プロセスは子プロセスがsetsid()システムコールを発行する前に終了してしまうため、setsid(2)のマニュアルにも書いてあるとおり、子プロセスが新しく開いたセッションのオーナーとなる。更に、開いたセッションでは子プロセスのみが存在しているため子プロセスがプロセスグループのリーダーとなる。この状況で、execvp()システムコールで指定されたコマンドを実行することでsetsidコマンドで指定されたコマンドがセッションオーナーかつプロセスグループリーダーとなるようになっている。以上でsetsidコマンドによって1番目の条件が満たされる。
以上の手順を踏むことで起動した/bin/shでジョブコントロールができるようになる。