1 /* $OpenBSD: date.c,v 1.53 2018/04/25 19:37:09 deraadt Exp $ */ 2 /* $NetBSD: date.c,v 1.11 1995/09/07 06:21:05 jtc Exp $ */ 3 4 /* 5 * Copyright (c) 1985, 1987, 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/time.h> 35 36 #include <ctype.h> 37 #include <err.h> 38 #include <fcntl.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <syslog.h> 44 #include <time.h> 45 #include <unistd.h> 46 #include <util.h> 47 48 extern char *__progname; 49 50 time_t tval; 51 int jflag; 52 int slidetime; 53 54 static void setthetime(char *); 55 static void badformat(void); 56 static void __dead usage(void); 57 58 int 59 main(int argc, char *argv[]) 60 { 61 struct timezone tz; 62 const char *errstr; 63 struct tm *tp; 64 int ch, rflag; 65 char *format, buf[1024], *outzone = NULL; 66 67 tz.tz_dsttime = tz.tz_minuteswest = 0; 68 rflag = 0; 69 while ((ch = getopt(argc, argv, "ad:jr:ut:z:")) != -1) 70 switch(ch) { 71 case 'd': /* daylight saving time */ 72 tz.tz_dsttime = atoi(optarg) ? 1 : 0; 73 break; 74 case 'a': 75 slidetime = 1; 76 break; 77 case 'j': /* don't set */ 78 jflag = 1; 79 break; 80 case 'r': /* user specified seconds */ 81 rflag = 1; 82 tval = strtonum(optarg, LLONG_MIN, LLONG_MAX, &errstr); 83 if (errstr) 84 errx(1, "seconds is %s: %s", errstr, optarg); 85 break; 86 case 'u': /* do everything in UTC */ 87 if (setenv("TZ", "UTC", 1) == -1) 88 err(1, "cannot unsetenv TZ"); 89 break; 90 case 't': /* minutes west of GMT */ 91 tz.tz_minuteswest = strtonum(optarg, 0, 24*60-1, &errstr); 92 if (errstr) 93 errx(1, "-t %s: %s", optarg, errstr); 94 break; 95 case 'z': 96 outzone = optarg; 97 break; 98 default: 99 usage(); 100 } 101 argc -= optind; 102 argv += optind; 103 104 /* 105 * If -d or -t, set the timezone or daylight saving time; this 106 * doesn't belong here, the kernel should not know about either. 107 */ 108 if ((tz.tz_minuteswest || tz.tz_dsttime) && 109 settimeofday(NULL, &tz)) 110 err(1, "settimeofday"); 111 112 if (!rflag && time(&tval) == -1) 113 err(1, "time"); 114 115 format = "%a %b %e %H:%M:%S %Z %Y"; 116 117 /* allow the operands in any order */ 118 if (*argv && **argv == '+') { 119 format = *argv + 1; 120 argv++; 121 argc--; 122 } 123 124 if (*argv) { 125 setthetime(*argv); 126 argv++; 127 argc--; 128 } 129 130 if (pledge("stdio rpath", NULL) == -1) 131 err(1, "pledge"); 132 133 if (*argv && **argv == '+') { 134 format = *argv + 1; 135 argc--; 136 } 137 138 if (argc > 0) 139 errx(1, "too many arguments"); 140 141 if (outzone) 142 setenv("TZ", outzone, 1); 143 144 tp = localtime(&tval); 145 if (tp == NULL) 146 errx(1, "conversion error"); 147 (void)strftime(buf, sizeof(buf), format, tp); 148 (void)printf("%s\n", buf); 149 return 0; 150 } 151 152 #define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0')) 153 void 154 setthetime(char *p) 155 { 156 struct tm *lt; 157 struct timeval tv; 158 char *dot, *t; 159 time_t now; 160 int yearset = 0; 161 162 if (pledge("stdio settime rpath wpath", NULL) == -1) 163 err(1, "pledge"); 164 165 for (t = p, dot = NULL; *t; ++t) { 166 if (isdigit((unsigned char)*t)) 167 continue; 168 if (*t == '.' && dot == NULL) { 169 dot = t; 170 continue; 171 } 172 badformat(); 173 } 174 175 lt = localtime(&tval); 176 177 lt->tm_isdst = -1; /* correct for DST */ 178 179 if (dot != NULL) { /* .SS */ 180 *dot++ = '\0'; 181 if (strlen(dot) != 2) 182 badformat(); 183 lt->tm_sec = ATOI2(dot); 184 if (lt->tm_sec > 61) 185 badformat(); 186 } else 187 lt->tm_sec = 0; 188 189 switch (strlen(p)) { 190 case 12: /* cc */ 191 lt->tm_year = (ATOI2(p) * 100) - 1900; 192 yearset = 1; 193 /* FALLTHROUGH */ 194 case 10: /* yy */ 195 if (!yearset) { 196 /* mask out current year, leaving only century */ 197 lt->tm_year = ((lt->tm_year / 100) * 100); 198 } 199 lt->tm_year += ATOI2(p); 200 /* FALLTHROUGH */ 201 case 8: /* mm */ 202 lt->tm_mon = ATOI2(p); 203 if ((lt->tm_mon > 12) || !lt->tm_mon) 204 badformat(); 205 --lt->tm_mon; /* time struct is 0 - 11 */ 206 /* FALLTHROUGH */ 207 case 6: /* dd */ 208 lt->tm_mday = ATOI2(p); 209 if ((lt->tm_mday > 31) || !lt->tm_mday) 210 badformat(); 211 /* FALLTHROUGH */ 212 case 4: /* HH */ 213 lt->tm_hour = ATOI2(p); 214 if (lt->tm_hour > 23) 215 badformat(); 216 /* FALLTHROUGH */ 217 case 2: /* MM */ 218 lt->tm_min = ATOI2(p); 219 if (lt->tm_min > 59) 220 badformat(); 221 break; 222 default: 223 badformat(); 224 } 225 226 /* convert broken-down time to UTC clock time */ 227 if ((tval = mktime(lt)) < 0) 228 errx(1, "specified date is outside allowed range"); 229 230 if (jflag) 231 return; 232 233 /* set the time */ 234 if (slidetime) { 235 if ((now = time(NULL)) == -1) 236 err(1, "time"); 237 tv.tv_sec = tval - now; 238 tv.tv_usec = 0; 239 if (adjtime(&tv, NULL) == -1) 240 err(1, "adjtime"); 241 } else { 242 #ifndef SMALL 243 logwtmp("|", "date", ""); 244 #endif 245 tv.tv_sec = tval; 246 tv.tv_usec = 0; 247 if (settimeofday(&tv, NULL)) 248 err(1, "settimeofday"); 249 #ifndef SMALL 250 logwtmp("{", "date", ""); 251 #endif 252 } 253 254 if ((p = getlogin()) == NULL) 255 p = "???"; 256 syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 257 } 258 259 static void 260 badformat(void) 261 { 262 warnx("illegal time format"); 263 usage(); 264 } 265 266 static void __dead 267 usage(void) 268 { 269 (void)fprintf(stderr, 270 "usage: %s [-aju] [-d dst] [-r seconds] [-t minutes_west] [-z output_zone]\n", 271 __progname); 272 (void)fprintf(stderr, 273 "%-*s[+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]]\n", (int)strlen(__progname) + 8, ""); 274 exit(1); 275 } 276