xref: /openbsd-src/bin/date/date.c (revision 55449a4bb35a049d6de07a109bfa26688f55c824)
1*55449a4bSflorian /*	$OpenBSD: date.c,v 1.60 2024/04/28 16:43:15 florian Exp $	*/
2df930be7Sderaadt /*	$NetBSD: date.c,v 1.11 1995/09/07 06:21:05 jtc Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1985, 1987, 1988, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt  * modification, are permitted provided that the following conditions
10df930be7Sderaadt  * are met:
11df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
1629295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
18df930be7Sderaadt  *    without specific prior written permission.
19df930be7Sderaadt  *
20df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt  * SUCH DAMAGE.
31df930be7Sderaadt  */
32df930be7Sderaadt 
33c939d236Sderaadt #include <sys/types.h>
34df930be7Sderaadt #include <sys/time.h>
35df930be7Sderaadt 
36df930be7Sderaadt #include <ctype.h>
37df930be7Sderaadt #include <err.h>
38df930be7Sderaadt #include <fcntl.h>
393be3ac17Scheloha #include <limits.h>
40df930be7Sderaadt #include <stdio.h>
41df930be7Sderaadt #include <stdlib.h>
42df930be7Sderaadt #include <string.h>
43df930be7Sderaadt #include <syslog.h>
4400cf17e4Spjanzen #include <time.h>
45df930be7Sderaadt #include <unistd.h>
468e4809e2Sderaadt #include <util.h>
47df930be7Sderaadt 
489517852aSmpech extern	char *__progname;
499517852aSmpech 
50df930be7Sderaadt time_t tval;
51551167c6Sschwarze int jflag;
52a635c382Sderaadt int slidetime;
53df930be7Sderaadt 
543cdedcc6Stedu static void setthetime(char *, const char *);
55c72b5b24Smillert static void badformat(void);
568351f622Sschwarze static void __dead usage(void);
57df930be7Sderaadt 
58df930be7Sderaadt int
main(int argc,char * argv[])59ab83b6d6Sderaadt main(int argc, char *argv[])
60df930be7Sderaadt {
61788b78fcSderaadt 	const char *errstr;
62fea246c5Sotto 	struct tm *tp;
63df930be7Sderaadt 	int ch, rflag;
6480e7afe2Sderaadt 	char *format, buf[1024], *outzone = NULL;
653cdedcc6Stedu 	const char *pformat = NULL;
66df930be7Sderaadt 
67df930be7Sderaadt 	rflag = 0;
688c02daa0Scheloha 	while ((ch = getopt(argc, argv, "af:jr:uz:")) != -1)
695195d91eSokan 		switch(ch) {
703cdedcc6Stedu 		case 'a':
713cdedcc6Stedu 			slidetime = 1;
723cdedcc6Stedu 			break;
733cdedcc6Stedu 		case 'f':		/* parse with strptime */
743cdedcc6Stedu 			pformat = optarg;
75a635c382Sderaadt 			break;
7695dac055Sdhartmei 		case 'j':		/* don't set */
7795dac055Sdhartmei 			jflag = 1;
7895dac055Sdhartmei 			break;
79df930be7Sderaadt 		case 'r':		/* user specified seconds */
80df930be7Sderaadt 			rflag = 1;
813be3ac17Scheloha 			tval = strtonum(optarg, LLONG_MIN, LLONG_MAX, &errstr);
823be3ac17Scheloha 			if (errstr)
833be3ac17Scheloha 				errx(1, "seconds is %s: %s", errstr, optarg);
84df930be7Sderaadt 			break;
85ede69b58Sd 		case 'u':		/* do everything in UTC */
863f7bf70cSnaddy 			if (setenv("TZ", "UTC", 1) == -1)
872c20747dSderaadt 				err(1, "cannot unsetenv TZ");
88df930be7Sderaadt 			break;
8980e7afe2Sderaadt 		case 'z':
9080e7afe2Sderaadt 			outzone = optarg;
9180e7afe2Sderaadt 			break;
92df930be7Sderaadt 		default:
93df930be7Sderaadt 			usage();
94df930be7Sderaadt 		}
95df930be7Sderaadt 	argc -= optind;
96df930be7Sderaadt 	argv += optind;
97df930be7Sderaadt 
98df930be7Sderaadt 	if (!rflag && time(&tval) == -1)
99df930be7Sderaadt 		err(1, "time");
100df930be7Sderaadt 
101df930be7Sderaadt 	format = "%a %b %e %H:%M:%S %Z %Y";
102df930be7Sderaadt 
103df930be7Sderaadt 	/* allow the operands in any order */
104df930be7Sderaadt 	if (*argv && **argv == '+') {
105df930be7Sderaadt 		format = *argv + 1;
106a6a04eb3Sderaadt 		argv++;
107a6a04eb3Sderaadt 		argc--;
108df930be7Sderaadt 	}
109df930be7Sderaadt 
110df930be7Sderaadt 	if (*argv) {
1113cdedcc6Stedu 		setthetime(*argv, pformat);
112a6a04eb3Sderaadt 		argv++;
113a6a04eb3Sderaadt 		argc--;
114df930be7Sderaadt 	}
115df930be7Sderaadt 
1168815d529Sflorian 	if (pledge("stdio", NULL) == -1)
1170bd1216cSderaadt 		err(1, "pledge");
1189dcdb68eSderaadt 
119a6a04eb3Sderaadt 	if (*argv && **argv == '+') {
120df930be7Sderaadt 		format = *argv + 1;
121a6a04eb3Sderaadt 		argc--;
122a6a04eb3Sderaadt 	}
123a6a04eb3Sderaadt 
124a6a04eb3Sderaadt 	if (argc > 0)
125a6a04eb3Sderaadt 		errx(1, "too many arguments");
126df930be7Sderaadt 
12780e7afe2Sderaadt 	if (outzone)
12880e7afe2Sderaadt 		setenv("TZ", outzone, 1);
12980e7afe2Sderaadt 
130fea246c5Sotto 	tp = localtime(&tval);
131fea246c5Sotto 	if (tp == NULL)
132fea246c5Sotto 		errx(1, "conversion error");
133fea246c5Sotto 	(void)strftime(buf, sizeof(buf), format, tp);
134df930be7Sderaadt 	(void)printf("%s\n", buf);
1358351f622Sschwarze 	return 0;
136df930be7Sderaadt }
137df930be7Sderaadt 
13872140d88Smillert #define	ATOI2(ar)	((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0'))
139df930be7Sderaadt void
setthetime(char * p,const char * pformat)1403cdedcc6Stedu setthetime(char *p, const char *pformat)
141df930be7Sderaadt {
1423cdedcc6Stedu 	struct tm *lt, tm;
143df930be7Sderaadt 	struct timeval tv;
144df930be7Sderaadt 	char *dot, *t;
145ed1d13dfScheloha 	time_t now;
14600cf17e4Spjanzen 	int yearset = 0;
147df930be7Sderaadt 
148d54c1ef4Sflorian 	/* Let us set the time even if logwtmp would fail. */
149d54c1ef4Sflorian 	unveil("/var/log/wtmp", "w");
1508815d529Sflorian 	if (pledge("stdio settime wpath", NULL) == -1)
1513c74b493Sderaadt 		err(1, "pledge");
1523c74b493Sderaadt 
1533cdedcc6Stedu 	lt = localtime(&tval);
154*55449a4bSflorian 	if (lt == NULL)
155*55449a4bSflorian 		errx(1, "conversion error");
1563cdedcc6Stedu 
1573cdedcc6Stedu 	lt->tm_isdst = -1;			/* correct for DST */
1583cdedcc6Stedu 
1593cdedcc6Stedu 	if (pformat) {
1603cdedcc6Stedu 		tm = *lt;
1613cdedcc6Stedu 		if (strptime(p, pformat, &tm) == NULL) {
1623cdedcc6Stedu 			fprintf(stderr, "trouble %s %s\n", p, pformat);
1633cdedcc6Stedu 			badformat();
1643cdedcc6Stedu 		}
1653cdedcc6Stedu 		lt = &tm;
1663cdedcc6Stedu 	} else {
167df930be7Sderaadt 		for (t = p, dot = NULL; *t; ++t) {
168cd3e3e8cSderaadt 			if (isdigit((unsigned char)*t))
169df930be7Sderaadt 				continue;
170df930be7Sderaadt 			if (*t == '.' && dot == NULL) {
171df930be7Sderaadt 				dot = t;
172df930be7Sderaadt 				continue;
173df930be7Sderaadt 			}
174df930be7Sderaadt 			badformat();
175df930be7Sderaadt 		}
176df930be7Sderaadt 
177d7eb0c30Sbri 		if (dot != NULL) {			/* .SS */
178df930be7Sderaadt 			*dot++ = '\0';
179df930be7Sderaadt 			if (strlen(dot) != 2)
180df930be7Sderaadt 				badformat();
181df930be7Sderaadt 			lt->tm_sec = ATOI2(dot);
182df930be7Sderaadt 			if (lt->tm_sec > 61)
183df930be7Sderaadt 				badformat();
184df930be7Sderaadt 		} else
185df930be7Sderaadt 			lt->tm_sec = 0;
186df930be7Sderaadt 
187df930be7Sderaadt 		switch (strlen(p)) {
188ede69b58Sd 		case 12:				/* cc */
18978badebcSmillert 			lt->tm_year = (ATOI2(p) * 100) - 1900;
19000cf17e4Spjanzen 			yearset = 1;
1917ff72386Sderaadt 			/* FALLTHROUGH */
192df930be7Sderaadt 		case 10:				/* yy */
19372140d88Smillert 			if (!yearset) {
19472140d88Smillert 				/* mask out current year, leaving only century */
19572140d88Smillert 				lt->tm_year = ((lt->tm_year / 100) * 100);
1967ff72386Sderaadt 			}
19772140d88Smillert 			lt->tm_year += ATOI2(p);
198df930be7Sderaadt 			/* FALLTHROUGH */
199df930be7Sderaadt 		case 8:					/* mm */
200df930be7Sderaadt 			lt->tm_mon = ATOI2(p);
20100cf17e4Spjanzen 			if ((lt->tm_mon > 12) || !lt->tm_mon)
202df930be7Sderaadt 				badformat();
203df930be7Sderaadt 			--lt->tm_mon;			/* time struct is 0 - 11 */
204df930be7Sderaadt 			/* FALLTHROUGH */
205df930be7Sderaadt 		case 6:					/* dd */
206df930be7Sderaadt 			lt->tm_mday = ATOI2(p);
20700cf17e4Spjanzen 			if ((lt->tm_mday > 31) || !lt->tm_mday)
208df930be7Sderaadt 				badformat();
209df930be7Sderaadt 			/* FALLTHROUGH */
210d7eb0c30Sbri 		case 4:					/* HH */
211df930be7Sderaadt 			lt->tm_hour = ATOI2(p);
212df930be7Sderaadt 			if (lt->tm_hour > 23)
213df930be7Sderaadt 				badformat();
214df930be7Sderaadt 			/* FALLTHROUGH */
215d7eb0c30Sbri 		case 2:					/* MM */
216df930be7Sderaadt 			lt->tm_min = ATOI2(p);
217df930be7Sderaadt 			if (lt->tm_min > 59)
218df930be7Sderaadt 				badformat();
219df930be7Sderaadt 			break;
220df930be7Sderaadt 		default:
221df930be7Sderaadt 			badformat();
222df930be7Sderaadt 		}
2233cdedcc6Stedu 	}
224df930be7Sderaadt 
225ede69b58Sd 	/* convert broken-down time to UTC clock time */
226c96a7dffSschwarze 	if (pformat != NULL && strstr(pformat, "%s") != NULL)
227c96a7dffSschwarze 		tval = timegm(lt);
228c96a7dffSschwarze 	else
229c96a7dffSschwarze 		tval = mktime(lt);
230c96a7dffSschwarze 	if (tval == -1)
23100cf17e4Spjanzen 		errx(1, "specified date is outside allowed range");
232df930be7Sderaadt 
23395dac055Sdhartmei 	if (jflag)
23495dac055Sdhartmei 		return;
23595dac055Sdhartmei 
236df930be7Sderaadt 	/* set the time */
237a635c382Sderaadt 	if (slidetime) {
238ed1d13dfScheloha 		if ((now = time(NULL)) == -1)
239ed1d13dfScheloha 			err(1, "time");
240ed1d13dfScheloha 		tv.tv_sec = tval - now;
241a635c382Sderaadt 		tv.tv_usec = 0;
242a635c382Sderaadt 		if (adjtime(&tv, NULL) == -1)
243ed1d13dfScheloha 			err(1, "adjtime");
244a635c382Sderaadt 	} else {
245bcbc4ef9Sderaadt #ifndef SMALL
246df930be7Sderaadt 		logwtmp("|", "date", "");
247bcbc4ef9Sderaadt #endif
248df930be7Sderaadt 		tv.tv_sec = tval;
249df930be7Sderaadt 		tv.tv_usec = 0;
25000cf17e4Spjanzen 		if (settimeofday(&tv, NULL))
251c2deeeafSmpech 			err(1, "settimeofday");
252bcbc4ef9Sderaadt #ifndef SMALL
253df930be7Sderaadt 		logwtmp("{", "date", "");
254bcbc4ef9Sderaadt #endif
255df930be7Sderaadt 	}
256df930be7Sderaadt 
257df930be7Sderaadt 	if ((p = getlogin()) == NULL)
258df930be7Sderaadt 		p = "???";
259df930be7Sderaadt 	syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
260df930be7Sderaadt }
261df930be7Sderaadt 
262df930be7Sderaadt static void
badformat(void)263ab83b6d6Sderaadt badformat(void)
264df930be7Sderaadt {
265df930be7Sderaadt 	warnx("illegal time format");
266df930be7Sderaadt 	usage();
267df930be7Sderaadt }
268df930be7Sderaadt 
2698351f622Sschwarze static void __dead
usage(void)270ab83b6d6Sderaadt usage(void)
271df930be7Sderaadt {
2728c02daa0Scheloha 	fprintf(stderr,
2738c02daa0Scheloha 	    "usage: %s [-aju] [-f pformat] [-r seconds]\n"
2743cdedcc6Stedu 	    "\t[-z output_zone] [+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]]\n",
2759517852aSmpech 	    __progname);
276df930be7Sderaadt 	exit(1);
277df930be7Sderaadt }
278