Many files:
  pass1.c, pass2.c, pass3.c, pass4.c, pass5.c: Add calls to the progress
  	indicator function.
  pass1.c (scan_callback): Add call to the progress feedback function
  	(if it exists).
  super.c (check_super_block): Skip the device size check if the
  	get_device_size returns EXT2_EXT_UNIMPLEMENTED.
  iscan.c (main): Don't use fatal_error() anymore.
  pass1b.c, swapfs.c, badblocks.c: Set E2F_FLAG_ABORT instead of calling
  	fatal_error(0).
  problem.c, pass3.c (PR_3_ROOT_NOT_DIR_ABORT,
  	PR_3_NO_ROOT_INODE_ABORT): New problem codes.
  problem.c, pass2.c (PR_2_SPLIT_DOT): New problem code.
  problem.c, pass1.c (PR_1_SUPPRESS_MESSAGES): New problem code.
  problemP.h: New file which separates out the private fix_problem data
  	structures.
  util.c, dirinfo.c, pass1.c, pass1b.c, pass2.c, pass5.c, super.c,
  	swapfs.c util.c: allocate_memory() now takes a e2fsck context as its
  	first argument, and rename it to be e2fsck_allocate_memory().
problemP.h:
  New file which contains the private problem abstraction definitions.
Makefile.pq:
  Remove include of MAKEFILE.STD, which doesn't exist at this point.

diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 42a9023..c5942c7 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,3 +1,36 @@
+Thu Nov  6 16:10:20 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* pass1.c, pass2.c, pass3.c, pass4.c, pass5.c: Add calls to the 
+		progress indicator function.
+
+	* pass1.c (scan_callback): Add call to the progress feedback
+		function (if it exists).
+
+Tue Nov  4 09:45:36 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* super.c (check_super_block): Skip the device size check if the
+		get_device_size returns EXT2_EXT_UNIMPLEMENTED.
+
+	* iscan.c (main): Don't use fatal_error() anymore.
+
+	* pass1b.c, swapfs.c, badblocks.c: Set E2F_FLAG_ABORT instead of
+ 		calling fatal_error(0).
+
+	* problem.c, pass3.c (PR_3_ROOT_NOT_DIR_ABORT, 
+		PR_3_NO_ROOT_INODE_ABORT): New problem codes.
+	
+	* problem.c, pass2.c (PR_2_SPLIT_DOT): New problem code.
+
+	* problem.c, pass1.c (PR_1_SUPPRESS_MESSAGES): New problem code.
+	
+	* problemP.h: New file which separates out the private fix_problem
+		data structures.
+
+	* util.c, dirinfo.c, pass1.c, pass1b.c, pass2.c, pass5.c, super.c,
+ 		swapfs.c util.c: allocate_memory() now takes a e2fsck
+ 		context as its first argument, and rename it to be
+ 		e2fsck_allocate_memory().
+
 Mon Nov  3 14:35:29 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
 	* unix.c (main): Add a special case check for the error code EROFS
diff --git a/e2fsck/Makefile.pq b/e2fsck/Makefile.pq
index 86b2c48..18a3cd3 100644
--- a/e2fsck/Makefile.pq
+++ b/e2fsck/Makefile.pq
@@ -7,6 +7,3 @@
 
 !include $(TOPSRC)\powerquest\MCONFIG
 
-ALL:: $(OBJS)
-
-!include $(TOPSRC)\powerquest\MAKEFILE.STD
diff --git a/e2fsck/badblocks.c b/e2fsck/badblocks.c
index a9addf7..b9b7cca 100644
--- a/e2fsck/badblocks.c
+++ b/e2fsck/badblocks.c
@@ -32,7 +32,7 @@
 	FILE		*f;
 	char		buf[1024];
 
-	read_bitmaps(ctx);
+	e2fsck_read_bitmaps(ctx);
 
 	/*
 	 * Make sure the bad block inode is sane.  If there are any
@@ -43,7 +43,7 @@
 	if (retval) {
 		com_err("ext2fs_block_iterate", retval,
 			"while sanity checking the bad blocks inode");
-		fatal_error(0);
+		goto fatal;
 	}
 	
 	/*
@@ -55,7 +55,7 @@
 		if (retval) {
 			com_err("ext2fs_read_bb_inode", retval,
 				"while reading the bad blocks inode");
-			fatal_error(0);
+			goto fatal;
 		}
 	}
 	
@@ -69,7 +69,7 @@
 		if (!f) {
 			com_err("read_bad_blocks_file", errno,
 				"while trying to open %s", bad_blocks_file);
-			fatal_error(0);
+			goto fatal;
 		}
 	} else {
 		sprintf(buf, "badblocks -b %d %s%s %d", fs->blocksize,
@@ -79,7 +79,7 @@
 		if (!f) {
 			com_err("read_bad_blocks_file", errno,
 				"while trying popen '%s'", buf);
-			fatal_error(0);
+			goto fatal;
 		}
 	}
 	retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
@@ -90,7 +90,7 @@
 	if (retval) {
 		com_err("ext2fs_read_bb_FILE", retval,
 			"while reading in list of bad blocks from file");
-		fatal_error(0);
+		goto fatal;
 	}
 	
 	/*
@@ -100,11 +100,16 @@
 	if (retval) {
 		com_err("ext2fs_update_bb_inode", retval,
 			"while updating bad block inode");
-		fatal_error(0);
+		goto fatal;
 	}
 
 	badblocks_list_free(bb_list);
 	return;
+	
+fatal:
+	ctx->flags |= E2F_FLAG_ABORT;
+	return;
+	
 }
 
 void test_disk(e2fsck_t ctx)
diff --git a/e2fsck/dirinfo.c b/e2fsck/dirinfo.c
index 8d37544..38a8e43 100644
--- a/e2fsck/dirinfo.c
+++ b/e2fsck/dirinfo.c
@@ -38,9 +38,9 @@
 		ctx->dir_info_count = 0;
 		ctx->dir_info_size = e2fsck_get_num_dirs(ctx) + 10;
 
-		ctx->dir_info  = allocate_memory(ctx->dir_info_size *
-						 sizeof (struct dir_info),
-						 "directory map");
+		ctx->dir_info  = e2fsck_allocate_memory(ctx,
+			ctx->dir_info_size * sizeof (struct dir_info),
+			"directory map");
 	}
 	
 	if (ctx->dir_info_count >= ctx->dir_info_size) {
@@ -125,6 +125,14 @@
 }
 
 /*
+ * Return the count of number of directories in the dir_info structure
+ */
+int e2fsck_get_num_dirinfo(e2fsck_t ctx)
+{
+	return ctx->dir_info_count;
+}
+
+/*
  * A simple interator function
  */
 struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index a497fb2..d83c8cb 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -117,10 +117,12 @@
 	int	options;
 	blk_t	use_superblock;	/* sb requested by user */
 	blk_t	superblock;	/* sb used to open fs */
