読者です 読者をやめる 読者になる 読者になる

デーモンの仕組み

デーモンはバックグラウンドで動き、terminalからインタラクティブに操作されることがないプロセスである。起動時に開始し、rootユーザやapachepostfixなどの特権ユーザにより動かされる。systemdで操作するcrondとかsshdとかのことである。

デーモンは一般的に、initプロセスの子プロセスとして動く、terminalから接続されないという2つの要件を満たしている。initプロセスとはシステム起動後にカーネルが最初に実行するプロセスでこのpidは1である。

以下のようにしてデーモンは起動される。

  1. fork()を呼び、デーモンとなる新しいプロセスを作る。
  2. デーモンの親プロセスがexit()を呼んで終了する。親プロセスがすぐに死に、デーモンはプロセスグループのリーダーにならない。
  3. setsid()を呼び、デーモンに新しいプロセスグループとセッションを与え、デーモンがリーダーになるようにする。これによりプロセスを制御するterminalがないことも保証できる。
  4. chdir()でワーキングディレクトリをrootディレクトリに変更する。これはデーモンが他のディレクトリを使用中にしないようにするため、adminにワーキングディレクトリをunmountされることを避けるためである。
  5. 全てのファイルディスクリプタを閉じる。機能的に必要であればそこは開けておく。
  6. ファイルディスクリプタの0(stdin)、1(stdout)、2(stderror)を開き/dev/nullにリダイレクトする。

これらに基づき、デーモン化するコードは以下のようになる。このコードはLinuxシステムプログラミング | Robert Love, ロバート ラブ, 千住 治郎より拝借した。

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fs.h>

int main (void)
{
 pid_t pid;
 int i;

 /* forkして新しいプロセスを作る */
 pid = fork();
 if (pid == -1)
  return -1;
 else if (pid != 0)
  exit(EXIT_SUCCESS);

 /* 新しいセッションとプロセスグループを作る */
 if (setsid() == -1)
  return -1;

 /* ワーキングディレクトリをルートに変更 */
 if (chdir("/") == -1)
  return -1;

 /* NR_OPENを使って全てのファイルディスクリプタを閉じる */
 for (i = 0; i < NR_OPEN; i++)
  close(i);

 /* ファイルディスクリプタ 0, 1, 2を /dev/nullにリダイレクト */
 open("/dev/null", O_RDWR); /* stdin */
 dup(0); /* stdout */
 dup(0); /* stderror */

 return 0;
}

デーモンを生成する関数はglibcではdaemon()として実装されている。