1 /* $OpenBSD: date.c,v 1.60 2024/04/28 16:43:15 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
main(int argc,char * argv[])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
setthetime(char * p,const char * pformat)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 if (lt == NULL)
155 errx(1, "conversion error");
156
157 lt->tm_isdst = -1; /* correct for DST */
158
159 if (pformat) {
160 tm = *lt;
161 if (strptime(p, pformat, &tm) == NULL) {
162 fprintf(stderr, "trouble %s %s\n", p, pformat);
163 badformat();
164 }
165 lt = &tm;
166 } else {
167 for (t = p, dot = NULL; *t; ++t) {
168 if (isdigit((unsigned char)*t))
169 continue;
170 if (*t == '.' && dot == NULL) {
171 dot = t;
172 continue;
173 }
174 badformat();
175 }
176
177 if (dot != NULL) { /* .SS */
178 *dot++ = '\0';
179 if (strlen(dot) != 2)
180 badformat();
181 lt->tm_sec = ATOI2(dot);
182 if (lt->tm_sec > 61)
183 badformat();
184 } else
185 lt->tm_sec = 0;
186
187 switch (strlen(p)) {
188 case 12: /* cc */
189 lt->tm_year = (ATOI2(p) * 100) - 1900;
190 yearset = 1;
191 /* FALLTHROUGH */
192 case 10: /* yy */
193 if (!yearset) {
194 /* mask out current year, leaving only century */
195 lt->tm_year = ((lt->tm_year / 100) * 100);
196 }
197 lt->tm_year += ATOI2(p);
198 /* FALLTHROUGH */
199 case 8: /* mm */
200 lt->tm_mon = ATOI2(p);
201 if ((lt->tm_mon > 12) || !lt->tm_mon)
202 badformat();
203 --lt->tm_mon; /* time struct is 0 - 11 */
204 /* FALLTHROUGH */
205 case 6: /* dd */
206 lt->tm_mday = ATOI2(p);
207 if ((lt->tm_mday > 31) || !lt->tm_mday)
208 badformat();
209 /* FALLTHROUGH */
210 case 4: /* HH */
211 lt->tm_hour = ATOI2(p);
212 if (lt->tm_hour > 23)
213 badformat();
214 /* FALLTHROUGH */
215 case 2: /* MM */
216 lt->tm_min = ATOI2(p);
217 if (lt->tm_min > 59)
218 badformat();
219 break;
220 default:
221 badformat();
222 }
223 }
224
225 /* convert broken-down time to UTC clock time */
226 if (pformat != NULL && strstr(pformat, "%s") != NULL)
227 tval = timegm(lt);
228 else
229 tval = mktime(lt);
230 if (tval == -1)
231 errx(1, "specified date is outside allowed range");
232
233 if (jflag)
234 return;
235
236 /* set the time */
237 if (slidetime) {
238 if ((now = time(NULL)) == -1)
239 err(1, "time");
240 tv.tv_sec = tval - now;
241 tv.tv_usec = 0;
242 if (adjtime(&tv, NULL) == -1)
243 err(1, "adjtime");
244 } else {
245 #ifndef SMALL
246 logwtmp("|", "date", "");
247 #endif
248 tv.tv_sec = tval;
249 tv.tv_usec = 0;
250 if (settimeofday(&tv, NULL))
251 err(1, "settimeofday");
252 #ifndef SMALL
253 logwtmp("{", "date", "");
254 #endif
255 }
256
257 if ((p = getlogin()) == NULL)
258 p = "???";
259 syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
260 }
261
262 static void
badformat(void)263 badformat(void)
264 {
265 warnx("illegal time format");
266 usage();
267 }
268
269 static void __dead
usage(void)270 usage(void)
271 {
272 fprintf(stderr,
273 "usage: %s [-aju] [-f pformat] [-r seconds]\n"
274 "\t[-z output_zone] [+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]]\n",
275 __progname);
276 exit(1);
277 }
278