From 60702c267d83bc75ca22e8efb5eff0e1a8821800 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 22 Sep 2007 20:42:04 -0400 Subject: [PATCH] Work around lame Ubuntu init scripts / installer bugs The Ubuntu init scripts don't properly set the system time correctly from hardware clock if the hardware clock is configured to tick local time instead of GMT time. Work around this as best as we can by providing an option in /etc/e2fsck.conf which can be set on Ubuntu systems: [options] buggy_init_scripts = 1 Addresses-Debian-Bug: #441093 Addresses-Ubuntu-Bug: #131201 Signed-off-by: "Theodore Ts'o" --- debian/rules | 6 ++++++ e2fsck/e2fsck.conf.5.in | 14 ++++++++++++++ e2fsck/e2fsck.h | 1 + e2fsck/super.c | 26 ++++++++++++++++++++++++-- e2fsck/unix.c | 7 +++++-- 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/debian/rules b/debian/rules index bb3f1d3b..842965e4 100755 --- a/debian/rules +++ b/debian/rules @@ -342,6 +342,12 @@ binary-arch: install install-udeb $(INSTALL) -d ${debdir}/uuid-dev/usr/share/doc/libuuid${UUID_SOVERSION} + if test -f /etc/lsb-release && \ + grep -q DISTRIB_ID=Ubuntu /etc/lsb-release; then \ + $(INSTALL) -p -m 0644 e2fsck/e2fsck.conf.ubuntu \ + ${debdir}/e2fsprogs/etc/e2fsck.conf; \ + fi + dh_installinfo -pcomerr-dev ${stdbuilddir}/lib/et/com_err.info dh_installinfo -pe2fslibs-dev ${stdbuilddir}/doc/libext2fs.info diff --git a/e2fsck/e2fsck.conf.5.in b/e2fsck/e2fsck.conf.5.in index 8c580d23..9d121716 100644 --- a/e2fsck/e2fsck.conf.5.in +++ b/e2fsck/e2fsck.conf.5.in @@ -86,6 +86,20 @@ If this relation is set to a boolean value of true, then if the user interrupts e2fsck using ^C, and the filesystem is not explicitly flagged as containing errors, e2fsck will exit with an exit status of 0 instead of 32. This setting defaults to false. +.TP +.I buggy_init_scripts +Some buggy distributions (such as Ubuntu) have init scripts and/or +installers which fail to correctly set the system clock before running +e2fsck and/or formatting the filesystem initially. Normally this +happens because the hardware clock is ticking localtime, instead of the +more proper and less error-prone UTC time. So while the kernel is +booting, the system time (which in Linux systems always ticks in UTC +time) is set from the hardware clock, but since the hardware clock is +ticking localtime, the system time is incorrect. Unfortunately, some +buggy distributions do not correct this before running e2fsck. If this +option is set to a boolean value of true, we attempt to work around this +situation by allowing the superblock last write time, last mount time, +and last check time to be in the future by up to 24 hours. .TP .I defer_check_on_battery This boolean relation controls whether or not the interval between diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index 25a97737..57adb2a7 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -329,6 +329,7 @@ struct e2fsck_struct { /* misc fields */ time_t now; + time_t time_fudge; /* For working around buggy init scripts */ int ext_attr_ver; profile_t profile; int blocks_per_page; diff --git a/e2fsck/super.c b/e2fsck/super.c index 00a131ce..e90e9610 100644 --- a/e2fsck/super.c +++ b/e2fsck/super.c @@ -463,6 +463,7 @@ void check_super_block(e2fsck_t ctx) int inodes_per_block; int ipg_max; int inode_size; + int buggy_init_scripts; dgrp_t i; blk_t should_be; struct problem_context pctx; @@ -711,18 +712,39 @@ void check_super_block(e2fsck_t ctx) ext2fs_mark_super_dirty(fs); } + /* + * Some buggy distributions (such as Ubuntu) have init scripts + * and/or installers which fail to correctly set the system + * clock before running e2fsck and/or formatting the + * filesystem initially. Normally this happens because the + * hardware clock is ticking localtime, instead of the more + * proper and less error-prone UTC time. So while the kernel + * is booting, the system time (which in Linux systems always + * ticks in UTC time) is set from the hardware clock, but + * since the hardware clock is ticking localtime, the system + * time is incorrect. Unfortunately, some buggy distributions + * do not correct this before running e2fsck. If this option + * is set to a boolean value of true, we attempt to work + * around this situation by allowing the superblock last write + * time, last mount time, and last check time to be in the + * future by up to 24 hours. + */ + profile_get_boolean(ctx->profile, "options", "buggy_init_scripts", + 0, 0, &buggy_init_scripts); + ctx->time_fudge = buggy_init_scripts ? 86400 : 0; + /* * Check to see if the superblock last mount time or last * write time is in the future. */ - if (fs->super->s_mtime > (__u32) ctx->now) { + if (fs->super->s_mtime > (__u32) ctx->now + ctx->time_fudge) { pctx.num = fs->super->s_mtime; if (fix_problem(ctx, PR_0_FUTURE_SB_LAST_MOUNT, &pctx)) { fs->super->s_mtime = ctx->now; ext2fs_mark_super_dirty(fs); } } - if (fs->super->s_wtime > (__u32) ctx->now) { + if (fs->super->s_wtime > (__u32) ctx->now + ctx->time_fudge) { pctx.num = fs->super->s_wtime; if (fix_problem(ctx, PR_0_FUTURE_SB_LAST_WRITE, &pctx)) { fs->super->s_wtime = ctx->now; diff --git a/e2fsck/unix.c b/e2fsck/unix.c index 950e2d4b..72545dab 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -260,6 +260,7 @@ static void check_if_skip(e2fsck_t ctx) long next_check; int batt = is_on_batt(); int defer_check_on_battery; + time_t lastcheck; profile_get_boolean(ctx->profile, "options", "defer_check_on_battery", 0, 1, @@ -271,6 +272,9 @@ static void check_if_skip(e2fsck_t ctx) cflag || swapfs) return; + lastcheck = fs->super->s_lastcheck; + if (lastcheck > ctx->now) + lastcheck -= ctx->time_fudge; if ((fs->super->s_state & EXT2_ERROR_FS) || !ext2fs_test_valid(fs)) reason = _(" contains a file system with errors"); @@ -285,8 +289,7 @@ static void check_if_skip(e2fsck_t ctx) (unsigned) fs->super->s_max_mnt_count*2)) reason = 0; } else if (fs->super->s_checkinterval && - ((ctx->now - fs->super->s_lastcheck) >= - fs->super->s_checkinterval)) { + ((ctx->now - lastcheck) >= fs->super->s_checkinterval)) { reason = _(" has gone %u days without being checked"); reason_arg = (ctx->now - fs->super->s_lastcheck)/(3600*24); if (batt && ((ctx->now - fs->super->s_lastcheck) < -- 2.11.0