技術しばらくLinuxネタが続く・・。近いうちに最近出たJava8ネタを書いてみようと思います。Linuxネタにお付き合いください。前回はsshdを対象に親プロセスをkillした場合の動作を確認した。killされたプロセスの子プロセスは孤児プロセスとなり、カーネルによって自動的にinitプロセスの子として扱われる事を説明した。(この動作を「リペアレンティング」と呼ぶ)今回はこの続き。Linuxで作業していてCtrl+Cしてプロセスを終了した場合、フォアグラウンドのプロセスやその子プロセスも一緒に終了する。いうことは、子プロセスは孤児として扱われず、リペアレンティングされていないことになる。-SIGINTコマンドとCtrl+Cの違いについて考えていく。そもそもkillコマンドやCtrl+Cは何をしているのか?プロセスに対してシグナルを送っている。シグナルとはプロセス間通信の一種で、他のプロセスに対してイベントを通知することができる仕組みだ。シグナルを受け取ったプロセスは現在実行中の処理を中断し、シグナルに応じた処理を実行する。killコマンドは特定のプロセスにシグナルを送ることができるし、Ctrl+Cはフォアグラウンドで起動中のプロセスに対するシグナル送信を行う。やり方は違っても、killや、Ctrl+Cはプロセスに対してシグナルを送っている点で同様なのだ。以下はよく使うシグナルの一覧だ。割り込み(Interrupt)の発生。プロセスの一時停止(フォアグラウンドプロセスをバックグラウンドに移す場合によく使う)シグナル受信時のプロセスの振る舞い注意が必要なのは、シグナル受信時の振る舞いは個々のプロセスの実装によるということだ。SIGINTシグナルを受け取ったからといって必ずプロセスが終了するかというとそうではない。シグナル受信時の振る舞いはプロセスの実装次第であり、”プロセスが終了する”というのはあくまでデフォルトの動作であって、実装指針でしかない。SIGKILLは特別SIGKILLシグナルだけは例外で、実装に依存しない。外部から強制的にプロセスを終了するため、個々のプロセスでこの振る舞いを変えることはできない。プロセス終了の最終手段な訳だが、正常な終了処理が実行されないため、実行以後予期せぬトラブルを招く可能性がある。いうことで、SIGKILLのご利用は計画的に!(そもそもSIGKILLの利用を計画している時点で間違いだが・・・)問題の動作を確認!プロセスをforkしてkill!それでは問題の振る舞いについて確認してみよう。検証に使うコード今回は検証用のコードとして以下の簡単なRubyコードを利用する。#{Process.pid}"#勝手に終了しないようにスリープsleeprubyのforkメソッドはプロセスをforkし、その子プロセスにブロック内のコードを実行させる。ブロック内の処理終了と同時に子プロセスを解放する。上記のコードは4〜8行目は子プロセスによってのみ実行され、10行目以降は親プロセスによってのみ実行されることになる。└──ruby(5663)となり、rubyプロセスに親子関係ができていることが分かる。親、子プロセスともsleepしているので、待機している状態だ。これで好き放題シグナルが送れる!やってみよう!では、Rubyの親プロセスに対してkillとCtrl+Cを実行し、それぞれの振る舞いを比較してみよう。Ctrl+Cで送るシグナルはSIGINTなので、killコマンドはオプションに-SIGINTを付けて比較する。Ctrl+Cする場合Ruby検証用コードをフォアグラウンドで起動させ、Ctrl+Cしてみる。#rubyプロセスなしCtrl+Cした後、rubyのプロセスは残っていなかった。Ctrl+Cすることによって、親子両方のプロセスが消滅した。-SIGINTする場合Ruby検証用コードをバックグラウンドで起動し、killコマンドでシグナルを送ってみる。├─ruby(5764)子プロセス(5764)が生き残り、親プロセスがinitになった。子プロセスは孤児プロセスとして扱われ、リペアレンティングされた。-SIGINTした場合は子プロセスのみ生き残った。どちらのコマンドも親プロセスに対してSIGINTシグナルを送っている点は同じである。このような振る舞いの違いが生まれたのだろうか?プロセスグループと端末(tty/pts)の仕様この振る舞いはプロセスグループと端末(tty/pts)の仕様が関係している。プロセスグループと、端末(tty/pts)について説明する。プロセスグループとは??プロセスグループとはLinux/Unixにおけるプロセス管理の仕組みであり、複数のプロセスを束ねた集合のことである。通常、プロセスをforkして子プロセスを作成した場合、親、子プロセスは同一プロセスグループに所属する。子がさらに子をforkしてもこれらはすべて同一の親にぶら下がる一つのグループとして扱われる。このプロセスグループはpsコマンドで確認できる。COMMAND|rubypsコマンド実行結果のPGID列を見て欲しい。今回rubyプロセス5909、5910は双方ともPGID列が5909となっている。これはこれらのプロセスが同一のプロセスグループ「5909」に所属していることを表している。通常、プロセスグループIDは親プロセスのプロセスIDと同様の値が割り当てられる。これらの2プロセスは、カーネル上同一グループに属するプロセスとして取り扱われる。端末って??tty?pts?次に端末やttyやptsについて解説する。端末とは?端末とはLinuxに対する標準入力や標準出力をLinuxと仲介する役割を担っている。キーボードで入力した文字列を標準入力としてLinux/Unixに渡す、標準出力をコンソール上に表示するなどといった動作だ。ttyやptsは両方とも端末の事を指している。ttyとptsの違いは?Linuxに直接接続している場合に使われる端末はttyであり、telnetやsshなど、遠隔地から接続している場合に利用される端末はptsである。現在利用している端末は「tty」コマンドで確認できる。tty/dev/tty1のように表示される。遠隔地から接続する場合はpts、直接接続はttyを経由していることが分かる。端末が分かればこんなイタズラもできるちなみに、標準入力や標準出力を仲介する役割があるということは、次のようなイタズラもできる。「/dev/pts/1」「/dev/pts/2」を経由し、2ユーザがLinuxに接続しているとする。このファイルに標準出力をリダイレクトすることで、相手の端末上に文字列を表示できる。シャットダウンする!早く接続を切れ!間に合わなくなってもしらんぞーーーっ!!!と勝手に表示され、pts2ユーザはいきなりベジータからのシャットダウン警告を受けることにってしまう訳だ。これは接続を切らざるを得ないだろう。Ctrl+Cの正体ここまで来れば、Ctrl+Cの正体まであと一歩だ。端末は標準入力を受け付け、Linuxに渡す役割を持っていた。キーボードでCtrl+Cを入力した際、このCtrl+C入力情報は端末に受け渡され、対応するシグナルに変換されてプロセスに通知される。-a」コマンドで確認できる。echokeこの結果ではCtrl+C(^C)に対して「intr」が割り当てられている。(3行目の先頭)つまり、端末はCtrl+Cを受け取った場合、SIGINTシグナルをプロセスに送っていることが分かる。-SIGINTの違い以上の内容を元に、違いをまとめる。どちらもプロセスにSIGINTシグナルを送っている点は同じだ。指定されたプロセスにSIGINTシグナルを送信やっていることは二つとも同じだが、異なる点が一カ所だけある。それは”シグナルを送信するプロセス”だ。-SIGINTのシグナル送信先をまとめると以下の通りである。フォアグラウンドで動作するプロセスのプロセスグループに属する全プロセスに対して送信killコマンドは特定のプロセスにのみ送信するのに対し、Ctrl+Cはプロセスグループ全体にシグナルを送信している。以下のようなイメージとなる。-SIGINTもCtrl+CもSIGINTシグナルを送信している点は同じであるが、送っているプロセスの範囲が異なるという訳だ。killした場合は特定のプロセスに対してのみシグナルが送られるのに対し、Ctrl+Cした場合は、入力情報が端末でSIGINTに変換され、プロセスグループ全体に送信される。これをrubyの実行結果で考えてみると、Ctrl+Cした場合、親rubyプロセスにぶら下がる子プロセスはすべて終了しているため、そもそもリペアレンティング対象となるプロセスが存在しない状態となっていた訳だ。-SIGINTした場合は子プロセスは生き残っているから、カーネルによって子プロセスのリペアレンティングが行われた。これが前述の振る舞いの違いの正体だ。今回は随分長丁場になった。Linux/Unixのプロセス管理の考え方としてプロセスグループとは別に「セッション」という考え方がある。セッションはプロセスグループよりも更に範囲を広くしたプロセス管理のグルーピングのことだ。いう場面で役立っているのか、近々まとめてみようと思う。ーシステム起動編ー2014年6月10日、とうとうRHEL7が正式リリースを迎えた。前回の記事「Systemd」を理解するーシステム起動編ーでは、Systemdの概念とSystemdに記事を読むJava8のインタフェース実装から多重継承とMixinを考える2014年3月18日、ついにJava8が正式にリリースを迎えた。今回も前回の記事につづき、Java8による変更点で未だあまり紹介されていないポイントを記事にしようと記事を読むsshd再起動時にssh接続が継続する動作についてLinux/Unixサーバにsshしている際、sshdを再起動したとする。ギークを目指して:メモ。結果に影響を与えないような気がしました。14:59匿名様コメントありがとうございます。/dev/pts/2」の部分は私の確認が不足していたようです。この点をクリアにするために以下の2点を補足させていただきます。補足1.tty/ptsファイルの所有者、グループ、およびパーミッションtty/ptsデバイスファイルは以下のルールで所有者、グループとパーミッションが設定されます。(検証環境はCentOS6.5、およびCentOS7です)所有者:接続したユーザグループ:ttyパーミッション:crw–w—-パーミッションを見ると所有者による読み込みと書き込みを許可している一方で、グループは書き込みのみ、その他ユーザは権限が一切与えられていないことが分かります。そのため、ttyにリダイレクトしてイタズラしたい場合、リダイレクト先ttyを利用しているユーザが、”同一ユーザ”、もしくは”同一グループ”でない限り、リダイレクトが権限違反により失敗してしまいます。これを実施するためには、”特権でリダイレクトを実施する”か、”tty/ptsのパーミッションを変更する”必要があります。今回紹介した例では前者の方法を用いましたが、以下「補足2」に記載する理由で、実はこれでもうまくいきません。補足2.sudoでリダイレクトした際に適用される権限sudoを利用した場合であっても、リダイレクトは実行元のユーザで実行(権限が戻ってしまう)されてしまいます。(この辺はsudoのmanに記載されています)そのため、tty/ptsへ文字列をリダイレクトできません。リダイレクトも含めて特権を適用したい場合はサブシェルを利用する必要があります。いうことで、次のコマンドを利用することで別ユーザへのtty/ptsによるイタズラを実行できるでしょう。プロセスグループにシグナル送れますよ。12:07とても分かりやすい解説でした。参考にさせていただきました。12:08とても分かりやすい解説でした。参考にさせていただきました。コメントをキャンセルメールアドレスが公開されることはありません。ーシステム起動編ー2014年6月10日、とうとうRHEL7が正式リリースを迎えた。