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