home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.2 / util-lin / util-linux-2.2 / time / date.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  21.2 KB  |  901 lines

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