1*5a5d821fSkre /* $NetBSD: date.c,v 1.70 2024/09/17 15:25:39 kre Exp $ */ 249f0ad86Scgd 361f28255Scgd /* 4667b5ea1Smycroft * Copyright (c) 1985, 1987, 1988, 1993 5667b5ea1Smycroft * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * Redistribution and use in source and binary forms, with or without 861f28255Scgd * modification, are permitted provided that the following conditions 961f28255Scgd * are met: 1061f28255Scgd * 1. Redistributions of source code must retain the above copyright 1161f28255Scgd * notice, this list of conditions and the following disclaimer. 1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1361f28255Scgd * notice, this list of conditions and the following disclaimer in the 1461f28255Scgd * documentation and/or other materials provided with the distribution. 15b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors 1661f28255Scgd * may be used to endorse or promote products derived from this software 1761f28255Scgd * without specific prior written permission. 1861f28255Scgd * 1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2961f28255Scgd * SUCH DAMAGE. 3061f28255Scgd */ 3161f28255Scgd 32634a8027Schristos #if HAVE_NBTOOL_CONFIG_H 33634a8027Schristos #include "nbtool_config.h" 34634a8027Schristos #endif 35634a8027Schristos 36a71a8b87Sthorpej #include <sys/cdefs.h> 3761f28255Scgd #ifndef lint 38a71a8b87Sthorpej __COPYRIGHT( 392fe2731dSlukem "@(#) Copyright (c) 1985, 1987, 1988, 1993\ 402fe2731dSlukem The Regents of the University of California. All rights reserved."); 4161f28255Scgd #endif /* not lint */ 4261f28255Scgd 4361f28255Scgd #ifndef lint 44d7290b76Scgd #if 0 455fc5415eSjtc static char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95"; 46d7290b76Scgd #else 47*5a5d821fSkre __RCSID("$NetBSD: date.c,v 1.70 2024/09/17 15:25:39 kre Exp $"); 48d7290b76Scgd #endif 4961f28255Scgd #endif /* not lint */ 5061f28255Scgd 5161f28255Scgd #include <sys/param.h> 5261f28255Scgd #include <sys/time.h> 53667b5ea1Smycroft 54667b5ea1Smycroft #include <ctype.h> 55667b5ea1Smycroft #include <err.h> 56667b5ea1Smycroft #include <fcntl.h> 5760c10f9bSchristos #include <errno.h> 58a824cb6aSwiz #include <locale.h> 5961f28255Scgd #include <stdio.h> 6061f28255Scgd #include <stdlib.h> 6161f28255Scgd #include <string.h> 62667b5ea1Smycroft #include <syslog.h> 63314d4116Skleink #include <time.h> 64f9a6471eSmycroft #include <tzfile.h> 65667b5ea1Smycroft #include <unistd.h> 664274523eScgd #include <util.h> 679337b5ddSchristos #if !HAVE_NBTOOL_CONFIG_H 689337b5ddSchristos #include <utmpx.h> 699337b5ddSchristos #endif 70667b5ea1Smycroft 71667b5ea1Smycroft #include "extern.h" 7261f28255Scgd 73a7151c0aSdsl static time_t tval; 7404f2a3c1Skim static int Rflag, aflag, jflag, rflag, nflag; 7561f28255Scgd 7633586bccSdholland __dead static void badcanotime(const char *, const char *, size_t); 77a824cb6aSwiz static void setthetime(const char *); 78aa6d7bb5Sjoerg __dead static void usage(void); 79667b5ea1Smycroft 80684d49e6Skre #if HAVE_NBTOOL_CONFIG_H 81684d49e6Skre static int parse_iso_datetime(time_t *, const char *); 82684d49e6Skre #else 83684d49e6Skre static char *fmt; 84684d49e6Skre #endif 85684d49e6Skre 86ad6bcacaSkre #if !defined(isleap) 87ad6bcacaSkre # define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) 88ad6bcacaSkre #endif 89ad6bcacaSkre 90667b5ea1Smycroft int 91a824cb6aSwiz main(int argc, char *argv[]) 9261f28255Scgd { 938a487b53Schristos char *buf; 948a487b53Schristos size_t bufsiz; 956310b596Schristos const char *format; 96a7151c0aSdsl int ch; 9760c10f9bSchristos long long val; 9860c10f9bSchristos struct tm *tm; 9902f83b58Skre char *default_tz; 10061f28255Scgd 101bb88f10dSwiz setprogname(argv[0]); 102bad15fd3Scgd (void)setlocale(LC_ALL, ""); 10318356811Sjtc 10402f83b58Skre default_tz = getenv("TZ"); 10502f83b58Skre 10602f83b58Skre while ((ch = getopt(argc, argv, "ad:f:jnRr:Uuz:")) != -1) { 10715bc25dcShubertf switch (ch) { 108a7151c0aSdsl case 'a': /* adjust time slowly */ 109a7151c0aSdsl aflag = 1; 110a7151c0aSdsl nflag = 1; 111a7151c0aSdsl break; 112aa62ece7Schristos case 'd': 113aa62ece7Schristos rflag = 1; 114684d49e6Skre #ifdef HAVE_NBTOOL_CONFIG_H 115684d49e6Skre if (parse_iso_datetime(&tval, optarg)) 116684d49e6Skre break; 117684d49e6Skre errx(EXIT_FAILURE, 118684d49e6Skre "-d only supports ISO format in the tool version"); 119684d49e6Skre break; 120684d49e6Skre #else 121684d49e6Skre errno = 0; 122ab56b9a7Schristos tval = parsedate(optarg, NULL, NULL); 123684d49e6Skre if (tval == -1 && errno != 0) { 12433586bccSdholland errx(EXIT_FAILURE, 12533586bccSdholland "%s: Unrecognized date format", optarg); 12633586bccSdholland } 127aa62ece7Schristos break; 1289337b5ddSchristos case 'f': 1299337b5ddSchristos fmt = optarg; 1309337b5ddSchristos break; 131684d49e6Skre #endif 1325d27a9d6Sjdarrow case 'j': /* don't set time */ 1335d27a9d6Sjdarrow jflag = 1; 1345d27a9d6Sjdarrow break; 13561f28255Scgd case 'n': /* don't set network */ 13661f28255Scgd nflag = 1; 13761f28255Scgd break; 13804f2a3c1Skim case 'R': /* RFC-5322 email format */ 13904f2a3c1Skim Rflag = 1; 14004f2a3c1Skim break; 14161f28255Scgd case 'r': /* user specified seconds */ 14233586bccSdholland if (optarg[0] == '\0') { 14333586bccSdholland errx(EXIT_FAILURE, "<empty>: Invalid number"); 14433586bccSdholland } 14560c10f9bSchristos errno = 0; 14660c10f9bSchristos val = strtoll(optarg, &buf, 0); 14733586bccSdholland if (errno) { 14833586bccSdholland err(EXIT_FAILURE, "%s", optarg); 14933586bccSdholland } 15033586bccSdholland if (optarg[0] == '\0' || *buf != '\0') { 15133586bccSdholland errx(EXIT_FAILURE, 15233586bccSdholland "%s: Invalid number", optarg); 15333586bccSdholland } 15461f28255Scgd rflag = 1; 15560c10f9bSchristos tval = (time_t)val; 15661f28255Scgd break; 15702f83b58Skre case 'U': /* reset to default timezone */ 15802f83b58Skre if (default_tz) 15902f83b58Skre (void)setenv("TZ", default_tz, 1); 16002f83b58Skre else 16102f83b58Skre (void)unsetenv("TZ"); 16202f83b58Skre break; 163d32f290dSmycroft case 'u': /* do everything in UTC */ 16410d3698aSgson (void)setenv("TZ", "UTC0", 1); 16561f28255Scgd break; 16602f83b58Skre case 'z': 16702f83b58Skre if (optarg[0] == '\0') 16802f83b58Skre (void)unsetenv("TZ"); 16902f83b58Skre else 17002f83b58Skre (void)setenv("TZ", optarg, 1); 17102f83b58Skre break; 17261f28255Scgd default: 17361f28255Scgd usage(); 17461f28255Scgd } 175a7151c0aSdsl } 17661f28255Scgd argc -= optind; 17761f28255Scgd argv += optind; 17861f28255Scgd 179667b5ea1Smycroft if (!rflag && time(&tval) == -1) 180fa141339Speter err(EXIT_FAILURE, "time"); 18161f28255Scgd 18261f28255Scgd 18361f28255Scgd /* allow the operands in any order */ 18461f28255Scgd if (*argv && **argv == '+') { 185a617f5fdSdholland format = *argv; 18661f28255Scgd ++argv; 18704f2a3c1Skim } else if (Rflag) { 18804f2a3c1Skim (void)setlocale(LC_TIME, "C"); 18904f2a3c1Skim format = "+%a, %-e %b %Y %H:%M:%S %z"; 19060c10f9bSchristos } else 19160c10f9bSchristos format = "+%a %b %e %H:%M:%S %Z %Y"; 19261f28255Scgd 19361f28255Scgd if (*argv) { 19461f28255Scgd setthetime(*argv); 19561f28255Scgd ++argv; 196684d49e6Skre #ifndef HAVE_NBTOOL_CONFIG_H 197684d49e6Skre } else if (fmt) { 1989337b5ddSchristos usage(); 199684d49e6Skre #endif 200684d49e6Skre } 20161f28255Scgd 20261f28255Scgd if (*argv && **argv == '+') 203a617f5fdSdholland format = *argv; 20461f28255Scgd 2058a487b53Schristos if ((buf = malloc(bufsiz = 1024)) == NULL) 2068a487b53Schristos goto bad; 20760c10f9bSchristos 20860c10f9bSchristos if ((tm = localtime(&tval)) == NULL) 20933586bccSdholland err(EXIT_FAILURE, "%lld: localtime", (long long)tval); 21060c10f9bSchristos 21160c10f9bSchristos while (strftime(buf, bufsiz, format, tm) == 0) 2128a487b53Schristos if ((buf = realloc(buf, bufsiz <<= 1)) == NULL) 2138a487b53Schristos goto bad; 21460c10f9bSchristos 215a617f5fdSdholland (void)printf("%s\n", buf + 1); 2168a487b53Schristos free(buf); 2178a487b53Schristos return 0; 2188a487b53Schristos bad: 21960c10f9bSchristos err(EXIT_FAILURE, "Cannot allocate format buffer"); 22061f28255Scgd } 22161f28255Scgd 222a824cb6aSwiz static void 22333586bccSdholland badcanotime(const char *msg, const char *val, size_t where) 224a824cb6aSwiz { 22533586bccSdholland warnx("%s in canonical time", msg); 22633586bccSdholland warnx("%s", val); 22733586bccSdholland warnx("%*s", (int)where + 1, "^"); 2289b5118f1Selad usage(); 2299b5118f1Selad } 2309b5118f1Selad 23165139bd9Smycroft #define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0')) 23265139bd9Smycroft 233684d49e6Skre #if HAVE_NBTOOL_CONFIG_H 234684d49e6Skre 235684d49e6Skre inline static int 236684d49e6Skre digitstring(const char *s, int len) 237684d49e6Skre { 238684d49e6Skre while (--len > 0) { 239684d49e6Skre if (!isdigit(*(unsigned char *)s)) 240684d49e6Skre return 0; 241684d49e6Skre s++; 242684d49e6Skre } 243684d49e6Skre return 1; 244684d49e6Skre } 245684d49e6Skre 246684d49e6Skre static int 247684d49e6Skre parse_iso_datetime(time_t * res, const char * string) 248684d49e6Skre { 249684d49e6Skre struct tm tm; 250684d49e6Skre time_t t; 251684d49e6Skre 252684d49e6Skre memset(&tm, 0, sizeof tm); 253684d49e6Skre 254684d49e6Skre if (!digitstring(string, 4)) 255684d49e6Skre return 0; 256684d49e6Skre tm.tm_year = ATOI2(string) * 100; 257684d49e6Skre tm.tm_year += ATOI2(string); 258684d49e6Skre tm.tm_year -= 1900; 259684d49e6Skre 260684d49e6Skre if (*string == '-') 261684d49e6Skre string++; 262684d49e6Skre 263684d49e6Skre if (!digitstring(string, 2)) 264684d49e6Skre return 0; 265684d49e6Skre 266684d49e6Skre tm.tm_mon = ATOI2(string); 267684d49e6Skre if (tm.tm_mon < 1 || tm.tm_mon > 12) 268684d49e6Skre return 0; 269684d49e6Skre tm.tm_mon--; 270684d49e6Skre 271684d49e6Skre if (*string == '-') 272684d49e6Skre string++; 273684d49e6Skre 274684d49e6Skre if (!digitstring(string, 2)) 275684d49e6Skre return 0; 276684d49e6Skre 277684d49e6Skre tm.tm_mday = ATOI2(string); 278684d49e6Skre if (tm.tm_mday < 1) 279684d49e6Skre return 0; 280684d49e6Skre switch (tm.tm_mon) { 281684d49e6Skre case 0: case 2: case 4: case 6: case 7: case 9: case 11: 282684d49e6Skre if (tm.tm_mday > 31) 283684d49e6Skre return 0; 284684d49e6Skre break; 285684d49e6Skre case 3: case 5: case 8: case 10: 286684d49e6Skre if (tm.tm_mday > 30) 287684d49e6Skre return 0; 288684d49e6Skre break; 289684d49e6Skre case 1: 290684d49e6Skre if (tm.tm_mday > 28 + isleap(tm.tm_year + 1900)) 291684d49e6Skre return 0; 292684d49e6Skre break; 293684d49e6Skre default: 294684d49e6Skre abort(); 295684d49e6Skre } 296684d49e6Skre 297684d49e6Skre do { 298684d49e6Skre if (*string == '\0') 299684d49e6Skre break; 300684d49e6Skre if (*string == 'T' || *string == 't' || *string == ' ' || 301684d49e6Skre *string == '-') 302684d49e6Skre string++; 303684d49e6Skre 304684d49e6Skre if (!digitstring(string, 2)) 305684d49e6Skre return 0; 306684d49e6Skre tm.tm_hour = ATOI2(string); 307684d49e6Skre if (tm.tm_hour > 23) 308684d49e6Skre return 0; 309684d49e6Skre 310684d49e6Skre if (*string == '\0') 311684d49e6Skre break; 312684d49e6Skre if (*string == ':') 313684d49e6Skre string++; 314684d49e6Skre 315684d49e6Skre if (!digitstring(string, 2)) 316684d49e6Skre return 0; 317684d49e6Skre tm.tm_min = ATOI2(string); 318684d49e6Skre if (tm.tm_min >= 60) 319684d49e6Skre return 0; 320684d49e6Skre 321684d49e6Skre if (*string == '\0') 322684d49e6Skre break; 323684d49e6Skre if (*string == ':') 324684d49e6Skre string++; 325684d49e6Skre 326684d49e6Skre if (!digitstring(string, 2)) 327684d49e6Skre return 0; 328684d49e6Skre tm.tm_sec = ATOI2(string); 329684d49e6Skre if (tm.tm_sec >= 60) 330684d49e6Skre return 0; 331684d49e6Skre } while (0); 332684d49e6Skre 333684d49e6Skre if (*string != '\0') 334684d49e6Skre return 0; 335684d49e6Skre 336684d49e6Skre tm.tm_isdst = -1; 337684d49e6Skre tm.tm_wday = -1; 338684d49e6Skre 339684d49e6Skre t = mktime(&tm); 340684d49e6Skre if (tm.tm_wday == -1) 341684d49e6Skre return 0; 342684d49e6Skre 343684d49e6Skre *res = t; 344684d49e6Skre return 1; 345684d49e6Skre } 346684d49e6Skre 347684d49e6Skre #endif /*NBTOOL*/ 348684d49e6Skre 34991825c12Sgmcgarry static void 350a824cb6aSwiz setthetime(const char *p) 35161f28255Scgd { 35261f28255Scgd struct timeval tv; 353a7151c0aSdsl time_t new_time; 354a824cb6aSwiz struct tm *lt; 35533586bccSdholland const char *dot, *t, *op; 3561b1ee3c7Scbiere size_t len; 3571b1ee3c7Scbiere int yearset; 35861f28255Scgd 3599337b5ddSchristos if ((lt = localtime(&tval)) == NULL) 3609337b5ddSchristos err(EXIT_FAILURE, "%lld: localtime", (long long)tval); 3619337b5ddSchristos 3629337b5ddSchristos lt->tm_isdst = -1; /* Divine correct DST */ 3639337b5ddSchristos 364684d49e6Skre #ifndef HAVE_NBTOOL_CONFIG_H 3659337b5ddSchristos if (fmt) { 3669337b5ddSchristos t = strptime(p, fmt, lt); 3679337b5ddSchristos if (t == NULL) { 3689337b5ddSchristos warnx("Failed conversion of ``%s''" 3699337b5ddSchristos " using format ``%s''\n", p, fmt); 3709337b5ddSchristos } else if (*t != '\0') 3719337b5ddSchristos warnx("Ignoring %zu extraneous" 3729337b5ddSchristos " characters in date string (%s)", 3739337b5ddSchristos strlen(t), t); 3749337b5ddSchristos goto setit; 3759337b5ddSchristos } 376*5a5d821fSkre if (getenv("POSIXLY_CORRECT") != NULL) { 377*5a5d821fSkre int yrdigs; 378*5a5d821fSkre const char * const e = "Bad POSIX format date ``%s''"; 379*5a5d821fSkre 380*5a5d821fSkre t = strptime(p, "%m%d%H%M", lt); 381*5a5d821fSkre if (t == NULL) 382*5a5d821fSkre errx(EXIT_FAILURE, e, p); 383*5a5d821fSkre if (*t != '\0') { 384*5a5d821fSkre yrdigs = strspn(t, "0123456789"); 385*5a5d821fSkre if (yrdigs != 2 && yrdigs != 4) 386*5a5d821fSkre errx(EXIT_FAILURE, e, p); 387*5a5d821fSkre t = strptime(t, yrdigs == 2 ? "%y" : "%Y", lt); 388*5a5d821fSkre if (t == NULL || *t != '\0') 389*5a5d821fSkre errx(EXIT_FAILURE, e, p); 390*5a5d821fSkre } 391*5a5d821fSkre goto setit; 392*5a5d821fSkre } 393684d49e6Skre #endif 394667b5ea1Smycroft for (t = p, dot = NULL; *t; ++t) { 39533586bccSdholland if (*t == '.') { 39633586bccSdholland if (dot == NULL) { 397667b5ea1Smycroft dot = t; 39833586bccSdholland } else { 39933586bccSdholland badcanotime("Unexpected dot", p, t - p); 400667b5ea1Smycroft } 40133586bccSdholland } else if (!isdigit((unsigned char)*t)) { 40233586bccSdholland badcanotime("Expected digit", p, t - p); 40333586bccSdholland } 404667b5ea1Smycroft } 40561f28255Scgd 406a17ce6adSbjh21 407667b5ea1Smycroft if (dot != NULL) { /* .ss */ 408dbfa4f81Smycroft len = strlen(dot); 40933586bccSdholland if (len > 3) { 41033586bccSdholland badcanotime("Unexpected digit after seconds field", 41133586bccSdholland p, strlen(p) - 1); 41233586bccSdholland } else if (len < 3) { 41333586bccSdholland badcanotime("Expected digit in seconds field", 41433586bccSdholland p, strlen(p)); 41533586bccSdholland } 416dbfa4f81Smycroft ++dot; 417667b5ea1Smycroft lt->tm_sec = ATOI2(dot); 4189b5118f1Selad if (lt->tm_sec > 61) 41933586bccSdholland badcanotime("Seconds out of range", p, strlen(p) - 1); 420dbfa4f81Smycroft } else { 421dbfa4f81Smycroft len = 0; 42261f28255Scgd lt->tm_sec = 0; 423dbfa4f81Smycroft } 42461f28255Scgd 42533586bccSdholland op = p; 426f9a6471eSmycroft yearset = 0; 427dbfa4f81Smycroft switch (strlen(p) - len) { 42865139bd9Smycroft case 12: /* cc */ 42965139bd9Smycroft lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE; 4309b5118f1Selad if (lt->tm_year < 0) 43133586bccSdholland badcanotime("Year before 1900", op, p - op + 1); 432f9a6471eSmycroft yearset = 1; 433f9a6471eSmycroft /* FALLTHROUGH */ 434f9a6471eSmycroft case 10: /* yy */ 435f9a6471eSmycroft if (yearset) { 43665139bd9Smycroft lt->tm_year += ATOI2(p); 437f9a6471eSmycroft } else { 438f9a6471eSmycroft yearset = ATOI2(p); 43965139bd9Smycroft if (yearset < 69) 44065139bd9Smycroft lt->tm_year = yearset + 2000 - TM_YEAR_BASE; 441eeec814aSmycroft else 44265139bd9Smycroft lt->tm_year = yearset + 1900 - TM_YEAR_BASE; 443f9a6471eSmycroft } 44461f28255Scgd /* FALLTHROUGH */ 44561f28255Scgd case 8: /* mm */ 44661f28255Scgd lt->tm_mon = ATOI2(p); 4479b5118f1Selad if (lt->tm_mon > 12 || lt->tm_mon == 0) 44833586bccSdholland badcanotime("Month out of range", op, p - op - 1); 44961f28255Scgd --lt->tm_mon; /* time struct is 0 - 11 */ 45061f28255Scgd /* FALLTHROUGH */ 45161f28255Scgd case 6: /* dd */ 45261f28255Scgd lt->tm_mday = ATOI2(p); 4539b5118f1Selad switch (lt->tm_mon) { 4549b5118f1Selad case 0: 4559b5118f1Selad case 2: 4569b5118f1Selad case 4: 4579b5118f1Selad case 6: 4589b5118f1Selad case 7: 4599b5118f1Selad case 9: 4609b5118f1Selad case 11: 4619b5118f1Selad if (lt->tm_mday > 31 || lt->tm_mday == 0) 46233586bccSdholland badcanotime("Day out of range (max 31)", 46333586bccSdholland op, p - op - 1); 4649b5118f1Selad break; 4659b5118f1Selad case 3: 4669b5118f1Selad case 5: 4679b5118f1Selad case 8: 4689b5118f1Selad case 10: 4699b5118f1Selad if (lt->tm_mday > 30 || lt->tm_mday == 0) 47033586bccSdholland badcanotime("Day out of range (max 30)", 47133586bccSdholland op, p - op - 1); 4729b5118f1Selad break; 4739b5118f1Selad case 1: 47433586bccSdholland if (isleap(lt->tm_year + TM_YEAR_BASE)) { 47533586bccSdholland if (lt->tm_mday > 29 || lt->tm_mday == 0) { 47633586bccSdholland badcanotime("Day out of range " 47733586bccSdholland "(max 29)", 47833586bccSdholland op, p - op - 1); 47933586bccSdholland } 48033586bccSdholland } else { 48133586bccSdholland if (lt->tm_mday > 28 || lt->tm_mday == 0) { 48233586bccSdholland badcanotime("Day out of range " 48333586bccSdholland "(max 28)", 48433586bccSdholland op, p - op - 1); 48533586bccSdholland } 48633586bccSdholland } 4879b5118f1Selad break; 4889b5118f1Selad default: 48933586bccSdholland /* 49033586bccSdholland * If the month was given, it's already been 49133586bccSdholland * checked. If a bad value came back from 49233586bccSdholland * localtime, something's badly broken. 49333586bccSdholland * (make this an assertion?) 49433586bccSdholland */ 49533586bccSdholland errx(EXIT_FAILURE, "localtime gave invalid month %d", 49633586bccSdholland lt->tm_mon); 4979b5118f1Selad } 49861f28255Scgd /* FALLTHROUGH */ 49961f28255Scgd case 4: /* hh */ 50061f28255Scgd lt->tm_hour = ATOI2(p); 5019b5118f1Selad if (lt->tm_hour > 23) 50233586bccSdholland badcanotime("Hour out of range", op, p - op - 1); 50361f28255Scgd /* FALLTHROUGH */ 50461f28255Scgd case 2: /* mm */ 50561f28255Scgd lt->tm_min = ATOI2(p); 5069b5118f1Selad if (lt->tm_min > 59) 50733586bccSdholland badcanotime("Minute out of range", op, p - op - 1); 50861f28255Scgd break; 509a7151c0aSdsl case 0: /* was just .sss */ 510a7151c0aSdsl if (len != 0) 511a7151c0aSdsl break; 512a7151c0aSdsl /* FALLTHROUGH */ 51361f28255Scgd default: 51433586bccSdholland if (strlen(p) - len > 12) { 51533586bccSdholland badcanotime("Too many digits", p, 12); 51633586bccSdholland } else { 51733586bccSdholland badcanotime("Not enough digits", p, strlen(p) - len); 51833586bccSdholland } 51961f28255Scgd } 5209337b5ddSchristos setit: 521d32f290dSmycroft /* convert broken-down time to UTC clock time */ 52233586bccSdholland if ((new_time = mktime(lt)) == -1) { 52333586bccSdholland /* Can this actually happen? */ 5249337b5ddSchristos err(EXIT_FAILURE, "mktime"); 52533586bccSdholland } 52661f28255Scgd 5275d27a9d6Sjdarrow /* if jflag is set, don't actually change the time, just return */ 5285d27a9d6Sjdarrow if (jflag) { 5295d27a9d6Sjdarrow tval = new_time; 5305d27a9d6Sjdarrow return; 5315d27a9d6Sjdarrow } 5325d27a9d6Sjdarrow 53361f28255Scgd /* set the time */ 534634a8027Schristos #ifndef HAVE_NBTOOL_CONFIG_H 5359337b5ddSchristos struct utmpx utx; 5369337b5ddSchristos memset(&utx, 0, sizeof(utx)); 5379337b5ddSchristos utx.ut_type = OLD_TIME; 5389337b5ddSchristos (void)gettimeofday(&utx.ut_tv, NULL); 5399337b5ddSchristos pututxline(&utx); 5409337b5ddSchristos 541a7151c0aSdsl if (nflag || netsettime(new_time)) { 54261f28255Scgd logwtmp("|", "date", ""); 543a7151c0aSdsl if (aflag) { 544a7151c0aSdsl tv.tv_sec = new_time - tval; 545a7151c0aSdsl tv.tv_usec = 0; 54615bc25dcShubertf if (adjtime(&tv, NULL)) 547a0cb2a83Sjnemeth err(EXIT_FAILURE, "adjtime"); 548a7151c0aSdsl } else { 549d8580191Sdsl tval = new_time; 55061f28255Scgd tv.tv_sec = tval; 55161f28255Scgd tv.tv_usec = 0; 55215bc25dcShubertf if (settimeofday(&tv, NULL)) 553a0cb2a83Sjnemeth err(EXIT_FAILURE, "settimeofday"); 554a7151c0aSdsl } 55561f28255Scgd logwtmp("{", "date", ""); 55661f28255Scgd } 5579337b5ddSchristos utx.ut_type = NEW_TIME; 5589337b5ddSchristos (void)gettimeofday(&utx.ut_tv, NULL); 5599337b5ddSchristos pututxline(&utx); 560667b5ea1Smycroft 561667b5ea1Smycroft if ((p = getlogin()) == NULL) 562667b5ea1Smycroft p = "???"; 563667b5ea1Smycroft syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 5649337b5ddSchristos #else 5659337b5ddSchristos errx(EXIT_FAILURE, "Can't set the time in the tools version"); 5669337b5ddSchristos #endif 56761f28255Scgd } 56861f28255Scgd 569667b5ea1Smycroft static void 570a824cb6aSwiz usage(void) 57161f28255Scgd { 57261f28255Scgd (void)fprintf(stderr, 57302f83b58Skre "Usage: %s [-ajnRUu] [-d date] [-r seconds] [-z zone] [+format]", 57460c10f9bSchristos getprogname()); 57502f83b58Skre (void)fprintf(stderr, "\n\t%*s[[[[[[CC]yy]mm]dd]HH]MM[.SS]]\n", 57602f83b58Skre (int)strlen(getprogname()), ""); 5779337b5ddSchristos (void)fprintf(stderr, 578219c5cc7Skim " %s [-ajnRu] -f input_format new_date [+format]\n", 5799337b5ddSchristos getprogname()); 58015bc25dcShubertf exit(EXIT_FAILURE); 5819dc385beSmycroft /* NOTREACHED */ 58261f28255Scgd } 583