diff --git a/configure.ac b/configure.ac index 483457f5..58b78ac5 100644 --- a/configure.ac +++ b/configure.ac @@ -177,9 +177,13 @@ AC_ARG_WITH(plugin-path, [plugin_path=$withval], [plugin_path=yes]) AC_ARG_WITH(rtc-date, - AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM", default "2000-01-01 00:00"]), + AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM:SS", default "2000-01-01 00:00:00"]), [rtc_date=$withval], [rtc_date=no]) +AC_ARG_WITH(rtc-file, + AS_HELP_STRING([--with-rtc-file=FILE], [If RTC is missing, save and restore system clock from this file, default: no]), + [rtc_file=$withval], [rtc_file=no]) + ### Enable features ########################################################################### # Create config.h from selected features and fallback defaults @@ -278,9 +282,16 @@ AS_IF([test "x$with_random_seed" != "xno"], [ AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])]) AS_IF([test "x$rtc_date" != "xno"], [ - AC_DEFINE(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [ + AC_DEFINE_UNQUOTED(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [ rtc_date=""]) +AS_IF([test "x$rtc_file" != "xno"], [ + AS_IF([test "x$rtc_file" = "xyes"], [ + rtc_file=/var/lib/misc/rtc]) + AC_EXPAND_DIR(rtcfile_path, "$rtc_file") + AC_DEFINE_UNQUOTED(RTC_FILE, "$rtcfile_path", [Save and restore system time from this file if /dev/rtc is missing.])],[ + AC_DEFINE_UNQUOTED(RTC_FILE, NULL)]) + AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes]) AS_IF([test "x$with_sulogin" != "xno"], [ @@ -387,6 +398,7 @@ Behavior: Boot heading..........: $heading Plugins...............: $plugins RTC restore date......: $RTC_DATE + RTC fallback file.....: $rtc_file Optional features: Install doc/..........: $enable_doc diff --git a/plugins/rtc.c b/plugins/rtc.c index 238791fe..96203a0a 100644 --- a/plugins/rtc.c +++ b/plugins/rtc.c @@ -36,8 +36,15 @@ #include "helpers.h" #include "plugin.h" -/* Kernel RTC driver validates against this date for sanity check */ +/* + * Kernel RTC driver validates against this date for sanity check. The + * on NTP sync the driver can also update the RTC every 11 mins. We use + * the same update interval to handle manual time set and file save. + */ #define RTC_TIMESTAMP_BEGIN_2000 "2000-01-01 00:00:00" +#define RTC_FMT "%Y-%m-%d %H:%M:%S" +#define RTC_PERIOD (11 * 60 * 1000) + #ifdef RTC_TIMESTAMP_CUSTOM static char *rtc_timestamp = RTC_TIMESTAMP_CUSTOM; #else @@ -45,6 +52,10 @@ static char *rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000; #endif static time_t rtc_date_fallback = 946684800LL; +static char *rtc_file = RTC_FILE; +static uev_t rtc_timer; + + static void tz_set(char *tz, size_t len) { char *ptr; @@ -68,6 +79,122 @@ static void tz_restore(char *tz) tzset(); } +static int time_set(struct tm *tm) +{ + struct tm fallback = { 0 }; + struct timeval tv = { 0 }; + char tz[128]; + int rc = 0; + + tz_set(tz, sizeof(tz)); + + if (!tm) { + logit(LOG_NOTICE, "Resetting system clock to kernel default, %s.", rtc_timestamp); + tm = &fallback; + + /* Attempt to set RTC to a sane value ... */ + tv.tv_sec = rtc_date_fallback; + if (!gmtime_r(&tv.tv_sec, tm)) { + rc = 1; + goto out; + } + } + + tm->tm_isdst = -1; /* Use tzdata to figure it out, please. */ + tv.tv_sec = mktime(tm); + if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) { + errno = EINVAL; + rc = 2; + } else { + if (settimeofday(&tv, NULL) == -1) + rc = 1; + } +out: + tz_restore(tz); + return rc; +} + +static int time_get(struct tm *tm) +{ + struct timeval tv = { 0 }; + char tz[128]; + int rc = 0; + + tz_set(tz, sizeof(tz)); + + rc = gettimeofday(&tv, NULL); + if (rc < 0 || tv.tv_sec < rtc_date_fallback) + rc = 2; + else + gmtime_r(&tv.tv_sec, tm); + + tz_restore(tz); + + return rc; +} + +static void file_save(void *arg) +{ + struct tm tm = { 0 }; + int rc = 0; + FILE *fp; + + fp = fopen(rtc_file, "w"); + if (!fp) { + logit(LOG_WARNING, "Failed saving system clock to %s, code %d: %s", + rtc_file, errno, strerror(errno)); + return; + } + + if ((rc = time_get(&tm))) { + logit(LOG_WARNING, "System clock invalid, before %s, not saving", rtc_timestamp); + print_desc(NULL, "System clock invalid, skipping"); + } else { + char buf[32] = { 0 }; + + print_desc(NULL, "Saving system clock to file"); + strftime(buf, sizeof(buf), RTC_FMT, &tm); + fprintf(fp, "%s\n", buf); + } + + print(rc, NULL); + fclose(fp); +} + +static void file_restore(void *arg) +{ + struct tm tm = { 0 }; + int rc = 1; + FILE *fp; + + if (!rtc_file) { + logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore."); + return; + } + + print_desc(NULL, "Restoring system clock from backup"); + + fp = fopen(rtc_file, "r"); + if (fp) { + char buf[32]; + + if (fgets(buf, sizeof(buf), fp)) { + chomp(buf); + strptime(buf, RTC_FMT, &tm); + rc = time_set(&tm); + } + fclose(fp); + } else + logit(LOG_WARNING, "Missing %s", rtc_file); + + if (rc) { + time_set(NULL); + rc = 2; + } + + print(rc, NULL); +} + static int rtc_open(void) { char *alt[] = { @@ -91,10 +218,8 @@ static int rtc_open(void) static void rtc_save(void *arg) { - struct timeval tv = { 0 }; struct tm tm = { 0 }; int fd, rc = 0; - char tz[128]; if (rescue) { dbg("Skipping %s plugin in rescue mode.", __FILE__); @@ -105,38 +230,26 @@ static void rtc_save(void *arg) if (fd < 0) return; - tz_set(tz, sizeof(tz)); - rc = gettimeofday(&tv, NULL); - if (rc < 0 || tv.tv_sec < rtc_date_fallback) { + if ((rc = time_get(&tm))) { print_desc(NULL, "System clock invalid, not saving to RTC"); - invalid: - logit(LOG_ERR, "System clock invalid, before %s, not saving to RTC", rtc_timestamp); - rc = 2; - goto out; + } else { + print_desc(NULL, "Saving system clock (UTC) to RTC"); + rc = ioctl(fd, RTC_SET_TIME, &tm); } - print_desc(NULL, "Saving system time (UTC) to RTC"); - - gmtime_r(&tv.tv_sec, &tm); - if (ioctl(fd, RTC_SET_TIME, &tm) < 0) { - if (EINVAL == errno) - goto invalid; - rc = 1; - goto out; + if (rc && errno == EINVAL) { + logit(LOG_WARNING, "System clock invalid, before %s, not saving to RTC", rtc_timestamp); + rc = 2; } -out: - tz_restore(tz); print(rc, NULL); close(fd); } static void rtc_restore(void *arg) { - struct timeval tv = { 0 }; struct tm tm = { 0 }; int fd, rc = 0; - char tz[128]; if (rescue) { dbg("Skipping %s plugin in rescue mode.", __FILE__); @@ -145,66 +258,62 @@ static void rtc_restore(void *arg) fd = rtc_open(); if (fd < 0) { - logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore."); + file_restore(arg); return; } - tz_set(tz, sizeof(tz)); - if (ioctl(fd, RTC_RD_TIME, &tm) < 0) { + if ((rc = ioctl(fd, RTC_RD_TIME, &tm)) < 0) { char msg[120]; snprintf(msg, sizeof(msg), "Failed restoring system clock, %s", EINVAL == errno ? "RTC time is too old" : ENOENT == errno ? "RTC has no saved time" : "see log for details"); print_desc(NULL, msg); + } else { + print_desc(NULL, "Restoring system clock (UTC) from RTC"); + rc = time_set(&tm); + } - invalid: - logit(LOG_ERR, "Failed restoring system clock from RTC."); + if (rc) { + logit(LOG_WARNING, "Failed restoring system clock from RTC."); if (EINVAL == errno) - logit(LOG_ERR, "RTC time is too old (before %s)", rtc_timestamp); + logit(LOG_WARNING, "RTC time is too old (before %s)", rtc_timestamp); else if (ENOENT == errno) - logit(LOG_ERR, "RTC has no previously saved (valid) time."); + logit(LOG_WARNING, "RTC has no previously saved (valid) time."); else - logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno)); + logit(LOG_WARNING, "RTC error code %d: %s", errno, strerror(errno)); - /* Been here already? */ - if (rc) - goto out; + print(2, NULL); - /* Attempt to set RTC to a sane value ... */ - tv.tv_sec = rtc_date_fallback; - if (!gmtime_r(&tv.tv_sec, &tm)) - goto out; + /* Try restoring from last save game */ + if (rtc_file) + file_restore(arg); + } else + print(0, NULL); - logit(LOG_NOTICE, "Resetting RTC to kernel default, %s.", rtc_timestamp); - rc = 2; - } + close(fd); +} - if (!rc) - print_desc(NULL, "Restoring system clock (UTC) from RTC"); - tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */ - tv.tv_sec = mktime(&tm); - if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) { - errno = EINVAL; - goto invalid; - } - if (settimeofday(&tv, NULL) == -1) - rc = 1; +static void save(void *arg) +{ + rtc_save(arg); + file_save(arg); +} -out: - tz_restore(tz); - print(rc, NULL); - close(fd); +static void update(uev_t *w, void *arg, int events) +{ + save(arg); } + static plugin_t plugin = { .name = __FILE__, .hook[HOOK_BASEFS_UP] = { .cb = rtc_restore }, .hook[HOOK_SHUTDOWN] = { - .cb = rtc_save + .cb = save } }; @@ -212,10 +321,14 @@ PLUGIN_INIT(plugin_init) { struct tm tm = { 0 }; - if (!strptime(rtc_timestamp, "%Y-%m-%d %H:%M", &tm)) - rtc_date_fallback = mktime(&tm); - else + if (!strptime(rtc_timestamp, RTC_FMT, &tm)) { + logit(LOG_WARNING, "Invalid restore date '%s', reverting to '%s'", + rtc_timestamp, RTC_TIMESTAMP_BEGIN_2000); rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000; + } else + rtc_date_fallback = mktime(&tm); + + uev_timer_init(ctx, &rtc_timer, update, NULL, RTC_PERIOD, RTC_PERIOD); plugin_register(&plugin); } diff --git a/plugins/urandom.c b/plugins/urandom.c index b9f6039d..6f827796 100644 --- a/plugins/urandom.c +++ b/plugins/urandom.c @@ -154,7 +154,7 @@ static void setup(void *arg) close(fd); free(rpi); if (rc < 0) - logit(LOG_ERR, "Failed adding entropy to kernel random pool: %s", strerror(err)); + logit(LOG_WARNING, "Failed adding entropy to kernel random pool: %s", strerror(err)); print_result(rc < 0); return; fallback: