/bin/date/date.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 309 lines · 238 code · 29 blank · 42 comment · 68 complexity · 06b39b30c8ac730698af87d52e681fc0 MD5 · raw file

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