/*
 *   デーモン作法サンプルスケルトン
 *   test3d.c
 *   by simamaru
 */

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

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

int errno_;
int is_exit_;

int app_init(void);
int app_daemon(void);
int app_mainloop(void);
pid_t app_fork(int is_parent_kill);
void sig(int signo);
int app_exit(int rtn);

int main(int argc, char *argv[])
{
    int rtn;
    if (app_init() < 0) {
        return EXIT_FAILURE;
    }

    rtn = (app_mainloop() == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
    return app_exit(rtn);
}

int app_init()
{
    int rtn;

    is_exit_ = 0;
    if ((rtn = app_daemon()) != 0) {
        return -1;
    }

    signal(SIGTERM, sig);
    return 0;
}

int app_daemon(void)
{
    const int parent_kill = 1;

    if (app_fork(parent_kill) < 0) {
        return -1;
    }
    if (app_fork(parent_kill) < 0) {
        return -1;
    }

    if (setsid() < 0) {
        errno_ = errno;
        return -1;
    }

    chdir("/");
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    return 0;
}

/*
 * この処理はダミー
 * 処理：ここではファイルに1行出力
 */
int app_mainloop(void)
{
    FILE *fp = NULL;
    char buf[256];
    int rtn = 0;
    int countdown;

    if ((fp = fopen(LOG_FILENAME, "a")) == NULL) {
        errno_ = errno;
        return -1;
    }

    while (1) {
        snprintf(buf, sizeof(buf) - 1, "%d - processed\n", time(NULL));
        if (fputs(buf, fp) == EOF) {
            errno_ = errno;
            rtn = -1;
            goto MAIN_LOOP_EXIT;
        }

        countdown = WAIT_TIME;
        do {
            if (is_exit_) {
                goto MAIN_LOOP_EXIT;
            }
            sleep(1);
        } while (--countdown != 0);
    }

MAIN_LOOP_EXIT:
    if (fp != NULL) {
        fclose(fp);
    }

    return rtn;
}

pid_t app_fork(int is_parent_kill)
{
    pid_t pid;

    switch (pid = fork()) {
    case -1:
        errno_ = errno;
        break;
    case 0:     /* child */
        break;
    default:    /* parent */
        if (is_parent_kill) {
            _exit(EXIT_SUCCESS);
        }
    }

    return pid;
}

void sig(int signo)
{
    if (signo == SIGTERM) {
        is_exit_ = 1;
        signal(SIGTERM, sig);
    }
}

int app_exit(int rtn)
{
    closelog();
    return rtn;
}
