date.c 22 KB

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