+	blk_t	num_blocks;	/* Total number of blocks */
 
 #ifdef HAVE_SETJMP_H
 	jmp_buf	abort_loc;
 #endif
+	unsigned long abort_code;
 
 	void (*progress)(e2fsck_t ctx, int pass, unsigned long cur,
 			 unsigned long max);
@@ -236,6 +238,7 @@
 extern struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ino_t ino);
 extern void e2fsck_free_dir_info(e2fsck_t ctx);
 extern int e2fsck_get_num_dirs(e2fsck_t ctx);
+extern int e2fsck_get_num_dirinfo(e2fsck_t ctx);
 extern struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control);
 
 /* ehandler.c */
@@ -249,12 +252,13 @@
 void swap_filesys(e2fsck_t ctx);
 
 /* util.c */
-extern void *allocate_memory(int size, const char *description);
+extern void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
+				    const char *description);
 extern int ask(e2fsck_t ctx, const char * string, int def);
 extern int ask_yn(const char * string, int def);
-extern void fatal_error (const char * fmt_string);
-extern void read_bitmaps(e2fsck_t ctx);
-extern void write_bitmaps(e2fsck_t ctx);
+extern void fatal_error(e2fsck_t ctx, const char * fmt_string);
+extern void e2fsck_read_bitmaps(e2fsck_t ctx);
+extern void e2fsck_write_bitmaps(e2fsck_t ctx);
 extern void preenhalt(e2fsck_t ctx);
 #ifdef RESOURCE_TRACK
 extern void print_resource_track(const char *desc,
diff --git a/e2fsck/iscan.c b/e2fsck/iscan.c
index 5a67b94..72acb01 100644
--- a/e2fsck/iscan.c
+++ b/e2fsck/iscan.c
@@ -66,7 +66,8 @@
 #ifdef BLKFLSBUF
 			flush = 1;
 #else
-			fatal_error ("-F not supported");
+			fprintf(stderr, "-F not supported");
+			exit(1);
 #endif
 			break;
 		case 'I':
@@ -92,7 +93,8 @@
 		}
 		close(fd);
 #else
-		fatal_error ("BLKFLSBUF not supported");
+		fprintf(stderr, "BLKFLSBUF not supported");
+		exit(1);
 #endif /* BLKFLSBUF */
 	}
 }
@@ -124,7 +126,7 @@
 	retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
 	if (retval) {
 		com_err(program_name, retval, "while opening inode scan");
-		fatal_error(0);
+		exit(1);
 	}
 
 	while (1) {
@@ -132,7 +134,7 @@
 		if (retval) {
 			com_err(program_name, retval,
 				"while getting next inode");
-			fatal_error(0);
+			exit(1);
 		}
 		if (ino == 0)
 			break;
diff --git a/e2fsck/message.c b/e2fsck/message.c
index e7bdd51..c464131 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -46,6 +46,7 @@
  *
  * The following '@' expansions are supported:
  *
+ * 	@A	error allocating
  * 	@b	block
  * 	@B	bitmap
  * 	@C	conflicts with some other fs block
@@ -90,6 +91,7 @@
  * letter <i> in the table below.
  */
 static const char *abbrevs[] = {
+	"Aerror allocating",
 	"bblock",
 	"Bbitmap",
 	"Cconflicts with some other fs @b",
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index ea443b8..c973fdb 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -84,6 +84,11 @@
 	struct ext2_inode inode;
 };
 
+struct scan_callback_struct {
+	e2fsck_t	ctx;
+	char		*block_buf;
+};
+
 /*
  * For the inodes to process list.
  */
@@ -126,6 +131,7 @@
 #endif
 	unsigned char	frag, fsize;
 	struct		problem_context pctx;
+	struct		scan_callback_struct scan_struct;
 	
 #ifdef RESOURCE_TRACK
 	init_resource_track(&rtrack);
@@ -181,9 +187,9 @@
 		ctx->flags |= E2F_FLAG_ABORT;
 		return;
 	}
-	inodes_to_process = allocate_memory(ctx->process_inode_size *
-					    sizeof(struct process_inode_block),
-					    "array of inodes to process");
+	inodes_to_process = e2fsck_allocate_memory(ctx,
+	   ctx->process_inode_size * sizeof(struct process_inode_block),
+	   "array of inodes to process");
 	process_inode_count = 0;
 
 	pctx.errcode = ext2fs_init_dblist(fs, 0);
@@ -194,7 +200,8 @@
 	}
 
 	mark_table_blocks(ctx);
-	block_buf = allocate_memory(fs->blocksize * 3, "block interate buffer");
+	block_buf = e2fsck_allocate_memory(ctx, fs->blocksize * 3,
+					   "block interate buffer");
 	fs->get_blocks = pass1_get_blocks;
 	fs->check_directory = pass1_check_directory;
 	fs->read_inode = pass1_read_inode;
@@ -215,7 +222,11 @@
 		return;
 	}
 	ctx->stashed_inode = &inode;
-	ext2fs_set_inode_callback(scan, scan_callback, block_buf);
+	scan_struct.ctx = ctx;
+	scan_struct.block_buf = block_buf;
+	ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
+	if (ctx->progress)
+		(ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count);
 	while (ino) {
 		pctx.ino = ino;
 		pctx.inode = &inode;
@@ -471,7 +482,16 @@
 static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
 			       dgrp_t group, void * private)
 {
-	process_inodes((e2fsck_t) fs->private, (char *) private);
+	struct scan_callback_struct *scan_struct = private;
+	e2fsck_t ctx;
+
+	ctx = scan_struct->ctx;
+	
+	process_inodes((e2fsck_t) fs->private, scan_struct->block_buf);
+
+	if (ctx->progress)
+		(ctx->progress)(ctx, 1, group+1, ctx->fs->group_desc_count);
+
 	return 0;
 }
 
