デーモンは、UNIX系のOSにおいて、バックグラウンドで起動され、サーバプロセスとして動作するプログラムのことです。
一般的にはシステムの起動時に起動され、常駐します。
Wikipediaによれば、技術的には以下の定義だそうです。
UNIXは親プロセスの番号が 1 (init) で、制御端末を持たないプロセスをデーモンと認識する。
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
int daemon(int nochdir, int noclose)
{
int fd;
switch (fork()) { // (1)forkして親プロセスを終了
case -1:
return (-1);
case 0:
break;
default:
_exit(EXIT_SUCCESS);
}
if (setsid() == -1)
return (-1); // (2)sesidして端末制御を切り離す
if (nochdir == 0)
(void)chdir("/"); // (3)chdirで作業ディレクトリを"/"へ
if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
// (4) 標準入出力、エラー出力を"/dev/null"へリダイレクト
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
(void)close(fd);
}
return (0);
}
【説明】
(1)forkして親プロセスを終了
setsid可能にするのと、親プロセスをinitにするため、fork(2)で子プロセスを起動し、fork元の親プロセスを終了します。
子プロセスは親プロセスがリーダのプロセスグループに属すため、グループリーダでないことが保証されます。
親プロセスが終了することで自動的にinitの子プロセスになります。
(2)sesidして端末制御を切り離す
端末制御(tty制御)を切り離すため、setsid(2)します。
これにより新たなセッションとプロセスグループが作成され、それぞれのリーダーとなります。
端末制御を切り離さないと、端末が終了した時に、自分も終了してしまいます。
ただし、自分がセッションリーダなので、再度端末制御を取得することが可能だそうです。(方法不明getty?)
そのため、厳密にするなら再度forkして親を終了させ、セッションリーダでなくした方がよいようです。
(3)chdirで作業ディレクトリを"/"へ
アンマウントされないディレクトリを作業ディレクトリ(カレントディレクトリ)とするため、chdir(2)で"/"に移動します。
アンマウントするファイルシステムを作業ディレクトリとするプロセスがいると、アンマウントできないためです。
(4)標準入出力、エラー出力を"/dev/null"へリダイレクト
端末制御を持たないため、標準入力、標準出力、標準エラー出力を/dev/nullにします。
上記の実装は以下のとおりですが、厳密には/dev/nullへも出力せず、完全にクローズするのが本来の定義のようです。
また、forkしても親プロセスがオープン中のファイルを引き継ぐため、それらもcloseすべきです。
なので、(4)は以下のようにするとよいかもしれません。
int fdmax = sysconf(_SC_OPEN_MAX); // プロセスオープン
for(int fd=0; fd < fdmax; fd++){
close(fd);
}
以上でデーモンとして動作可能です。
なお、上記にサンプルの関数は、Linuxだとdaemon(3)としてすでに存在します。
また、上記以外にも、以下も要件に応じて実装するとよいかもしれません。
(5)SIGCHLDの無視
子プロセスを生成した場合、子プロセス終了時にゾンビにならないよう、wait()またはwaitpid()で終了の刈り取りが必要です。
デーモンは子プロセスを起動するが、処理の都合でwaitできない場合は、以下でSIGCHLDシグナルを無視してゾンビ化を防ぎます。
signal(SIGCHLD, SIG_IGN); // signal(2)よりsigaction(2)が推奨
または
sigaction (SIGCHLD, &sa, NULL); // sigaction構造体(&sa)でSIGCHLDを無視に設定。
(6)ファイル生成マスク値の変更
ファイル生成マスク値(umask値)は親プロセスから引き継がれます。
Linuxではumask値は022がデフォルトですが、設定または元の親プロセスにより変更されている可能性があります。
以下でumask値を0にすることで、openなどで引数に指定したパーミッションがそのまま付与されるようになります。
umask(0)
最終更新:2010年08月15日 11:47