/*
 * Program for repeatedly calling gettimeofday() and printing a message
 * if the clock went backwards.
 * Maybe useful if your daily builds occasionally fail because Make decides
 * to randomly rebuild a file that is actually up-to-date, and you suspect
 * it's due to the system clock going back in time and giving you a bad
 * haircut.
 *
 * Run it for a few days.
 *
 * By Ted Percival <ted@midg3t.net>
 * Copyright 2011 Quest Software, Inc.
 * All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of Quest Software, Inc. nor the
 *       names of its contributors may be used to endorse or promote
 *       products derived from this software without specific prior
 *       written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY QUEST SOFTWARE, INC "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL QUEST SOFTWARE, INC BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>

char *hammertime(time_t time) {
    char gmtimestr[64], localtimestr[64];
    char fullstr[512]; /* Because there's no asprintf on Solaris. */
    const char FORMAT[] = "%Y-%m-%d %H:%M:%S";
    struct tm tm;
    gmtime_r(&time, &tm);
    strftime(gmtimestr, sizeof(gmtimestr), FORMAT, &tm);
    localtime_r(&time, &tm);
    strftime(localtimestr, sizeof(localtimestr), FORMAT, &tm);

    snprintf(fullstr, sizeof(fullstr), "%s (%s UTC)", localtimestr, gmtimestr);
    return strdup(fullstr);
}

int main(void) {
    struct timeval tv = {0,0}, lasttv = {0,0};

    while (gettimeofday(&tv, NULL) == 0) {
#if 0 /* Testing */
        lasttv.tv_sec = 1234;
        tv.tv_sec = 1233;
#endif
        /* Linux & BSD have the convenient timercmp() macro, but
         * Solaris remains programmer-hostile, of course. */
        if (tv.tv_sec < lasttv.tv_sec
            || (tv.tv_sec == lasttv.tv_sec && tv.tv_usec < lasttv.tv_usec))
        {
            char *oldtime, *newtime;
            oldtime = hammertime(lasttv.tv_sec);
            newtime = hammertime(tv.tv_sec);
            printf("\n");
            printf("Time went backwards!\n");
            printf("From: %s\n", oldtime);
            printf("To:   %s\n", newtime);
            printf("Recalculating the speed of light...\n");
            free(oldtime);
            free(newtime);
        }

        lasttv.tv_sec = tv.tv_sec;
        lasttv.tv_usec = tv.tv_usec;
    }

    return 0;
}

