ログイン
編集不可のページディスカッション情報添付ファイル

2015-05-09 02:55:13時点のリビジョン1

メッセージを消す
moba/cttyhack

MMA

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だけでなく

の3つがある。

さて、ジョブコントロールを行うためには「本物」の制御端末でなければならない。これを探してくれるのがcttyhackコマンド。このコマンドは「本物」の制御端末を探してその端末を現在の端末に設定してくれるコマンド。このコマンドを使うことで「本物」の端末を制御してくれる。

しかし、cttyhackを行っても依然としてcan't access ttyと怒られてジョブコントロールを切られた状態で/bin/shが起動してしまう。これはttyを制御端末にするために満たすべき次の条件のうち、cttyhackが2番めの条件のみを解決するため。

  1. セッションオーナーかつプロセスグループリーダーである
  2. 現在の端末が「本物」の制御端末であること
  3. ^Cや^Zなどが入力できる

  4. 標準入力の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がジョブコントロールできるようになる