@@ -826,7 +846,7 @@
 				p->clear = 1;
 				return BLOCK_ABORT;
 			}
-			if (ask(ctx, "Suppress messages", 0)) {
+			if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
 				p->suppress = 1;
 				set_latch_flags(PR_LATCH_BLOCK,
 						PRL_SUPPRESS, 0);
@@ -897,6 +917,7 @@
 	ctx = p->ctx;
 	pctx = p->pctx;
 	
+	pctx->ino = EXT2_BAD_INO;
 	pctx->blk = blk;
 	pctx->blkcount = blockcnt;
 
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index 1aa586b..fbd43ee 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -118,7 +118,8 @@
 		      "multiply claimed inode map", &inode_dup_map);
 	if (pctx.errcode) {
 		fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
 	
 	pass1b(ctx, block_buf);
@@ -172,12 +173,14 @@
 					      &scan);
 	if (pctx.errcode) {
 		fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
 	pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
 	if (pctx.errcode) {
 		fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
 	ctx->stashed_inode = &inode;
 	pb.ctx = ctx;
@@ -195,8 +198,9 @@
 					      process_pass1b_block, &pb);
 		if (pb.dup_blocks) {
 			end_problem_latch(ctx, PR_LATCH_DBLOCK);
-			dp = allocate_memory(sizeof(struct dup_inode),
-					     "duplicate inode record");
+			dp = e2fsck_allocate_memory(ctx,
+				    sizeof(struct dup_inode),
+				    "duplicate inode record");
 			dp->ino = ino;
 			dp->dir = 0;
 			dp->inode = inode;
@@ -216,7 +220,8 @@
 			goto next;
 		if (pctx.errcode) {
 			fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
-			fatal_error(0);
+			ctx->flags |= E2F_FLAG_ABORT;
+			return;
 		}
 	}
 	ext2fs_close_inode_scan(scan);
@@ -248,8 +253,8 @@
 		p->dup_blocks++;
 		ext2fs_mark_block_bitmap(ctx->block_dup_map, *block_nr);
 		ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
-		dp = allocate_memory(sizeof(struct dup_block),
-				      "duplicate block record");
+		dp = e2fsck_allocate_memory(ctx, sizeof(struct dup_block),
+					    "duplicate block record");
 		dp->block = *block_nr;
 		dp->ino = p->ino;
 		dp->num_bad = 0;
@@ -371,12 +376,12 @@
 	clear_problem_context(&pctx);
 	
 	fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
-	read_bitmaps(ctx);
+	e2fsck_read_bitmaps(ctx);
 
 	pctx.num = dup_inode_count;
 	fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
-	shared = allocate_memory(sizeof(ino_t) * dup_inode_count,
-				 "Shared inode list");
+	shared = e2fsck_allocate_memory(ctx, sizeof(ino_t) * dup_inode_count,
+					"Shared inode list");
 	for (p = dup_ino; p; p = p->next) {
 		shared_len = 0;
 		file_ok = 1;
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 4facc60..85a857b 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -63,6 +63,7 @@
 struct check_dir_struct {
 	char *buf;
 	struct problem_context	pctx;
+	int	count, max;
 	e2fsck_t ctx;
 };	
 
@@ -97,7 +98,8 @@
 		ctx->flags |= E2F_FLAG_ABORT;
 		return;
 	}
-	buf = allocate_memory(fs->blocksize, "directory scan buffer");
+	buf = e2fsck_allocate_memory(ctx, fs->blocksize,
+				     "directory scan buffer");
 
 	/*
 	 * Set up the parent pointer for the root directory, if
@@ -110,6 +112,8 @@
 
 	cd.buf = buf;
 	cd.ctx = ctx;
+	cd.count = 0;
+	cd.max = ext2fs_dblist_count(fs->dblist);
 	
 	cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
 						&cd);
@@ -177,9 +181,8 @@
 	if (dirent->rec_len > 12) {
 		new_len = dirent->rec_len - 12;
 		if (new_len > 12) {
-			preenhalt(ctx);
 			if (created ||
-			    ask(ctx, "Directory entry for '.' is big.  Split", 1)) {
+			    fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
 				nextdir = (struct ext2_dir_entry *)
 					((char *) dirent + 12);
 				dirent->rec_len = 12;
@@ -280,6 +283,9 @@
 
 	buf = cd->buf;
 	ctx = cd->ctx;
+
+	if (ctx->progress)
+		(ctx->progress)(ctx, 2, cd->count++, cd->max);
 	
 	/*
 	 * Make sure the inode is still in use (could have been 
@@ -553,7 +559,7 @@
 	/*
 	 * Fix up the bitmaps...
 	 */
-	read_bitmaps(ctx);
+	e2fsck_read_bitmaps(ctx);
 	ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
 	ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
 	if (ctx->inode_bad_map)
@@ -691,7 +697,7 @@
 	 * Read the inode and block bitmaps in; we'll be messing with
 	 * them.
 	 */
-	read_bitmaps(ctx);
+	e2fsck_read_bitmaps(ctx);
 	
 	/*
 	 * First, find a free block
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index f85d9bd..9af3be7 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -64,7 +64,8 @@
 #endif
 	struct problem_context	pctx;
 	struct dir_info	*dir;
-	
+	unsigned long max, count;
+
 #ifdef RESOURCE_TRACK
 	init_resource_track(&rtrack);
 #endif
@@ -108,11 +109,19 @@
 
 	ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
 
+	max = e2fsck_get_num_dirinfo(ctx);
+	count = 0;
+
+	if (ctx->progress)
+		(ctx->progress)(ctx, 3, 0, max);
 	for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
+		if (ctx->progress)
+			(ctx->progress)(ctx, 3, count++, max);
 		if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
 			check_directory(ctx, dir, &pctx);
 	}
-	
+	if (ctx->progress)
+		(ctx->progress)(ctx, 3, max, max);
 	
 	e2fsck_free_dir_info(ctx);
 	ext2fs_free_inode_bitmap(inode_loop_detect);
@@ -144,15 +153,20 @@
 		 * offered to clear it.
 		 */
 		if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
-					       EXT2_ROOT_INO)))
-			fatal_error("Root inode not directory");
+					       EXT2_ROOT_INO))) {
+			fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
+			ctx->flags |= E2F_FLAG_ABORT;
+		}
 		return;
 	}
 
