zdump.c revision 176407
1130819Sstefanfstatic const char elsieid[] = "@(#)zdump.c 7.31"; 22702Swollman 330829Scharnier#ifndef lint 430829Scharnierstatic const char rcsid[] = 550479Speter "$FreeBSD: head/usr.sbin/zic/zdump.c 176407 2008-02-19 07:09:19Z ru $"; 630829Scharnier#endif /* not lint */ 730829Scharnier 82702Swollman/* 92702Swollman** This code has been made independent of the rest of the time 102702Swollman** conversion package to increase confidence in the verification it provides. 112702Swollman** You can use this code to help in verifying other implementations. 122702Swollman*/ 132702Swollman 1430829Scharnier#include <err.h> 1530829Scharnier#include <stdio.h> /* for stdout, stderr */ 1630829Scharnier#include <stdlib.h> /* for exit, malloc, atoi */ 1730829Scharnier#include <string.h> /* for strcpy */ 1830829Scharnier#include <sys/types.h> /* for time_t */ 1930829Scharnier#include <time.h> /* for struct tm */ 2030829Scharnier#include <unistd.h> 212702Swollman 222702Swollman#ifndef MAX_STRING_LENGTH 232702Swollman#define MAX_STRING_LENGTH 1024 242702Swollman#endif /* !defined MAX_STRING_LENGTH */ 252702Swollman 262702Swollman#ifndef TRUE 272702Swollman#define TRUE 1 282702Swollman#endif /* !defined TRUE */ 292702Swollman 302702Swollman#ifndef FALSE 312702Swollman#define FALSE 0 322702Swollman#endif /* !defined FALSE */ 332702Swollman 342702Swollman#ifndef EXIT_SUCCESS 352702Swollman#define EXIT_SUCCESS 0 362702Swollman#endif /* !defined EXIT_SUCCESS */ 372702Swollman 382702Swollman#ifndef EXIT_FAILURE 392702Swollman#define EXIT_FAILURE 1 402702Swollman#endif /* !defined EXIT_FAILURE */ 412702Swollman 422702Swollman#ifndef SECSPERMIN 432702Swollman#define SECSPERMIN 60 442702Swollman#endif /* !defined SECSPERMIN */ 452702Swollman 462702Swollman#ifndef MINSPERHOUR 472702Swollman#define MINSPERHOUR 60 482702Swollman#endif /* !defined MINSPERHOUR */ 492702Swollman 502702Swollman#ifndef SECSPERHOUR 512702Swollman#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) 522702Swollman#endif /* !defined SECSPERHOUR */ 532702Swollman 542702Swollman#ifndef HOURSPERDAY 552702Swollman#define HOURSPERDAY 24 562702Swollman#endif /* !defined HOURSPERDAY */ 572702Swollman 582702Swollman#ifndef EPOCH_YEAR 592702Swollman#define EPOCH_YEAR 1970 602702Swollman#endif /* !defined EPOCH_YEAR */ 612702Swollman 622702Swollman#ifndef TM_YEAR_BASE 632702Swollman#define TM_YEAR_BASE 1900 642702Swollman#endif /* !defined TM_YEAR_BASE */ 652702Swollman 662702Swollman#ifndef DAYSPERNYEAR 672702Swollman#define DAYSPERNYEAR 365 682702Swollman#endif /* !defined DAYSPERNYEAR */ 692702Swollman 702702Swollman#ifndef isleap 712702Swollman#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) 722702Swollman#endif /* !defined isleap */ 732702Swollman 7417214Swollman#if HAVE_GETTEXT - 0 7517214Swollman#include "locale.h" /* for setlocale */ 7617214Swollman#include "libintl.h" 7717214Swollman#endif /* HAVE_GETTEXT - 0 */ 7817214Swollman 799937Swollman#ifndef GNUC_or_lint 809937Swollman#ifdef lint 819937Swollman#define GNUC_or_lint 829937Swollman#endif /* defined lint */ 839937Swollman#ifndef lint 849937Swollman#ifdef __GNUC__ 859937Swollman#define GNUC_or_lint 869937Swollman#endif /* defined __GNUC__ */ 879937Swollman#endif /* !defined lint */ 889937Swollman#endif /* !defined GNUC_or_lint */ 899937Swollman 909937Swollman#ifndef INITIALIZE 919937Swollman#ifdef GNUC_or_lint 929937Swollman#define INITIALIZE(x) ((x) = 0) 939937Swollman#endif /* defined GNUC_or_lint */ 949937Swollman#ifndef GNUC_or_lint 959937Swollman#define INITIALIZE(x) 969937Swollman#endif /* !defined GNUC_or_lint */ 979937Swollman#endif /* !defined INITIALIZE */ 989937Swollman 9917214Swollman/* 10017214Swollman** For the benefit of GNU folk... 10117214Swollman** `_(MSGID)' uses the current locale's message library string for MSGID. 10217214Swollman** The default is to use gettext if available, and use MSGID otherwise. 10317214Swollman*/ 10417214Swollman 10517214Swollman#ifndef _ 10617214Swollman#if HAVE_GETTEXT - 0 10717214Swollman#define _(msgid) gettext(msgid) 10817214Swollman#else /* !(HAVE_GETTEXT - 0) */ 10917214Swollman#define _(msgid) msgid 11017214Swollman#endif /* !(HAVE_GETTEXT - 0) */ 11117214Swollman#endif /* !defined _ */ 11217214Swollman 11317214Swollman#ifndef TZ_DOMAIN 11417214Swollman#define TZ_DOMAIN "tz" 11517214Swollman#endif /* !defined TZ_DOMAIN */ 11617214Swollman 11742997Swollman#ifndef P 11842997Swollman#ifdef __STDC__ 11942997Swollman#define P(x) x 12042997Swollman#endif /* defined __STDC__ */ 12142997Swollman#ifndef __STDC__ 12242997Swollman#define P(x) () 12342997Swollman#endif /* !defined __STDC__ */ 12442997Swollman#endif /* !defined P */ 12542997Swollman 1262702Swollmanextern char ** environ; 1272702Swollmanextern char * tzname[2]; 1282702Swollman 12942997Swollmanstatic char * abbr P((struct tm * tmp)); 13042997Swollmanstatic long delta P((struct tm * newp, struct tm * oldp)); 13142997Swollmanstatic time_t hunt P((char * name, time_t lot, time_t hit)); 13242997Swollmanstatic size_t longest; 13342997Swollmanstatic void show P((char * zone, time_t t, int v)); 13444233Seivindstatic void usage(void); 1352702Swollman 1362702Swollmanint 1372702Swollmanmain(argc, argv) 1382702Swollmanint argc; 1392702Swollmanchar * argv[]; 1402702Swollman{ 1419937Swollman register int i; 1429937Swollman register int c; 1439937Swollman register int vflag; 1449937Swollman register char * cutoff; 1459937Swollman register int cutyear; 1469937Swollman register long cuttime; 1479937Swollman char ** fakeenv; 1489937Swollman time_t now; 1499937Swollman time_t t; 1509937Swollman time_t newt; 1519937Swollman time_t hibit; 1529937Swollman struct tm tm; 1539937Swollman struct tm newtm; 1542702Swollman 1559937Swollman INITIALIZE(cuttime); 15617214Swollman#if HAVE_GETTEXT - 0 15717214Swollman (void) setlocale(LC_MESSAGES, ""); 15817214Swollman#ifdef TZ_DOMAINDIR 15917214Swollman (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 16017214Swollman#endif /* defined(TEXTDOMAINDIR) */ 16117214Swollman (void) textdomain(TZ_DOMAIN); 16217214Swollman#endif /* HAVE_GETTEXT - 0 */ 163130819Sstefanf for (i = 1; i < argc; ++i) 164130819Sstefanf if (strcmp(argv[i], "--version") == 0) { 165130819Sstefanf errx(EXIT_SUCCESS, "%s", elsieid); 166130819Sstefanf } 1672702Swollman vflag = 0; 1682702Swollman cutoff = NULL; 1692702Swollman while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 1702702Swollman if (c == 'v') 1712702Swollman vflag = 1; 1722702Swollman else cutoff = optarg; 173176407Sru if ((c != -1) || 1742702Swollman (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 17530829Scharnier usage(); 1762702Swollman } 1772702Swollman if (cutoff != NULL) { 1782702Swollman int y; 1792702Swollman 1802702Swollman cutyear = atoi(cutoff); 1812702Swollman cuttime = 0; 1822702Swollman for (y = EPOCH_YEAR; y < cutyear; ++y) 1832702Swollman cuttime += DAYSPERNYEAR + isleap(y); 1842702Swollman cuttime *= SECSPERHOUR * HOURSPERDAY; 1852702Swollman } 1862702Swollman (void) time(&now); 1872702Swollman longest = 0; 1882702Swollman for (i = optind; i < argc; ++i) 1892702Swollman if (strlen(argv[i]) > longest) 1902702Swollman longest = strlen(argv[i]); 1912702Swollman for (hibit = 1; (hibit << 1) != 0; hibit <<= 1) 1922702Swollman continue; 1939937Swollman { 1949937Swollman register int from; 1959937Swollman register int to; 1962702Swollman 1979937Swollman for (i = 0; environ[i] != NULL; ++i) 1989937Swollman continue; 1999937Swollman fakeenv = (char **) malloc((size_t) ((i + 2) * 2009937Swollman sizeof *fakeenv)); 2019937Swollman if (fakeenv == NULL || 2029937Swollman (fakeenv[0] = (char *) malloc((size_t) (longest + 20330829Scharnier 4))) == NULL) 20430829Scharnier errx(EXIT_FAILURE, 20530829Scharnier _("malloc() failed")); 2069937Swollman to = 0; 2079937Swollman (void) strcpy(fakeenv[to++], "TZ="); 2089937Swollman for (from = 0; environ[from] != NULL; ++from) 2099937Swollman if (strncmp(environ[from], "TZ=", 3) != 0) 2109937Swollman fakeenv[to++] = environ[from]; 2119937Swollman fakeenv[to] = NULL; 2122702Swollman environ = fakeenv; 2139937Swollman } 2149937Swollman for (i = optind; i < argc; ++i) { 2159937Swollman static char buf[MAX_STRING_LENGTH]; 2169937Swollman 2179937Swollman (void) strcpy(&fakeenv[0][3], argv[i]); 21817214Swollman if (!vflag) { 21917214Swollman show(argv[i], now, FALSE); 2202702Swollman continue; 22117214Swollman } 2222702Swollman /* 2232702Swollman ** Get lowest value of t. 2242702Swollman */ 2252702Swollman t = hibit; 2262702Swollman if (t > 0) /* time_t is unsigned */ 2272702Swollman t = 0; 2282702Swollman show(argv[i], t, TRUE); 2292702Swollman t += SECSPERHOUR * HOURSPERDAY; 2302702Swollman show(argv[i], t, TRUE); 2312702Swollman tm = *localtime(&t); 2322702Swollman (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); 2332702Swollman for ( ; ; ) { 2342702Swollman if (cutoff != NULL && t >= cuttime) 2352702Swollman break; 2362702Swollman newt = t + SECSPERHOUR * 12; 2372702Swollman if (cutoff != NULL && newt >= cuttime) 2382702Swollman break; 2392702Swollman if (newt <= t) 2402702Swollman break; 2412702Swollman newtm = *localtime(&newt); 2422702Swollman if (delta(&newtm, &tm) != (newt - t) || 2432702Swollman newtm.tm_isdst != tm.tm_isdst || 2442702Swollman strcmp(abbr(&newtm), buf) != 0) { 2452702Swollman newt = hunt(argv[i], t, newt); 2462702Swollman newtm = *localtime(&newt); 2472702Swollman (void) strncpy(buf, abbr(&newtm), 2482702Swollman (sizeof buf) - 1); 2492702Swollman } 2502702Swollman t = newt; 2512702Swollman tm = newtm; 2522702Swollman } 2532702Swollman /* 2542702Swollman ** Get highest value of t. 2552702Swollman */ 2562702Swollman t = ~((time_t) 0); 2572702Swollman if (t < 0) /* time_t is signed */ 2582702Swollman t &= ~hibit; 2592702Swollman t -= SECSPERHOUR * HOURSPERDAY; 2602702Swollman show(argv[i], t, TRUE); 2612702Swollman t += SECSPERHOUR * HOURSPERDAY; 2622702Swollman show(argv[i], t, TRUE); 2632702Swollman } 26430829Scharnier if (fflush(stdout) || ferror(stdout)) 26530829Scharnier errx(EXIT_FAILURE, _("error writing standard output")); 2662702Swollman exit(EXIT_SUCCESS); 2672702Swollman 2682702Swollman /* gcc -Wall pacifier */ 2692702Swollman for ( ; ; ) 2702702Swollman continue; 2712702Swollman} 2722702Swollman 27330829Scharnierstatic void 27444233Seivindusage(void) 27530829Scharnier{ 276130819Sstefanf fprintf(stderr, 277130819Sstefanf_("usage: zdump [--version] [-v] [-c cutoff] zonename ...\n")); 27830829Scharnier exit(EXIT_FAILURE); 27930829Scharnier} 28030829Scharnier 2812702Swollmanstatic time_t 2822702Swollmanhunt(name, lot, hit) 2832702Swollmanchar * name; 2842702Swollmantime_t lot; 2852702Swollmantime_t hit; 2862702Swollman{ 2872702Swollman time_t t; 2882702Swollman struct tm lotm; 2892702Swollman struct tm tm; 2902702Swollman static char loab[MAX_STRING_LENGTH]; 2912702Swollman 2922702Swollman lotm = *localtime(&lot); 2932702Swollman (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); 2942702Swollman while ((hit - lot) >= 2) { 2952702Swollman t = lot / 2 + hit / 2; 2962702Swollman if (t <= lot) 2972702Swollman ++t; 2982702Swollman else if (t >= hit) 2992702Swollman --t; 3002702Swollman tm = *localtime(&t); 3012702Swollman if (delta(&tm, &lotm) == (t - lot) && 3022702Swollman tm.tm_isdst == lotm.tm_isdst && 3032702Swollman strcmp(abbr(&tm), loab) == 0) { 3042702Swollman lot = t; 3052702Swollman lotm = tm; 3062702Swollman } else hit = t; 3072702Swollman } 3082702Swollman show(name, lot, TRUE); 3092702Swollman show(name, hit, TRUE); 3102702Swollman return hit; 3112702Swollman} 3122702Swollman 3132702Swollman/* 3142702Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta. 3152702Swollman*/ 3162702Swollman 3172702Swollmanstatic long 3182702Swollmandelta(newp, oldp) 3192702Swollmanstruct tm * newp; 3202702Swollmanstruct tm * oldp; 3212702Swollman{ 3222702Swollman long result; 3232702Swollman int tmy; 3242702Swollman 3252702Swollman if (newp->tm_year < oldp->tm_year) 3262702Swollman return -delta(oldp, newp); 3272702Swollman result = 0; 3282702Swollman for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 3292702Swollman result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE); 3302702Swollman result += newp->tm_yday - oldp->tm_yday; 3312702Swollman result *= HOURSPERDAY; 3322702Swollman result += newp->tm_hour - oldp->tm_hour; 3332702Swollman result *= MINSPERHOUR; 3342702Swollman result += newp->tm_min - oldp->tm_min; 3352702Swollman result *= SECSPERMIN; 3362702Swollman result += newp->tm_sec - oldp->tm_sec; 3372702Swollman return result; 3382702Swollman} 3392702Swollman 3402702Swollmanstatic void 3412702Swollmanshow(zone, t, v) 3422702Swollmanchar * zone; 3432702Swollmantime_t t; 3442702Swollmanint v; 3452702Swollman{ 3469937Swollman struct tm * tmp; 3472702Swollman 34842997Swollman (void) printf("%-*s ", (int) longest, zone); 3492702Swollman if (v) 35042997Swollman (void) printf("%.24s UTC = ", asctime(gmtime(&t))); 3512702Swollman tmp = localtime(&t); 3522702Swollman (void) printf("%.24s", asctime(tmp)); 3532702Swollman if (*abbr(tmp) != '\0') 3542702Swollman (void) printf(" %s", abbr(tmp)); 3552702Swollman if (v) { 3562702Swollman (void) printf(" isdst=%d", tmp->tm_isdst); 3572702Swollman#ifdef TM_GMTOFF 3582702Swollman (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 3592702Swollman#endif /* defined TM_GMTOFF */ 3602702Swollman } 3612702Swollman (void) printf("\n"); 3622702Swollman} 3632702Swollman 3642702Swollmanstatic char * 3652702Swollmanabbr(tmp) 3662702Swollmanstruct tm * tmp; 3672702Swollman{ 3682702Swollman register char * result; 3699937Swollman static char nada; 3702702Swollman 3712702Swollman if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 3729937Swollman return &nada; 3732702Swollman result = tzname[tmp->tm_isdst]; 3749937Swollman return (result == NULL) ? &nada : result; 3752702Swollman} 376