date.c revision 99109
1139969Simp/* 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. 321556Srgrimes */ 3390153Smarkm 341556Srgrimes#ifndef lint 3527967Sstevestatic char const copyright[] = 3690153Smarkm"@(#) Copyright (c) 1985, 1987, 1988, 1993\n\ 3727967Ssteve The Regents of the University of California. All rights reserved.\n"; 3899109Sobrien#endif /* not lint */ 3999109Sobrien 401556Srgrimes#ifndef lint 411556Srgrimes#if 0 421556Srgrimesstatic char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95"; 43106371Stjr#endif 441556Srgrimes#endif /* not lint */ 451556Srgrimes#include <sys/cdefs.h> 461556Srgrimes__FBSDID("$FreeBSD: head/bin/date/date.c 99109 2002-06-30 05:13:54Z obrien $"); 471556Srgrimes 4874566Sache#include <sys/param.h> 49129719Spjd#include <sys/time.h> 501556Srgrimes 51225847Sed#include <ctype.h> 521556Srgrimes#include <err.h> 531556Srgrimes#include <locale.h> 5491212Sbde#include <libutil.h> 551556Srgrimes#include <stdio.h> 5661294Sache#include <stdlib.h> 5761294Sache#include <string.h> 5861294Sache#include <syslog.h> 5961294Sache#include <unistd.h> 6061294Sache 611556Srgrimes#include "extern.h" 621556Srgrimes#include "vary.h" 631556Srgrimes 641556Srgrimes#ifndef TM_YEAR_BASE 65114583Smarkm#define TM_YEAR_BASE 1900 66202945Sjh#endif 67105780Smarkm 6890110Simptime_t tval; 6990110Simpint retval; 7090110Simp 7161321Sachestatic void setthetime(const char *, const char *, int, int); 7290110Simpstatic void badformat(void); 7390110Simpstatic void usage(void); 7461321Sache 75196712Straszint 761556Srgrimesmain(int argc, char *argv[]) 771556Srgrimes{ 781556Srgrimes struct timezone tz; 7961268Sjoe int ch, rflag; 8061178Sjoe int jflag, nflag; 8161178Sjoe const char *format; 8288602Sjoe char buf[1024]; 8388602Sjoe char *endptr, *fmt; 8488602Sjoe char *tmp; 8588602Sjoe int set_timezone; 8688602Sjoe struct vary *v; 8788602Sjoe const struct vary *badv; 8888602Sjoe struct tm lt; 8988602Sjoe 9088602Sjoe v = NULL; 9188602Sjoe fmt = NULL; 9288602Sjoe (void) setlocale(LC_TIME, ""); 9388602Sjoe tz.tz_dsttime = tz.tz_minuteswest = 0; 9488602Sjoe rflag = 0; 9588602Sjoe jflag = nflag = 0; 9688586Sjoe set_timezone = 0; 9761178Sjoe while ((ch = getopt(argc, argv, "d:f:jnr:t:uv:")) != -1) 9890150Smarkm switch((char)ch) { 9961178Sjoe case 'd': /* daylight savings time */ 10088583Sjoe tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0; 10188583Sjoe if (endptr == optarg || *endptr != '\0') 10288586Sjoe usage(); 10388586Sjoe set_timezone = 1; 10488583Sjoe break; 10561268Sjoe case 'f': 10661178Sjoe fmt = optarg; 1071556Srgrimes break; 108114583Smarkm case 'j': 1091556Srgrimes jflag = 1; /* don't set time */ 11088594Sjoe break; 1111556Srgrimes case 'n': /* don't set network */ 1121556Srgrimes nflag = 1; 1131556Srgrimes break; 1141556Srgrimes case 'r': /* user specified seconds */ 1151556Srgrimes rflag = 1; 1161556Srgrimes tval = strtoq(optarg, &tmp, 0); 1171556Srgrimes if (*tmp != 0) 1181556Srgrimes usage(); 1191556Srgrimes break; 12062597Sassar case 't': /* minutes west of UTC */ 12162597Sassar /* error check; don't allow "PST" */ 12262597Sassar tz.tz_minuteswest = strtol(optarg, &endptr, 10); 123105390Stjr if (endptr == optarg || *endptr != '\0') 12490110Simp usage(); 12562597Sassar set_timezone = 1; 12662597Sassar break; 12762597Sassar case 'u': /* do everything in UTC */ 12862597Sassar (void)setenv("TZ", "UTC0", 1); 12962597Sassar break; 13062597Sassar case 'v': 131128823Stjr v = vary_append(v, optarg); 13262597Sassar break; 13362597Sassar default: 1341556Srgrimes usage(); 135114583Smarkm } 1361556Srgrimes argc -= optind; 1371556Srgrimes argv += optind; 13888594Sjoe 13988594Sjoe /* 14088594Sjoe * If -d or -t, set the timezone or daylight savings time; this 14161292Sache * doesn't belong here; the kernel should not know about either. 14288594Sjoe */ 14361292Sache if (set_timezone && settimeofday((struct timeval *)NULL, &tz)) 1441556Srgrimes err(1, "settimeofday (timezone)"); 145130236Sdas 146130236Sdas if (!rflag && time(&tval) == -1) 1471556Srgrimes err(1, "time"); 148130236Sdas 1491556Srgrimes format = "%+"; 1501556Srgrimes 1511556Srgrimes /* allow the operands in any order */ 1521556Srgrimes if (*argv && **argv == '+') { 1531556Srgrimes format = *argv + 1; 1541556Srgrimes ++argv; 155241014Smdf } 156241014Smdf 1571556Srgrimes if (*argv) { 158114583Smarkm setthetime(fmt, *argv, jflag, nflag); 1591556Srgrimes ++argv; 16090150Smarkm } else if (fmt != NULL) 161196712Strasz usage(); 1621556Srgrimes 163177942Simp if (*argv && **argv == '+') 1641556Srgrimes format = *argv + 1; 1651556Srgrimes 1661556Srgrimes lt = *localtime(&tval); 1671556Srgrimes badv = vary_apply(v, <); 168105832Srwatson if (badv) { 169105832Srwatson fprintf(stderr, "%s: Cannot apply date adjustment\n", 1701556Srgrimes badv->arg); 171202945Sjh vary_destroy(v); 1721556Srgrimes usage(); 17388591Sjoe } 1741556Srgrimes vary_destroy(v); 1751556Srgrimes (void)strftime(buf, sizeof(buf), format, <); 176157098Sjhb (void)printf("%s\n", buf); 177157098Sjhb exit(retval); 1781556Srgrimes} 1791556Srgrimes 1801556Srgrimes#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0')) 1811556Srgrimes 18261268Sjoevoid 18361178Sjoesetthetime(const char *fmt, const char *p, int jflag, int nflag) 18461291Sache{ 18561268Sjoe struct tm *lt; 18662597Sassar struct timeval tv; 18761268Sjoe const char *dot, *t; 18861291Sache int century; 18961321Sache 19061268Sjoe if (fmt != NULL) { 1911556Srgrimes lt = localtime(&tval); 1921556Srgrimes t = strptime(p, fmt, lt); 1931556Srgrimes if (t == NULL) { 1941556Srgrimes fprintf(stderr, "Failed conversion of ``%s''" 1951556Srgrimes " using format ``%s''\n", p, fmt); 1961556Srgrimes badformat(); 1971556Srgrimes } else if (*t != '\0') 1981556Srgrimes fprintf(stderr, "Warning: Ignoring %ld extraneous" 1991556Srgrimes " characters in date string (%s)\n", 200114583Smarkm (long) strlen(t), t); 20196892Stjr } else { 20296892Stjr for (t = p, dot = NULL; *t; ++t) { 20396892Stjr if (isdigit(*t)) 20496892Stjr continue; 20596892Stjr if (*t == '.' && dot == NULL) { 20696892Stjr dot = t; 20796892Stjr continue; 208128823Stjr } 20996892Stjr badformat(); 21096892Stjr } 21196892Stjr 21296892Stjr lt = localtime(&tval); 21396892Stjr 21496892Stjr if (dot != NULL) { /* .ss */ 21596892Stjr dot++; /* *dot++ = '\0'; */ 21696892Stjr if (strlen(dot) != 2) 21796892Stjr badformat(); 21896892Stjr lt->tm_sec = ATOI2(dot); 21996892Stjr if (lt->tm_sec > 61) 22096892Stjr badformat(); 22196892Stjr } else 22296892Stjr lt->tm_sec = 0; 223177907Sgrog 22496892Stjr century = 0; 225114583Smarkm /* if p has a ".ss" field then let's pretend it's not there */ 2261556Srgrimes switch (strlen(p) - ((dot != NULL) ? 3 : 0)) { 2271556Srgrimes case 12: /* cc */ 2281556Srgrimes lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE; 22988594Sjoe century = 1; 230121124Stjr /* FALLTHROUGH */ 23188594Sjoe case 10: /* yy */ 23288594Sjoe if (century) 23388594Sjoe lt->tm_year += ATOI2(p); 23488594Sjoe else { /* hack for 2000 ;-} */ 23588594Sjoe lt->tm_year = ATOI2(p); 23688594Sjoe if (lt->tm_year < 69) 23788594Sjoe lt->tm_year += 2000 - TM_YEAR_BASE; 23888594Sjoe else 23988594Sjoe lt->tm_year += 1900 - TM_YEAR_BASE; 24088594Sjoe } 24188594Sjoe /* FALLTHROUGH */ 2421556Srgrimes case 8: /* mm */ 24337932Shoek lt->tm_mon = ATOI2(p); 24437932Shoek if (lt->tm_mon > 12) 24537932Shoek badformat(); 24637932Shoek --lt->tm_mon; /* time struct is 0 - 11 */ 24737932Shoek /* FALLTHROUGH */ 2481556Srgrimes case 6: /* dd */ 2491556Srgrimes lt->tm_mday = ATOI2(p); 2501556Srgrimes if (lt->tm_mday > 31) 2511556Srgrimes badformat(); 2521556Srgrimes /* FALLTHROUGH */ 253121124Stjr case 4: /* HH */ 2541556Srgrimes lt->tm_hour = ATOI2(p); 2551556Srgrimes if (lt->tm_hour > 23) 2561556Srgrimes badformat(); 257121124Stjr /* FALLTHROUGH */ 2581556Srgrimes case 2: /* MM */ 259121124Stjr lt->tm_min = ATOI2(p); 260121124Stjr if (lt->tm_min > 59) 2611556Srgrimes badformat(); 2621556Srgrimes break; 2631556Srgrimes default: 2641556Srgrimes badformat(); 2651556Srgrimes } 2661556Srgrimes } 2671556Srgrimes 2681556Srgrimes /* Let mktime() decide whether summer time is in effect. */ 2691556Srgrimes lt->tm_isdst = -1; 2701556Srgrimes 2711556Srgrimes /* convert broken-down time to GMT clock time */ 2721556Srgrimes if ((tval = mktime(lt)) == -1) 2731556Srgrimes errx(1, "nonexistent time"); 27437932Shoek 2751556Srgrimes if (!jflag) { 2761556Srgrimes /* set the time */ 2771556Srgrimes if (nflag || netsettime(tval)) { 2781556Srgrimes logwtmp("|", "date", ""); 2791556Srgrimes tv.tv_sec = tval; 2801556Srgrimes tv.tv_usec = 0; 2811556Srgrimes if (settimeofday(&tv, (struct timezone *)NULL)) 2821556Srgrimes err(1, "settimeofday (timeval)"); 2831556Srgrimes logwtmp("{", "date", ""); 284130236Sdas } 285130236Sdas 2861556Srgrimes if ((p = getlogin()) == NULL) 287130236Sdas p = "???"; 28896892Stjr syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 289102577Skeramida } 2901556Srgrimes} 2911556Srgrimes 29296892Stjrstatic void 29396892Stjrbadformat(void) 29496892Stjr{ 2951556Srgrimes warnx("illegal time format"); 2961556Srgrimes usage(); 29796892Stjr} 29896892Stjr 29996892Stjrstatic void 30096892Stjrusage(void) 30196892Stjr{ 3021556Srgrimes (void)fprintf(stderr, "%s\n%s\n", 30337932Shoek "usage: date [-jnu] [-d dst] [-r seconds] [-t west] " 30488595Sjoe "[-v[+|-]val[ymwdHMS]] ... ", 30596892Stjr " " 30696892Stjr "[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]"); 30737932Shoek exit(1); 3081556Srgrimes} 3091556Srgrimes