1 /*
   2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 #pragma ident   "%Z%%M% %I%     %E% SMI"
   7 
   8 /*
   9  * zdump 7.24
  10  * Taken from elsie.nci.nih.gov to replace the existing Solaris zdump,
  11  * which was based on an earlier version of the elsie code.
  12  *
  13  * For zdump 7.24, the following changes were made to the elsie code:
  14  *   locale/textdomain/messages to match existing Solaris style.
  15  *   Solaris verbose mode is documented to display the current time first.
  16  *   cstyle cleaned code.
  17  *   removed old locale/textdomain code.
  18  */
  19 
  20 static char     elsieid[] = "@(#)zdump.c        7.74";
  21 
  22 /*
  23  * This code has been made independent of the rest of the time
  24  * conversion package to increase confidence in the verification it provides.
  25  * You can use this code to help in verifying other implementations.
  26  */
  27 
  28 #include "stdio.h"      /* for stdout, stderr, perror */
  29 #include "string.h"     /* for strcpy */
  30 #include "sys/types.h"  /* for time_t */
  31 #include "time.h"       /* for struct tm */
  32 #include "stdlib.h"     /* for exit, malloc, atoi */
  33 #include "locale.h"     /* for setlocale, textdomain */
  34 #include "libintl.h"
  35 #include <ctype.h>
  36 #include "tzfile.h"     /* for defines */
  37 #include <limits.h>
  38 
  39 #ifndef ZDUMP_LO_YEAR
  40 #define ZDUMP_LO_YEAR   (-500)
  41 #endif /* !defined ZDUMP_LO_YEAR */
  42 
  43 #ifndef ZDUMP_HI_YEAR
  44 #define ZDUMP_HI_YEAR   2500
  45 #endif /* !defined ZDUMP_HI_YEAR */
  46 
  47 #ifndef MAX_STRING_LENGTH
  48 #define MAX_STRING_LENGTH       1024
  49 #endif /* !defined MAX_STRING_LENGTH */
  50 
  51 #ifndef TRUE
  52 #define TRUE            1
  53 #endif /* !defined TRUE */
  54 
  55 #ifndef FALSE
  56 #define FALSE           0
  57 #endif /* !defined FALSE */
  58 
  59 #ifndef isleap_sum
  60 /*
  61  * See tzfile.h for details on isleap_sum.
  62  */
  63 #define isleap_sum(a, b)        isleap((a) % 400 + (b) % 400)
  64 #endif /* !defined isleap_sum */
  65 
  66 #ifndef SECSPERDAY
  67 #define SECSPERDAY      ((long)SECSPERHOUR * HOURSPERDAY)
  68 #endif
  69 #define SECSPERNYEAR    (SECSPERDAY * DAYSPERNYEAR)
  70 #define SECSPERLYEAR    (SECSPERNYEAR + SECSPERDAY)
  71 
  72 #ifndef GNUC_or_lint
  73 #ifdef lint
  74 #define GNUC_or_lint
  75 #else /* !defined lint */
  76 #ifdef __GNUC__
  77 #define GNUC_or_lint
  78 #endif /* defined __GNUC__ */
  79 #endif /* !defined lint */
  80 #endif /* !defined GNUC_or_lint */
  81 
  82 #ifndef INITIALIZE
  83 #ifdef  GNUC_or_lint
  84 #define INITIALIZE(x)   ((x) = 0)
  85 #else /* !defined GNUC_or_lint */
  86 #define INITIALIZE(x)
  87 #endif /* !defined GNUC_or_lint */
  88 #endif /* !defined INITIALIZE */
  89 
  90 static time_t   absolute_min_time;
  91 static time_t   absolute_max_time;
  92 static size_t   longest;
  93 static char     *progname;
  94 static int      warned;
  95 
  96 static char     *abbr(struct tm *);
  97 static void     abbrok(const char *, const char *);
  98 static long     delta(struct tm *, struct tm *);
  99 static void     dumptime(const struct tm *);
 100 static time_t   hunt(char *, time_t, time_t);
 101 static void     setabsolutes(void);
 102 static void     show(char *, time_t, int);
 103 static void     usage(void);
 104 static const char       *tformat(void);
 105 static time_t   yeartot(long y);
 106 
 107 #ifndef TYPECHECK
 108 #define my_localtime    localtime
 109 #else /* !defined TYPECHECK */
 110 static struct tm *
 111 my_localtime(tp)
 112 time_t *tp;
 113 {
 114         register struct tm *tmp;
 115 
 116         tmp = localtime(tp);
 117         if (tp != NULL && tmp != NULL) {
 118                 struct tm       tm;
 119                 register time_t t;
 120 
 121                 tm = *tmp;
 122                 t = mktime(&tm);
 123                 if (t - *tp >= 1 || *tp - t >= 1) {
 124                         (void) fflush(stdout);
 125                         (void) fprintf(stderr, "\n%s: ", progname);
 126                         (void) fprintf(stderr, tformat(), *tp);
 127                         (void) fprintf(stderr, " ->");
 128                         (void) fprintf(stderr, " year=%d", tmp->tm_year);
 129                         (void) fprintf(stderr, " mon=%d", tmp->tm_mon);
 130                         (void) fprintf(stderr, " mday=%d", tmp->tm_mday);
 131                         (void) fprintf(stderr, " hour=%d", tmp->tm_hour);
 132                         (void) fprintf(stderr, " min=%d", tmp->tm_min);
 133                         (void) fprintf(stderr, " sec=%d", tmp->tm_sec);
 134                         (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
 135                         (void) fprintf(stderr, " -> ");
 136                         (void) fprintf(stderr, tformat(), t);
 137                         (void) fprintf(stderr, "\n");
 138                 }
 139         }
 140         return (tmp);
 141 }
 142 #endif /* !defined TYPECHECK */
 143 
 144 static void
 145 abbrok(abbrp, zone)
 146 const char * const      abbrp;
 147 const char * const      zone;
 148 {
 149         register const char *cp;
 150         int error = 0;
 151 
 152         if (warned)
 153                 return;
 154         cp = abbrp;
 155         while (isascii(*cp) && isalpha((unsigned char)*cp))
 156                 ++cp;
 157         (void) fflush(stdout);
 158         if (cp - abbrp == 0) {
 159                 /*
 160                  * TRANSLATION_NOTE
 161                  * The first %s prints for the program name (zdump),
 162                  * the second %s prints the timezone name, the third
 163                  * %s prints the timezone abbreviation (tzname[0] or
 164                  * tzname[1]).
 165                  */
 166                 (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
 167                     "abbreviation \"%s\" lacks alphabetic at start\n"),
 168                     progname, zone, abbrp);
 169                 error = 1;
 170         } else if (cp - abbrp < 3) {
 171                 (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
 172                     "abbreviation \"%s\" has fewer than 3 alphabetics\n"),
 173                     progname, zone, abbrp);
 174                 error = 1;
 175         } else if (cp - abbrp > 6) {
 176                 (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
 177                     "abbreviation \"%s\" has more than 6 alphabetics\n"),
 178                     progname, zone, abbrp);
 179                 error = 1;
 180         }
 181         if (error == 0 && (*cp == '+' || *cp == '-')) {
 182                 ++cp;
 183                 if (isascii(*cp) && isdigit((unsigned char)*cp))
 184                         if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
 185                                 ++cp;
 186                 if (*cp != '\0') {
 187                         (void) fprintf(stderr, gettext("%s: warning: "
 188                             "zone \"%s\" abbreviation \"%s\" differs from "
 189                             "POSIX standard\n"), progname, zone, abbrp);
 190                         error = 1;
 191                 }
 192         }
 193         if (error)
 194                 warned = TRUE;
 195 }
 196 
 197 int
 198 main(argc, argv)
 199 int     argc;
 200 char    *argv[];
 201 {
 202         register int            i;
 203         register int            c;
 204         register int            vflag;
 205         register char           *cutarg;
 206         register long           cutloyear = ZDUMP_LO_YEAR;
 207         register long           cuthiyear = ZDUMP_HI_YEAR;
 208         register time_t         cutlotime;
 209         register time_t         cuthitime;
 210         time_t                  now;
 211         time_t                  t;
 212         time_t                  newt;
 213         struct tm               tm;
 214         struct tm               newtm;
 215         register struct tm      *tmp;
 216         register struct tm      *newtmp;
 217 
 218         INITIALIZE(cutlotime);
 219         INITIALIZE(cuthitime);
 220 
 221         (void) setlocale(LC_ALL, "");
 222 #if !defined(TEXT_DOMAIN)               /* Should be defined by cc -D */
 223 #define TEXT_DOMAIN     "SYS_TEST"      /* Use this only if it weren't */
 224 #endif
 225         (void) textdomain(TEXT_DOMAIN);
 226 
 227         progname = argv[0];
 228         for (i = 1; i < argc; ++i)
 229                 if (strcmp(argv[i], "--version") == 0) {
 230                         (void) printf("%s\n", elsieid);
 231                         exit(EXIT_SUCCESS);
 232                 }
 233         vflag = 0;
 234         cutarg = NULL;
 235         while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
 236                 if (c == 'v')
 237                         vflag = 1;
 238                 else    cutarg = optarg;
 239         if (c != EOF ||
 240                 (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
 241                         usage();
 242                         /* NOTREACHED */
 243         }
 244         if (vflag) {
 245                 if (cutarg != NULL) {
 246                         long    lo;
 247                         long    hi;
 248                         char    dummy;
 249 
 250                         if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
 251                                 cuthiyear = hi;
 252                         } else if (sscanf(cutarg, "%ld,%ld%c",
 253                                 &lo, &hi, &dummy) == 2) {
 254                                         cutloyear = lo;
 255                                         cuthiyear = hi;
 256                         } else {
 257 (void) fprintf(stderr, gettext("%s: wild -c argument %s\n"),
 258                                         progname, cutarg);
 259                                 exit(EXIT_FAILURE);
 260                         }
 261                 }
 262                 setabsolutes();
 263                 cutlotime = yeartot(cutloyear);
 264                 cuthitime = yeartot(cuthiyear);
 265         }
 266         (void) time(&now);
 267         longest = 0;
 268         for (i = optind; i < argc; ++i)
 269                 if (strlen(argv[i]) > longest)
 270                         longest = strlen(argv[i]);
 271 
 272         for (i = optind; i < argc; ++i) {
 273                 static char     buf[MAX_STRING_LENGTH];
 274                 static char     *tzp = NULL;
 275 
 276                 (void) unsetenv("TZ");
 277                 if (tzp != NULL)
 278                         free(tzp);
 279                 if ((tzp = malloc(3 + strlen(argv[i]) + 1)) == NULL) {
 280                         perror(progname);
 281                         exit(EXIT_FAILURE);
 282                 }
 283                 (void) strcpy(tzp, "TZ=");
 284                 (void) strcat(tzp, argv[i]);
 285                 if (putenv(tzp) != 0) {
 286                         perror(progname);
 287                         exit(EXIT_FAILURE);
 288                 }
 289                 if (!vflag) {
 290                         show(argv[i], now, FALSE);
 291                         continue;
 292                 }
 293 
 294 #if defined(sun)
 295                 /*
 296                  * We show the current time first, probably because we froze
 297                  * the behavior of zdump some time ago and then it got
 298                  * changed.
 299                  */
 300                 show(argv[i], now, TRUE);
 301 #endif
 302                 warned = FALSE;
 303                 t = absolute_min_time;
 304                 show(argv[i], t, TRUE);
 305                 t += SECSPERHOUR * HOURSPERDAY;
 306                 show(argv[i], t, TRUE);
 307                 if (t < cutlotime)
 308                         t = cutlotime;
 309                 tmp = my_localtime(&t);
 310                 if (tmp != NULL) {
 311                         tm = *tmp;
 312                         (void) strncpy(buf, abbr(&tm), sizeof (buf) - 1);
 313                 }
 314                 for (;;) {
 315                         if (t >= cuthitime)
 316                                 break;
 317                         /* check if newt will overrun maximum time_t value */
 318                         if (t > LONG_MAX - (SECSPERHOUR * 12))
 319                                 break;
 320                         newt = t + SECSPERHOUR * 12;
 321                         if (newt >= cuthitime)
 322                                 break;
 323                         newtmp = localtime(&newt);
 324                         if (newtmp != NULL)
 325                                 newtm = *newtmp;
 326                         if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
 327                                 (delta(&newtm, &tm) != (newt - t) ||
 328                                 newtm.tm_isdst != tm.tm_isdst ||
 329                                 strcmp(abbr(&newtm), buf) != 0)) {
 330                                         newt = hunt(argv[i], t, newt);
 331                                         newtmp = localtime(&newt);
 332                                         if (newtmp != NULL) {
 333                                                 newtm = *newtmp;
 334                                                 (void) strncpy(buf,
 335                                                         abbr(&newtm),
 336                                                         sizeof (buf) - 1);
 337                                         }
 338                         }
 339                         t = newt;
 340                         tm = newtm;
 341                         tmp = newtmp;
 342                 }
 343                 t = absolute_max_time;
 344 #if defined(sun)
 345                 show(argv[i], t, TRUE);
 346                 t -= SECSPERHOUR * HOURSPERDAY;
 347                 show(argv[i], t, TRUE);
 348 #else /* !defined(sun) */
 349                 t -= SECSPERHOUR * HOURSPERDAY;
 350                 show(argv[i], t, TRUE);
 351                 t += SECSPERHOUR * HOURSPERDAY;
 352                 show(argv[i], t, TRUE);
 353 #endif /* !defined(sun) */
 354         }
 355         if (fflush(stdout) || ferror(stdout)) {
 356                 (void) fprintf(stderr, "%s: ", progname);
 357                 (void) perror(gettext("Error writing standard output"));
 358                 exit(EXIT_FAILURE);
 359         }
 360         return (EXIT_SUCCESS);
 361 }
 362 
 363 static void
 364 setabsolutes()
 365 {
 366 #if defined(sun)
 367         absolute_min_time = LONG_MIN;
 368         absolute_max_time = LONG_MAX;
 369 #else
 370         if (0.5 == (time_t)0.5) {
 371                 /*
 372                  * time_t is floating.
 373                  */
 374                 if (sizeof (time_t) == sizeof (float)) {
 375                         absolute_min_time = (time_t)-FLT_MAX;
 376                         absolute_max_time = (time_t)FLT_MAX;
 377                 } else if (sizeof (time_t) == sizeof (double)) {
 378                         absolute_min_time = (time_t)-DBL_MAX;
 379                         absolute_max_time = (time_t)DBL_MAX;
 380                 } else {
 381                         (void) fprintf(stderr, gettext("%s: use of -v on "
 382                             "system with floating time_t other than float "
 383                             "or double\n"), progname);
 384                         exit(EXIT_FAILURE);
 385                 }
 386         } else
 387         /*CONSTANTCONDITION*/
 388         if (0 > (time_t)-1) {
 389                 /*
 390                  * time_t is signed.
 391                  */
 392                 register time_t hibit;
 393 
 394                 for (hibit = 1; (hibit * 2) != 0; hibit *= 2)
 395                         continue;
 396                 absolute_min_time = hibit;
 397                 absolute_max_time = -(hibit + 1);
 398         } else {
 399                 /*
 400                  * time_t is unsigned.
 401                  */
 402                 absolute_min_time = 0;
 403                 absolute_max_time = absolute_min_time - 1;
 404         }
 405 #endif
 406 }
 407 
 408 static time_t
 409 yeartot(y)
 410 const long      y;
 411 {
 412         register long   myy;
 413         register long   seconds;
 414         register time_t t;
 415 
 416         myy = EPOCH_YEAR;
 417         t = 0;
 418         while (myy != y) {
 419                 if (myy < y) {
 420                         seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
 421                         ++myy;
 422                         if (t > absolute_max_time - seconds) {
 423                                 t = absolute_max_time;
 424                                 break;
 425                         }
 426                         t += seconds;
 427                 } else {
 428                         --myy;
 429                         seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
 430                         if (t < absolute_min_time + seconds) {
 431                                 t = absolute_min_time;
 432                                 break;
 433                         }
 434                         t -= seconds;
 435                 }
 436         }
 437         return (t);
 438 }
 439 
 440 static time_t
 441 hunt(name, lot, hit)
 442 char    *name;
 443 time_t  lot;
 444 time_t  hit;
 445 {
 446         time_t                  t;
 447         long                    diff;
 448         struct tm               lotm;
 449         register struct tm      *lotmp;
 450         struct tm               tm;
 451         register struct tm      *tmp;
 452         char                    loab[MAX_STRING_LENGTH];
 453 
 454         lotmp = my_localtime(&lot);
 455         if (lotmp != NULL) {
 456                 lotm = *lotmp;
 457                 (void) strncpy(loab, abbr(&lotm), sizeof (loab) - 1);
 458         }
 459         for (;;) {
 460                 diff = (long)(hit - lot);
 461                 if (diff < 2)
 462                         break;
 463                 t = lot;
 464                 t += diff / 2;
 465                 if (t <= lot)
 466                         ++t;
 467                 else if (t >= hit)
 468                         --t;
 469                 tmp = my_localtime(&t);
 470                 if (tmp != NULL)
 471                         tm = *tmp;
 472                 if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
 473                         (delta(&tm, &lotm) == (t - lot) &&
 474                         tm.tm_isdst == lotm.tm_isdst &&
 475                         strcmp(abbr(&tm), loab) == 0)) {
 476                                 lot = t;
 477                                 lotm = tm;
 478                                 lotmp = tmp;
 479                 } else  hit = t;
 480         }
 481         show(name, lot, TRUE);
 482         show(name, hit, TRUE);
 483         return (hit);
 484 }
 485 
 486 /*
 487  * Thanks to Paul Eggert for logic used in delta.
 488  */
 489 
 490 static long
 491 delta(newp, oldp)
 492 struct tm       *newp;
 493 struct tm       *oldp;
 494 {
 495         register long   result;
 496         register int    tmy;
 497 
 498         if (newp->tm_year < oldp->tm_year)
 499                 return (-delta(oldp, newp));
 500         result = 0;
 501         for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
 502                 result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
 503         result += newp->tm_yday - oldp->tm_yday;
 504         result *= HOURSPERDAY;
 505         result += newp->tm_hour - oldp->tm_hour;
 506         result *= MINSPERHOUR;
 507         result += newp->tm_min - oldp->tm_min;
 508         result *= SECSPERMIN;
 509         result += newp->tm_sec - oldp->tm_sec;
 510         return (result);
 511 }
 512 
 513 static void
 514 show(zone, t, v)
 515 char    *zone;
 516 time_t  t;
 517 int     v;
 518 {
 519         register struct tm      *tmp;
 520 
 521         (void) printf("%-*s  ", (int)longest, zone);
 522         if (v) {
 523                 tmp = gmtime(&t);
 524                 if (tmp == NULL) {
 525                         (void) printf(tformat(), t);
 526                 } else {
 527                         dumptime(tmp);
 528                         (void) printf(" UTC");
 529                 }
 530                 (void) printf(" = ");
 531         }
 532         tmp = my_localtime(&t);
 533         dumptime(tmp);
 534         if (tmp != NULL) {
 535                 if (*abbr(tmp) != '\0')
 536                         (void) printf(" %s", abbr(tmp));
 537                 if (v) {
 538                         (void) printf(" isdst=%d", tmp->tm_isdst);
 539 #ifdef TM_GMTOFF
 540                         (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
 541 #endif /* defined TM_GMTOFF */
 542                 }
 543         }
 544         (void) printf("\n");
 545         if (tmp != NULL && *abbr(tmp) != '\0')
 546                 abbrok(abbr(tmp), zone);
 547 }
 548 
 549 static char *
 550 abbr(tmp)
 551 struct tm       *tmp;
 552 {
 553         register char   *result;
 554         static char     nada;
 555 
 556         if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
 557                 return (&nada);
 558         result = tzname[tmp->tm_isdst];
 559         return ((result == NULL) ? &nada : result);
 560 }
 561 
 562 /*
 563  * The code below can fail on certain theoretical systems;
 564  * it works on all known real-world systems as of 2004-12-30.
 565  */
 566 
 567 static const char *
 568 tformat()
 569 {
 570 #if defined(sun)
 571         /* time_t is signed long */
 572         return ("%ld");
 573 #else
 574         /*CONSTANTCONDITION*/
 575         if (0.5 == (time_t)0.5) {       /* floating */
 576                 /*CONSTANTCONDITION*/
 577                 if (sizeof (time_t) > sizeof (double))
 578                         return ("%Lg");
 579                 return ("%g");
 580         }
 581         /*CONSTANTCONDITION*/
 582         if (0 > (time_t)-1) {                /* signed */
 583                 /*CONSTANTCONDITION*/
 584                 if (sizeof (time_t) > sizeof (long))
 585                         return ("%lld");
 586                 /*CONSTANTCONDITION*/
 587                 if (sizeof (time_t) > sizeof (int))
 588                         return ("%ld");
 589                 return ("%d");
 590         }
 591         /*CONSTANTCONDITION*/
 592         if (sizeof (time_t) > sizeof (unsigned long))
 593                 return ("%llu");
 594         /*CONSTANTCONDITION*/
 595         if (sizeof (time_t) > sizeof (unsigned int))
 596                 return ("%lu");
 597         return ("%u");
 598 #endif
 599 }
 600 
 601 static void
 602 dumptime(timeptr)
 603 register const struct tm        *timeptr;
 604 {
 605         static const char       wday_name[][3] = {
 606                 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
 607         };
 608         static const char       mon_name[][3] = {
 609                 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
 610                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 611         };
 612         register const char     *wn;
 613         register const char     *mn;
 614         register int            lead;
 615         register int            trail;
 616 
 617         if (timeptr == NULL) {
 618                 (void) printf("NULL");
 619                 return;
 620         }
 621         /*
 622          * The packaged versions of localtime and gmtime never put out-of-range
 623          * values in tm_wday or tm_mon, but since this code might be compiled
 624          * with other (perhaps experimental) versions, paranoia is in order.
 625          */
 626         if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
 627                 (int)(sizeof (wday_name) / sizeof (wday_name[0])))
 628                         wn = "???";
 629         else            wn = wday_name[timeptr->tm_wday];
 630         if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
 631                 (int)(sizeof (mon_name) / sizeof (mon_name[0])))
 632                         mn = "???";
 633         else            mn = mon_name[timeptr->tm_mon];
 634         (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
 635                 wn, mn,
 636                 timeptr->tm_mday, timeptr->tm_hour,
 637                 timeptr->tm_min, timeptr->tm_sec);
 638 #define DIVISOR 10
 639         trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
 640         lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
 641                 trail / DIVISOR;
 642         trail %= DIVISOR;
 643         if (trail < 0 && lead > 0) {
 644                 trail += DIVISOR;
 645                 --lead;
 646         } else if (lead < 0 && trail > 0) {
 647                 trail -= DIVISOR;
 648                 ++lead;
 649         }
 650         if (lead == 0)
 651                 (void) printf("%d", trail);
 652         else
 653                 (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
 654 }
 655 
 656 static void
 657 usage()
 658 {
 659         (void) fprintf(stderr, gettext(
 660             "%s: [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"),
 661                 progname);
 662         exit(EXIT_FAILURE);
 663         /* NOTREACHED */
 664 }