1 /* $OpenBSD: date.c,v 1.37 2011/07/08 18:07:16 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/param.h> 34 #include <sys/time.h> 35 36 #include <ctype.h> 37 #include <err.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <locale.h> 43 #include <syslog.h> 44 #include <time.h> 45 #include <tzfile.h> 46 #include <unistd.h> 47 #include <util.h> 48 49 extern char *__progname; 50 51 time_t tval; 52 int retval, jflag; 53 int slidetime; 54 55 static void setthetime(char *); 56 static void badformat(void); 57 static void usage(void); 58 59 int 60 main(int argc, char *argv[]) 61 { 62 struct timezone tz; 63 int ch, rflag; 64 char *format, buf[1024], *outzone = NULL; 65 66 setlocale(LC_ALL, ""); 67 68 tz.tz_dsttime = tz.tz_minuteswest = 0; 69 rflag = 0; 70 while ((ch = getopt(argc, argv, "ad:jr:ut:z:")) != -1) 71 switch((char)ch) { 72 case 'd': /* daylight saving time */ 73 tz.tz_dsttime = atoi(optarg) ? 1 : 0; 74 break; 75 case 'a': 76 slidetime++; 77 break; 78 case 'j': /* don't set */ 79 jflag = 1; 80 break; 81 case 'r': /* user specified seconds */ 82 rflag = 1; 83 tval = atol(optarg); 84 break; 85 case 'u': /* do everything in UTC */ 86 if (setenv("TZ", "UTC", 1) == -1) 87 err(1, "cannot unsetenv TZ"); 88 break; 89 case 't': /* minutes west of GMT */ 90 /* error check; don't allow "PST" */ 91 if (isdigit(*optarg)) { 92 tz.tz_minuteswest = atoi(optarg); 93 break; 94 } 95 /* FALLTHROUGH */ 96 case 'z': 97 outzone = optarg; 98 break; 99 default: 100 usage(); 101 } 102 argc -= optind; 103 argv += optind; 104 105 /* 106 * If -d or -t, set the timezone or daylight saving time; this 107 * doesn't belong here, the kernel should not know about either. 108 */ 109 if ((tz.tz_minuteswest || tz.tz_dsttime) && 110 settimeofday(NULL, &tz)) 111 err(1, "settimeofday"); 112 113 if (!rflag && time(&tval) == -1) 114 err(1, "time"); 115 116 format = "%a %b %e %H:%M:%S %Z %Y"; 117 118 /* allow the operands in any order */ 119 if (*argv && **argv == '+') { 120 format = *argv + 1; 121 argv++; 122 argc--; 123 } 124 125 if (*argv) { 126 setthetime(*argv); 127 argv++; 128 argc--; 129 } 130 131 if (*argv && **argv == '+') { 132 format = *argv + 1; 133 argc--; 134 } 135 136 if (argc > 0) 137 errx(1, "too many arguments"); 138 139 if (outzone) 140 setenv("TZ", outzone, 1); 141 142 (void)strftime(buf, sizeof(buf), format, localtime(&tval)); 143 (void)printf("%s\n", buf); 144 exit(retval); 145 } 146 147 #define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0')) 148 void 149 setthetime(char *p) 150 { 151 struct tm *lt; 152 struct timeval tv; 153 char *dot, *t; 154 int yearset = 0; 155 156 for (t = p, dot = NULL; *t; ++t) { 157 if (isdigit(*t)) 158 continue; 159 if (*t == '.' && dot == NULL) { 160 dot = t; 161 continue; 162 } 163 badformat(); 164 } 165 166 lt = localtime(&tval); 167 168 lt->tm_isdst = -1; /* correct for DST */ 169 170 if (dot != NULL) { /* .SS */ 171 *dot++ = '\0'; 172 if (strlen(dot) != 2) 173 badformat(); 174 lt->tm_sec = ATOI2(dot); 175 if (lt->tm_sec > 61) 176 badformat(); 177 } else 178 lt->tm_sec = 0; 179 180 switch (strlen(p)) { 181 case 12: /* cc */ 182 lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE; 183 yearset = 1; 184 /* FALLTHROUGH */ 185 case 10: /* yy */ 186 if (!yearset) { 187 /* mask out current year, leaving only century */ 188 lt->tm_year = ((lt->tm_year / 100) * 100); 189 } 190 lt->tm_year += ATOI2(p); 191 /* FALLTHROUGH */ 192 case 8: /* mm */ 193 lt->tm_mon = ATOI2(p); 194 if ((lt->tm_mon > 12) || !lt->tm_mon) 195 badformat(); 196 --lt->tm_mon; /* time struct is 0 - 11 */ 197 /* FALLTHROUGH */ 198 case 6: /* dd */ 199 lt->tm_mday = ATOI2(p); 200 if ((lt->tm_mday > 31) || !lt->tm_mday) 201 badformat(); 202 /* FALLTHROUGH */ 203 case 4: /* HH */ 204 lt->tm_hour = ATOI2(p); 205 if (lt->tm_hour > 23) 206 badformat(); 207 /* FALLTHROUGH */ 208 case 2: /* MM */ 209 lt->tm_min = ATOI2(p); 210 if (lt->tm_min > 59) 211 badformat(); 212 break; 213 default: 214 badformat(); 215 } 216 217 /* convert broken-down time to UTC clock time */ 218 if ((tval = mktime(lt)) < 0) 219 errx(1, "specified date is outside allowed range"); 220 221 if (jflag) 222 return; 223 224 /* set the time */ 225 if (slidetime) { 226 struct timeval tv_current; 227 228 if (gettimeofday(&tv_current, NULL) == -1) 229 err(1, "Could not get local time of day"); 230 231 tv.tv_sec = tval - tv_current.tv_sec; 232 tv.tv_usec = 0; 233 if (adjtime(&tv, NULL) == -1) 234 errx(1, "adjtime"); 235 } else { 236 #ifndef SMALL 237 logwtmp("|", "date", ""); 238 #endif 239 tv.tv_sec = tval; 240 tv.tv_usec = 0; 241 if (settimeofday(&tv, NULL)) 242 err(1, "settimeofday"); 243 #ifndef SMALL 244 logwtmp("{", "date", ""); 245 #endif 246 } 247 248 if ((p = getlogin()) == NULL) 249 p = "???"; 250 syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 251 } 252 253 static void 254 badformat(void) 255 { 256 warnx("illegal time format"); 257 usage(); 258 } 259 260 static void 261 usage(void) 262 { 263 (void)fprintf(stderr, 264 "usage: %s [-aju] [-d dst] [-r seconds] [-t minutes_west] [-z output_zone]\n", 265 __progname); 266 (void)fprintf(stderr, 267 "%-*s[+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]]\n", (int)strlen(__progname) + 8, ""); 268 exit(1); 269 } 270