#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <sys/wait.h>
#include <signal.h>
#include "../lpi.h"     // for struct sig and getSignam()
                        // they are implemented in ../defs.c

void sig_handler(int signo);
int gotSigTerm;

int
main(int argc, char *argv[])
{
    struct sigaction sa;
    pid_t pid;
    int i;
    extern int NSIGS;
    extern struct sig sigs[];

    for (i = 1; i < NSIGS; i++) {
        if (signal(sigs[i].no, sig_handler) == SIG_ERR) {
            if (sigs[i].no == SIGSTOP || sigs[i].no == SIGKILL)
                continue;

            err(EXIT_FAILURE, "signal(%d, sig_handler)", sigs[i].no);
        }
    }

    if ((pid = fork()) == -1)
        err(EXIT_FAILURE, "fork");

    if (pid == 0) {
        while (1) {
            printf("PID=%ld waits for signal\n", (long) getpid());
            pause();
            /* if last child's signal is SIGTERM break and exit */
            if (gotSigTerm == getpid())
                break;
        }
        printf("PID=%ld got SIGTERM. exiting...\n", (long) getpid());
        exit(100);
    }

    sa.sa_handler = sig_handler;
    /*
     * disable child SIGSTOP and SIGCONT
     * to be reported to parent
     */
    sa.sa_flags = SA_NOCLDSTOP;

    if (sigaction(SIGCHLD, &sa, NULL) == -1)
        err(EXIT_FAILURE, "sigaction");

    printf("PID=%ld created PID=%ld\n", (long) getpid(), (long) pid);
    pause();
    printf("PID=%ld exiting...\n", (long) getpid());
    exit(EXIT_SUCCESS);
}

void
sig_handler(int signo)
{
    pid_t pid;
    int status;

    gotSigTerm = 0;
    printf("PID=%ld caught signal %2d %s\n",
            (long) getpid(), signo, getSigname(signo));

    if (signo == SIGCHLD) {
        pid = wait(&status);
        printf("PID=%ld terminates with status=%d\n",
                (long) pid, WEXITSTATUS(status));
    } else if (signo == SIGTERM)
        gotSigTerm = getpid();
}
