1 /* $NetBSD: date.c,v 1.61 2014/09/01 21:42:21 dholland Exp $ */
4 * Copyright (c) 1985, 1987, 1988, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 "@(#) Copyright (c) 1985, 1987, 1988, 1993\
36 The Regents of the University of California. All rights reserved.");
41 static char sccsid
[] = "@(#)date.c 8.2 (Berkeley) 4/28/95";
43 __RCSID("$NetBSD: date.c,v 1.61 2014/09/01 21:42:21 dholland Exp $");
47 #include <sys/param.h>
67 static int aflag
, jflag
, rflag
, nflag
;
69 __dead
static void badcanotime(const char *, const char *, size_t);
70 static void setthetime(const char *);
71 __dead
static void usage(void);
74 main(int argc
, char *argv
[])
84 (void)setlocale(LC_ALL
, "");
86 while ((ch
= getopt(argc
, argv
, "ad:jnr:u")) != -1) {
88 case 'a': /* adjust time slowly */
95 tval
= parsedate(optarg
, NULL
, NULL
);
98 "%s: Unrecognized date format", optarg
);
102 "%s: Unrecognized date format", optarg
);
103 #endif /* !defined(__minix) */
105 case 'j': /* don't set time */
108 case 'n': /* don't set network */
111 case 'r': /* user specified seconds */
112 if (optarg
[0] == '\0') {
113 errx(EXIT_FAILURE
, "<empty>: Invalid number");
116 val
= strtoll(optarg
, &buf
, 0);
118 err(EXIT_FAILURE
, "%s", optarg
);
120 if (optarg
[0] == '\0' || *buf
!= '\0') {
122 "%s: Invalid number", optarg
);
127 case 'u': /* do everything in UTC */
128 (void)setenv("TZ", "UTC0", 1);
137 if (!rflag
&& time(&tval
) == -1)
138 err(EXIT_FAILURE
, "time");
141 /* allow the operands in any order */
142 if (*argv
&& **argv
== '+') {
146 format
= "+%a %b %e %H:%M:%S %Z %Y";
153 if (*argv
&& **argv
== '+')
156 if ((buf
= malloc(bufsiz
= 1024)) == NULL
)
159 if ((tm
= localtime(&tval
)) == NULL
)
160 err(EXIT_FAILURE
, "%lld: localtime", (long long)tval
);
162 while (strftime(buf
, bufsiz
, format
, tm
) == 0)
163 if ((buf
= realloc(buf
, bufsiz
<<= 1)) == NULL
)
166 (void)printf("%s\n", buf
+ 1);
170 err(EXIT_FAILURE
, "Cannot allocate format buffer");
174 badcanotime(const char *msg
, const char *val
, size_t where
)
176 warnx("%s in canonical time", msg
);
178 warnx("%*s", (int)where
+ 1, "^");
182 #define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
185 setthetime(const char *p
)
190 const char *dot
, *t
, *op
;
194 for (t
= p
, dot
= NULL
; *t
; ++t
) {
199 badcanotime("Unexpected dot", p
, t
- p
);
201 } else if (!isdigit((unsigned char)*t
)) {
202 badcanotime("Expected digit", p
, t
- p
);
206 if ((lt
= localtime(&tval
)) == NULL
)
207 err(EXIT_FAILURE
, "%lld: localtime", (long long)tval
);
209 lt
->tm_isdst
= -1; /* Divine correct DST */
211 if (dot
!= NULL
) { /* .ss */
214 badcanotime("Unexpected digit after seconds field",
216 } else if (len
< 3) {
217 badcanotime("Expected digit in seconds field",
221 lt
->tm_sec
= ATOI2(dot
);
223 badcanotime("Seconds out of range", p
, strlen(p
) - 1);
231 switch (strlen(p
) - len
) {
233 lt
->tm_year
= ATOI2(p
) * 100 - TM_YEAR_BASE
;
235 badcanotime("Year before 1900", op
, p
- op
+ 1);
240 lt
->tm_year
+= ATOI2(p
);
244 lt
->tm_year
= yearset
+ 2000 - TM_YEAR_BASE
;
246 lt
->tm_year
= yearset
+ 1900 - TM_YEAR_BASE
;
250 lt
->tm_mon
= ATOI2(p
);
251 if (lt
->tm_mon
> 12 || lt
->tm_mon
== 0)
252 badcanotime("Month out of range", op
, p
- op
- 1);
253 --lt
->tm_mon
; /* time struct is 0 - 11 */
256 lt
->tm_mday
= ATOI2(p
);
257 switch (lt
->tm_mon
) {
265 if (lt
->tm_mday
> 31 || lt
->tm_mday
== 0)
266 badcanotime("Day out of range (max 31)",
273 if (lt
->tm_mday
> 30 || lt
->tm_mday
== 0)
274 badcanotime("Day out of range (max 30)",
278 if (isleap(lt
->tm_year
+ TM_YEAR_BASE
)) {
279 if (lt
->tm_mday
> 29 || lt
->tm_mday
== 0) {
280 badcanotime("Day out of range "
285 if (lt
->tm_mday
> 28 || lt
->tm_mday
== 0) {
286 badcanotime("Day out of range "
294 * If the month was given, it's already been
295 * checked. If a bad value came back from
296 * localtime, something's badly broken.
297 * (make this an assertion?)
299 errx(EXIT_FAILURE
, "localtime gave invalid month %d",
304 lt
->tm_hour
= ATOI2(p
);
305 if (lt
->tm_hour
> 23)
306 badcanotime("Hour out of range", op
, p
- op
- 1);
309 lt
->tm_min
= ATOI2(p
);
311 badcanotime("Minute out of range", op
, p
- op
- 1);
313 case 0: /* was just .sss */
318 if (strlen(p
) - len
> 12) {
319 badcanotime("Too many digits", p
, 12);
321 badcanotime("Not enough digits", p
, strlen(p
) - len
);
325 /* convert broken-down time to UTC clock time */
326 if ((new_time
= mktime(lt
)) == -1) {
327 /* Can this actually happen? */
328 err(EXIT_FAILURE
, "%s: mktime", op
);
331 /* if jflag is set, don't actually change the time, just return */
338 if (nflag
|| netsettime(new_time
)) {
339 logwtmp("|", "date", "");
341 tv
.tv_sec
= new_time
- tval
;
343 if (adjtime(&tv
, NULL
))
344 err(EXIT_FAILURE
, "adjtime");
349 if (settimeofday(&tv
, NULL
))
350 err(EXIT_FAILURE
, "settimeofday");
352 logwtmp("{", "date", "");
355 if ((p
= getlogin()) == NULL
)
357 syslog(LOG_AUTH
| LOG_NOTICE
, "date set by %s", p
);
363 (void)fprintf(stderr
,
364 "Usage: %s [-ajnu] [-d date] [-r seconds] [+format]",
366 (void)fprintf(stderr
, " [[[[[[CC]yy]mm]dd]HH]MM[.SS]]\n");