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