Many files:
  Change ext2fs_read_inode, ext2fs_write_inode to take the e2fsck
  context as their first argument.
  Change dir_info.c routines to take an e2fsck_context, renamed them to
  start with e2fsck_ to avoid namespace issues, and changed them to
  store the directory information inside the e2fsck context.
  Added e2fsck_run() which calls all of the e2fsck passes in the correct
  order, and which handles the return of abort codes.
  Added abort processing, both via setjmp/longjmp and via flags in the
  e2fsck context.
  Use a flag in the e2fsck context instead of the restart_e2fsck global
  variable.
  Change uses of free and malloc to ext2fs_free_mem and ext2fs_get_mem.

diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index edb2482..4facc60 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -66,7 +66,7 @@
 	e2fsck_t ctx;
 };	
 
-void pass2(e2fsck_t ctx)
+void e2fsck_pass2(e2fsck_t ctx)
 {
 	ext2_filsys 	fs = ctx->fs;
 	char	*buf;
@@ -94,7 +94,8 @@
 						&ctx->inode_count);
 	if (cd.pctx.errcode) {
 		fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
 	buf = allocate_memory(fs->blocksize, "directory scan buffer");
 
@@ -103,7 +104,7 @@
 	 * present.  (If the root directory is not present, we will
 	 * create it in pass 3.)
 	 */
-	dir = get_dir_info(EXT2_ROOT_INO);
+	dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
 	if (dir)
 		dir->parent = EXT2_ROOT_INO;
 
@@ -112,12 +113,15 @@
 	
 	cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
 						&cd);
+	if (ctx->flags & E2F_FLAG_ABORT)
+		return;
 	if (cd.pctx.errcode) {
 		fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
 	
-	free(buf);
+	ext2fs_free_mem((void **) &buf);
 	ext2fs_free_dblist(fs->dblist);
 
 	if (ctx->inode_bad_map) {
@@ -309,8 +313,10 @@
 	
 	cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
 	if (cd->pctx.errcode) {
-		if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx))
-			fatal_error(0);
+		if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
+			ctx->flags |= E2F_FLAG_ABORT;
+			return DIRENT_ABORT;
+		}
 		memset(buf, 0, fs->blocksize);
 	}
 
@@ -343,10 +349,11 @@
 			if (check_dot(ctx, dirent, ino, &cd->pctx))
 				dir_modified++;
 		} else if (dot_state == 2) {
-			dir = get_dir_info(ino);
+			dir = e2fsck_get_dir_info(ctx, ino);
 			if (!dir) {
 				fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
-				fatal_error(0);
+				ctx->flags |= E2F_FLAG_ABORT;
+				return DIRENT_ABORT;
 			}
 			if (check_dotdot(ctx, dirent, dir, &cd->pctx))
 				dir_modified++;
@@ -438,6 +445,8 @@
 				dir_modified++;
 				goto next;
 			}
+			if (ctx->flags & E2F_FLAG_ABORT)
+				return DIRENT_ABORT;
 		}
 
 		if (check_name(ctx, dirent, ino, &cd->pctx))
@@ -453,11 +462,12 @@
 		if ((dot_state > 2) &&
 		    (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
 					      dirent->inode))) {
-			subdir = get_dir_info(dirent->inode);
+			subdir = e2fsck_get_dir_info(ctx, dirent->inode);
 			if (!subdir) {
 				cd->pctx.ino = dirent->inode;
 				fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
-				fatal_error(0);
+				ctx->flags |= E2F_FLAG_ABORT;
+				return DIRENT_ABORT;
 			}
 			if (subdir->parent) {
 				cd->pctx.ino2 = subdir->parent;
@@ -493,8 +503,11 @@
 	if (dir_modified) {
 		cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
 		if (cd->pctx.errcode) {
-			if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK, &cd->pctx))
-				fatal_error(0);
+			if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
+					 &cd->pctx)) {
+				ctx->flags |= E2F_FLAG_ABORT;
+				return DIRENT_ABORT;
+			}
 		}
 		ext2fs_mark_changed(fs);
 	}
