date.c revision 28025
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.14 1997/08/04 03:37:06 brian 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:nr:ut:v:")) != -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 'v': 118 v = vary_append(v, optarg); 119 break; 120 default: 121 usage(); 122 } 123 argc -= optind; 124 argv += optind; 125 126 /* 127 * If -d or -t, set the timezone or daylight savings time; this 128 * doesn't belong here; the kernel should not know about either. 129 */ 130 if (set_timezone && settimeofday((struct timeval *)NULL, &tz)) 131 err(1, "settimeofday (timezone)"); 132 133 if (!rflag && time(&tval) == -1) 134 err(1, "time"); 135 136 format = "%+"; 137 138 /* allow the operands in any order */ 139 if (*argv && **argv == '+') { 140 format = *argv + 1; 141 ++argv; 142 } 143 144 if (*argv) { 145 setthetime(*argv); 146 ++argv; 147 } 148 149 if (*argv && **argv == '+') 150 format = *argv + 1; 151 152 lt = *localtime(&tval); 153 badv = vary_apply(v, <); 154 if (badv) { 155 fprintf(stderr, "%s: Cannot apply date adjustment\n", 156 badv->arg); 157 vary_destroy(v); 158 usage(); 159 } 160 vary_destroy(v); 161 (void)strftime(buf, sizeof(buf), format, <); 162 (void)printf("%s\n", buf); 163 exit(retval); 164} 165 166#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; 167void 168setthetime(p) 169 register char *p; 170{ 171 register struct tm *lt; 172 struct timeval tv; 173 char *dot, *t; 174 175 for (t = p, dot = NULL; *t; ++t) { 176 if (isdigit(*t)) 177 continue; 178 if (*t == '.' && dot == NULL) { 179 dot = t; 180 continue; 181 } 182 badformat(); 183 } 184 185 lt = localtime(&tval); 186 187 if (dot != NULL) { /* .ss */ 188 *dot++ = '\0'; 189 if (strlen(dot) != 2) 190 badformat(); 191 lt->tm_sec = ATOI2(dot); 192 if (lt->tm_sec > 61) 193 badformat(); 194 } else 195 lt->tm_sec = 0; 196 197 switch (strlen(p)) { 198 case 10: /* yy */ 199 lt->tm_year = ATOI2(p); 200 if (lt->tm_year < 69) /* hack for 2000 ;-} */ 201 lt->tm_year += 100; 202 /* FALLTHROUGH */ 203 case 8: /* mm */ 204 lt->tm_mon = ATOI2(p); 205 if (lt->tm_mon > 12) 206 badformat(); 207 --lt->tm_mon; /* time struct is 0 - 11 */ 208 /* FALLTHROUGH */ 209 case 6: /* dd */ 210 lt->tm_mday = ATOI2(p); 211 if (lt->tm_mday > 31) 212 badformat(); 213 /* FALLTHROUGH */ 214 case 4: /* hh */ 215 lt->tm_hour = ATOI2(p); 216 if (lt->tm_hour > 23) 217 badformat(); 218 /* FALLTHROUGH */ 219 case 2: /* mm */ 220 lt->tm_min = ATOI2(p); 221 if (lt->tm_min > 59) 222 badformat(); 223 break; 224 default: 225 badformat(); 226 } 227 228 /* convert broken-down time to GMT clock time */ 229 if ((tval = mktime(lt)) == -1) 230 errx(1, "nonexistent time"); 231 232 /* set the time */ 233 if (nflag || netsettime(tval)) { 234 logwtmp("|", "date", ""); 235 tv.tv_sec = tval; 236 tv.tv_usec = 0; 237 if (settimeofday(&tv, (struct timezone *)NULL)) 238 err(1, "settimeofday (timeval)"); 239 logwtmp("{", "date", ""); 240 } 241 242 if ((p = getlogin()) == NULL) 243 p = "???"; 244 syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 245} 246 247static void 248badformat() 249{ 250 warnx("illegal time format"); 251 usage(); 252} 253 254static void 255usage() 256{ 257 (void)fprintf(stderr, "%s\n%s\n", 258 "usage: date [-nu] [-d dst] [-r seconds] [-t west] [+format]", 259 " [-v [+|-]val[ymwdHM]]... [[[[yy]mm]dd]HH]MM[.ss]]"); 260 exit(1); 261} 262