date.c revision 1.36
1/* $NetBSD: date.c,v 1.36 2003/08/04 22:31:22 jschauma Exp $ */
2
3/*
4 * Copyright (c) 1985, 1987, 1988, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37#ifndef lint
38__COPYRIGHT(
39"@(#) Copyright (c) 1985, 1987, 1988, 1993\n\
40	The Regents of the University of California.  All rights reserved.\n");
41#endif /* not lint */
42
43#ifndef lint
44#if 0
45static char sccsid[] = "@(#)date.c	8.2 (Berkeley) 4/28/95";
46#else
47__RCSID("$NetBSD: date.c,v 1.36 2003/08/04 22:31:22 jschauma Exp $");
48#endif
49#endif /* not lint */
50
51#include <sys/param.h>
52#include <sys/time.h>
53
54#include <ctype.h>
55#include <err.h>
56#include <fcntl.h>
57#include <locale.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <syslog.h>
62#include <time.h>
63#include <tzfile.h>
64#include <unistd.h>
65#include <util.h>
66
67#include "extern.h"
68
69time_t tval;
70int retval, nflag;
71
72int main(int, char *[]);
73static void badformat(void);
74static void badtime(void);
75static void setthetime(const char *);
76static void usage(void);
77
78int
79main(int argc, char *argv[])
80{
81	char buf[1024], *format;
82	int ch, rflag;
83
84	setprogname(argv[0]);
85	(void)setlocale(LC_ALL, "");
86
87	rflag = 0;
88	while ((ch = getopt(argc, argv, "nr:u")) != -1)
89		switch((char)ch) {
90		case 'n':		/* don't set network */
91			nflag = 1;
92			break;
93		case 'r':		/* user specified seconds */
94			rflag = 1;
95			tval = strtol(optarg, NULL, 0);
96			break;
97		case 'u':		/* do everything in UTC */
98			(void)putenv("TZ=UTC0");
99			break;
100		default:
101			usage();
102		}
103	argc -= optind;
104	argv += optind;
105
106	if (!rflag && time(&tval) == -1)
107		err(1, "time");
108
109	format = "%a %b %e %H:%M:%S %Z %Y";
110
111	/* allow the operands in any order */
112	if (*argv && **argv == '+') {
113		format = *argv + 1;
114		++argv;
115	}
116
117	if (*argv) {
118		setthetime(*argv);
119		++argv;
120	}
121
122	if (*argv && **argv == '+')
123		format = *argv + 1;
124
125	(void)strftime(buf, sizeof(buf), format, localtime(&tval));
126	(void)printf("%s\n", buf);
127	exit(retval);
128	/* NOTREACHED */
129}
130
131static void
132badformat(void)
133{
134	warnx("illegal time format");
135	usage();
136}
137
138static void
139badtime(void)
140{
141	errx(EXIT_FAILURE, "illegal time");
142	/* NOTREACHED */
143}
144
145#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
146
147static void
148setthetime(const char *p)
149{
150	struct timeval tv;
151	struct tm *lt;
152	const char *dot, *t;
153	int len, yearset;
154
155	for (t = p, dot = NULL; *t; ++t) {
156		if (isdigit((unsigned char)*t))
157			continue;
158		if (*t == '.' && dot == NULL) {
159			dot = t;
160			continue;
161		}
162		badformat();
163	}
164
165	lt = localtime(&tval);
166
167	lt->tm_isdst = -1;			/* Divine correct DST */
168
169	if (dot != NULL) {			/* .ss */
170		len = strlen(dot);
171		if (len != 3)
172			badformat();
173		++dot;
174		lt->tm_sec = ATOI2(dot);
175	} else {
176		len = 0;
177		lt->tm_sec = 0;
178	}
179
180	yearset = 0;
181	switch (strlen(p) - len) {
182	case 12:				/* cc */
183		lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE;
184		yearset = 1;
185		/* FALLTHROUGH */
186	case 10:				/* yy */
187		if (yearset) {
188			lt->tm_year += ATOI2(p);
189		} else {
190			yearset = ATOI2(p);
191			if (yearset < 69)
192				lt->tm_year = yearset + 2000 - TM_YEAR_BASE;
193			else
194				lt->tm_year = yearset + 1900 - TM_YEAR_BASE;
195		}
196		/* FALLTHROUGH */
197	case 8:					/* mm */
198		lt->tm_mon = ATOI2(p);
199		--lt->tm_mon;			/* time struct is 0 - 11 */
200		/* FALLTHROUGH */
201	case 6:					/* dd */
202		lt->tm_mday = ATOI2(p);
203		/* FALLTHROUGH */
204	case 4:					/* hh */
205		lt->tm_hour = ATOI2(p);
206		/* FALLTHROUGH */
207	case 2:					/* mm */
208		lt->tm_min = ATOI2(p);
209		break;
210	default:
211		badformat();
212	}
213
214	/* convert broken-down time to UTC clock time */
215	if ((tval = mktime(lt)) == -1)
216		badtime();
217
218	/* set the time */
219	if (nflag || netsettime(tval)) {
220		logwtmp("|", "date", "");
221		tv.tv_sec = tval;
222		tv.tv_usec = 0;
223		if (settimeofday(&tv, NULL)) {
224			perror("date: settimeofday");
225			exit(1);
226		}
227		logwtmp("{", "date", "");
228	}
229
230	if ((p = getlogin()) == NULL)
231		p = "???";
232	syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
233}
234
235static void
236usage(void)
237{
238	(void)fprintf(stderr,
239	    "usage: %s [-nu] [-r seconds] [+format]\n", getprogname());
240	(void)fprintf(stderr, "       %s [[[[[cc]yy]mm]dd]hh]mm[.ss]\n", getprogname());
241	exit(1);
242	/* NOTREACHED */
243}
244