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