date.c revision 27874
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.13 1997/06/06 06:34:37 charnier Exp $ 34 */ 35 36#ifndef lint 37static 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 43static 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 62time_t tval; 63int retval, nflag; 64 65static void setthetime __P((char *)); 66static void badformat __P((void)); 67static void usage __P((void)); 68 69int logwtmp __P((char *, char *, char *)); 70 71int 72main(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; 82 int set_timezone; 83 struct vary *v; 84 const struct vary *badv; 85 struct tm lt; 86 87 v = NULL; 88 (void) setlocale(LC_TIME, ""); 89 tz.tz_dsttime = tz.tz_minuteswest = 0; 90 rflag = 0; 91 set_timezone = 0; 92 while ((ch = getopt(argc, argv, "D:W:M:Y:d:nr:ut:")) != -1) 93 switch((char)ch) { 94 case 'd': /* daylight savings time */ 95 tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0; 96 if (endptr == optarg || *endptr != '\0') 97 usage(); 98 set_timezone = 1; 99 break; 100 case 'n': /* don't set network */ 101 nflag = 1; 102 break; 103 case 'r': /* user specified seconds */ 104 rflag = 1; 105 tval = atol(optarg); 106 break; 107 case 'u': /* do everything in GMT */ 108 (void)setenv("TZ", "GMT0", 1); 109 break; 110 case 't': /* minutes west of GMT */ 111 /* error check; don't allow "PST" */ 112 tz.tz_minuteswest = strtol(optarg, &endptr, 10); 113 if (endptr == optarg || *endptr != '\0') 114 usage(); 115 set_timezone = 1; 116 break; 117 case 'D': 118 case 'W': 119 case 'M': 120 case 'Y': 121 v = vary_append(v, ch, optarg); 122 break; 123 default: 124 usage(); 125 } 126 argc -= optind; 127 argv += optind; 128 129 /* 130 * If -d or -t, set the timezone or daylight savings time; this 131 * doesn't belong here; the kernel should not know about either. 132 */ 133 if (set_timezone && settimeofday((struct timeval *)NULL, &tz)) 134 err(1, "settimeofday (timezone)"); 135 136 if (!rflag && time(&tval) == -1) 137 err(1, "time"); 138 139 format = "%+"; 140 141 /* allow the operands in any order */ 142 if (*argv && **argv == '+') { 143 format = *argv + 1; 144 ++argv; 145 } 146 147 if (*argv) { 148 setthetime(*argv); 149 ++argv; 150 } 151 152 if (*argv && **argv == '+') 153 format = *argv + 1; 154 155 lt = *localtime(&tval); 156 badv = vary_apply(v, <); 157 if (badv) { 158 fprintf(stderr, "-%c %s: Cannot apply date adjustment\n", 159 badv->flag, badv->arg); 160 vary_destroy(v); 161 usage(); 162 } 163 vary_destroy(v); 164 (void)strftime(buf, sizeof(buf), format, <); 165 (void)printf("%s\n", buf); 166 exit(retval); 167} 168 169#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; 170void 171setthetime(p) 172 register char *p; 173{ 174 register struct tm *lt; 175 struct timeval tv; 176 char *dot, *t; 177 178 for (t = p, dot = NULL; *t; ++t) { 179 if (isdigit(*t)) 180 continue; 181 if (*t == '.' && dot == NULL) { 182 dot = t; 183 continue; 184 } 185 badformat(); 186 } 187 188 lt = localtime(&tval); 189 190 if (dot != NULL) { /* .ss */ 191 *dot++ = '\0'; 192 if (strlen(dot) != 2) 193 badformat(); 194 lt->tm_sec = ATOI2(dot); 195 if (lt->tm_sec > 61) 196 badformat(); 197 } else 198 lt->tm_sec = 0; 199 200 switch (strlen(p)) { 201 case 10: /* yy */ 202 lt->tm_year = ATOI2(p); 203 if (lt->tm_year < 69) /* hack for 2000 ;-} */ 204 lt->tm_year += 100; 205 /* FALLTHROUGH */ 206 case 8: /* mm */ 207 lt->tm_mon = ATOI2(p); 208 if (lt->tm_mon > 12) 209 badformat(); 210 --lt->tm_mon; /* time struct is 0 - 11 */ 211 /* FALLTHROUGH */ 212 case 6: /* dd */ 213 lt->tm_mday = ATOI2(p); 214 if (lt->tm_mday > 31) 215 badformat(); 216 /* FALLTHROUGH */ 217 case 4: /* hh */ 218 lt->tm_hour = ATOI2(p); 219 if (lt->tm_hour > 23) 220 badformat(); 221 /* FALLTHROUGH */ 222 case 2: /* mm */ 223 lt->tm_min = ATOI2(p); 224 if (lt->tm_min > 59) 225 badformat(); 226 break; 227 default: 228 badformat(); 229 } 230 231 /* convert broken-down time to GMT clock time */ 232 if ((tval = mktime(lt)) == -1) 233 errx(1, "nonexistent time"); 234 235 /* set the time */ 236 if (nflag || netsettime(tval)) { 237 logwtmp("|", "date", ""); 238 tv.tv_sec = tval; 239 tv.tv_usec = 0; 240 if (settimeofday(&tv, (struct timezone *)NULL)) 241 err(1, "settimeofday (timeval)"); 242 logwtmp("{", "date", ""); 243 } 244 245 if ((p = getlogin()) == NULL) 246 p = "???"; 247 syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 248} 249 250static void 251badformat() 252{ 253 warnx("illegal time format"); 254 usage(); 255} 256 257static void 258usage() 259{ 260 (void)fprintf(stderr, "%s\n%s\n", 261 "usage: date [-nu] [-d dst] [-r seconds] [-t west] [+format]", 262 " [-DWMY [+|-]val] [[[[yy]mm]dd]HH]MM[.ss]]"); 263 exit(1); 264} 265