#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include <errno.h>
#include "check_neocast.h"

/*
void sig_handler(int signo)
{
    fprintf(stderr, "SIGNAL thid %d : %d\n", pthread_self(), signo);
	pthread_exit((void *)NULL);
}
*/

void makedaemon(int mode)
{
#ifdef SIGTTOU
    signal(SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
    signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
    signal(SIGTSTP, SIG_IGN);
#endif
#ifdef SIGINT
    signal(SIGINT, SIG_IGN);
#endif
#ifdef SIGSTP
    signal(SIGSTP, SIG_IGN);
#endif

    pid_t pid;
    if ((pid = fork()) < 0)
        exit(0);

    else if (pid != 0)
        exit(0);

    if (mode == 0)
    {
        close(0);
        close(1);
        close(2);
    }
    setsid();
}

void HandleCoreDump(int signum)
{
    signal(signum, SIG_DFL);
    kill(getpid(), SIGKILL);
    sleep(3);
}

void HandleChildHang(int signum)
{
    int status = 1;

    while (waitpid(-1, &status, WNOHANG) > 0)
    {
        fprintf(stderr, "decrease one child process!\n");
    }
}

static int SetSigHandle(int Option)
{
    struct sigaction sa;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

#if defined(SA_ONESHOT)
    sa.sa_flags = SA_ONESHOT;
#elif defined(SA_RESETHAND)
    sa.sa_flags = SA_RESETHAND;
#endif

    if(Option == 1)
    {
        sa.sa_handler = HandleChildHang;
        if(sigaction(SIGCHLD, &sa, NULL) < 0)
        {
            //DISPLAY_SIGNAL_ACTION_ERROR(-1);
        }
    }
    else
    {
        sa.sa_handler = HandleCoreDump;
    }

    if(sigaction(SIGSEGV, &sa, NULL) == -1)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-2);
    }

#ifdef SIGBUS
    if(sigaction(SIGBUS, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-3);
    }
#endif
#ifdef SIGABORT
    if(sigaction(SIGABORT, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-4);
    }
#endif
#ifdef SIGABRT
    if(sigaction(SIGABRT, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-5);
    }
#endif
#ifdef SIGILL
	if(sigaction(SIGILL, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-6);
    }
#endif
    if(sigaction(SIGHUP, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-7);
    }
    if(sigaction(SIGUSR1, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-8);
    }
#ifdef SIGINT
    if(sigaction(SIGINT, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-9);
    }
#endif
#ifdef SIGXCPU
    sa.sa_handler = SIG_DFL;
    if(sigaction(SIGXCPU, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-10);
    }
#endif
#ifdef SIGXPSZ
    sa.sa_handler = SIG_DFL;
    if(sigaction(SIGSEGV, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-11);
    }
#endif
#ifdef SIGPIPE
    sa.sa_handler = SIG_IGN;
    if(sigaction(SIGPIPE, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-12);
    }
#endif
#ifdef SIGSYS
    sa.sa_handler = SIG_IGN;
    if(sigaction(SIGPIPE, &sa, NULL) < 0)
    {
        //DISPLAY_SIGNAL_ACTION_ERROR(-13);
    }
#endif
    return 1;
}

void setsighandle_pthread(void)
{
	sigset_t newmask;
	sigemptyset(&newmask);
	sigaddset(&newmask, SIGINT);
	sigaddset(&newmask, SIGSEGV);
	pthread_sigmask(SIG_BLOCK, &newmask, NULL);
}

static pid_t pids[3];

#define RELEASE_MODE 0

int main()
{
	pid_t check_process();

	/* damonlizing... */
	makedaemon(RELEASE_MODE);

	pids[0] = check_process();

	setproctitle("parents: monitoring all process..");
	for (;;)
		pause();

	return 0;
}

pid_t check_process()
{
	pid_t pid;
	void check_child_process();

	if ((pid = fork()) > 0)
		return (pid);

	check_child_process();
}

void check_child_process()
{
	void thread_func(int);
	pid_t cpid;
	int cstatus = 0;
	
	while (1)
	{
		if ((cpid = fork()) < 0)
		{
			fprintf(stderr, "Cannot Fork(child)\n");
			exit(0);
		}
		else if (cpid == 0)
		{
			fprintf(stderr, "start check child process\n");
			setproctitle("child(check): running...");
			SetSigHandle(0);
			// NeoCast monitoring section
			loop_check();
		}
		setproctitle("guard(check) : waiting....until work process die");
		wait(&cstatus);
	}
}

void thread_func(int arg)
{
	void *thread_one_func(void *);
	void *thread_two_func(void *);

	pthread_t t1, t2;
	int a;
	int b;

	a = arg;
	b = arg+1;

	pthread_create(&t1, NULL, &thread_one_func, (void *)a);
    pthread_create(&t2, NULL, &thread_two_func, (void *)b);

	pthread_join(t1, NULL);
	pthread_join(t2, NULL);
}

void *thread_one_func(void *arg)
{
	int one = 1;

	while(1)
	{
		fprintf(stderr, "thread_one --> %d(%d)\n", one, (int)arg);
		sleep(5);
	}
}

void *thread_two_func(void *arg)
{
	int two = 2;

	while(1)
	{
		fprintf(stderr, "thread_two --> %d(%d)\n", two, (int)arg);
	}
}
