/*
    デーモン作法サンプルスケルトン
    test2d.c
    by J.r0ck
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

#define _PATH_DEVNULL   "/dev/null"
#define STDIN_FILENO    0
#define STDOUT_FILENO   1
#define STDERR_FILENO   2

#define WAIT_TIME       10
#define LOGFILENAME     "/tmp/test.log"

/*
    デーモン初期化
*/
int
init_daemon(nochdir, noclose)
    int nochdir, noclose;
{
    int fd;

    switch (fork()) {
    case -1:
        return errno;
    case 0:
        /* 子プロセスをターミナルから切り離す */
        if (setsid() == -1)
            return errno;
        break;
    default:
        exit(0);
    }

    /* System V系セッションリーダーでなければ制御端末を再取得
       できないのでこれを保証するためには更にforkが必要 */
    switch (fork()) {
    case -1:
        return errno;
    case 0:
        break;
    default:
        exit(0);
    }

    /* ファイルシステムがumountできるような配慮 */
    if (!nochdir)
        chdir("/");

    /* STDIN、STDOUT、STDERRを閉じておく */
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    /* ファイルシステムがumountできるような配慮 */
    if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
        dup2(fd, STDIN_FILENO);
        dup2(fd, STDOUT_FILENO);
        dup2(fd, STDERR_FILENO);
        if (fd > 2)
            close(fd);
    }
    return 0;
}

/*
    イベント待ち
    この処理はダミー
*/
int
wait_event(int debug_mode)
{
    FILE    *fp = NULL;
    char    buf[256];
    int     ret_code = 0;

    while(1) {
        /* 待ち */
        sleep(WAIT_TIME);

        /* 処理：ここではファイルに1行出力 */
        if((fp = fopen(LOGFILENAME, "a")) == NULL) {
            ret_code = errno;
            perror("fopen");
            break;
        }

        sprintf(buf, "%d - processed\n", time(NULL));
        fputs(buf, fp);
        if(fclose(fp) == EOF) {
            ret_code = errno;
            perror("fclose");
            break;
        }
        if(debug_mode) {
            printf(buf);
        }
        /* --->ここまで処理 */
    }
    return ret_code;
}

/*
    メイン
*/
int
main(int argc, char *argv[])
{
    int debug_mode = 0;
    int ret_code = 0;
    int chdir_mode = 1;
    int close_mode = 1;

    /* デバッグモードオプションチェック */
    if(argc >= 2) {
        if(strcmp(argv[1], "-d") == 0) {
            debug_mode = 1;
        }
        else {
            puts("usage: testd [-d]");
            puts("      -d ... debug_mode");
            return 1;
        }
    }

    /* デバッグの場合は、デーモン化しない */
    if(!debug_mode) {

        /* デーモン初期化 */
        if((ret_code = init_daemon(chdir_mode, close_mode)) != 0) {
            fprintf(stderr, "init daemon failed code = %d\n", ret_code);
            return 2;
        }

        /* 不要なシグナルへの対処 */
        signal(SIGALRM, SIG_IGN);
        signal(SIGCHLD, SIG_IGN);    //ゾンビ禁止 BSD系では更に処理が必要
        signal(SIGHUP, SIG_IGN);     //本来は、SIGHUPで再起動するべき
        signal(SIGPIPE, SIG_IGN);
        signal(SIGTERM, SIG_IGN);

        /* 親のmaskを引き継がない */
        umask(0);
    }
    else
        fprintf(stdout, "-- Debug mode --\n");


    /* イベント待ち */
    if((ret_code = wait_event(debug_mode)) != 0) {
        fprintf(stderr, "wait event failed code = %d\n", ret_code);
        return 3;
    }

    return 0;
}