@@ -530,10 +543,10 @@
 	struct problem_context	pctx;
 	
 	ext2fs_icount_store(ctx->inode_link_info, ino, 0);
-	e2fsck_read_inode(fs, ino, &inode, "deallocate_inode");
+	e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
 	inode.i_links_count = 0;
 	inode.i_dtime = time(0);
-	e2fsck_write_inode(fs, ino, &inode, "deallocate_inode");
+	e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
 	clear_problem_context(&pctx);
 	pctx.ino = ino;
 
@@ -556,7 +569,8 @@
 					    deallocate_inode_block, ctx);
 	if (pctx.errcode) {
 		fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
-		fatal_error(0);
+		ctx->flags |= E2F_FLAG_ABORT;
+		return;
 	}
 }
 
@@ -567,8 +581,9 @@
 	int			inode_modified = 0;
 	unsigned char		*frag, *fsize;
 	struct problem_context	pctx;
+	int	problem = 0;
 
-	e2fsck_read_inode(fs, ino, &inode, "process_bad_inode");
+	e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
 
 	clear_problem_context(&pctx);
 	pctx.ino = ino;
@@ -578,29 +593,26 @@
 	if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
 	    !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
 	    !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
-	    !(LINUX_S_ISSOCK(inode.i_mode))) {
-		if (fix_problem(ctx, PR_2_BAD_MODE, &pctx)) {
-			deallocate_inode(ctx, ino, 0);
-			return 1;
-		}
-	}
+	    !(LINUX_S_ISSOCK(inode.i_mode)))
+		problem = PR_2_BAD_MODE;
 
 	if (LINUX_S_ISCHR(inode.i_mode)
-	    && !e2fsck_pass1_check_device_inode(&inode)) {
-		if (fix_problem(ctx, PR_2_BAD_CHAR_DEV, &pctx)) {
-			deallocate_inode(ctx, ino, 0);
-			return 1;
-		}
-	}
+	    && !e2fsck_pass1_check_device_inode(&inode))
+		problem = PR_2_BAD_CHAR_DEV;
 		
 	if (LINUX_S_ISBLK(inode.i_mode)
-	    && !e2fsck_pass1_check_device_inode(&inode)) {
-		if (fix_problem(ctx, PR_2_BAD_BLOCK_DEV, &pctx)) {
+	    && !e2fsck_pass1_check_device_inode(&inode))
+		problem = PR_2_BAD_BLOCK_DEV;
+
+	if (problem) {
+		if (fix_problem(ctx, problem, &pctx)) {
 			deallocate_inode(ctx, ino, 0);
+			if (ctx->flags & E2F_FLAG_ABORT)
+				return 0;
 			return 1;
 		}
+		problem = 0;
 	}
-
 		
 	if (inode.i_faddr &&
 	    fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
@@ -652,7 +664,7 @@
 		inode_modified++;
 	}
 	if (inode_modified)
-		e2fsck_write_inode(fs, ino, &inode, "process_bad_inode");
+		e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
 	return 0;
 }
 
@@ -710,7 +722,7 @@
 	}
 
 	pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
-	free(block);
+	ext2fs_free_mem((void **) &block);
 	if (pctx->errcode) {
 		pctx->str = "ext2fs_write_dir_block";
 		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
@@ -720,11 +732,11 @@
 	/*
 	 * Update the inode block count
 	 */
-	e2fsck_read_inode(fs, db->ino, &inode, "allocate_dir_block");
+	e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
 	inode.i_blocks += fs->blocksize / 512;
 	if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
 		inode.i_size = (db->blockcnt+1) * fs->blocksize;
-	e2fsck_write_inode(fs, db->ino, &inode, "allocate_dir_block");
+	e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
 
 	/*
 	 * Finally, update the block pointers for the inode