-	if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx))
-		fatal_error("Cannot proceed without a root inode.");
+	if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
+		fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
+	}
 
-	read_bitmaps(ctx);
+	e2fsck_read_bitmaps(ctx);
 	
 	/*
 	 * First, find a free block
@@ -330,7 +344,7 @@
 	 * Read the inode and block bitmaps in; we'll be messing with
 	 * them.
 	 */
-	read_bitmaps(ctx);
+	e2fsck_read_bitmaps(ctx);
 	
 	/*
 	 * First, find a free block
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index 6aca7d4..a140be7 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -47,7 +47,7 @@
 			/*
 			 * Fix up the bitmaps...
 			 */
-			read_bitmaps(ctx);
+			e2fsck_read_bitmaps(ctx);
 			ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
 			ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
 			ext2fs_unmark_inode_bitmap(fs->inode_map, i);
@@ -85,6 +85,7 @@
 #endif
 	struct problem_context	pctx;
 	__u16	link_count, link_counted;
+	int	group, max, j;
 	
 #ifdef RESOURCE_TRACK
 	init_resource_track(&rtrack);
@@ -99,7 +100,17 @@
 	if (!(ctx->options & E2F_OPT_PREEN))
 		fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
 
+	group = 0;
+	max = fs->group_desc_count;
+	if (ctx->progress)
+		(ctx->progress)(ctx, 4, 0, max);
+	
 	for (i=1; i <= fs->super->s_inodes_count; i++) {
+		if ((i % fs->super->s_inodes_per_group) == 0) {
+			group++;
+			if (ctx->progress)
+				(ctx->progress)(ctx, 4, group, max);
+		}
 		if (i == EXT2_BAD_INO ||
 		    (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
 			continue;
@@ -137,6 +148,8 @@
 	ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
 	ext2fs_free_inode_bitmap(ctx->inode_bb_map);
 	ctx->inode_bb_map = 0;
+	if (ctx->progress)
+		(ctx->progress)(ctx, 4, max, max);	
 #ifdef RESOURCE_TRACK
 	if (ctx->options & E2F_OPT_TIME2)
 		print_resource_track("Pass 4", &rtrack);
diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
index 9dcb7fd..3afd2ed 100644
--- a/e2fsck/pass5.c
+++ b/e2fsck/pass5.c
@@ -38,7 +38,13 @@
 	if (!(ctx->options & E2F_OPT_PREEN))
 		fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
 
-	read_bitmaps(ctx);
+	if (ctx->progress)
+		(ctx->progress)(ctx, 5, 0, 3);
+
+	e2fsck_read_bitmaps(ctx);
+
+	if (ctx->progress)
+		(ctx->progress)(ctx, 5, 2, 3);
 
 	check_block_bitmaps(ctx);
 	if (ctx->flags & E2F_FLAG_ABORT)
@@ -53,6 +59,9 @@
 	if (ctx->flags & E2F_FLAG_ABORT)
 		return;
 
+	if (ctx->progress)
+		(ctx->progress)(ctx, 5, 3, 3);
+
 	ext2fs_free_inode_bitmap(ctx->inode_used_map);
 	ctx->inode_used_map = 0;
 	ext2fs_free_inode_bitmap(ctx->inode_dir_map);
@@ -81,8 +90,8 @@
 	errcode_t	retval;
 	
 	clear_problem_context(&pctx);
-	free_array = allocate_memory(fs->group_desc_count * sizeof(int),
-				     "free block count array");
+	free_array = e2fsck_allocate_memory(ctx,
+	    fs->group_desc_count * sizeof(int), "free block count array");
 
 	if ((fs->super->s_first_data_block <
 	     ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
@@ -214,11 +223,11 @@
 	int	problem, fixit;
 	
 	clear_problem_context(&pctx);
-	free_array = allocate_memory(fs->group_desc_count * sizeof(int),
-				     "free inode count array");
+	free_array = e2fsck_allocate_memory(ctx,
+	    fs->group_desc_count * sizeof(int), "free inode count array");
 				     
-	dir_array = allocate_memory(fs->group_desc_count * sizeof(int),
-				    "directory count array");
+	dir_array = e2fsck_allocate_memory(ctx,
+	   fs->group_desc_count * sizeof(int), "directory count array");
 				     
 	if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
 	    (fs->super->s_inodes_count > 
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index eae98b1..503e61e 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -18,6 +18,7 @@
 #include "e2fsck.h"
 
 #include "problem.h"
+#include "problemP.h"
 
 #define PROMPT_NONE	0
 #define PROMPT_FIX	1
@@ -35,6 +36,7 @@
 #define PROMPT_CONTINUE	13
 #define PROMPT_CLONE	14
 #define PROMPT_DELETE 	15
+#define PROMPT_SUPPRESS 16
 
 /*
  * These are the prompts which are used to ask the user if they want
@@ -57,6 +59,7 @@
 	"Continue",		/* 13 */
 	"Clone duplicate/bad blocks", /* 14 */
 	"Delete file",		/* 15 */
+	"Suppress messages",	/* 16 */
 };
 
 /*
@@ -80,6 +83,7 @@
 	"CONTINUING",		/* 13 */
 	"DUPLICATE/BAD BLOCKS CLONED", /* 14 */
 	"FILE DELETED",		/* 15 */
+	"SUPPRESSED",		/* 16 */
 };
 
 static const struct e2fsck_problem problem_table[] = {
@@ -297,7 +301,7 @@
 	/* Bad primary block group descriptors */
 	{ PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
 	  "Block %b in the primary @g descriptors "
-	  "is on the bad block list\n",
+	  "is on the bad @b list\n",
 	  PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
 		  
 	/* Bad superblock in group */
@@ -317,14 +321,14 @@
 	  "process_bad_@b.\n",
 	  PROMPT_NONE, PR_PREEN_OK },
 
-	/* Could not allocate blocks for relocating metadata */
+	/* Error allocating blocks for relocating metadata */
 	{ PR_1_RELOC_BLOCK_ALLOCATE,
-	  "Could not allocate %N @b(s) for %s: %m\n",
+	  "@A %N @b(s) for %s: %m\n",
 	  PROMPT_NONE, PR_PREEN_OK },
 		
-	/* Could not allocate memory during relocation process */
+	/* Error allocating block buffer during relocation process */
 	{ PR_1_RELOC_MEMORY_ALLOCATE,
-	  "Could not allocate @b buffer for relocating %s\n",
+	  "@A @b buffer for relocating %s\n",
 	  PROMPT_NONE, PR_PREEN_OK },
 		
 	/* Relocating metadata group information from X to Y */	
@@ -349,49 +353,52 @@
 
 	/* Error allocating inode bitmap */
 	{ PR_1_ALLOCATE_IBITMAP_ERROR,
-	  "Error allocating @i @B (%N): %m\n",
+	  "@A @i @B (%N): %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error allocating block bitmap */
 	{ PR_1_ALLOCATE_BBITMAP_ERROR,
-	  "Error allocating @b @B (%N): %m\n",
+	  "@A @b @B (%N): %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error allocating icount structure */
 	{ PR_1_ALLOCATE_ICOUNT,
-	  "Error allocating icount link information: %m\n",
+	  "@A icount link information: %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error allocating dbcount */
 	{ PR_1_ALLOCATE_DBCOUNT,
-	  "Error allocating directory @b array: %m\n",
+	  "@A @d @b array: %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error while scanning inodes */
 	{ PR_1_ISCAN_ERROR,
-	  "Error while scanning inodes (%i): %m\n",
+	  "Error while scanning @is (%i): %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error while iterating over blocks */
 	{ PR_1_BLOCK_ITERATE,
-	  "Error while iterating over blocks in inode %i: %m\n",
+	  "Error while iterating over blocks in @i %i: %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error while storing inode count information */	  
 	{ PR_1_ICOUNT_STORE,
-	  "Error storing inode count information (inode=%i, count=%N): %m\n",
+	  "Error storing @i count information (inode=%i, count=%N): %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error while storing directory block information */	  
 	{ PR_1_ADD_DBLOCK,
-	  "Error storing dir block information "
+	  "Error storing @d @b information "
 	  "(inode=%i, block=%b, num=%N): %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error while reading inode (for clearing) */	  
 	{ PR_1_READ_INODE,
-	  "Error reading inode %i: %m\n",
+	  "Error reading @i %i: %m\n",
 	  PROMPT_NONE, PR_FATAL },
+
+	/* Suppress messages prompt */
+	{ PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
 		  
 	/* Pass 1b errors */
 
@@ -423,7 +430,7 @@
 
 	/* Error allocating inode bitmap */
 	{ PR_1B_ALLOCATE_IBITMAP_ERROR,
-	  "Error allocating @i @B (inode_dup_map): %m\n",
+	  "@A @i @B (inode_dup_map): %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 
@@ -590,12 +597,12 @@
 
 	/* '.' is not NULL terminated */
 	{ PR_2_DOT_NULL_TERM,
-	  "'.' directory entry in @d @i %i is not NULL terminated\n",
+	  "'.' @d @e in @d @i %i is not NULL terminated\n",
 	  PROMPT_FIX, 0 },
 
 	/* '..' is not NULL terminated */
 	{ PR_2_DOT_DOT_NULL_TERM,
-	  "'..' directory entry in @d @i %i is not NULL terminated\n",
+	  "'..' @d @e in @d @i %i is not NULL terminated\n",
 	  PROMPT_FIX, 0 },
 
 	/* Illegal character device inode */
@@ -630,34 +637,38 @@
 		  
 	/* Error allocating icount structure */
 	{ PR_2_ALLOCATE_ICOUNT,
-	  "Error allocating icount structure: %m\n",
+	  "@A icount structure: %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error iterating over directory blocks */
 	{ PR_2_DBLIST_ITERATE,
-	  "Error interating over directory blocks: %m\n",
+	  "Error interating over @d @bs: %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error reading directory block */
 	{ PR_2_READ_DIRBLOCK,
-	  "Error reading directory block %b (inode %i): %m\n",
+	  "Error reading @d @b %b (@i %i): %m\n",
 	  PROMPT_CONTINUE, 0 },
 
 	/* Error writing directory block */
 	{ PR_2_WRITE_DIRBLOCK,
-	  "Error writing directory block %b (inode %i): %m\n",
+	  "Error writing @d @b %b (@i %i): %m\n",
 	  PROMPT_CONTINUE, 0 },
 
 	/* Error allocating new directory block */
 	{ PR_2_ALLOC_DIRBOCK,
-	  "Error allocating new directory block for inode %i (%s): %m\n",
+	  "@A new @d @b for @i %i (%s): %m\n",
 	  PROMPT_NONE, 0 },
 
 	/* Error deallocating inode */
 	{ PR_2_DEALLOC_INODE,
-	  "Error deallocating inode %i: %m\n",
+	  "Error deallocating @i %i: %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
+	/* Directory entry for '.' is big.  Split? */
+	{ PR_2_SPLIT_DOT,
+	  "@d @e for '.' is big.  ",
+	  PROMPT_SPLIT, PR_NO_OK },
 
 	/* Pass 3 errors */
 
@@ -748,7 +759,7 @@
 
 	/* Error allocating inode bitmap */
 	{ PR_3_ALLOCATE_IBITMAP_ERROR,
-	  "Error allocating @i @B (%N): %m\n",
+	  "@A @i @B (%N): %m\n",
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Error creating root directory */
@@ -761,6 +772,16 @@
 	  "Error creating /@l @d (%s): %m\n",
 	  PROMPT_NONE, PR_FATAL },  
 
+	/* Root inode is not directory; aborting */
+	{ PR_3_ROOT_NOT_DIR_ABORT,
+	  "@r is not a @d; aborting.\n",
+	  PROMPT_NONE, PR_FATAL },  
+
+	/* Cannot proceed without a root inode. */
+	{ PR_3_NO_ROOT_INODE_ABORT,
+	  "Cannot proceed without a @r.\n",
+	  PROMPT_NONE, PR_FATAL },  
+
 	/* Pass 4 errors */
 	
 	/* Pass 4: Checking reference counts */
@@ -1021,7 +1042,7 @@
 		preenhalt(ctx);
 
 	if (ptr->flags & PR_FATAL)
-		fatal_error(0);
+		fatal_error(ctx, 0);
 
 	if (ptr->prompt == PROMPT_NONE) {
 		if (ptr->flags & PR_NOCOLLATE)
@@ -1055,8 +1076,8 @@
 	if (ptr->flags & PR_AFTER_CODE)
 		(void) fix_problem(ctx, ptr->second_code, pctx);
 
-	if (ptr->prompt == PROMPT_ABORT)
-		fatal_error(0);
+	if ((ptr->prompt == PROMPT_ABORT) && answer)
+		fatal_error(ctx, 0);
 
 	return answer;
 }
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 3fbbb2a..5788703 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -22,31 +22,6 @@
 	const char *str;
 };
 
-struct e2fsck_problem {
-	problem_t	e2p_code;
-	const char *	e2p_description;
-	char		prompt;
-	short		flags;
-	problem_t	second_code;
-};
-
-struct latch_descr {
-	int		latch_code;
-	problem_t	question;
-	problem_t	end_message;
-	int		flags;
-};
-
-#define PR_PREEN_OK	0x0001	/* Don't need to do preenhalt */
-#define PR_NO_OK	0x0002	/* If user answers no, don't make fs invalid */
-#define PR_NO_DEFAULT	0x0004	/* Default to no */
-#define PR_MSG_ONLY	0x0008	/* Print message only */
-#define PR_FATAL	0x0080	/* Fatal error */
-#define PR_AFTER_CODE	0x0100	/* After asking the first question, */
-				/* ask another */
-#define PR_PREEN_NOMSG	0x0200	/* Don't print a message if we're preening */
-#define PR_NOCOLLATE	0x0400	/* Don't collate answers for this latch */
-
 /*
  * We define a set of "latch groups"; these are problems which are
  * handled as a set.  The user answers once for a particular latch
@@ -206,10 +181,10 @@
 /* Block claimed for no reason */	  
 #define PR_1_PROGERR_CLAIMED_BLOCK	0x010001D
 
-/* Could not allocate blocks for relocating metadata */
+/* Error allocating blocks for relocating metadata */
 #define PR_1_RELOC_BLOCK_ALLOCATE	0x010001E
 		
-/* Could not allocate memory during relocation process */
+/* Error allocating block buffer during relocation process */
 #define PR_1_RELOC_MEMORY_ALLOCATE	0x010001F
 		
 /* Relocating metadata group information from X to Y */	
@@ -251,6 +226,8 @@
 /* Error while reading inode (for clearing) */
 #define PR_1_READ_INODE			0x010002C
 
+/* Suppress messages prompt */
+#define PR_1_SUPPRESS_MESSAGES		0x010002D
 
 /*
  * Pass 1b errors
@@ -418,6 +395,9 @@
 /* Error deallocating inode */
 #define PR_2_DEALLOC_INODE	0x020023
 
+/* Directory entry for '.' is big.  Split? */
+#define PR_2_SPLIT_DOT		0x0200024
+
 /*
  * Pass 3 errors
  */
@@ -482,6 +462,12 @@
 /* Error creating lost and found directory */
 #define PR_3_CREATE_LPF_ERROR		0x030013
 
+/* Root inode is not directory; aborting */
+#define PR_3_ROOT_NOT_DIR_ABORT		0x030014
+
+/* Cannot proceed without a root inode. */
+#define PR_3_NO_ROOT_INODE_ABORT	0x030015
+
 /*
  * Pass 4 errors
  */
diff --git a/e2fsck/problemP.h b/e2fsck/problemP.h
new file mode 100644
index 0000000..ceb7bd3
--- /dev/null
+++ b/e2fsck/problemP.h
@@ -0,0 +1,36 @@
+/*
+ * problemP.h --- Private header file for fix_problem()
+ *
+ * Copyright 1997 by Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+struct e2fsck_problem {
+	problem_t	e2p_code;
+	const char *	e2p_description;
+	char		prompt;
+	short		flags;
+	problem_t	second_code;
+};
+
+struct latch_descr {
+	int		latch_code;
+	problem_t	question;
+	problem_t	end_message;
+	int		flags;
+};
+
+#define PR_PREEN_OK	0x0001	/* Don't need to do preenhalt */
+#define PR_NO_OK	0x0002	/* If user answers no, don't make fs invalid */
+#define PR_NO_DEFAULT	0x0004	/* Default to no */
+#define PR_MSG_ONLY	0x0008	/* Print message only */
+#define PR_FATAL	0x0080	/* Fatal error */
+#define PR_AFTER_CODE	0x0100	/* After asking the first question, */
+				/* ask another */
+#define PR_PREEN_NOMSG	0x0200	/* Don't print a message if we're preening */
+#define PR_NOCOLLATE	0x0400	/* Don't collate answers for this latch */
+
diff --git a/e2fsck/super.c b/e2fsck/super.c
index 1b6fb04..a0a2f19 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -60,15 +60,12 @@
 	blk_t	should_be;
 	struct problem_context	pctx;
 
-	ctx->invalid_inode_bitmap_flag = allocate_memory(sizeof(int) *
-					       fs->group_desc_count,
-					       "invalid_inode_bitmap");
-	ctx->invalid_block_bitmap_flag = allocate_memory(sizeof(int) *
-					       fs->group_desc_count,
-					       "invalid_block_bitmap");
-	ctx->invalid_inode_table_flag = allocate_memory(sizeof(int) *
-					      fs->group_desc_count,
-					      "invalid_inode_table");
+	ctx->invalid_inode_bitmap_flag = e2fsck_allocate_memory(ctx,
+		 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
+	ctx->invalid_block_bitmap_flag = e2fsck_allocate_memory(ctx,
+		 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
+	ctx->invalid_inode_table_flag = e2fsck_allocate_memory(ctx,
+		sizeof(int) * fs->group_desc_count, "invalid_inode_table");
 		
 	clear_problem_context(&pctx);
 
@@ -95,21 +92,23 @@
 	check_super_value(ctx, "r_blocks_count", s->s_r_blocks_count,
 			  MAX_CHECK, 0, s->s_blocks_count);
 
-	pctx.errcode = ext2fs_get_device_size(ctx->filesystem_name,
-					      EXT2_BLOCK_SIZE(s),
-					      &should_be);
-	if (pctx.errcode) {
-		fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
-		ctx->flags |= E2F_FLAG_ABORT;
-		return;
-	}
-	if (should_be < s->s_blocks_count) {
-		pctx.blk = s->s_blocks_count;
-		pctx.blk2 = should_be;
-		if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
+	if (!ctx->num_blocks) {
+		pctx.errcode = ext2fs_get_device_size(ctx->filesystem_name,
+			      EXT2_BLOCK_SIZE(s), &ctx->num_blocks);
+		if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
+			fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
 			ctx->flags |= E2F_FLAG_ABORT;
 			return;
 		}
+		if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
+		    (ctx->num_blocks < s->s_blocks_count)) {
+			pctx.blk = s->s_blocks_count;
+			pctx.blk2 = ctx->num_blocks;
+			if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
+				ctx->flags |= E2F_FLAG_ABORT;
+				return;
+			}
+		}
 	}
 
 	if (s->s_log_block_size != s->s_log_frag_size) {
diff --git a/e2fsck/swapfs.c b/e2fsck/swapfs.c
index ab012c7..209a57a 100644
--- a/e2fsck/swapfs.c
+++ b/e2fsck/swapfs.c
@@ -75,7 +75,7 @@
  * This function is responsible for byte-swapping all of the indirect,
  * block pointers.  It is also responsible for byte-swapping directories.
  */
-static void swap_inode_blocks(ext2_filsys fs, ino_t ino, char *block_buf,
+static void swap_inode_blocks(e2fsck_t ctx, ino_t ino, char *block_buf,
 			      struct ext2_inode *inode)
 {
 	errcode_t			retval;
@@ -83,22 +83,25 @@
 
 	sb.ino = ino;
 	sb.inode = inode;
-	sb.dir_buf = block_buf + fs->blocksize*3;
+	sb.dir_buf = block_buf + ctx->fs->blocksize*3;
 	sb.errcode = 0;
 	sb.isdir = 0;
 	if (LINUX_S_ISDIR(inode->i_mode))
 		sb.isdir = 1;
 
-	retval = ext2fs_block_iterate(fs, ino, 0, block_buf, swap_block, &sb);
+	retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
+				      swap_block, &sb);
 	if (retval) {
 		com_err("swap_inode_blocks", retval,
 			"while calling ext2fs_block_iterate");
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
 	if (sb.errcode) {
 		com_err("swap_inode_blocks", sb.errcode,
 			"while calling iterator function");
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
 }
 
@@ -119,10 +122,11 @@
 	if (retval) {
 		com_err("swap_inodes", retval,
 			"while allocating inode buffer");
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
-	block_buf = allocate_memory(fs->blocksize * 4,
-				    "block interate buffer");
+	block_buf = e2fsck_allocate_memory(ctx, fs->blocksize * 4,
+					   "block interate buffer");
 	for (group = 0; group < fs->group_desc_count; group++) {
 		retval = io_channel_read_blk(fs->io,
 		      fs->group_desc[group].bg_inode_table,
@@ -131,7 +135,8 @@
 			com_err("swap_inodes", retval,
 				"while reading inode table (group %d)",
 				group);
-			fatal_error(0);
+			ctx->flags |= E2F_FLAG_ABORT;
+			return;
 		}
 		inode = (struct ext2_inode *) buf;
 		for (i=0; i < fs->super->s_inodes_per_group;
@@ -153,7 +158,10 @@
 			      inode->i_block[EXT2_DIND_BLOCK] ||
 			      inode->i_block[EXT2_TIND_BLOCK]) &&
 			     ext2fs_inode_has_valid_blocks(inode)))
-				swap_inode_blocks(fs, ino, block_buf, inode);
+				swap_inode_blocks(ctx, ino, block_buf, inode);
+
+			if (ctx->flags & E2F_FLAG_ABORT)
+				return;
 			
 			if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
 				ext2fs_swap_inode(fs, inode, inode, 1);
@@ -165,7 +173,8 @@
 			com_err("swap_inodes", retval,
 				"while writing inode table (group %d)",
 				group);
-			fatal_error(0);
+			ctx->flags |= E2F_FLAG_ABORT;
+			return;
 		}
 	}
 	ext2fs_free_mem((void **) &buf);
@@ -195,7 +204,8 @@
 			"checked using fsck\n"
 			"and not mounted before trying to "
 			"byte-swap it.\n", ctx->device_name);
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
 	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
 		fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
@@ -206,6 +216,8 @@
 		fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
 	}
 	swap_inodes(ctx);
+	if (ctx->flags & E2F_FLAG_ABORT)
+		return;
 	if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
 		fs->flags |= EXT2_FLAG_SWAP_BYTES;
 	fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index f5c3191..7c27a2a 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -170,8 +170,8 @@
 	}
 
 	printf("%s is mounted.\n\n", ctx->device_name);
-	printf("\a\a\a\aWARNING!!!  Running e2fsck on a mounted filesystem "
-	       "may cause\nSEVERE filesystem damage.\a\a\a\n\n");
+	printf("\007\007\007\007WARNING!!!  Running e2fsck on a mounted filesystem "
+	       "may cause\nSEVERE filesystem damage.\007\007\007\n\n");
 	if (isatty (0) && isatty (1))
 		cont = ask_yn("Do you really want to continue", -1);
 	else
@@ -254,7 +254,7 @@
 
 		newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
 		if (!newpath)
-			fatal_error("Couldn't malloc() newpath");
+			fatal_error(ctx, "Couldn't malloc() newpath");
 		strcpy (newpath, PATH_SET);
 		strcat (newpath, ":");
 		strcat (newpath, oldpath);
@@ -320,7 +320,8 @@
 		case 'l':
 			bad_blocks_file = malloc(strlen(optarg)+1);
 			if (!bad_blocks_file)
-				fatal_error("Couldn't malloc bad_blocks_file");
+				fatal_error(ctx,
+					    "Couldn't malloc bad_blocks_file");
 			strcpy(bad_blocks_file, optarg);
 			break;
 		case 'd':
@@ -333,7 +334,7 @@
 #ifdef BLKFLSBUF
 			flush = 1;
 #else
-			fatal_error ("-F not supported");
+			fatal_error(ctx, "-F not supported");
 #endif
 			break;
 		case 'v':
@@ -384,14 +385,14 @@
 		}
 		close(fd);
 #else
-		fatal_error ("BLKFLSBUF not supported");
+		fatal_error(ctx, "BLKFLSBUF not supported");
 #endif /* BLKFLSBUF */
 	}
 	if (swapfs) {
 		if (cflag || bad_blocks_file) {
 			fprintf(stderr, "Incompatible options not "
 				"allowed when byte-swapping.\n");
-			fatal_error(0);
+			exit(FSCK_ERROR);
 		}
 	}
 	return 0;
@@ -457,7 +458,8 @@
 	    !(ctx->options & E2F_OPT_NO) &&
 	    !(ctx->options & E2F_OPT_YES)) {
 		if (!isatty (0) || !isatty (1))
-			fatal_error("need terminal for interactive repairs");
+			fatal_error(ctx,
+				    "need terminal for interactive repairs");
 	}
 	ctx->superblock = ctx->use_superblock;
 restart:
@@ -520,7 +522,7 @@
 #endif
 		else
 			fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
-		fatal_error(0);
+		exit(FSCK_ERROR);
 	}
 	ctx->fs = fs;
 	fs->private = ctx;
@@ -529,7 +531,8 @@
 		com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH,
 			"while trying to open %s",
 			ctx->filesystem_name);
-		goto get_newer;
+	get_newer:
+		fatal_error(ctx, "Get a newer version of e2fsck!");
 	}
 #endif
 	/*
@@ -541,9 +544,7 @@
 	    (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
 		com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
 			"(%s)", ctx->filesystem_name);
-	get_newer:
-		printf ("Get a newer version of e2fsck!\n");
-		fatal_error(0);
+		goto get_newer;
 	}
 	if (s->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
 		com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE,
@@ -571,22 +572,29 @@
 	if (ctx->superblock)
 		set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
 	check_super_block(ctx);
+	if (ctx->flags & E2F_FLAG_ABORT)
+		exit(FSCK_ERROR);
 	check_if_skip(ctx);
 	if (bad_blocks_file)
 		read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks);
 	else if (cflag)
 		test_disk(ctx);
+	if (ctx->flags & E2F_FLAG_ABORT)
+		exit(FSCK_ERROR);
 
 	if (normalize_swapfs) {
 		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
 		    ext2fs_native_flag()) {
 			fprintf(stderr, "%s: Filesystem byte order "
 				"already normalized.\n", ctx->device_name);
-			fatal_error(0);
+			exit(FSCK_ERROR);
 		}
 	}
-	if (swapfs)
+	if (swapfs) {
 		swap_filesys(ctx);
+		if (ctx->flags & E2F_FLAG_ABORT)
+			exit(FSCK_ERROR);
+	}
 
 	/*
 	 * Mark the system as valid, 'til proven otherwise
@@ -649,7 +657,7 @@
 	}
 	show_stats(ctx);
 
-	write_bitmaps(ctx);
+	e2fsck_write_bitmaps(ctx);
 	ext2fs_close(fs);
 	sync_disks();
 	
diff --git a/e2fsck/util.c b/e2fsck/util.c
index 46ceaa9..37509c8 100644
--- a/e2fsck/util.c
+++ b/e2fsck/util.c
@@ -20,14 +20,18 @@
 #include <sys/time.h>
 #include <sys/resource.h>
 
-void fatal_error (const char *msg)
+void fatal_error(e2fsck_t ctx, const char *msg)
 {
 	if (msg) 
 		fprintf (stderr, "e2fsck: %s\n", msg);
+	ctx->flags |= E2F_FLAG_ABORT;
+	if (ctx->flags & E2F_FLAG_SETJMP_OK)
+		longjmp(ctx->abort_loc, 1);
 	exit(FSCK_ERROR);
 }
 
-void *allocate_memory(int size, const char *description)
+void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
+			     const char *description)
 {
 	void *ret;
 	char buf[256];
@@ -38,7 +42,7 @@
 	ret = malloc(size);
 	if (!ret) {
 		sprintf(buf, "Can't allocate %s\n", description);
-		fatal_error(buf);
+		fatal_error(ctx, buf);
 	}
 	memset(ret, 0, size);
 	return ret;
@@ -105,16 +109,16 @@
 	return ask_yn(string, def);
 }
 
-void read_bitmaps(e2fsck_t ctx)
+void e2fsck_read_bitmaps(e2fsck_t ctx)
 {
 	ext2_filsys fs = ctx->fs;
 	errcode_t	retval;
 
 	if (ctx->invalid_bitmaps) {
 		com_err(ctx->program_name, 0,
-			"read_bitmaps: illegal bitmap block(s) for %s",
+			"e2fsck_read_bitmaps: illegal bitmap block(s) for %s",
 			ctx->device_name);
-		fatal_error(0);
+		fatal_error(ctx, 0);
 	}
 
 	ehandler_operation("reading inode and block bitmaps");
@@ -124,11 +128,11 @@
 		com_err(ctx->program_name, retval,
 			"while retrying to read bitmaps for %s",
 			ctx->device_name);
-		fatal_error(0);
+		fatal_error(ctx, 0);
 	}
 }
 
-void write_bitmaps(e2fsck_t ctx)
+void e2fsck_write_bitmaps(e2fsck_t ctx)
 {
 	ext2_filsys fs = ctx->fs;
 	errcode_t	retval;
@@ -141,7 +145,7 @@
 			com_err(ctx->program_name, retval,
 				"while retrying to write block bitmaps for %s",
 				ctx->device_name);
-			fatal_error(0);
+			fatal_error(ctx, 0);
 		}
 	}
 
@@ -153,7 +157,7 @@
 			com_err(ctx->program_name, retval,
 				"while retrying to write inode bitmaps for %s",
 				ctx->device_name);
-			fatal_error(0);
+			fatal_error(ctx, 0);
 		}
 	}
 }
@@ -247,7 +251,7 @@
 	if (retval) {
 		com_err("ext2fs_read_inode", retval,
 			"while reading inode %ld in %s", ino, proc);
-		fatal_error(0);
+		fatal_error(ctx, 0);
 	}
 }
 
@@ -260,7 +264,7 @@
 	if (retval) {
 		com_err("ext2fs_write_inode", retval,
 			"while writing inode %ld in %s", ino, proc);
-		fatal_error(0);
+		fatal_error(ctx, 0);
 	}
 }