home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.10 / util-lin / util-linux-1.10 / time / date.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-30  |  20.0 KB  |  877 lines

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