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

のぴぴのメモ

自分用のLinuxとかの技術メモ

デーモンは2度forkするのが作法らしい

Cプログラム Linux

デーモンプロセス起動時の作法

デーモンを起動する場合、2度forkするのが作法らしく、これは「セッションリーダにならないようにすることで端末の制御を誤ってしないように」ということらしい。

詳しくはこちらを参照

そうなのかぁと思いながら、見よう見まねでdaemonの関数を作ってみました。

サンプルプログラム

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

static pid_t do_daemon(int close_interface)
{

        pid_t ret;
        int   fd;

        /*create child process and terminate parent process*/
        ret = fork();
        if( ret < 0 ){
                /* fork error */
                perror("Cannot fork");
                return(-1);
        }else if( ret != 0 ){
                /* parent process */
                return(ret);

        }
        /* child process */

        /* change chiled process to session gruop reader */
        ret = setsid();
        if( ret < 0 ){
                perror("Cannot create a session");
                return(-1);
        }

        /* create 2nd child process and terminate parent process again
         * to never connect terminal
         */
        ret = fork();
        if( ret < 0 ){
                /* fork error */
                perror("Cannot fork");
                return(-1);
        }else if( ret != 0 ){
                /* parent process */
                return(ret);
        }

        /* change the current directory to root directory */
        (void) chdir("/");

        /* close stdin/stdout/stderr */
        fd = open("/dev/null", O_RDWR);
        if( fd < 0 ){
                perror("Cannot open NULL device");
                return(-1);
        }

        /* close the STDIN file descriptor */
        if ((fd != STDIN_FILENO) && (dup2(fd, STDIN_FILENO) < 0)){
                perror("Cannot close the STDIN");
                (void)close(fd);
                return(-1);
        }

        /* close the STDOUT and STDERR file descriptor, if option is TRUE */
        if( close_interface ){
                /* close the STDOUT file descriptor */
                if ((fd != STDOUT_FILENO) && (dup2(fd, STDOUT_FILENO) < 0)) {
                        perror("Cannot close the STDOUT");
                        (void)close(fd);
                        return(-1);
                }

                /* close the STDERR file descriptor */
                if ((fd != STDERR_FILENO) && (dup2(fd, STDERR_FILENO) < 0)) {
                        perror("Cannot close the STDERR");
                        (void)close(fd);
                        return(-1);
                }
        }

        if( fd > STDERR_FILENO ){
                (void)close(fd);
        }

        /* daemon complete */
        return(0);

}

でもudevとかsyslogdとかのソースを見ると、案外fork一度しかやってなかったりするんだけどね。