ChangeLog, Makefile.in, e2fsck.h, journal.c, unix.c:
  unix.c (check_if_skip): Modify algorithm for checking s_max_mnt_count
  	to match with the kernel.  (If s_max_mnt_count is negative, ignore the
  	mnt_count check.)
  unix.c (e2fsck_update_progress): Adjust the width of the progress bar
  	dynamically, based on the filesystem name that we need to display.
  unix.c (main): If the ext3 needs_recovery flag is set, call
  	e2fsck_run_ext3_journal() and then restart the e2fsck run.
  journal.c (e2fsck_run_ext3_journal): New file which contains logic to
  	recover the ext3 journal.  This version relies on the kernel being
  	able to mount the filesystem in order to run the journal.

diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index abaa9bc..a3e2d70 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,3 +1,21 @@
+2000-07-06  Theodore Ts'o  <tytso@valinux.com>
+
+	* unix.c (check_if_skip): Modify algorithm for checking
+		s_max_mnt_count to match with the kernel.  (If
+		s_max_mnt_count is negative, ignore the mnt_count check.)
+
+	* unix.c (e2fsck_update_progress): Adjust the width of the
+		progress bar dynamically, based on the filesystem name
+		that we need to display.
+
+	* unix.c (main): If the ext3 needs_recovery flag is set, call
+		e2fsck_run_ext3_journal() and then restart the e2fsck run.
+
+	* journal.c (e2fsck_run_ext3_journal): New file which contains
+		logic to recover the ext3 journal.  This version relies on
+		the kernel being able to mount the filesystem in order to
+		run the journal.
+
 2000-07-05  Theodore Ts'o  <tytso@valinux.com>
 
 	* unix.c (e2fsck_update_progress): Only save and check the last
diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in
index a4e49e6..9cbb3a0 100644
--- a/e2fsck/Makefile.in
+++ b/e2fsck/Makefile.in
@@ -55,15 +55,15 @@
 #MCHECK= -DMCHECK
 
 OBJS= unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o pass3.o pass4.o \
-	pass5.o swapfs.o badblocks.o util.o dirinfo.o ehandler.o \
+	pass5.o journal.o swapfs.o badblocks.o util.o dirinfo.o ehandler.o \
 	problem.o message.o $(MTRACE_OBJ)
 
 PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o profiled/super.o \
 	profiled/pass1.o profiled/pass1b.o \
 	profiled/pass2.o profiled/pass3.o profiled/pass4.o profiled/pass5.o \
-	profiled/badblocks.o profiled/util.o profiled/dirinfo.o \
-	profiled/ehandler.o profiled/message.o profiled/problem.o \
-	profiled/swapfs.o
+	profiled/journal.o profiled/badblocks.o profiled/util.o \
+	profiled/dirinfo.o profiled/ehandler.o profiled/message.o \
+	profiled/problem.o profiled/swapfs.o
 
 SRCS= $(srcdir)/e2fsck.c \
 	$(srcdir)/super.c \
@@ -73,6 +73,7 @@
 	$(srcdir)/pass3.c \
 	$(srcdir)/pass4.c \
 	$(srcdir)/pass5.c \
+	$(srcdir)/journal.c \
 	$(srcdir)/badblocks.c \
 	$(srcdir)/util.c \
 	$(srcdir)/unix.c \
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index b0ba043..6b69ed7 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -282,6 +282,9 @@
 extern const char *ehandler_operation(const char *op);
 extern void ehandler_init(io_channel channel);
 
+/* journal.c */
+extern int e2fsck_run_ext3_journal(const char *device);
+
 /* pass1.c */
 extern void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
 extern int e2fsck_pass1_check_device_inode(struct ext2_inode *inode);
