1 /* $OpenBSD: date.c,v 1.59 2022/09/23 16:58:33 florian Exp $ */ 2 /* $NetBSD: date.c,v 1.11 1995/09/07 06:21:05 jtc Exp $ */ 3 4 /* 5 * Copyright (c) 1985, 1987, 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/time.h> 35 36 #include <ctype.h> 37 #include <err.h> 38 #include <fcntl.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <syslog.h> 44 #include <time.h> 45 #include <unistd.h> 46 #include <util.h> 47 48 extern char *__progname; 49 50 time_t tval; 51 int jflag; 52 int slidetime; 53 54 static void setthetime(char *, const char *); 55 static void badformat(void); 56 static void __dead usage(void); 57 58 int 59 main(int argc, char *argv[]) 60 { 61 const char *errstr; 62 struct tm *tp; 63 int ch, rflag; 64 char *format, buf[1024], *outzone = NULL; 65 const char *pformat = NULL; 66 67 rflag = 0; 68 while ((ch = getopt(argc, argv, "af:jr:uz:")) != -1) 69 switch(ch) { 70 case 'a': 71 slidetime = 1; 72 break; 73 case 'f': /* parse with strptime */ 74 pformat = optarg; 75 break; 76 case 'j': /* don't set */ 77 jflag = 1; 78 break; 79 case 'r': /* user specified seconds */ 80 rflag = 1; 81 tval = strtonum(optarg, LLONG_MIN, LLONG_MAX, &errstr); 82 if (errstr) 83 errx(1, "seconds is %s: %s", errstr, optarg); 84 break; 85 case 'u': /* do everything in UTC */ 86 if (setenv("TZ", "UTC", 1) == -1) 87 err(1, "cannot unsetenv TZ"); 88 break; 89 case 'z': 90 outzone = optarg; 91 break; 92 default: 93 usage(); 94 } 95 argc -= optind; 96 argv += optind; 97 98 if (!rflag && time(&tval) == -1) 99 err(1, "time"); 100 101 format = "%a %b %e %H:%M:%S %Z %Y"; 102 103 /* allow the operands in any order */ 104 if (*argv && **argv == '+') { 105 format = *argv + 1; 106 argv++; 107 argc--; 108 } 109 110 if (*argv) { 111 setthetime(*argv, pformat); 112 argv++; 113 argc--; 114 } 115 116 if (pledge("stdio", NULL) == -1) 117 err(1, "pledge"); 118 119 if (*argv && **argv == '+') { 120 format = *argv + 1; 121 argc--; 122 } 123 124 if (argc > 0) 125 errx(1, "too many arguments"); 126 127 if (outzone) 128 setenv("TZ", outzone, 1); 129 130 tp = localtime(&tval); 131 if (tp == NULL) 132 errx(1, "conversion error"); 133 (void)strftime(buf, sizeof(buf), format, tp); 134 (void)printf("%s\n", buf); 135 return 0; 136 } 137 138 #define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0')) 139 void 140 setthetime(char *p, const char *pformat) 141 { 142 struct tm *lt, tm; 143 struct timeval tv; 144 char *dot, *t; 145 time_t now; 146 int yearset = 0; 147 148 /* Let us set the time even if logwtmp would fail. */ 149 unveil("/var/log/wtmp", "w"); 150 if (pledge("stdio settime wpath", NULL) == -1) 151 err(1, "pledge"); 152 153 lt = localtime(&tval); 154 155 lt->tm_isdst = -1; /* correct for DST */ 156 157 if (pformat) { 158 tm = *lt; 159 if (strptime(p, pformat, &tm) == NULL) { 160 fprintf(stderr, "trouble %s %s\n", p, pformat); 161 badformat(); 162 } 163 lt = &tm; 164 } else { 165 for (t = p, dot = NULL; *t; ++t) { 166 if (isdigit((unsigned char)*t)) 167 continue; 168 if (*t == '.' && dot == NULL) { 169 dot = t; 170 continue; 171 } 172 badformat(); 173 } 174 175 if (dot != NULL) { /* .SS */ 176 *dot++ = '\0'; 177 if (strlen(dot) != 2) 178 badformat(); 179 lt->tm_sec = ATOI2(dot); 180 if (lt->tm_sec > 61) 181 badformat(); 182 } else 183 lt->tm_sec = 0; 184 185 switch (strlen(p)) { 186 case 12: /* cc */ 187 lt->tm_year = (ATOI2(p) * 100) - 1900; 188 yearset = 1; 189 /* FALLTHROUGH */ 190 case 10: /* yy */ 191 if (!yearset) { 192 /* mask out current year, leaving only century */ 193 lt->tm_year = ((lt->tm_year / 100) * 100); 194 } 195 lt->tm_year += ATOI2(p); 196 /* FALLTHROUGH */ 197 case 8: /* mm */ 198 lt->tm_mon = ATOI2(p); 199 if ((lt->tm_mon > 12) || !lt->tm_mon) 200 badformat(); 201 --lt->tm_mon; /* time struct is 0 - 11 */ 202 /* FALLTHROUGH */ 203 case 6: /* dd */ 204 lt->tm_mday = ATOI2(p); 205 if ((lt->tm_mday > 31) || !lt->tm_mday) 206 badformat(); 207 /* FALLTHROUGH */ 208 case 4: /* HH */ 209 lt->tm_hour = ATOI2(p); 210 if (lt->tm_hour > 23) 211 badformat(); 212 /* FALLTHROUGH */ 213 case 2: /* MM */ 214 lt->tm_min = ATOI2(p); 215 if (lt->tm_min > 59) 216 badformat(); 217 break; 218 default: 219 badformat(); 220 } 221 } 222 223 /* convert broken-down time to UTC clock time */ 224 if (pformat != NULL && strstr(pformat, "%s") != NULL) 225 tval = timegm(lt); 226 else 227 tval = mktime(lt); 228 if (tval == -1) 229 errx(1, "specified date is outside allowed range"); 230 231 if (jflag) 232 return; 233 234 /* set the time */ 235 if (slidetime) { 236 if ((now = time(NULL)) == -1) 237 err(1, "time"); 238 tv.tv_sec = tval - now; 239 tv.tv_usec = 0; 240 if (adjtime(&tv, NULL) == -1) 241 err(1, "adjtime"); 242 } else { 243 #ifndef SMALL 244 logwtmp("|", "date", ""); 245 #endif 246 tv.tv_sec = tval; 247 tv.tv_usec = 0; 248 if (settimeofday(&tv, NULL)) 249 err(1, "settimeofday"); 250 #ifndef SMALL 251 logwtmp("{", "date", ""); 252 #endif 253 } 254 255 if ((p = getlogin()) == NULL) 256 p = "???"; 257 syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 258 } 259 260 static void 261 badformat(void) 262 { 263 warnx("illegal time format"); 264 usage(); 265 } 266 267 static void __dead 268 usage(void) 269 { 270 fprintf(stderr, 271 "usage: %s [-aju] [-f pformat] [-r seconds]\n" 272 "\t[-z output_zone] [+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]]\n", 273 __progname); 274 exit(1); 275 } 276