1/* $OpenBSD: date.c,v 1.60 2024/04/28 16:43:15 florian 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#include <sys/types.h> 34#include <sys/time.h> 35 36#include <ctype.h> 37#include <err.h> 38#include <fcntl.h> 39#include <limits.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <syslog.h> 44#include <time.h> 45#include <unistd.h> 46#include <util.h> 47 48extern char *__progname; 49 50time_t tval; 51int jflag; 52int slidetime; 53 54static void setthetime(char *, const char *); 55static void badformat(void); 56static void __dead usage(void); 57 58int 59main(int argc, char *argv[]) 60{ 61 const char *errstr; 62 struct tm *tp; 63 int ch, rflag; 64 char *format, buf[1024], *outzone = NULL; 65 const char *pformat = NULL; 66 67 rflag = 0; 68 while ((ch = getopt(argc, argv, "af:jr:uz:")) != -1) 69 switch(ch) { 70 case 'a': 71 slidetime = 1; 72 break; 73 case 'f': /* parse with strptime */ 74 pformat = optarg; 75 break; 76 case 'j': /* don't set */ 77 jflag = 1; 78 break; 79 case 'r': /* user specified seconds */ 80 rflag = 1; 81 tval = strtonum(optarg, LLONG_MIN, LLONG_MAX, &errstr); 82 if (errstr) 83 errx(1, "seconds is %s: %s", errstr, optarg); 84 break; 85 case 'u': /* do everything in UTC */ 86 if (setenv("TZ", "UTC", 1) == -1) 87 err(1, "cannot unsetenv TZ"); 88 break; 89 case 'z': 90 outzone = optarg; 91 break; 92 default: 93 usage(); 94 } 95 argc -= optind; 96 argv += optind; 97 98 if (!rflag && time(&tval) == -1) 99 err(1, "time"); 100 101 format = "%a %b %e %H:%M:%S %Z %Y"; 102 103 /* allow the operands in any order */ 104 if (*argv && **argv == '+') { 105 format = *argv + 1; 106 argv++; 107 argc--; 108 } 109 110 if (*argv) { 111 setthetime(*argv, pformat); 112 argv++; 113 argc--; 114 } 115 116 if (pledge("stdio", NULL) == -1) 117 err(1, "pledge"); 118 119 if (*argv && **argv == '+') { 120 format = *argv + 1; 121 argc--; 122 } 123 124 if (argc > 0) 125 errx(1, "too many arguments"); 126 127 if (outzone) 128 setenv("TZ", outzone, 1); 129 130 tp = localtime(&tval); 131 if (tp == NULL) 132 errx(1, "conversion error"); 133 (void)strftime(buf, sizeof(buf), format, tp); 134 (void)printf("%s\n", buf); 135 return 0; 136} 137 138#define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0')) 139void 140setthetime(char *p, const char *pformat) 141{ 142 struct tm *lt, tm; 143 struct timeval tv; 144 char *dot, *t; 145 time_t now; 146 int yearset = 0; 147 148 /* Let us set the time even if logwtmp would fail. */ 149 unveil("/var/log/wtmp", "w"); 150 if (pledge("stdio settime wpath", NULL) == -1) 151 err(1, "pledge"); 152 153 lt = localtime(&tval); 154 if (lt == NULL) 155 errx(1, "conversion error"); 156 157 lt->tm_isdst = -1; /* correct for DST */ 158 159 if (pformat) { 160 tm = *lt; 161 if (strptime(p, pformat, &tm) == NULL) { 162 fprintf(stderr, "trouble %s %s\n", p, pformat); 163 badformat(); 164 } 165 lt = &tm; 166 } else { 167 for (t = p, dot = NULL; *t; ++t) { 168 if (isdigit((unsigned char)*t)) 169 continue; 170 if (*t == '.' && dot == NULL) { 171 dot = t; 172 continue; 173 } 174 badformat(); 175 } 176 177 if (dot != NULL) { /* .SS */ 178 *dot++ = '\0'; 179 if (strlen(dot) != 2) 180 badformat(); 181 lt->tm_sec = ATOI2(dot); 182 if (lt->tm_sec > 61) 183 badformat(); 184 } else 185 lt->tm_sec = 0; 186 187 switch (strlen(p)) { 188 case 12: /* cc */ 189 lt->tm_year = (ATOI2(p) * 100) - 1900; 190 yearset = 1; 191 /* FALLTHROUGH */ 192 case 10: /* yy */ 193 if (!yearset) { 194 /* mask out current year, leaving only century */ 195 lt->tm_year = ((lt->tm_year / 100) * 100); 196 } 197 lt->tm_year += ATOI2(p); 198 /* FALLTHROUGH */ 199 case 8: /* mm */ 200 lt->tm_mon = ATOI2(p); 201 if ((lt->tm_mon > 12) || !lt->tm_mon) 202 badformat(); 203 --lt->tm_mon; /* time struct is 0 - 11 */ 204 /* FALLTHROUGH */ 205 case 6: /* dd */ 206 lt->tm_mday = ATOI2(p); 207 if ((lt->tm_mday > 31) || !lt->tm_mday) 208 badformat(); 209 /* FALLTHROUGH */ 210 case 4: /* HH */ 211 lt->tm_hour = ATOI2(p); 212 if (lt->tm_hour > 23) 213 badformat(); 214 /* FALLTHROUGH */ 215 case 2: /* MM */ 216 lt->tm_min = ATOI2(p); 217 if (lt->tm_min > 59) 218 badformat(); 219 break; 220 default: 221 badformat(); 222 } 223 } 224 225 /* convert broken-down time to UTC clock time */ 226 if (pformat != NULL && strstr(pformat, "%s") != NULL) 227 tval = timegm(lt); 228 else 229 tval = mktime(lt); 230 if (tval == -1) 231 errx(1, "specified date is outside allowed range"); 232 233 if (jflag) 234 return; 235 236 /* set the time */ 237 if (slidetime) { 238 if ((now = time(NULL)) == -1) 239 err(1, "time"); 240 tv.tv_sec = tval - now; 241 tv.tv_usec = 0; 242 if (adjtime(&tv, NULL) == -1) 243 err(1, "adjtime"); 244 } else { 245#ifndef SMALL 246 logwtmp("|", "date", ""); 247#endif 248 tv.tv_sec = tval; 249 tv.tv_usec = 0; 250 if (settimeofday(&tv, NULL)) 251 err(1, "settimeofday"); 252#ifndef SMALL 253 logwtmp("{", "date", ""); 254#endif 255 } 256 257 if ((p = getlogin()) == NULL) 258 p = "???"; 259 syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); 260} 261 262static void 263badformat(void) 264{ 265 warnx("illegal time format"); 266 usage(); 267} 268 269static void __dead 270usage(void) 271{ 272 fprintf(stderr, 273 "usage: %s [-aju] [-f pformat] [-r seconds]\n" 274 "\t[-z output_zone] [+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]]\n", 275 __progname); 276 exit(1); 277} 278