diff --git a/e2fsck/journal.c b/e2fsck/journal.c
new file mode 100644
index 0000000..15b86cc
--- /dev/null
+++ b/e2fsck/journal.c
@@ -0,0 +1,72 @@
+/*
+ * journal.c --- code for handling the "ext3" journal
+ */
+
+#include <errno.h>
+
+#include "e2fsck.h"
+
+/*
+ * This is a list of directories to try.  The first element may get
+ * replaced by a mktemp'ed generated temp directory if possible.
+ */
+static char *dirlist[] = { "/mnt", "/tmp", "/root", "/boot", 0 };
+
+/*
+ * This function attempts to mount and unmount an ext3 filesystem,
+ * which is a cheap way to force the kernel to run the journal and
+ * handle the recovery for us.
+ */
+int e2fsck_run_ext3_journal(const char *device)
+{
+	int	ret = 0;
+	char	**cpp, *dir;
+	char	template[] = "/tmp/ext3.XXXXXX";
+	char	*tmpdir;
+
+	/*
+	 * First try to make a temporary directory.  This may fail if
+	 * the root partition is still mounted read-only.
+	 */
+	tmpdir = mktemp(template);
+	if (tmpdir) {
+		ret = mkdir(template, 0700);
+		if (ret)
+			tmpdir = 0;
+	}
+	if (tmpdir) {
+		ret = mount(device, tmpdir, "ext3", 0xC0ED, NULL);
+		if (ret) {
+			ret = errno;
+			rmdir(tmpdir);
+			return (ret);
+		}
+	} else {
+		/*
+		 * OK, creating a temporary directory didn't work.
+		 * Let's try a list of possible temporary mountpoints.
+		 */
+		for (cpp = dirlist; dir = *cpp; cpp++) {
+			ret = mount(device, dir, "ext3", 0xC0ED, NULL);
+			if (ret == 0)
+				break;
+		}
+		if (!dir)
+			return errno;
+	}
+
+	/*
+	 * Now that it mounted cleanly, the filesystem will have been
+	 * recovered, so we can now unmount it.
+	 */
+	ret = umount(device);
+	if (ret)
+		return errno;
+	/*
+	 * Remove the temporary directory, if it was created.
+	 */
+	if (tmpdir)
+		rmdir(tmpdir);
+	return 0;
+}
+
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index 1675817..9503471 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -260,8 +260,9 @@
 		reason = _("contains a file system with errors");
 	else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
 		reason = _("was not cleanly unmounted");
-	else if (fs->super->s_mnt_count >=
-		 (unsigned) fs->super->s_max_mnt_count)
+	else if ((fs->super->s_max_mnt_count >= 0) &&
+		 (fs->super->s_mnt_count >=
+		  (unsigned) fs->super->s_max_mnt_count))
 		reason = _("has reached maximal mount count");
 	else if (fs->super->s_checkinterval &&
 		 time(0) >= (fs->super->s_lastcheck +
@@ -290,7 +291,6 @@
 struct percent_tbl e2fsck_tbl = {
 	5, { 0, 70, 90, 92,  95, 100 }
 };
-static int dpywidth = 50;
 static char bar[] =
 	"==============================================================="
 	"===============================================================";
@@ -330,6 +330,7 @@
 	float percent;
 	int	tick;
 	struct timeval	tv;
+	static int dpywidth = 0;
 
 	if (pass == 0)
 		return 0;
@@ -340,6 +341,10 @@
 	} else {
 		if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
 			return 0;
+		if (dpywidth == 0) {
+			dpywidth = 66 - strlen(ctx->device_name);
+			dpywidth = 8 * (dpywidth / 8);
+		}
 		/*
 		 * Calculate the new progress position.  If the
 		 * percentage hasn't changed, then we skip out right
@@ -701,7 +706,10 @@
 	io_ptr = test_io_manager;
 	test_io_backing_manager = unix_io_manager;
 #endif
-	flags = (ctx->options & E2F_OPT_READONLY) ? 0 : EXT2_FLAG_RW;
+	flags = 0;
+	if ((ctx->options & E2F_OPT_READONLY) == 0)
+		flags |= EXT2_FLAG_RW;
+
 	if (ctx->superblock && blocksize) {
 		retval = ext2fs_open(ctx->filesystem_name, flags,
 				     ctx->superblock, blocksize, io_ptr, &fs);
@@ -769,11 +777,28 @@
 		fatal_error(ctx, _("Get a newer version of e2fsck!"));
 	}
 #endif
+	s = (struct ext2fs_sb *) fs->super;
+	/*
+	 * Check to see if we need to do ext3-style recovery.  If so,
+	 * do it, and then restart the fsck.
+	 */
+	if (s->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
+		printf("%s: reading journal for ext3 filesystem...\n",
+		       ctx->filesystem_name);
+		ext2fs_close(fs);
+		retval = e2fsck_run_ext3_journal(ctx->filesystem_name);
+		if (retval) {
+			com_err(ctx->program_name, retval,
+				": couldn't load ext3 journal for %s",
+				ctx->filesystem_name);
+			exit(FSCK_ERROR);
+		}
+		goto restart;
+	}
 	/*
 	 * Check for compatibility with the feature sets.  We need to
 	 * be more stringent than ext2fs_open().
 	 */
-	s = (struct ext2fs_sb *) fs->super;
 	if ((s->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
 	    (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
 		com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,