date.c revision 15068
11556Srgrimes/*
21556Srgrimes * Copyright (c) 1985, 1987, 1988, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * Redistribution and use in source and binary forms, with or without
61556Srgrimes * modification, are permitted provided that the following conditions
71556Srgrimes * are met:
81556Srgrimes * 1. Redistributions of source code must retain the above copyright
91556Srgrimes *    notice, this list of conditions and the following disclaimer.
101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111556Srgrimes *    notice, this list of conditions and the following disclaimer in the
121556Srgrimes *    documentation and/or other materials provided with the distribution.
131556Srgrimes * 3. All advertising materials mentioning features or use of this software
141556Srgrimes *    must display the following acknowledgement:
151556Srgrimes *	This product includes software developed by the University of
161556Srgrimes *	California, Berkeley and its contributors.
171556Srgrimes * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
323044Sdg *
3315068Sache *	$Id: date.c,v 1.6 1995/10/23 20:26:53 ache Exp $
341556Srgrimes */
351556Srgrimes
361556Srgrimes#ifndef lint
371556Srgrimesstatic char copyright[] =
381556Srgrimes"@(#) Copyright (c) 1985, 1987, 1988, 1993\n\
391556Srgrimes	The Regents of the University of California.  All rights reserved.\n";
401556Srgrimes#endif /* not lint */
411556Srgrimes
421556Srgrimes#ifndef lint
431556Srgrimesstatic char sccsid[] = "@(#)date.c	8.1 (Berkeley) 5/31/93";
441556Srgrimes#endif /* not lint */
451556Srgrimes
461556Srgrimes#include <sys/param.h>
471556Srgrimes#include <sys/time.h>
481556Srgrimes
491556Srgrimes#include <ctype.h>
501556Srgrimes#include <err.h>
511556Srgrimes#include <fcntl.h>
521556Srgrimes#include <stdio.h>
531556Srgrimes#include <stdlib.h>
541556Srgrimes#include <string.h>
551556Srgrimes#include <syslog.h>
561556Srgrimes#include <unistd.h>
5711738Sache#include <locale.h>
581556Srgrimes
591556Srgrimes#include "extern.h"
601556Srgrimes
611556Srgrimestime_t tval;
621556Srgrimesint retval, nflag;
631556Srgrimes
641556Srgrimesstatic void setthetime __P((char *));
651556Srgrimesstatic void badformat __P((void));
661556Srgrimesstatic void usage __P((void));
671556Srgrimes
681556Srgrimesint logwtmp __P((char *, char *, char *));
691556Srgrimes
701556Srgrimesint
711556Srgrimesmain(argc, argv)
721556Srgrimes	int argc;
731556Srgrimes	char **argv;
741556Srgrimes{
751556Srgrimes	extern int optind;
761556Srgrimes	extern char *optarg;
771556Srgrimes	struct timezone tz;
781556Srgrimes	int ch, rflag;
791556Srgrimes	char *format, buf[1024];
805233Sbde	char *endptr;
815233Sbde	int set_timezone;
821556Srgrimes
8311738Sache	(void) setlocale(LC_TIME, "");
841556Srgrimes	tz.tz_dsttime = tz.tz_minuteswest = 0;
851556Srgrimes	rflag = 0;
865233Sbde	set_timezone = 0;
871556Srgrimes	while ((ch = getopt(argc, argv, "d:nr:ut:")) != EOF)
881556Srgrimes		switch((char)ch) {
891556Srgrimes		case 'd':		/* daylight savings time */
905233Sbde			tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;
915233Sbde			if (endptr == optarg || *endptr != '\0')
925233Sbde				usage();
935233Sbde			set_timezone = 1;
941556Srgrimes			break;
951556Srgrimes		case 'n':		/* don't set network */
961556Srgrimes			nflag = 1;
971556Srgrimes			break;
981556Srgrimes		case 'r':		/* user specified seconds */
991556Srgrimes			rflag = 1;
1001556Srgrimes			tval = atol(optarg);
1011556Srgrimes			break;
1021556Srgrimes		case 'u':		/* do everything in GMT */
1031556Srgrimes			(void)setenv("TZ", "GMT0", 1);
1041556Srgrimes			break;
1051556Srgrimes		case 't':		/* minutes west of GMT */
1061556Srgrimes					/* error check; don't allow "PST" */
1075233Sbde			tz.tz_minuteswest = strtol(optarg, &endptr, 10);
1085233Sbde			if (endptr == optarg || *endptr != '\0')
1095233Sbde				usage();
1105233Sbde			set_timezone = 1;
1115233Sbde			break;
1121556Srgrimes		default:
1131556Srgrimes			usage();
1141556Srgrimes		}
1151556Srgrimes	argc -= optind;
1161556Srgrimes	argv += optind;
1171556Srgrimes
1181556Srgrimes	/*
1191556Srgrimes	 * If -d or -t, set the timezone or daylight savings time; this
1201556Srgrimes	 * doesn't belong here, there kernel should not know about either.
1211556Srgrimes	 */
1225233Sbde	if (set_timezone && settimeofday((struct timeval *)NULL, &tz))
1235233Sbde		err(1, "settimeofday (timezone)");
1241556Srgrimes
1251556Srgrimes	if (!rflag && time(&tval) == -1)
1261556Srgrimes		err(1, "time");
1271556Srgrimes
1289944Sache	format = "%+";
1291556Srgrimes
1301556Srgrimes	/* allow the operands in any order */
1311556Srgrimes	if (*argv && **argv == '+') {
1321556Srgrimes		format = *argv + 1;
1331556Srgrimes		++argv;
1341556Srgrimes	}
1351556Srgrimes
1361556Srgrimes	if (*argv) {
1371556Srgrimes		setthetime(*argv);
1381556Srgrimes		++argv;
1391556Srgrimes	}
1401556Srgrimes
1411556Srgrimes	if (*argv && **argv == '+')
1421556Srgrimes		format = *argv + 1;
1431556Srgrimes
1441556Srgrimes	(void)strftime(buf, sizeof(buf), format, localtime(&tval));
1457608Sjoerg	(void)printf("%s\n", buf);
1461556Srgrimes	exit(retval);
1471556Srgrimes}
1481556Srgrimes
1491556Srgrimes#define	ATOI2(ar)	((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
1501556Srgrimesvoid
1511556Srgrimessetthetime(p)
1521556Srgrimes	register char *p;
1531556Srgrimes{
1541556Srgrimes	register struct tm *lt;
1551556Srgrimes	struct timeval tv;
1561556Srgrimes	char *dot, *t;
1571556Srgrimes
1581556Srgrimes	for (t = p, dot = NULL; *t; ++t) {
1591556Srgrimes		if (isdigit(*t))
1601556Srgrimes			continue;
1611556Srgrimes		if (*t == '.' && dot == NULL) {
1621556Srgrimes			dot = t;
1631556Srgrimes			continue;
1641556Srgrimes		}
1651556Srgrimes		badformat();
1661556Srgrimes	}
1671556Srgrimes
1681556Srgrimes	lt = localtime(&tval);
1691556Srgrimes
1701556Srgrimes	if (dot != NULL) {			/* .ss */
1711556Srgrimes		*dot++ = '\0';
1721556Srgrimes		if (strlen(dot) != 2)
1731556Srgrimes			badformat();
1741556Srgrimes		lt->tm_sec = ATOI2(dot);
1751556Srgrimes		if (lt->tm_sec > 61)
1761556Srgrimes			badformat();
1771556Srgrimes	} else
1781556Srgrimes		lt->tm_sec = 0;
1791556Srgrimes
1801556Srgrimes	switch (strlen(p)) {
1811556Srgrimes	case 10:				/* yy */
1821556Srgrimes		lt->tm_year = ATOI2(p);
1831556Srgrimes		if (lt->tm_year < 69)		/* hack for 2000 ;-} */
1841556Srgrimes			lt->tm_year += 100;
1851556Srgrimes		/* FALLTHROUGH */
1861556Srgrimes	case 8:					/* mm */
1871556Srgrimes		lt->tm_mon = ATOI2(p);
1881556Srgrimes		if (lt->tm_mon > 12)
1891556Srgrimes			badformat();
1901556Srgrimes		--lt->tm_mon;			/* time struct is 0 - 11 */
1911556Srgrimes		/* FALLTHROUGH */
1921556Srgrimes	case 6:					/* dd */
1931556Srgrimes		lt->tm_mday = ATOI2(p);
1941556Srgrimes		if (lt->tm_mday > 31)
1951556Srgrimes			badformat();
1961556Srgrimes		/* FALLTHROUGH */
1971556Srgrimes	case 4:					/* hh */
1981556Srgrimes		lt->tm_hour = ATOI2(p);
1991556Srgrimes		if (lt->tm_hour > 23)
2001556Srgrimes			badformat();
2011556Srgrimes		/* FALLTHROUGH */
2021556Srgrimes	case 2:					/* mm */
2031556Srgrimes		lt->tm_min = ATOI2(p);
2041556Srgrimes		if (lt->tm_min > 59)
2051556Srgrimes			badformat();
2061556Srgrimes		break;
2071556Srgrimes	default:
2081556Srgrimes		badformat();
2091556Srgrimes	}
2101556Srgrimes
2111556Srgrimes	/* convert broken-down time to GMT clock time */
2121556Srgrimes	if ((tval = mktime(lt)) == -1)
21315068Sache		errx(1, "nonexistent time");
2141556Srgrimes
2151556Srgrimes	/* set the time */
2161556Srgrimes	if (nflag || netsettime(tval)) {
2171556Srgrimes		logwtmp("|", "date", "");
2181556Srgrimes		tv.tv_sec = tval;
2191556Srgrimes		tv.tv_usec = 0;
2205233Sbde		if (settimeofday(&tv, (struct timezone *)NULL))
2215233Sbde			err(1, "settimeofday (timeval)");
2221556Srgrimes		logwtmp("{", "date", "");
2231556Srgrimes	}
2241556Srgrimes
2251556Srgrimes	if ((p = getlogin()) == NULL)
2261556Srgrimes		p = "???";
2271556Srgrimes	syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
2281556Srgrimes}
2291556Srgrimes
2301556Srgrimesstatic void
2311556Srgrimesbadformat()
2321556Srgrimes{
2331556Srgrimes	warnx("illegal time format");
2341556Srgrimes	usage();
2351556Srgrimes}
2361556Srgrimes
2371556Srgrimesstatic void
2381556Srgrimesusage()
2391556Srgrimes{
2401556Srgrimes	(void)fprintf(stderr,
2411556Srgrimes	    "usage: date [-nu] [-d dst] [-r seconds] [-t west] [+format]\n");
2421556Srgrimes	(void)fprintf(stderr, "            [yy[mm[dd[hh]]]]mm[.ss]]\n");
2431556Srgrimes	exit(1);
2441556Srgrimes}
245