2008年1月7日月曜日

lsof

特定のポートをオープンしているプロセスを調査する。
(日 1月 06 11:38:29) root@R60e:~: lsof -i:22
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
sshd 6514 root 3u IPv6 25503 TCP *:ssh (LISTEN)
(日 1月 06 11:39:15) root@R60e:~:
(日 1月 06 11:39:15) root@R60e:~: lsof -i:8899
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
tst020 6311 indou 3u IPv4 22535 TCP *:8899 (LISTEN)
(日 1月 06 11:40:34) root@R60e:~:

デーモンプログラムの作成方法


デーモンプログラム

  1. fork()、その後親プロセス終了。
  2. プログラムを起動したシェルに制御が戻る。
  3. このfork()は新しいプロセスが プロセスグループリーダーにならないようにするため。 setsid()はプロセスグループリーダーだと失敗する。
  4. setsid()によりプロセスグループとセッショングループのリーダーとなる。制御端末はセッションに関連づけらている。この新しいセッショ ンは制御端末を持たない。そのためこのプロセスは制御端末を持たない。
  5. fork()して、親プロセス(セッショングループリーダー)は終了。デーモンが、セッショングループリーダーでないので、以後制御端末 を持つことがない。
  6. chdir("/")。ファイルシステムを アンマウント出来ないことを避ける。
  7. umask(0)として、書き出すあらゆるファイルのパーミッションを制御。 やらなくてもいいけど。
  8. ファイルディスクリプタ0、1、2をclose()。親プロセ スから引き継いだ標準入力、出力、エラー出力を解放する。これらのファ イルディスクリプタがどこかにリダイレクトされているかどうか分からな いため。制限値_SC_OPEN_MAXを知るために多くのデーモンが sysconf()を用いていることに注意してください。_SC_OPEN_MAXはプロセス 当たりの最大ファイルオープン数です。次にループに入り、全ての有り得 るファイルディスクリプタをクローズ。同時に使えるファイルディスクリプタの数 には限りがあるため、オープンされているファイルディスクリプタがあり 得るとなら、それらをクローズする。
  9. stdin、stdout、stderr用に新しいディスクリプタをオープン。例えば、stdoutか stderrとしてそれをオープンし、stdinには`/dev/null'オープン。または、`/dev/console'をstderrと/またはstdoutとし てオープンし、`/dev/null'をstdinとする。

デーモンがinetdから起動されるものの場合は、 これらの手順は不要。その場合、 stdin、stdout、stderrは既にどれもネットワーク接続を対象として 設定されていますし、 fork()やセッション操作はするべきではない (inetdを混乱させることを防ぐ)。 chdir()umask()のステップだけは必要。

親プロセスは forkし、そ こで wait し、子プロセスが死ぬのを待つ。子プロセスはさらに fork し、孫プロセスを作る。そこで子プロセスは直ちに終了し(すると親 は、その死の知らせを待っていたので、実行を続ける)、もともと子がやるは ずだった仕事を孫が行なう。親が死んでいるので、孫は init に継承され、 必要な wait などを行なってくれる。この方法は余分な fork を行なうので 非効率だが、移植性は完璧。

WebSiteから要約。

デーモンの作り方

上記サイトに詳しい解説がありますが、デーモンは、制御端末を持たず、独立したセッションで動くバックグラウンドプロセスです。

  1. fork() し、親プロセス(Webサーバに起動されたプロセス)はすぐに終了します。次のsetsid() の呼び出しを成功させるために必要です。
  2. 子プロセスで setsid() を呼び出します。新しいセッションが作られ、そこのセッションリーダ兼プロセスグループリーダになります。
  3. セッションリーダは後から制御端末を得ることができるため、もう一度 fork() し、親プロセスはすぐに終了します。
  4. chdir("/") します。プロセスが握っているディレクトリはunmountできないので、邪魔にならないようにします。
  5. umask(0) するか、しないか。
  6. stdin, stdout, stderr を close() します。