#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <err.h>
#include <string.h>
#include <errno.h>
#include <signal.h>

void usage(void);
void sig_handler(int signo);

int
main(int argc, char *argv[])
{
    struct timespec req, rem;
    time_t t0;
    int flag;
    int ret;
    clockid_t clock_id;

    if (argc != 4) {
        usage();
        /* UNREACHABLE */
    }

    memset(&rem, 0, sizeof(struct timespec));

    t0 = time(NULL);
    printf("t0=%ld\n", (long) t0);
    fflush(stdout);

    if (strcmp(argv[1], "CLOCK_REALTIME") == 0)
        clock_id = CLOCK_REALTIME;
    else if (strcmp(argv[1], "CLOCK_TAI") == 0)
        clock_id = CLOCK_TAI;
    else if (strcmp(argv[1], "CLOCK_MONOTONIC") == 0)
        clock_id = CLOCK_MONOTONIC;
    else if (strcmp(argv[1], "CLOCK_BOOTTIME") == 0)
        clock_id = CLOCK_BOOTTIME;
    else if (strcmp(argv[1], "CLOCK_PROCESS_CPUTIME_ID") == 0)
        clock_id = CLOCK_PROCESS_CPUTIME_ID;
    else if (strcmp(argv[1], "CLOCK_THREAD_CPUTIME_ID") == 0)
        clock_id = CLOCK_THREAD_CPUTIME_ID;
    else if (strcmp(argv[1], "FAKE_CLOCK_ID") == 0)
        clock_id = -5;
    else {
        usage();
        /* UNREACHABLE */
    }

    signal(SIGINT, sig_handler);
    clock_gettime(clock_id, &req);

    if (strcmp(argv[2], "rel") == 0) {
        req.tv_sec = atoi(argv[3]);
        flag = 0;
    } else if (strcmp(argv[2], "abs") == 0) {
        req.tv_sec += atoi(argv[3]);
        flag = TIMER_ABSTIME;
    } else {
        usage();
        /* UNREACHABLE */
    }

    if ((ret = clock_nanosleep(clock_id, flag, &req, &rem)) != 0) {
        errno = ret;
        printf("remaining sec=%ld nsec=%ld\n",
                (long)rem.tv_sec, (long)rem.tv_nsec);
        err(EXIT_FAILURE, "clock_nanosleep");
    } else {
        printf("t1=%ld\n", (long) time(NULL));
        printf("sleeping done");
    }
    exit(EXIT_SUCCESS);
}

void
usage(void)
{
    fprintf(stderr, "usage: %s clock_id abs|rel seconds\n",
            program_invocation_short_name);
    exit(EXIT_FAILURE);
}

void
sig_handler(int signo)
{
    return;
}
