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 * 4. Neither the name of the University nor the names of its contributors 141556Srgrimes * may be used to endorse or promote products derived from this software 151556Srgrimes * without specific prior written permission. 161556Srgrimes * 171556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271556Srgrimes * SUCH DAMAGE. 281556Srgrimes */ 291556Srgrimes 301556Srgrimes#ifndef lint 3120413Sstevestatic char const copyright[] = 321556Srgrimes"@(#) Copyright (c) 1985, 1987, 1988, 1993\n\ 331556Srgrimes The Regents of the University of California. All rights reserved.\n"; 341556Srgrimes#endif /* not lint */ 351556Srgrimes 36110390Scharnier#if 0 371556Srgrimes#ifndef lint 3836006Scharnierstatic char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95"; 39110390Scharnier#endif /* not lint */ 4035773Scharnier#endif 41110390Scharnier 4299109Sobrien#include <sys/cdefs.h> 4399109Sobrien__FBSDID("$FreeBSD: stable/11/bin/date/date.c 323044 2017-08-31 02:37:44Z emaste $"); 441556Srgrimes 4536006Scharnier#include <sys/param.h> 461556Srgrimes#include <sys/time.h> 47282608Sdelphij#include <sys/stat.h> 481556Srgrimes 491556Srgrimes#include <ctype.h> 501556Srgrimes#include <err.h> 5191079Smarkm#include <locale.h> 521556Srgrimes#include <stdio.h> 531556Srgrimes#include <stdlib.h> 5439925Salex#include <string.h> 551556Srgrimes#include <syslog.h> 561556Srgrimes#include <unistd.h> 57202193Sed#include <utmpx.h> 581556Srgrimes 591556Srgrimes#include "extern.h" 6027874Sbrian#include "vary.h" 611556Srgrimes 6255225Ssheldonh#ifndef TM_YEAR_BASE 6355225Ssheldonh#define TM_YEAR_BASE 1900 6455225Ssheldonh#endif 6555225Ssheldonh 66105396Smarkmstatic time_t tval; 6747129Sjmgint retval; 681556Srgrimes 6990108Simpstatic void setthetime(const char *, const char *, int, int); 7090108Simpstatic void badformat(void); 7190108Simpstatic void usage(void); 721556Srgrimes 73264968Sdumbbellstatic const char *rfc2822_format = "%a, %d %b %Y %T %z"; 74264968Sdumbbell 751556Srgrimesint 7690108Simpmain(int argc, char *argv[]) 771556Srgrimes{ 781556Srgrimes struct timezone tz; 7930073Sdanny int ch, rflag; 80264968Sdumbbell int jflag, nflag, Rflag; 8191079Smarkm const char *format; 8291079Smarkm char buf[1024]; 8328037Sbrian char *endptr, *fmt; 8485615Sdillon char *tmp; 855233Sbde int set_timezone; 8627874Sbrian struct vary *v; 8727874Sbrian const struct vary *badv; 88323044Semaste struct tm *lt; 89282608Sdelphij struct stat sb; 901556Srgrimes 9127874Sbrian v = NULL; 9228037Sbrian fmt = NULL; 9311738Sache (void) setlocale(LC_TIME, ""); 941556Srgrimes tz.tz_dsttime = tz.tz_minuteswest = 0; 9530073Sdanny rflag = 0; 96264968Sdumbbell jflag = nflag = Rflag = 0; 975233Sbde set_timezone = 0; 98264968Sdumbbell while ((ch = getopt(argc, argv, "d:f:jnRr:t:uv:")) != -1) 991556Srgrimes switch((char)ch) { 1001556Srgrimes case 'd': /* daylight savings time */ 1015233Sbde tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0; 1025233Sbde if (endptr == optarg || *endptr != '\0') 1035233Sbde usage(); 1045233Sbde set_timezone = 1; 1051556Srgrimes break; 10628037Sbrian case 'f': 10728037Sbrian fmt = optarg; 10828037Sbrian break; 10947129Sjmg case 'j': 11047129Sjmg jflag = 1; /* don't set time */ 11147129Sjmg break; 1121556Srgrimes case 'n': /* don't set network */ 1131556Srgrimes nflag = 1; 1141556Srgrimes break; 115264968Sdumbbell case 'R': /* RFC 2822 datetime format */ 116264968Sdumbbell Rflag = 1; 117264968Sdumbbell break; 1181556Srgrimes case 'r': /* user specified seconds */ 1191556Srgrimes rflag = 1; 12085615Sdillon tval = strtoq(optarg, &tmp, 0); 121282608Sdelphij if (*tmp != 0) { 122282608Sdelphij if (stat(optarg, &sb) == 0) 123282608Sdelphij tval = sb.st_mtim.tv_sec; 124282608Sdelphij else 125282608Sdelphij usage(); 126282608Sdelphij } 1271556Srgrimes break; 12860718Sdbaker case 't': /* minutes west of UTC */ 1291556Srgrimes /* error check; don't allow "PST" */ 1305233Sbde tz.tz_minuteswest = strtol(optarg, &endptr, 10); 1315233Sbde if (endptr == optarg || *endptr != '\0') 1325233Sbde usage(); 1335233Sbde set_timezone = 1; 1345233Sbde break; 13560718Sdbaker case 'u': /* do everything in UTC */ 13660718Sdbaker (void)setenv("TZ", "UTC0", 1); 13728037Sbrian break; 13828025Sbrian case 'v': 13928025Sbrian v = vary_append(v, optarg); 14027874Sbrian break; 1411556Srgrimes default: 1421556Srgrimes usage(); 1431556Srgrimes } 1441556Srgrimes argc -= optind; 1451556Srgrimes argv += optind; 1461556Srgrimes 1471556Srgrimes /* 1481556Srgrimes * If -d or -t, set the timezone or daylight savings time; this 14924976Sdanny * doesn't belong here; the kernel should not know about either. 1501556Srgrimes */ 151239991Sed if (set_timezone && settimeofday(NULL, &tz) != 0) 1525233Sbde err(1, "settimeofday (timezone)"); 1531556Srgrimes 1541556Srgrimes if (!rflag && time(&tval) == -1) 1551556Srgrimes err(1, "time"); 1561556Srgrimes 1579944Sache format = "%+"; 1581556Srgrimes 159264968Sdumbbell if (Rflag) 160264968Sdumbbell format = rfc2822_format; 161264968Sdumbbell 1621556Srgrimes /* allow the operands in any order */ 1631556Srgrimes if (*argv && **argv == '+') { 1641556Srgrimes format = *argv + 1; 1651556Srgrimes ++argv; 1661556Srgrimes } 1671556Srgrimes 1681556Srgrimes if (*argv) { 16947129Sjmg setthetime(fmt, *argv, jflag, nflag); 1701556Srgrimes ++argv; 17128037Sbrian } else if (fmt != NULL) 17228037Sbrian usage(); 1731556Srgrimes 1741556Srgrimes if (*argv && **argv == '+') 1751556Srgrimes format = *argv + 1; 1761556Srgrimes 177323044Semaste lt = localtime(&tval); 178323044Semaste if (lt == NULL) 179323044Semaste errx(1, "invalid time"); 180323044Semaste badv = vary_apply(v, lt); 18127874Sbrian if (badv) { 18228025Sbrian fprintf(stderr, "%s: Cannot apply date adjustment\n", 18328025Sbrian badv->arg); 18427874Sbrian vary_destroy(v); 18527874Sbrian usage(); 18627874Sbrian } 18727874Sbrian vary_destroy(v); 188264968Sdumbbell 189264968Sdumbbell if (format == rfc2822_format) 190264968Sdumbbell /* 191264968Sdumbbell * When using RFC 2822 datetime format, don't honor the 192264968Sdumbbell * locale. 193264968Sdumbbell */ 194264968Sdumbbell setlocale(LC_TIME, "C"); 195264968Sdumbbell 196323044Semaste (void)strftime(buf, sizeof(buf), format, lt); 19730073Sdanny (void)printf("%s\n", buf); 198120729Sdds if (fflush(stdout)) 199120729Sdds err(1, "stdout"); 2001556Srgrimes exit(retval); 2011556Srgrimes} 2021556Srgrimes 20355225Ssheldonh#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0')) 20455225Ssheldonh 205105396Smarkmstatic void 20690108Simpsetthetime(const char *fmt, const char *p, int jflag, int nflag) 2071556Srgrimes{ 208200157Sed struct utmpx utx; 20990108Simp struct tm *lt; 2101556Srgrimes struct timeval tv; 21128037Sbrian const char *dot, *t; 21255225Ssheldonh int century; 2131556Srgrimes 214176094Sru lt = localtime(&tval); 215323044Semaste if (lt == NULL) 216323044Semaste errx(1, "invalid time"); 217176094Sru lt->tm_isdst = -1; /* divine correct DST */ 218176094Sru 21928037Sbrian if (fmt != NULL) { 22028037Sbrian t = strptime(p, fmt, lt); 22128037Sbrian if (t == NULL) { 22228037Sbrian fprintf(stderr, "Failed conversion of ``%s''" 22328037Sbrian " using format ``%s''\n", p, fmt); 22448214Scracauer badformat(); 22528037Sbrian } else if (*t != '\0') 22632756Sjb fprintf(stderr, "Warning: Ignoring %ld extraneous" 22728037Sbrian " characters in date string (%s)\n", 22832756Sjb (long) strlen(t), t); 22928037Sbrian } else { 23028037Sbrian for (t = p, dot = NULL; *t; ++t) { 23128037Sbrian if (isdigit(*t)) 23228037Sbrian continue; 23328037Sbrian if (*t == '.' && dot == NULL) { 23428037Sbrian dot = t; 23528037Sbrian continue; 23628037Sbrian } 23728037Sbrian badformat(); 2381556Srgrimes } 2391556Srgrimes 24028037Sbrian if (dot != NULL) { /* .ss */ 24128037Sbrian dot++; /* *dot++ = '\0'; */ 24228037Sbrian if (strlen(dot) != 2) 24328037Sbrian badformat(); 24428037Sbrian lt->tm_sec = ATOI2(dot); 24528037Sbrian if (lt->tm_sec > 61) 24628037Sbrian badformat(); 24728037Sbrian } else 24828037Sbrian lt->tm_sec = 0; 2491556Srgrimes 25055225Ssheldonh century = 0; 25130013Sjoerg /* if p has a ".ss" field then let's pretend it's not there */ 25230013Sjoerg switch (strlen(p) - ((dot != NULL) ? 3 : 0)) { 25353082Ssheldonh case 12: /* cc */ 25455225Ssheldonh lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE; 25555225Ssheldonh century = 1; 25655225Ssheldonh /* FALLTHROUGH */ 25728037Sbrian case 10: /* yy */ 25855225Ssheldonh if (century) 25955225Ssheldonh lt->tm_year += ATOI2(p); 260126605Smtm else { 26155225Ssheldonh lt->tm_year = ATOI2(p); 262126605Smtm if (lt->tm_year < 69) /* hack for 2000 ;-} */ 26355225Ssheldonh lt->tm_year += 2000 - TM_YEAR_BASE; 26455225Ssheldonh else 26555225Ssheldonh lt->tm_year += 1900 - TM_YEAR_BASE; 26655225Ssheldonh } 26755225Ssheldonh /* FALLTHROUGH */ 26828037Sbrian case 8: /* mm */ 26928037Sbrian lt->tm_mon = ATOI2(p); 27028037Sbrian if (lt->tm_mon > 12) 27128037Sbrian badformat(); 27228037Sbrian --lt->tm_mon; /* time struct is 0 - 11 */ 27328037Sbrian /* FALLTHROUGH */ 27428037Sbrian case 6: /* dd */ 27528037Sbrian lt->tm_mday = ATOI2(p); 27628037Sbrian if (lt->tm_mday > 31) 27728037Sbrian badformat(); 27828037Sbrian /* FALLTHROUGH */ 27928037Sbrian case 4: /* HH */ 28028037Sbrian lt->tm_hour = ATOI2(p); 28128037Sbrian if (lt->tm_hour > 23) 28228037Sbrian badformat(); 28328037Sbrian /* FALLTHROUGH */ 28428037Sbrian case 2: /* MM */ 28528037Sbrian lt->tm_min = ATOI2(p); 28628037Sbrian if (lt->tm_min > 59) 28728037Sbrian badformat(); 28828037Sbrian break; 28928037Sbrian default: 2901556Srgrimes badformat(); 29128037Sbrian } 2921556Srgrimes } 2931556Srgrimes 2941556Srgrimes /* convert broken-down time to GMT clock time */ 2951556Srgrimes if ((tval = mktime(lt)) == -1) 29615068Sache errx(1, "nonexistent time"); 2971556Srgrimes 29847129Sjmg if (!jflag) { 29947129Sjmg /* set the time */ 30047129Sjmg if (nflag || netsettime(tval)) { 301200157Sed utx.ut_type = OLD_TIME; 302239991Sed (void)gettimeofday(&utx.ut_tv, NULL); 303200157Sed pututxline(&utx); 30447129Sjmg tv.tv_sec = tval; 30547129Sjmg tv.tv_usec = 0; 306239991Sed if (settimeofday(&tv, NULL) != 0) 30747129Sjmg err(1, "settimeofday (timeval)"); 308200157Sed utx.ut_type = NEW_TIME; 309239991Sed (void)gettimeofday(&utx.ut_tv, NULL); 310200157Sed pututxline(&utx); 31147129Sjmg } 31247129Sjmg 31347129Sjmg if ((p = getlogin()) == NULL) 31447129Sjmg p = "???"; 31547129Sjmg syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 3161556Srgrimes } 3171556Srgrimes} 3181556Srgrimes 3191556Srgrimesstatic void 32090108Simpbadformat(void) 3211556Srgrimes{ 3221556Srgrimes warnx("illegal time format"); 3231556Srgrimes usage(); 3241556Srgrimes} 3251556Srgrimes 3261556Srgrimesstatic void 32790108Simpusage(void) 3281556Srgrimes{ 32926465Scharnier (void)fprintf(stderr, "%s\n%s\n", 330264968Sdumbbell "usage: date [-jnRu] [-d dst] [-r seconds] [-t west] " 33144598Sbrian "[-v[+|-]val[ymwdHMS]] ... ", 33253082Ssheldonh " " 33353082Ssheldonh "[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]"); 3341556Srgrimes exit(1); 3351556Srgrimes} 336