home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / zoneinfo / src / date.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-12  |  22.2 KB  |  938 lines

  1. #ifndef lint
  2. #ifndef NOID
  3. static char    elsieid[] = "@(#)date.c    7.32";
  4. /*
  5. ** Modified from the UCB version with the SCCS ID appearing below.
  6. */
  7. #endif /* !defined NOID */
  8. #endif /* !defined lint */
  9.  
  10. /*
  11.  * Copyright (c) 1985, 1987, 1988 The Regents of the University of California.
  12.  * All rights reserved.
  13.  *
  14.  * Redistribution and use in source and binary forms are permitted
  15.  * provided that the above copyright notice and this paragraph are
  16.  * duplicated in all such forms and that any documentation,
  17.  * advertising materials, and other materials related to such
  18.  * distribution and use acknowledge that the software was developed
  19.  * by the University of California, Berkeley.  The name of the
  20.  * University may not be used to endorse or promote products derived
  21.  * from this software without specific prior written permission.
  22.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  23.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  24.  * WARRANTIES OF MERCHANT[A]BILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  25.  */
  26.  
  27. #ifndef lint
  28. char copyright[] =
  29. "@(#) Copyright (c) 1985, 1987, 1988 The Regents of the University of California.\n\
  30.  All rights reserved.\n";
  31. #endif /* not lint */
  32.  
  33. #ifndef lint
  34. static char sccsid[] = "@(#)date.c    4.23 (Berkeley) 9/20/88";
  35. #endif /* not lint */
  36.  
  37. #include "private.h"
  38. #if HAVE_ADJTIME || HAVE_SETTIMEOFDAY
  39. #include "sys/time.h"    /* for struct timeval, struct timezone */
  40. #endif /* HAVE_ADJTIME || HAVE_SETTIMEOFDAY */
  41. #include "locale.h"
  42. #include "utmp.h"    /* for OLD_TIME (or its absence) */
  43. #if HAVE_UTMPX_H
  44. #include "utmpx.h"
  45. #endif
  46.  
  47. /*
  48. ** The two things date knows about time are. . .
  49. */
  50.  
  51. #ifndef TM_YEAR_BASE
  52. #define TM_YEAR_BASE    1900
  53. #endif /* !defined TM_YEAR_BASE */
  54.  
  55. #ifndef SECSPERMIN
  56. #define SECSPERMIN    60
  57. #endif /* !defined SECSPERMIN */
  58.  
  59. extern double        atof();
  60. extern char **        environ;
  61. extern char *        getlogin();
  62. extern time_t        mktime();
  63. extern char *        optarg;
  64. extern int        optind;
  65. extern char *        strchr();
  66. extern time_t        time();
  67. extern char *        tzname[2];
  68.  
  69. static int        retval = EXIT_SUCCESS;
  70.  
  71. static void        checkfinal P((const char *, int, time_t, time_t));
  72. static int        comptm P((const struct tm *, const struct tm *));
  73. static time_t        convert P((const char *, int, time_t));
  74. static void        display P((const char *));
  75. static void        dogmt P((void));
  76. static void        errensure P((void));
  77. static void        iffy P((time_t, time_t, const char *, const char *));
  78. int            main P((int, char**));
  79. static const char *    nondigit P((const char *));
  80. static void        oops P((const char *));
  81. static void        reset P((time_t, int));
  82. static void        timeout P((FILE *, const char *, const struct tm *));
  83. static void        usage P((void));
  84. static void        wildinput P((const char *, const char *,
  85.                 const char *));
  86.  
  87. int
  88. main(argc, argv)
  89. const int    argc;
  90. char *        argv[];
  91. {
  92.     register const char *    format;
  93.     register const char *    value;
  94.     register const char *    cp;
  95.     register int        ch;
  96.     register int        dousg;
  97.     register int        aflag = 0;
  98.     register int        dflag = 0;
  99.     register int        nflag = 0;
  100.     register int        tflag = 0;
  101.     register int        minuteswest;
  102.     register int        dsttime;
  103.     register double        adjust;
  104.     time_t            now;
  105.     time_t            t;
  106.  
  107.     INITIALIZE(dousg);
  108.     INITIALIZE(minuteswest);
  109.     INITIALIZE(dsttime);
  110.     INITIALIZE(adjust);
  111.     INITIALIZE(t);
  112. #if HAVE_GETTEXT - 0
  113.     (void) setlocale(LC_MESSAGES, "");
  114. #ifdef TZ_DOMAINDIR
  115.     (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
  116. #endif /* defined(TEXTDOMAINDIR) */
  117.     (void) textdomain(TZ_DOMAIN);
  118. #endif /* HAVE_GETTEXT - 0 */
  119.     (void) setlocale(LC_TIME, "");
  120.     (void) time(&now);
  121.     format = value = NULL;
  122.     while ((ch = getopt(argc, argv, "ucnd:t:a:")) != EOF) {
  123.         switch (ch) {
  124.         default:
  125.             usage();
  126.         case 'u':        /* do it in GMT */
  127.         case 'c':
  128.             dogmt();
  129.             break;
  130.         case 'n':        /* don't set network */
  131.             nflag = 1;
  132.             break;
  133.         case 'd':        /* daylight savings time */
  134.             if (dflag) {
  135.                 (void) fprintf(stderr,
  136.                     _("date: error: multiple -d's used"));
  137.                 usage();
  138.             }
  139.             dflag = 1;
  140.             cp = optarg;
  141.             dsttime = atoi(cp);
  142.             if (*cp == '\0' || *nondigit(cp) != '\0')
  143.                 wildinput(_("-t value"), optarg,
  144.                     _("must be a non-negative number"));
  145.             break;
  146.         case 't':        /* minutes west of GMT */
  147.             if (tflag) {
  148.                 (void) fprintf(stderr,
  149.                     _("date: error: multiple -t's used"));
  150.                 usage();
  151.             }
  152.             tflag = 1;
  153.             cp = optarg;
  154.             minuteswest = atoi(cp);
  155.             if (*cp == '+' || *cp == '-')
  156.                 ++cp;
  157.             if (*cp == '\0' || *nondigit(cp) != '\0')
  158.                 wildinput(_("-d value"), optarg,
  159.                     _("must be a number"));
  160.             break;
  161.         case 'a':        /* adjustment */
  162.             if (aflag) {
  163.                 (void) fprintf(stderr,
  164.                     _("date: error: multiple -a's used"));
  165.                 usage();
  166.             }
  167.             aflag = 1;
  168.             cp = optarg;
  169.             adjust = atof(cp);
  170.             if (*cp == '+' || *cp == '-')
  171.                 ++cp;
  172.             if (*cp == '\0' || strcmp(cp, ".") == 0)
  173.                 wildinput(_("-a value"), optarg,
  174.                     _("must be a number"));
  175.             cp = nondigit(cp);
  176.             if (*cp == '.')
  177.                 ++cp;
  178.             if (*nondigit(cp) != '\0')
  179.                 wildinput(_("-a value"), optarg,
  180.                     _("must be a number"));
  181.             break;
  182.         }
  183.     }
  184.     while (optind < argc) {
  185.         cp = argv[optind++];
  186.         if (*cp == '+')
  187.             if (format == NULL)
  188.                 format = cp + 1;
  189.             else {
  190.                 (void) fprintf(stderr,
  191. _("date: error: multiple formats in command line\n"));
  192.                 usage();
  193.             }
  194.         else    if (value == NULL)
  195.                 value = cp;
  196.             else {
  197.                 (void) fprintf(stderr,
  198. _("date: error: multiple values in command line\n"));
  199.                 usage();
  200.             }
  201.     }
  202.     if (value != NULL) {
  203.         /*
  204.         ** This order ensures that "reasonable" twelve-digit inputs
  205.         ** (such as 120203042006) won't be misinterpreted
  206.         ** even if time_t's range all the way back to the thirteenth
  207.         ** century.  Do not change the order.
  208.         */
  209.         t = convert(value, (dousg = TRUE), now);
  210.         if (t == -1)
  211.             t = convert(value, (dousg = FALSE), now);
  212.         if (t == -1) {
  213.             /*
  214.             ** Out of range values,
  215.             ** or time that falls in a DST transition hole?
  216.             */
  217.             if ((cp = strchr(value, '.')) != NULL) {
  218.                 /*
  219.                 ** Ensure that the failure of
  220.                 **    TZ=America/New_York date 8712312359.60
  221.                 ** doesn't get misdiagnosed.  (It was
  222.                 **    TZ=America/New_York date 8712311859.60
  223.                 ** when the leap second was inserted.)
  224.                 ** The normal check won't work since
  225.                 ** the given time is valid in GMT.
  226.                 */
  227.                 if (atoi(cp + 1) >= SECSPERMIN)
  228.                     wildinput(_("time"), value,
  229.                         _("out of range seconds given"));
  230.             }
  231.             dogmt();
  232.             t = convert(value, FALSE, now);
  233.             if (t == -1)
  234.                 t = convert(value, TRUE, now);
  235.             wildinput(_("time"), value,
  236.                 (t == -1) ?
  237.                 _("out of range value given") :
  238.                 _("time skipped when clock springs forward"));
  239.         }
  240.     }
  241.     /*
  242.     ** Entire command line has now been checked.
  243.     */
  244.     if (aflag) {
  245. #if HAVE_ADJTIME
  246.         struct timeval    tv;
  247.  
  248.         tv.tv_sec = (int) adjust;
  249.         tv.tv_usec = (int) ((adjust - tv.tv_sec) * 1000000);
  250.         if (adjtime(&tv, (struct timeval *) NULL) != 0)
  251.             oops("adjtime");
  252. #endif /* HAVE_ADJTIME */
  253. #if !HAVE_ADJTIME
  254.         reset((time_t) (now + adjust), nflag);
  255. #endif /* !HAVE_ADJTIME */
  256.         /*
  257.         ** Sun silently ignores everything else; we follow suit.
  258.         */
  259.         (void) exit(retval);
  260.     }
  261.     if (dflag || tflag) {
  262. #if HAVE_SETTIMEOFDAY == 2
  263.         struct timezone    tz;
  264.  
  265.         if (!dflag || !tflag)
  266.             if (gettimeofday((struct timeval *) NULL, &tz) != 0)
  267.                 oops("gettimeofday");
  268.         if (dflag)
  269.             tz.tz_dsttime = dsttime;
  270.         if (tflag)
  271.             tz.tz_minuteswest = minuteswest;
  272.         if (settimeofday((struct timeval *) NULL, &tz) != 0)
  273.             oops("settimeofday");
  274. #endif /* HAVE_SETTIMEOFDAY == 2 */
  275. #if HAVE_SETTIMEOFDAY != 2
  276.         (void) fprintf(stderr,
  277. _("date: warning: kernel doesn't keep -d/-t information, option ignored\n"));
  278. #endif /* HAVE_SETTIMEOFDAY != 2 */
  279.     }
  280.  
  281.     if (value == NULL)
  282.         display(format);
  283.  
  284.     reset(t, nflag);
  285.  
  286.     checkfinal(value, dousg, t, now);
  287.  
  288. #ifdef EBUG
  289.     {
  290.         struct tm    tm;
  291.  
  292.         tm = *localtime(&t);
  293.         timeout(stdout, "%c\n", &tm);
  294.         (void) exit(retval);
  295.     }
  296. #endif /* defined EBUG */
  297.  
  298.     display(format);
  299.  
  300.     /* gcc -Wall pacifier */
  301.     for ( ; ; )
  302.         continue;
  303. }
  304.  
  305. static void
  306. dogmt()
  307. {
  308.     static char **    fakeenv;
  309.  
  310.     if (fakeenv == NULL) {
  311.         register int    from;
  312.         register int    to;
  313.         register int    n;
  314.         static char    tzegmt0[] = "TZ=GMT0";
  315.  
  316.         for (n = 0;  environ[n] != NULL;  ++n)
  317.             continue;
  318.         fakeenv = (char **) malloc((size_t) (n + 2) * sizeof *fakeenv);
  319.         if (fakeenv == NULL) {
  320.             (void) perror(_("Memory exhausted"));
  321.             errensure();
  322.             (void) exit(retval);
  323.         }
  324.         to = 0;
  325.         fakeenv[to++] = tzegmt0;
  326.         for (from = 1; environ[from] != NULL; ++from)
  327.             if (strncmp(environ[from], "TZ=", 3) != 0)
  328.                 fakeenv[to++] = environ[from];
  329.         fakeenv[to] = NULL;
  330.         environ = fakeenv;
  331.     }
  332. }
  333.  
  334. #ifdef OLD_TIME
  335.  
  336. /*
  337. ** We assume we're on a System-V-based system,
  338. ** should use stime,
  339. ** should write System-V-format utmp entries,
  340. ** and don't have network notification to worry about.
  341. */
  342.  
  343. #include "fcntl.h"    /* for O_WRONLY, O_APPEND */
  344.  
  345. /*ARGSUSED*/
  346. static void
  347. reset(newt, nflag)
  348. const time_t    newt;
  349. const int    nflag;
  350. {
  351.     register int        fid;
  352.     time_t            oldt;
  353.     static struct {
  354.         struct utmp    before;
  355.         struct utmp    after;
  356.     } s;
  357. #if HAVE_UTMPX_H
  358.     static struct {
  359.         struct utmpx    before;
  360.         struct utmpx    after;
  361.     } sx;
  362. #endif
  363.  
  364.     /*
  365.     ** Wouldn't it be great if stime returned the old time?
  366.     */
  367.     (void) time(&oldt);
  368.     if (stime(&newt) != 0)
  369.         oops("stime");
  370.     s.before.ut_type = OLD_TIME;
  371.     s.before.ut_time = oldt;
  372.     (void) strcpy(s.before.ut_line, OTIME_MSG);
  373.     s.after.ut_type = NEW_TIME;
  374.     s.after.ut_time = newt;
  375.     (void) strcpy(s.after.ut_line, NTIME_MSG);
  376.     fid = open(WTMP_FILE, O_WRONLY | O_APPEND);
  377.     if (fid < 0)
  378.         oops(_("log file open"));
  379.     if (write(fid, (char *) &s, sizeof s) != sizeof s)
  380.         oops(_("log file write"));
  381.     if (close(fid) != 0)
  382.         oops(_("log file close"));
  383. #if !HAVE_UTMPX_H
  384.     pututline(&s.before);
  385.     pututline(&s.after);
  386. #endif /* !HAVE_UTMPX_H */
  387. #if HAVE_UTMPX_H
  388.     sx.before.ut_type = OLD_TIME;
  389.     sx.before.ut_tv.tv_sec = oldt;
  390.     (void) strcpy(sx.before.ut_line, OTIME_MSG);
  391.     sx.after.ut_type = NEW_TIME;
  392.     sx.after.ut_tv.tv_sec = newt;
  393.     (void) strcpy(sx.after.ut_line, NTIME_MSG);
  394. #if !SUPPRESS_WTMPX_FILE_UPDATE
  395.     /* In Solaris 2.5 (and presumably other systems),
  396.        `date' does not update /var/adm/wtmpx.
  397.        This must be a bug.  If you'd like to reproduce the bug,
  398.        define SUPPRESS_WTMPX_FILE_UPDATE to be nonzero.  */
  399.     fid = open(WTMPX_FILE, O_WRONLY | O_APPEND);
  400.     if (fid < 0)
  401.         oops(_("log file open"));
  402.     if (write(fid, (char *) &sx, sizeof sx) != sizeof sx)
  403.         oops(_("log file write"));
  404.     if (close(fid) != 0)
  405.         oops(_("log file close"));
  406. #endif /* !SUPPRESS_WTMPX_FILE_UPDATE */
  407.     pututxline(&sx.before);
  408.     pututxline(&sx.after);
  409. #endif /* HAVE_UTMPX_H */
  410. }
  411.  
  412. #endif /* defined OLD_TIME */
  413. #ifndef OLD_TIME
  414.  
  415. /*
  416. ** We assume we're on a BSD-based system,
  417. ** should use settimeofday,
  418. ** should write BSD-format utmp entries (using logwtmp),
  419. ** and may get to worry about network notification.
  420. ** The "time name" changes between 4.3-tahoe and 4.4;
  421. ** we include sys/param.h to determine which we should use.
  422. */
  423.  
  424. #ifndef TIME_NAME
  425. #include "sys/param.h"
  426. #ifdef BSD4_4
  427. #define TIME_NAME    "date"
  428. #endif /* defined BSD4_4 */
  429. #ifndef BSD4_4
  430. #define TIME_NAME    ""
  431. #endif /* !defined BSD4_4 */
  432. #endif /* !defined TIME_NAME */
  433.  
  434. #include "syslog.h"
  435. #include "sys/socket.h"
  436. #include "netinet/in.h"
  437. #include "netdb.h"
  438. #define TSPTYPES
  439. #include "protocols/timed.h"
  440.  
  441. extern int        logwtmp();
  442.  
  443. #if HAVE_SETTIMEOFDAY == 1
  444. #define settimeofday(t, tz) (settimeofday)(t)
  445. #endif /* HAVE_SETTIMEOFDAY == 1 */
  446.  
  447. #ifndef TSP_SETDATE
  448. /*ARGSUSED*/
  449. #endif /* !defined TSP_SETDATE */
  450. static void
  451. reset(newt, nflag)
  452. const time_t    newt;
  453. const int    nflag;
  454. {
  455.     register const char *    username;
  456.     static struct timeval    tv;    /* static so tv_usec is 0 */
  457.  
  458. #ifdef EBUG
  459.     return;
  460. #endif /* defined EBUG */
  461.     username = getlogin();
  462.     if (username == NULL || *username == '\0') /* single-user or no tty */
  463.         username = "root";
  464.     tv.tv_sec = newt;
  465. #ifdef TSP_SETDATE
  466.     if (nflag || !netsettime(tv))
  467. #endif /* defined TSP_SETDATE */
  468.     {
  469.         /*
  470.         ** "old" entry is always written, for compatibility.
  471.         */
  472.         logwtmp("|", TIME_NAME, "");
  473.         if (settimeofday(&tv, (struct timezone *) NULL) == 0) {
  474.             logwtmp("{", TIME_NAME, "");    /* } */
  475.             syslog(LOG_AUTH | LOG_NOTICE, _("date set by %s"),
  476.                 username);
  477.         } else    oops("settimeofday");
  478.     }
  479. }
  480.  
  481. #endif /* !defined OLD_TIME */
  482.  
  483. static void
  484. wildinput(item, value, reason)
  485. const char * const    item;
  486. const char * const    value;
  487. const char * const    reason;
  488. {
  489.     (void) fprintf(stderr,
  490.         _("date: error: bad command line %s \"%s\", %s\n"),
  491.         item, value, reason);
  492.     usage();
  493. }
  494.  
  495. static void
  496. errensure P((void))
  497. {
  498.     if (retval == EXIT_SUCCESS)
  499.         retval = EXIT_FAILURE;
  500. }
  501.  
  502. static const char *
  503. nondigit(cp)
  504. register const char *    cp;
  505. {
  506.     while (is_digit(*cp))
  507.         ++cp;
  508.     return cp;
  509. }
  510.  
  511. static void
  512. usage P((void))
  513. {
  514.     (void) fprintf(stderr, _("date: usage is date [-u] [-c] [-n] [-d dst] \
  515. [-t min-west] [-a sss.fff] [[yyyy]mmddhhmm[yyyy][.ss]] [+format]\n"));
  516.     errensure();
  517.     (void) exit(retval);
  518. }
  519.  
  520. static void
  521. oops(string)
  522. const char * const    string;
  523. {
  524.     int        e = errno;
  525.  
  526.     (void) fprintf(stderr, _("date: error: "));
  527.     errno = e;
  528.     (void) perror(string);
  529.     errensure();
  530.     display((char *) NULL);
  531. }
  532.  
  533. static void
  534. display(format)
  535. const char * const    format;
  536. {
  537.     struct tm    tm;
  538.     time_t        now;
  539.  
  540.     (void) time(&now);
  541.     tm = *localtime(&now);
  542.     timeout(stdout, format ? format : "%+", &tm);
  543.     (void) putchar('\n');
  544.     (void) fflush(stdout);
  545.     (void) fflush(stderr);
  546.     if (ferror(stdout) || ferror(stderr)) {
  547.         (void) fprintf(stderr,
  548.             _("date: error: couldn't write results\n"));
  549.         errensure();
  550.     }
  551.     (void) exit(retval);
  552. }
  553.  
  554. extern size_t    strftime();
  555.  
  556. #define INCR    1024
  557.  
  558. static void
  559. timeout(fp, format, tmp)
  560. FILE * const        fp;
  561. const char * const    format;
  562. const struct tm * const    tmp;
  563. {
  564.     char *    cp;
  565.     size_t    result;
  566.     size_t    size;
  567.  
  568.     if (*format == '\0')
  569.         return;
  570.     size = INCR;
  571.     cp = malloc((size_t) size);
  572.     for ( ; ; ) {
  573.         if (cp == NULL) {
  574.             (void) fprintf(stderr,
  575.                 _("date: error: can't get memory\n"));
  576.             errensure();
  577.             (void) exit(retval);
  578.         }
  579.         result = strftime(cp, size, format, tmp);
  580.         if (result != 0)
  581.             break;
  582.         size += INCR;
  583.         cp = realloc(cp, (size_t) size);
  584.     }
  585.     (void) fwrite(cp, 1, result, fp);
  586.     free(cp);
  587. }
  588.  
  589. static int
  590. comptm(atmp, btmp)
  591. register const struct tm * const atmp;
  592. register const struct tm * const btmp;
  593. {
  594.     register int    result;
  595.  
  596.     if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
  597.         (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
  598.         (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
  599.         (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
  600.         (result = (atmp->tm_min - btmp->tm_min)) == 0)
  601.             result = atmp->tm_sec - btmp->tm_sec;
  602.     return result;
  603. }
  604.  
  605. /*
  606. ** convert --
  607. **    convert user's input into a time_t.
  608. */
  609.  
  610. #define ATOI2(ar)    (ar[0] - '0') * 10 + (ar[1] - '0'); ar += 2;
  611.  
  612. static time_t
  613. convert(value, dousg, t)
  614. register const char * const    value;
  615. const int            dousg;
  616. const time_t            t;
  617. {
  618.     register const char *    cp;
  619.     register const char *    dotp;
  620.     register int    cent, year_in_cent, month, hour, day, mins, secs;
  621.     struct tm    tm, outtm;
  622.     time_t        outt;
  623.  
  624.     tm = *localtime(&t);
  625.     cent = (tm.tm_year + TM_YEAR_BASE) / 100;
  626.     year_in_cent = (tm.tm_year + TM_YEAR_BASE) - cent * 100;
  627.     month = tm.tm_mon + 1;
  628.     day = tm.tm_mday;
  629.     hour = tm.tm_hour;
  630.     mins = tm.tm_min;
  631.     secs = 0;
  632.  
  633.     dotp = strchr(value, '.');
  634.     for (cp = value; *cp != '\0'; ++cp)
  635.         if (!is_digit(*cp) && cp != dotp)
  636.             wildinput(_("time"), value, _("contains a nondigit"));
  637.  
  638.     if (dotp == NULL)
  639.         dotp = strchr(value, '\0');
  640.     else {
  641.         cp = dotp + 1;
  642.         if (strlen(cp) != 2)
  643.             wildinput(_("time"), value,
  644.                 _("seconds part is not two digits"));
  645.         secs = ATOI2(cp);
  646.     }
  647.  
  648.     cp = value;
  649.     switch (dotp - cp) {
  650.         default:
  651.             wildinput(_("time"), value, _("main part is wrong length"));
  652.         case 12:
  653.             if (!dousg) {
  654.                 cent = ATOI2(cp);
  655.                 year_in_cent = ATOI2(cp);
  656.             }
  657.             month = ATOI2(cp);
  658.             day = ATOI2(cp);
  659.             hour = ATOI2(cp);
  660.             mins = ATOI2(cp);
  661.             if (dousg) {
  662.                 cent = ATOI2(cp);
  663.                 year_in_cent = ATOI2(cp);
  664.             }
  665.             break;
  666.         case 8:    /* mmddhhmm */
  667.             month = ATOI2(cp);
  668.             /* fall through to. . . */
  669.         case 6:    /* ddhhmm */
  670.             day = ATOI2(cp);
  671.             /* fall through to. . . */
  672.         case 4:    /* hhmm */
  673.             hour = ATOI2(cp);
  674.             mins = ATOI2(cp);
  675.             break;
  676.         case 10:
  677.             if (!dousg) {
  678.                 year_in_cent = ATOI2(cp);
  679.             }
  680.             month = ATOI2(cp);
  681.             day = ATOI2(cp);
  682.             hour = ATOI2(cp);
  683.             mins = ATOI2(cp);
  684.             if (dousg) {
  685.                 year_in_cent = ATOI2(cp);
  686.             }
  687.             break;
  688.     }
  689.  
  690.     tm.tm_year = cent * 100 + year_in_cent - TM_YEAR_BASE;
  691.     tm.tm_mon = month - 1;
  692.     tm.tm_mday = day;
  693.     tm.tm_hour = hour;
  694.     tm.tm_min = mins;
  695.     tm.tm_sec = secs;
  696.     tm.tm_isdst = -1;
  697.     outtm = tm;
  698.     outt = mktime(&outtm);
  699.     return (comptm(&tm, &outtm) == 0) ? outt : -1;
  700. }
  701.  
  702. /*
  703. ** Code from here on out is either based on code provided by UCB
  704. ** or is only called just before the program exits.
  705. */
  706.  
  707. /*
  708. ** Check for iffy input.
  709. */
  710.  
  711. static void
  712. checkfinal(value, didusg, t, oldnow)
  713. const char * const    value;
  714. const int        didusg;
  715. const time_t        t;
  716. const time_t        oldnow;
  717. {
  718.     time_t        othert;
  719.     struct tm    tm;
  720.     struct tm    othertm;
  721.     register int    pass;
  722.     register long    offset;
  723.  
  724.     /*
  725.     ** See if there's both a USG and a BSD interpretation.
  726.     */
  727.     othert = convert(value, !didusg, oldnow);
  728.     if (othert != -1 && othert != t)
  729.         iffy(t, othert, value, _("year could be at start or end"));
  730.     /*
  731.     ** See if there's both a DST and a STD version.
  732.     */
  733.     tm = *localtime(&t);
  734.     othertm = tm;
  735.     othertm.tm_isdst = !tm.tm_isdst;
  736.     othert = mktime(&othertm);
  737.     if (othert != -1 && othertm.tm_isdst != tm.tm_isdst &&
  738.         comptm(&tm, &othertm) == 0)
  739.             iffy(t, othert, value,
  740.                 _("both standard and summer time versions exist"));
  741. /*
  742. ** Final check.
  743. **
  744. ** If a jurisdiction shifts time *without* shifting whether time is
  745. ** summer or standard (as Hawaii, the United Kingdom, and Saudi Arabia
  746. ** have done), routine checks for iffy times may not work.
  747. ** So we perform this final check, deferring it until after the time has
  748. ** been set--it may take a while, and we don't want to introduce an unnecessary
  749. ** lag between the time the user enters their command and the time that
  750. ** stime/settimeofday is called.
  751. **
  752. ** We just check nearby times to see if any have the same representation
  753. ** as the time that convert returned.  We work our way out from the center
  754. ** for quick response in solar time situations.  We only handle common cases--
  755. ** offsets of at most a minute, and offsets of exact numbers of minutes
  756. ** and at most an hour.
  757. */
  758.     for (offset = 1; offset <= 60; ++offset)
  759.         for (pass = 1; pass <= 4; ++pass) {
  760.             if (pass == 1)
  761.                 othert = t + offset;
  762.             else if (pass == 2)
  763.                 othert = t - offset;
  764.             else if (pass == 3)
  765.                 othert = t + 60 * offset;
  766.             else    othert = t - 60 * offset;
  767.             othertm = *localtime(&othert);
  768.             if (comptm(&tm, &othertm) == 0)
  769.                 iffy(t, othert, value,
  770.                     _("multiple matching times exist"));
  771.         }
  772. }
  773.  
  774. static void
  775. iffy(thist, thatt, value, reason)
  776. const time_t        thist;
  777. const time_t        thatt;
  778. const char * const    value;
  779. const char * const    reason;
  780. {
  781.     struct tm    tm;
  782.  
  783.     (void) fprintf(stderr, _("date: warning: ambiguous time \"%s\", %s.\n"),
  784.         value, reason);
  785.     tm = *gmtime(&thist);
  786.     /*
  787.     ** Avoid running afoul of SCCS!
  788.     */
  789.     timeout(stderr, _("Time was set as if you used\n\tdate -u %m%d%H\
  790. %M\
  791. %Y.%S\n"), &tm);
  792.     tm = *localtime(&thist);
  793.     timeout(stderr, _("to get %c"), &tm);
  794.     (void) fprintf(stderr, _(" (%s).  Use\n"),
  795.         tm.tm_isdst ? _("summer time") : _("standard time"));
  796.     tm = *gmtime(&thatt);
  797.     timeout(stderr, _("\tdate -u %m%d%H\
  798. %M\
  799. %Y.%S\n"), &tm);
  800.     tm = *localtime(&thatt);
  801.     timeout(stderr, _("to get %c"), &tm);
  802.     (void) fprintf(stderr, _(" (%s).\n"),
  803.         tm.tm_isdst ? _("summer time") : _("standard time"));
  804.     errensure();
  805.     (void) exit(retval);
  806. }
  807.  
  808. #ifdef TSP_SETDATE
  809. #define WAITACK        2    /* seconds */
  810. #define WAITDATEACK    5    /* seconds */
  811.  
  812. /*
  813.  * Set the date in the machines controlled by timedaemons
  814.  * by communicating the new date to the local timedaemon.
  815.  * If the timedaemon is in the master state, it performs the
  816.  * correction on all slaves.  If it is in the slave state, it
  817.  * notifies the master that a correction is needed.
  818.  * Returns 1 on success, 0 on failure.
  819.  */
  820. netsettime(ntv)
  821.     struct timeval ntv;
  822. {
  823.     int s, length, port, timed_ack, found, err;
  824.     long waittime;
  825.     fd_set ready;
  826.     char hostname[MAXHOSTNAMELEN];
  827.     struct timeval tout;
  828.     struct servent *sp;
  829.     struct tsp msg;
  830.     struct sockaddr_in sin, dest, from;
  831.  
  832.     sp = getservbyname("timed", "udp");
  833.     if (sp == 0) {
  834.         fputs(_("udp/timed: unknown service\n"), stderr);
  835.         retval = 2;
  836.         return (0);
  837.     }
  838.     dest.sin_port = sp->s_port;
  839.     dest.sin_family = AF_INET;
  840.     dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
  841.     s = socket(AF_INET, SOCK_DGRAM, 0);
  842.     if (s < 0) {
  843.         if (errno != EPROTONOSUPPORT)
  844.             perror("date: socket");
  845.         goto bad;
  846.     }
  847.     bzero((char *)&sin, sizeof (sin));
  848.     sin.sin_family = AF_INET;
  849.     for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
  850.         sin.sin_port = htons((u_short)port);
  851.         if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
  852.             break;
  853.         if (errno != EADDRINUSE) {
  854.             if (errno != EADDRNOTAVAIL)
  855.                 perror("date: bind");
  856.             goto bad;
  857.         }
  858.     }
  859.     if (port == IPPORT_RESERVED / 2) {
  860.         fputs(_("date: All ports in use\n"), stderr);
  861.         goto bad;
  862.     }
  863.     msg.tsp_type = TSP_SETDATE;
  864.     msg.tsp_vers = TSPVERSION;
  865.     if (gethostname(hostname, sizeof (hostname))) {
  866.         perror("gethostname");
  867.         goto bad;
  868.     }
  869.     (void) strncpy(msg.tsp_name, hostname, sizeof (hostname));
  870.     msg.tsp_seq = htons((u_short)0);
  871.     msg.tsp_time.tv_sec = htonl((u_long)ntv.tv_sec);
  872.     msg.tsp_time.tv_usec = htonl((u_long)ntv.tv_usec);
  873.     length = sizeof (struct sockaddr_in);
  874.     if (connect(s, &dest, length) < 0) {
  875.         perror("date: connect");
  876.         goto bad;
  877.     }
  878.     if (send(s, (char *)&msg, sizeof (struct tsp), 0) < 0) {
  879.         if (errno != ECONNREFUSED)
  880.             perror("date: send");
  881.         goto bad;
  882.     }
  883.     timed_ack = -1;
  884.     waittime = WAITACK;
  885. loop:
  886.     tout.tv_sec = waittime;
  887.     tout.tv_usec = 0;
  888.     FD_ZERO(&ready);
  889.     FD_SET(s, &ready);
  890.     found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
  891.     length = sizeof(err);
  892.     if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&err, &length) == 0
  893.         && err) {
  894.         errno = err;
  895.         if (errno != ECONNREFUSED)
  896.             perror(_("date: send (delayed error)"));
  897.         goto bad;
  898.     }
  899.     if (found > 0 && FD_ISSET(s, &ready)) {
  900.         length = sizeof (struct sockaddr_in);
  901.         if (recvfrom(s, (char *)&msg, sizeof (struct tsp), 0, &from,
  902.             &length) < 0) {
  903.             if (errno != ECONNREFUSED)
  904.                 perror("date: recvfrom");
  905.             goto bad;
  906.         }
  907.         msg.tsp_seq = ntohs(msg.tsp_seq);
  908.         msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
  909.         msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
  910.         switch (msg.tsp_type) {
  911.  
  912.         case TSP_ACK:
  913.             timed_ack = TSP_ACK;
  914.             waittime = WAITDATEACK;
  915.             goto loop;
  916.  
  917.         case TSP_DATEACK:
  918.             (void)close(s);
  919.             return (1);
  920.  
  921.         default:
  922.             fprintf(stderr,
  923.                 _("date: Wrong ack received from timed: %s\n"),
  924.                 tsptype[msg.tsp_type]);
  925.             timed_ack = -1;
  926.             break;
  927.         }
  928.     }
  929.     if (timed_ack == -1)
  930.         fputs(_("date: Can't reach time daemon, time set locally.\n"),
  931.             stderr);
  932. bad:
  933.     (void)close(s);
  934.     retval = 2;
  935.     return (0);
  936. }
  937. #endif /* defined TSP_SETDATE */
  938.