date.c revision 53082
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. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 3520413Sstevestatic char const copyright[] = 361556Srgrimes"@(#) Copyright (c) 1985, 1987, 1988, 1993\n\ 371556Srgrimes The Regents of the University of California. All rights reserved.\n"; 381556Srgrimes#endif /* not lint */ 391556Srgrimes 401556Srgrimes#ifndef lint 4135773Scharnier#if 0 4236006Scharnierstatic char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95"; 4335773Scharnier#endif 4435773Scharnierstatic const char rcsid[] = 4550471Speter "$FreeBSD: head/bin/date/date.c 53082 1999-11-10 13:34:39Z sheldonh $"; 461556Srgrimes#endif /* not lint */ 471556Srgrimes 4836006Scharnier#include <sys/param.h> 491556Srgrimes#include <sys/time.h> 501556Srgrimes 511556Srgrimes#include <ctype.h> 521556Srgrimes#include <err.h> 531556Srgrimes#include <stdio.h> 541556Srgrimes#include <stdlib.h> 5539925Salex#include <string.h> 561556Srgrimes#include <syslog.h> 571556Srgrimes#include <unistd.h> 5811738Sache#include <locale.h> 591556Srgrimes 601556Srgrimes#include "extern.h" 6127874Sbrian#include "vary.h" 621556Srgrimes 631556Srgrimestime_t tval; 6447129Sjmgint retval; 651556Srgrimes 6647129Sjmgstatic void setthetime __P((const char *, const char *, int, int)); 671556Srgrimesstatic void badformat __P((void)); 681556Srgrimesstatic void usage __P((void)); 691556Srgrimes 701556Srgrimesint logwtmp __P((char *, char *, char *)); 711556Srgrimes 721556Srgrimesint 731556Srgrimesmain(argc, argv) 741556Srgrimes int argc; 751556Srgrimes char **argv; 761556Srgrimes{ 771556Srgrimes extern int optind; 781556Srgrimes extern char *optarg; 791556Srgrimes struct timezone tz; 8030073Sdanny int ch, rflag; 8147129Sjmg int jflag, nflag; 821556Srgrimes char *format, buf[1024]; 8328037Sbrian char *endptr, *fmt; 845233Sbde int set_timezone; 8527874Sbrian struct vary *v; 8627874Sbrian const struct vary *badv; 8727874Sbrian struct tm lt; 881556Srgrimes 8927874Sbrian v = NULL; 9028037Sbrian fmt = NULL; 9111738Sache (void) setlocale(LC_TIME, ""); 921556Srgrimes tz.tz_dsttime = tz.tz_minuteswest = 0; 9330073Sdanny rflag = 0; 9447129Sjmg jflag = nflag = 0; 955233Sbde set_timezone = 0; 9647129Sjmg while ((ch = getopt(argc, argv, "d:f:jnr:t:uv:")) != -1) 971556Srgrimes switch((char)ch) { 981556Srgrimes case 'd': /* daylight savings time */ 995233Sbde tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0; 1005233Sbde if (endptr == optarg || *endptr != '\0') 1015233Sbde usage(); 1025233Sbde set_timezone = 1; 1031556Srgrimes break; 10428037Sbrian case 'f': 10528037Sbrian fmt = optarg; 10628037Sbrian break; 10747129Sjmg case 'j': 10847129Sjmg jflag = 1; /* don't set time */ 10947129Sjmg break; 1101556Srgrimes case 'n': /* don't set network */ 1111556Srgrimes nflag = 1; 1121556Srgrimes break; 1131556Srgrimes case 'r': /* user specified seconds */ 1141556Srgrimes rflag = 1; 1151556Srgrimes tval = atol(optarg); 1161556Srgrimes break; 1171556Srgrimes case 't': /* minutes west of GMT */ 1181556Srgrimes /* error check; don't allow "PST" */ 1195233Sbde tz.tz_minuteswest = strtol(optarg, &endptr, 10); 1205233Sbde if (endptr == optarg || *endptr != '\0') 1215233Sbde usage(); 1225233Sbde set_timezone = 1; 1235233Sbde break; 12428037Sbrian case 'u': /* do everything in GMT */ 12528037Sbrian (void)setenv("TZ", "GMT0", 1); 12628037Sbrian break; 12728025Sbrian case 'v': 12828025Sbrian v = vary_append(v, optarg); 12927874Sbrian break; 1301556Srgrimes default: 1311556Srgrimes usage(); 1321556Srgrimes } 1331556Srgrimes argc -= optind; 1341556Srgrimes argv += optind; 1351556Srgrimes 1361556Srgrimes /* 1371556Srgrimes * If -d or -t, set the timezone or daylight savings time; this 13824976Sdanny * doesn't belong here; the kernel should not know about either. 1391556Srgrimes */ 1405233Sbde if (set_timezone && settimeofday((struct timeval *)NULL, &tz)) 1415233Sbde err(1, "settimeofday (timezone)"); 1421556Srgrimes 1431556Srgrimes if (!rflag && time(&tval) == -1) 1441556Srgrimes err(1, "time"); 1451556Srgrimes 1469944Sache format = "%+"; 1471556Srgrimes 1481556Srgrimes /* allow the operands in any order */ 1491556Srgrimes if (*argv && **argv == '+') { 1501556Srgrimes format = *argv + 1; 1511556Srgrimes ++argv; 1521556Srgrimes } 1531556Srgrimes 1541556Srgrimes if (*argv) { 15547129Sjmg setthetime(fmt, *argv, jflag, nflag); 1561556Srgrimes ++argv; 15728037Sbrian } else if (fmt != NULL) 15828037Sbrian usage(); 1591556Srgrimes 1601556Srgrimes if (*argv && **argv == '+') 1611556Srgrimes format = *argv + 1; 1621556Srgrimes 16327874Sbrian lt = *localtime(&tval); 16427874Sbrian badv = vary_apply(v, <); 16527874Sbrian if (badv) { 16628025Sbrian fprintf(stderr, "%s: Cannot apply date adjustment\n", 16728025Sbrian badv->arg); 16827874Sbrian vary_destroy(v); 16927874Sbrian usage(); 17027874Sbrian } 17127874Sbrian vary_destroy(v); 17227874Sbrian (void)strftime(buf, sizeof(buf), format, <); 17330073Sdanny (void)printf("%s\n", buf); 1741556Srgrimes exit(retval); 1751556Srgrimes} 1761556Srgrimes 1771556Srgrimes#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; 17853082Ssheldonh#define ATOI4(ar) ((ar)[0] - '0') * 1000 + ((ar)[1] - '0') * 100 + \ 17953082Ssheldonh ((ar)[2] - '0') * 10 + ((ar)[3] - '0'); (ar) += 4; 1801556Srgrimesvoid 18147129Sjmgsetthetime(fmt, p, jflag, nflag) 18228037Sbrian const char *fmt; 18328037Sbrian register const char *p; 18447129Sjmg int jflag, nflag; 1851556Srgrimes{ 1861556Srgrimes register struct tm *lt; 1871556Srgrimes struct timeval tv; 18828037Sbrian const char *dot, *t; 1891556Srgrimes 19028037Sbrian if (fmt != NULL) { 19128037Sbrian lt = localtime(&tval); 19228037Sbrian t = strptime(p, fmt, lt); 19328037Sbrian if (t == NULL) { 19428037Sbrian fprintf(stderr, "Failed conversion of ``%s''" 19528037Sbrian " using format ``%s''\n", p, fmt); 19648214Scracauer badformat(); 19728037Sbrian } else if (*t != '\0') 19832756Sjb fprintf(stderr, "Warning: Ignoring %ld extraneous" 19928037Sbrian " characters in date string (%s)\n", 20032756Sjb (long) strlen(t), t); 20128037Sbrian } else { 20228037Sbrian for (t = p, dot = NULL; *t; ++t) { 20328037Sbrian if (isdigit(*t)) 20428037Sbrian continue; 20528037Sbrian if (*t == '.' && dot == NULL) { 20628037Sbrian dot = t; 20728037Sbrian continue; 20828037Sbrian } 20928037Sbrian badformat(); 2101556Srgrimes } 2111556Srgrimes 21228037Sbrian lt = localtime(&tval); 2131556Srgrimes 21428037Sbrian if (dot != NULL) { /* .ss */ 21528037Sbrian dot++; /* *dot++ = '\0'; */ 21628037Sbrian if (strlen(dot) != 2) 21728037Sbrian badformat(); 21828037Sbrian lt->tm_sec = ATOI2(dot); 21928037Sbrian if (lt->tm_sec > 61) 22028037Sbrian badformat(); 22128037Sbrian } else 22228037Sbrian lt->tm_sec = 0; 2231556Srgrimes 22430013Sjoerg /* if p has a ".ss" field then let's pretend it's not there */ 22530013Sjoerg switch (strlen(p) - ((dot != NULL) ? 3 : 0)) { 22653082Ssheldonh case 12: /* cc */ 22753082Ssheldonh lt->tm_year = -1900 + ATOI4(p); 22853082Ssheldonh if (lt->tm_year < 0) 22953082Ssheldonh badformat(); 23053082Ssheldonh goto year_done; 23128037Sbrian case 10: /* yy */ 23228037Sbrian lt->tm_year = ATOI2(p); 23328037Sbrian if (lt->tm_year < 69) /* hack for 2000 ;-} */ 23428037Sbrian lt->tm_year += 100; 23553082Ssheldonhyear_done: /* FALLTHROUGH */ 23628037Sbrian case 8: /* mm */ 23728037Sbrian lt->tm_mon = ATOI2(p); 23828037Sbrian if (lt->tm_mon > 12) 23928037Sbrian badformat(); 24028037Sbrian --lt->tm_mon; /* time struct is 0 - 11 */ 24128037Sbrian /* FALLTHROUGH */ 24228037Sbrian case 6: /* dd */ 24328037Sbrian lt->tm_mday = ATOI2(p); 24428037Sbrian if (lt->tm_mday > 31) 24528037Sbrian badformat(); 24628037Sbrian /* FALLTHROUGH */ 24728037Sbrian case 4: /* HH */ 24828037Sbrian lt->tm_hour = ATOI2(p); 24928037Sbrian if (lt->tm_hour > 23) 25028037Sbrian badformat(); 25128037Sbrian /* FALLTHROUGH */ 25228037Sbrian case 2: /* MM */ 25328037Sbrian lt->tm_min = ATOI2(p); 25428037Sbrian if (lt->tm_min > 59) 25528037Sbrian badformat(); 25628037Sbrian break; 25728037Sbrian default: 2581556Srgrimes badformat(); 25928037Sbrian } 2601556Srgrimes } 2611556Srgrimes 2621556Srgrimes /* convert broken-down time to GMT clock time */ 2631556Srgrimes if ((tval = mktime(lt)) == -1) 26415068Sache errx(1, "nonexistent time"); 2651556Srgrimes 26647129Sjmg if (!jflag) { 26747129Sjmg /* set the time */ 26847129Sjmg if (nflag || netsettime(tval)) { 26947129Sjmg logwtmp("|", "date", ""); 27047129Sjmg tv.tv_sec = tval; 27147129Sjmg tv.tv_usec = 0; 27247129Sjmg if (settimeofday(&tv, (struct timezone *)NULL)) 27347129Sjmg err(1, "settimeofday (timeval)"); 27447129Sjmg logwtmp("{", "date", ""); 27547129Sjmg } 27647129Sjmg 27747129Sjmg if ((p = getlogin()) == NULL) 27847129Sjmg p = "???"; 27947129Sjmg syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 2801556Srgrimes } 2811556Srgrimes} 2821556Srgrimes 2831556Srgrimesstatic void 2841556Srgrimesbadformat() 2851556Srgrimes{ 2861556Srgrimes warnx("illegal time format"); 2871556Srgrimes usage(); 2881556Srgrimes} 2891556Srgrimes 2901556Srgrimesstatic void 2911556Srgrimesusage() 2921556Srgrimes{ 29326465Scharnier (void)fprintf(stderr, "%s\n%s\n", 29431668Sbrian "usage: date [-nu] [-d dst] [-r seconds] [-t west] " 29544598Sbrian "[-v[+|-]val[ymwdHMS]] ... ", 29653082Ssheldonh " " 29753082Ssheldonh "[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]"); 2981556Srgrimes exit(1); 2991556Srgrimes} 300