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