static void getoffset(char *timearg) { struct tm *lt; char *p; time_t now; int this_year; (void)time(&now); if (!strcasecmp(timearg, "now")) { /* now */ offset = 0; shuttime = now; return; } if (*timearg == '+') { /* +minutes */ if (!isdigit(*++timearg)) badtime(); if ((offset = atoi(timearg) * 60) < 0) badtime(); shuttime = now + offset; return; } /* handle hh:mm by getting rid of the colon */ for (p = timearg; *p; ++p) if (!isascii(*p) || !isdigit(*p)) { if (*p == ':' && strlen(p) == 3) { p[0] = p[1]; p[1] = p[2]; p[2] = '\0'; } else badtime(); } unsetenv("TZ"); /* OUR timezone */ lt = localtime(&now); /* current time val */ switch(strlen(timearg)) { case 10: this_year = lt->tm_year; lt->tm_year = ATOI2(timearg); /* * check if the specified year is in the next century. * allow for one year of user error as many people will * enter n - 1 at the start of year n. */ if (lt->tm_year < (this_year % 100) - 1) lt->tm_year += 100; /* adjust for the year 2000 and beyond */ lt->tm_year += (this_year - (this_year % 100)); /* FALLTHROUGH */ case 8: lt->tm_mon = ATOI2(timearg); if (--lt->tm_mon < 0 || lt->tm_mon > 11) badtime(); /* FALLTHROUGH */ case 6: lt->tm_mday = ATOI2(timearg); if (lt->tm_mday < 1 || lt->tm_mday > 31) badtime(); /* FALLTHROUGH */ case 4: lt->tm_hour = ATOI2(timearg); if (lt->tm_hour < 0 || lt->tm_hour > 23) badtime(); lt->tm_min = ATOI2(timearg); if (lt->tm_min < 0 || lt->tm_min > 59) badtime(); lt->tm_sec = 0; if ((shuttime = mktime(lt)) == -1) badtime(); if ((offset = shuttime - now) < 0) errx(1, "that time is already past."); break; default: badtime(); } }
static void setthetime(const char *p) { struct timeval tv; time_t new_time; struct tm *lt; const char *dot, *t; size_t len; int yearset; for (t = p, dot = NULL; *t; ++t) { if (isdigit((unsigned char)*t)) continue; if (*t == '.' && dot == NULL) { dot = t; continue; } badformat(); } lt = localtime(&tval); lt->tm_isdst = -1; /* Divine correct DST */ if (dot != NULL) { /* .ss */ len = strlen(dot); if (len != 3) badformat(); ++dot; lt->tm_sec = ATOI2(dot); if (lt->tm_sec > 61) badvalue("seconds"); } else { len = 0; lt->tm_sec = 0; } yearset = 0; switch (strlen(p) - len) { case 12: /* cc */ lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE; if (lt->tm_year < 0) badtime(); yearset = 1; /* FALLTHROUGH */ case 10: /* yy */ if (yearset) { lt->tm_year += ATOI2(p); } else { yearset = ATOI2(p); if (yearset < 69) lt->tm_year = yearset + 2000 - TM_YEAR_BASE; else lt->tm_year = yearset + 1900 - TM_YEAR_BASE; } /* FALLTHROUGH */ case 8: /* mm */ lt->tm_mon = ATOI2(p); if (lt->tm_mon > 12 || lt->tm_mon == 0) badvalue("month"); --lt->tm_mon; /* time struct is 0 - 11 */ /* FALLTHROUGH */ case 6: /* dd */ lt->tm_mday = ATOI2(p); switch (lt->tm_mon) { case 0: case 2: case 4: case 6: case 7: case 9: case 11: if (lt->tm_mday > 31 || lt->tm_mday == 0) badvalue("day of month"); break; case 3: case 5: case 8: case 10: if (lt->tm_mday > 30 || lt->tm_mday == 0) badvalue("day of month"); break; case 1: if (lt->tm_mday > 29 || lt->tm_mday == 0 || (lt->tm_mday == 29 && !isleap(lt->tm_year + TM_YEAR_BASE))) badvalue("day of month"); break; default: badvalue("month"); break; } /* FALLTHROUGH */ case 4: /* hh */ lt->tm_hour = ATOI2(p); if (lt->tm_hour > 23) badvalue("hour"); /* FALLTHROUGH */ case 2: /* mm */ lt->tm_min = ATOI2(p); if (lt->tm_min > 59) badvalue("minute"); break; case 0: /* was just .sss */ if (len != 0) break; /* FALLTHROUGH */ default: badformat(); } /* convert broken-down time to UTC clock time */ if ((new_time = mktime(lt)) == -1) badtime(); /* if jflag is set, don't actually change the time, just return */ if (jflag) { tval = new_time; return; } /* set the time */ if (nflag || netsettime(new_time)) { logwtmp("|", "date", ""); if (aflag) { tv.tv_sec = new_time - tval; tv.tv_usec = 0; if (adjtime(&tv, NULL)) err(EXIT_FAILURE, "adjtime"); } else { tval = new_time; tv.tv_sec = tval; tv.tv_usec = 0; if (settimeofday(&tv, NULL)) err(EXIT_FAILURE, "settimeofday"); } logwtmp("{", "date", ""); } if ((p = getlogin()) == NULL) p = "???"; syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); }