Whamcloud - gitweb
Merge branch 'maint' into next
[tools/e2fsprogs.git] / e2fsck / e2fsck.c
index 37d202b..1e295e3 100644 (file)
 /*
  * e2fsck.c - a consistency checker for the new extended file system.
- * 
- * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
- * redistributed under the terms of the GNU Public License.
- */
-
-/* Usage: e2fsck [-dfpnsvy] device
- *     -d -- debugging this program
- *     -f -- check the fs even if it is marked valid
- *     -p -- "preen" the filesystem
- *     -n -- open the filesystem r/o mode; never try to fix problems
- *     -v -- verbose (tells how many files)
- *     -y -- always answer yes to questions
  *
- * The device may be a block device or a image of one, but this isn't
- * enforced (but it's not much fun on a character device :-). 
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
  */
 
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <termios.h>
-#include <time.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <mntent.h>
-#include <sys/ioctl.h>
-#include <malloc.h>
+#include "config.h"
+#include <errno.h>
 
-#include "et/com_err.h"
 #include "e2fsck.h"
-#include "../version.h"
-
-extern int isatty(int);
-
-const char * program_name = "e2fsck";
-const char * device_name = NULL;
-
-/* Command line options */
-int nflag = 0;
-int yflag = 0;
-int tflag = 0;                 /* Do timing */
-int cflag = 0;                 /* check disk */
-int preen = 0;
-int rwflag = 1;
-int inode_buffer_blocks = 0;
-blk_t superblock;
-int blocksize = 0;
-int verbose = 0;
-int list = 0;
-int debug = 0;
-int force = 0;
-static int show_version_only = 0;
-
-static int replace_bad_blocks = 0;
-static char *bad_blocks_file = 0;
+#include "problem.h"
 
-static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
-
-struct resource_track  global_rtrack;
-
-static int root_filesystem = 0;
-static int read_only_root = 0;
-
-static void usage(NOARGS)
-{
-       fprintf(stderr,
-               "Usage: %s [-panyrdfvtFV] [-b superblock] [-B blocksize]\n"
-               "\t\tdevice\n", program_name);
-       exit(FSCK_USAGE);
-}
-
-static void show_stats(ext2_filsys fs)
+/*
+ * This function allocates an e2fsck context
+ */
+errcode_t e2fsck_allocate_context(e2fsck_t *ret)
 {
-       int inodes, inodes_used, blocks, blocks_used;
-       int dir_links;
-       int num_files, num_links;
-
-       dir_links = 2 * fs_directory_count - 1;
-       num_files = fs_total_count - dir_links;
-       num_links = fs_links_count - dir_links;
-       inodes = fs->super->s_inodes_count;
-       inodes_used = (fs->super->s_inodes_count -
-                      fs->super->s_free_inodes_count);
-       blocks = fs->super->s_blocks_count;
-       blocks_used = (fs->super->s_blocks_count -
-                      fs->super->s_free_blocks_count);
-       
-       if (!verbose) {
-               printf("%s: %d/%d files, %d/%d blocks\n", device_name,
-                      inodes_used, inodes, blocks_used, blocks);
-               return;
+       e2fsck_t        context;
+       errcode_t       retval;
+       char            *time_env;
+
+       retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
+       if (retval)
+               return retval;
+
+       memset(context, 0, sizeof(struct e2fsck_struct));
+
+       context->process_inode_size = 256;
+       context->ext_attr_ver = 2;
+       context->blocks_per_page = 1;
+       context->htree_slack_percentage = 255;
+
+       time_env = getenv("E2FSCK_TIME");
+       if (time_env)
+               context->now = (time_t) strtoull(time_env, NULL, 0);
+       else {
+               context->now = time(0);
+               if (context->now < 1262322000) /* January 1 2010 */
+                       context->flags |= E2F_FLAG_TIME_INSANE;
        }
-       printf ("\n%6d inode%s used (%d%%)\n", inodes_used,
-               (inodes_used != 1) ? "s" : "",
-               100 * inodes_used / inodes);
-       printf ("%6d block%s used (%d%%)\n"
-               "%6d bad block%s\n", blocks_used,
-               (blocks_used != 1) ? "s" : "",
-               100 * blocks_used / blocks, fs_badblocks_count,
-               fs_badblocks_count != 1 ? "s" : "");
-       printf ("\n%6d regular file%s\n"
-               "%6d director%s\n"
-               "%6d character device file%s\n"
-               "%6d block device file%s\n"
-               "%6d fifo%s\n"
-               "%6d link%s\n"
-               "%6d symbolic link%s (%d fast symbolic link%s)\n"
-               "%6d socket%s\n"
-               "------\n"
-               "%6d file%s\n",
-               fs_regular_count, (fs_regular_count != 1) ? "s" : "",
-               fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
-               fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
-               fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
-               fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
-               fs_links_count - dir_links,
-               ((fs_links_count - dir_links) != 1) ? "s" : "",
-               fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
-               fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
-               fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
-               fs_total_count - dir_links,
-               ((fs_total_count - dir_links) != 1) ? "s" : "");
+
+       *ret = context;
+       return 0;
 }
 
-static void check_mount(NOARGS)
+/*
+ * This function resets an e2fsck context; it is called when e2fsck
+ * needs to be restarted.
+ */
+errcode_t e2fsck_reset_context(e2fsck_t ctx)
 {
-       FILE * f;
-       struct mntent * mnt;
-       int cont;
-       int fd;
-
-       if ((f = setmntent (MOUNTED, "r")) == NULL)
-               return;
-       while ((mnt = getmntent (f)) != NULL)
-               if (strcmp (device_name, mnt->mnt_fsname) == 0)
-                       break;
-       endmntent (f);
-       if (!mnt)
-               return;
+       int     i;
 
-       if  (!strcmp(mnt->mnt_dir, "/"))
-               root_filesystem = 1;
+       ctx->flags &= E2F_RESET_FLAGS;
+       ctx->lost_and_found = 0;
+       ctx->bad_lost_and_found = 0;
+       if (ctx->inode_used_map) {
+               ext2fs_free_inode_bitmap(ctx->inode_used_map);
+               ctx->inode_used_map = 0;
+       }
+       if (ctx->inode_dir_map) {
+               ext2fs_free_inode_bitmap(ctx->inode_dir_map);
+               ctx->inode_dir_map = 0;
+       }
+       if (ctx->inode_reg_map) {
+               ext2fs_free_inode_bitmap(ctx->inode_reg_map);
+               ctx->inode_reg_map = 0;
+       }
+       if (ctx->block_found_map) {
+               ext2fs_free_block_bitmap(ctx->block_found_map);
+               ctx->block_found_map = 0;
+       }
+       if (ctx->inode_casefold_map) {
+               ext2fs_free_block_bitmap(ctx->inode_casefold_map);
+               ctx->inode_casefold_map = 0;
+       }
+       if (ctx->inode_link_info) {
+               ext2fs_free_icount(ctx->inode_link_info);
+               ctx->inode_link_info = 0;
+       }
+       if (ctx->journal_io) {
+               if (ctx->fs && ctx->fs->io != ctx->journal_io)
+                       io_channel_close(ctx->journal_io);
+               ctx->journal_io = 0;
+       }
+       if (ctx->fs && ctx->fs->dblist) {
+               ext2fs_free_dblist(ctx->fs->dblist);
+               ctx->fs->dblist = 0;
+       }
+       e2fsck_free_dir_info(ctx);
+       e2fsck_free_dx_dir_info(ctx);
+       if (ctx->refcount) {
+               ea_refcount_free(ctx->refcount);
+               ctx->refcount = 0;
+       }
+       if (ctx->refcount_extra) {
+               ea_refcount_free(ctx->refcount_extra);
+               ctx->refcount_extra = 0;
+       }
+       if (ctx->ea_block_quota_blocks) {
+               ea_refcount_free(ctx->ea_block_quota_blocks);
+               ctx->ea_block_quota_blocks = 0;
+       }
+       if (ctx->ea_block_quota_inodes) {
+               ea_refcount_free(ctx->ea_block_quota_inodes);
+               ctx->ea_block_quota_inodes = 0;
+       }
+       if (ctx->ea_inode_refs) {
+               ea_refcount_free(ctx->ea_inode_refs);
+               ctx->ea_inode_refs = 0;
+       }
+       if (ctx->block_dup_map) {
+               ext2fs_free_block_bitmap(ctx->block_dup_map);
+               ctx->block_dup_map = 0;
+       }
+       if (ctx->block_ea_map) {
+               ext2fs_free_block_bitmap(ctx->block_ea_map);
+               ctx->block_ea_map = 0;
+       }
+       if (ctx->block_metadata_map) {
+               ext2fs_free_block_bitmap(ctx->block_metadata_map);
+               ctx->block_metadata_map = 0;
+       }
+       if (ctx->inode_bb_map) {
+               ext2fs_free_inode_bitmap(ctx->inode_bb_map);
+               ctx->inode_bb_map = 0;
+       }
+       if (ctx->inode_bad_map) {
+               ext2fs_free_inode_bitmap(ctx->inode_bad_map);
+               ctx->inode_bad_map = 0;
+       }
+       if (ctx->inode_imagic_map) {
+               ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
+               ctx->inode_imagic_map = 0;
+       }
+       if (ctx->dirs_to_hash) {
+               ext2fs_u32_list_free(ctx->dirs_to_hash);
+               ctx->dirs_to_hash = 0;
+       }
+       destroy_encrypted_file_info(ctx);
 
        /*
-        * If the root is mounted read-only, then /etc/mtab is
-        * probably not correct; so we won't issue a warning based on
-        * it.
+        * Clear the array of invalid meta-data flags
         */
-       fd = open(MOUNTED, O_RDWR);
-       if (fd < 0) {
-               if (errno == EROFS) {
-                       read_only_root = 1;
-                       return;
-               }
-       } else
-               close(fd);
-       
-       if (!rwflag) {
-               printf("Warning!  %s is mounted.\n", device_name);
-               return;
+       if (ctx->invalid_inode_bitmap_flag) {
+               ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
+               ctx->invalid_inode_bitmap_flag = 0;
        }
-
-       printf ("%s is mounted.  ", device_name);
-       if (isatty (0) && isatty (1))
-               cont = ask_yn("Do you really want to continue", -1);
-       else
-               cont = 0;
-       if (!cont) {
-               printf ("check aborted.\n");
-               exit (0);
+       if (ctx->invalid_block_bitmap_flag) {
+               ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
+               ctx->invalid_block_bitmap_flag = 0;
        }
-       return;
-}
-
-static void sync_disks(NOARGS)
-{
-       sync();
-       sync();
-       sleep(1);
-       sync();
-}
-
-static void check_super_block(ext2_filsys fs)
-{
-       blk_t   first_block, last_block;
-       int     blocks_per_group = fs->super->s_blocks_per_group;
-       int     i;
-
-       first_block =  fs->super->s_first_data_block;
-       last_block = first_block + blocks_per_group;
-
-       for (i = 0; i < fs->group_desc_count; i++) {
-               if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
-                   (fs->group_desc[i].bg_block_bitmap >= last_block)) {
-                       printf("Block bitmap %ld for group %d not in group.\n",
-                              fs->group_desc[i].bg_block_bitmap, i);
-                       fatal_error(0);
-               }
-               if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
-                   (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
-                       printf("Inode bitmap %ld for group %d not in group.\n",
-                              fs->group_desc[i].bg_inode_bitmap, i);
-                       fatal_error(0);
-               }
-               if ((fs->group_desc[i].bg_inode_table < first_block) ||
-                   ((fs->group_desc[i].bg_inode_table +
-                     fs->inode_blocks_per_group - 1) >= last_block)) {
-                       printf("Inode table %ld for group %d not in group.\n",
-                              fs->group_desc[i].bg_inode_table, i);
-                       fatal_error(0);
-               }
-               first_block += fs->super->s_blocks_per_group;
-               last_block += fs->super->s_blocks_per_group;
+       if (ctx->invalid_inode_table_flag) {
+               ext2fs_free_mem(&ctx->invalid_inode_table_flag);
+               ctx->invalid_inode_table_flag = 0;
+       }
+       if (ctx->casefolded_dirs) {
+               ext2fs_u32_list_free(ctx->casefolded_dirs);
+               ctx->casefolded_dirs = 0;
        }
-       return;
+       if (ctx->inode_count) {
+               ext2fs_free_icount(ctx->inode_count);
+               ctx->inode_count = 0;
+       }
+
+       /* Clear statistic counters */
+       ctx->fs_directory_count = 0;
+       ctx->fs_regular_count = 0;
+       ctx->fs_blockdev_count = 0;
+       ctx->fs_chardev_count = 0;
+       ctx->fs_links_count = 0;
+       ctx->fs_symlinks_count = 0;
+       ctx->fs_fast_symlinks_count = 0;
+       ctx->fs_fifo_count = 0;
+       ctx->fs_total_count = 0;
+       ctx->fs_badblocks_count = 0;
+       ctx->fs_sockets_count = 0;
+       ctx->fs_ind_count = 0;
+       ctx->fs_dind_count = 0;
+       ctx->fs_tind_count = 0;
+       ctx->fs_fragmented = 0;
+       ctx->fs_fragmented_dir = 0;
+       ctx->large_files = 0;
+       ctx->large_dirs = 0;
+
+       for (i=0; i < MAX_EXTENT_DEPTH_COUNT; i++)
+               ctx->extent_depth_count[i] = 0;
+
+       /* Reset the superblock to the user's requested value */
+       ctx->superblock = ctx->use_superblock;
+
+       return 0;
 }
 
-/*
- * This routine checks to see if a filesystem can be skipped; if so,
- * it will exit with E2FSCK_OK.  Under some conditions it will print a
- * message explaining why a check is being forced.
- */
-static void check_if_skip(ext2_filsys fs)
+void e2fsck_free_context(e2fsck_t ctx)
 {
-       const char *reason = NULL;
-       
-       if (force || bad_blocks_file || cflag)
-               return;
-       
-       if (fs->super->s_state & EXT2_ERROR_FS)
-               reason = "contains a file system with errors";
-       else if (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 +
-                            fs->super->s_checkinterval))
-               reason = "has gone too long without being checked";
-       if (reason) {
-               printf("%s %s, check forced.\n", device_name, reason);
+       if (!ctx)
                return;
-       }
-       if (fs->super->s_state & EXT2_VALID_FS) {
-               printf("%s is clean, no check.\n", device_name);
-               exit(FSCK_OK);
-       }
-}      
 
-static void PRS(int argc, char *argv[])
-{
-       int flush = 0;
-       char c;
-#ifdef MTRACE
-       extern void *mallwatch;
-#endif
-       char *oldpath, newpath[PATH_MAX];
+       e2fsck_reset_context(ctx);
+       if (ctx->blkid)
+               blkid_put_cache(ctx->blkid);
 
-       /* Update our PATH to include /sbin  */
-       strcpy(newpath, "PATH=/sbin:");
-       if ((oldpath = getenv("PATH")) != NULL)
-               strcat(newpath, oldpath);
-       putenv(newpath);
+       if (ctx->profile)
+               profile_release(ctx->profile);
 
-       setbuf(stdout, NULL);
-       setbuf(stderr, NULL);
-       initialize_ext2_error_table();
-       
-       if (argc && *argv)
-               program_name = *argv;
-       while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:")) != EOF)
-               switch (c) {
-               case 'p':
-               case 'a':
-                       preen = 1;
-                       yflag = nflag = 0;
-                       break;
-               case 'n':
-                       nflag = 1;
-                       preen = yflag = 0;
-                       break;
-               case 'y':
-                       yflag = 1;
-                       preen = nflag = 0;
-                       break;
-               case 't':
-                       tflag++;
-                       break;
-               case 'c':
-                       cflag++;
-                       break;
-               case 'r':
-                       /* What we do by default, anyway! */
-                       break;
-               case 'b':
-                       superblock = atoi(optarg);
-                       break;
-               case 'B':
-                       blocksize = atoi(optarg);
-                       break;
-               case 'I':
-                       inode_buffer_blocks = atoi(optarg);
-                       break;
-               case 'P':
-                       process_inode_size = atoi(optarg);
-                       break;
-               case 'L':
-                       replace_bad_blocks++;
-               case 'l':
-                       bad_blocks_file = malloc(strlen(optarg)+1);
-                       if (!bad_blocks_file)
-                               fatal_error("Couldn't malloc bad_blocks_file");
-                       strcpy(bad_blocks_file, optarg);
-                       break;
-               case 'd':
-                       debug = 1;
-                       break;
-               case 'f':
-                       force = 1;
-                       break;
-               case 'F':
-                       flush = 1;
-                       break;
-               case 'v':
-                       verbose = 1;
-                       break;
-               case 'V':
-                       show_version_only = 1;
-                       break;
-#ifdef MTRACE
-               case 'M':
-                       mallwatch = (void *) strtol(optarg, NULL, 0);
-                       break;
-#endif
-               default:
-                       usage ();
-               }
-       if (show_version_only)
-               return;
-       if (optind != argc - 1)
-               usage ();
-       if (nflag && !bad_blocks_file && !cflag)
-               rwflag = 0;
-       device_name = argv[optind];
-       if (flush) {
-               int     fd = open(device_name, O_RDONLY, 0);
+       if (ctx->filesystem_name)
+               ext2fs_free_mem(&ctx->filesystem_name);
 
-               if (fd < 0) {
-                       com_err("open", errno, "while opening %s for flushing",
-                               device_name);
-                       exit(FSCK_ERROR);
-               }
-               if (ioctl(fd, BLKFLSBUF, 0) < 0) {
-                       com_err("BLKFLSBUF", errno, "while trying to flush %s",
-                               device_name);
-                       exit(FSCK_ERROR);
-               }
-               close(fd);
-       }
-}
-                                       
-int main (int argc, char *argv[])
-{
-       errcode_t       retval = 0;
-       int             exit_value = FSCK_OK;
-       int             i;
-       ext2_filsys     fs;
-       
-#ifdef MTRACE
-       mtrace();
-#endif
-#ifdef MCHECK
-       mcheck(0);
-#endif
-       
-       init_resource_track(&global_rtrack);
+       if (ctx->device_name)
+               ext2fs_free_mem(&ctx->device_name);
 
-       PRS(argc, argv);
+       if (ctx->log_fn)
+               free(ctx->log_fn);
 
-       if (!preen)
-               fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
-                        E2FSPROGS_VERSION, E2FSPROGS_DATE,
-                        EXT2FS_VERSION, EXT2FS_DATE);
+       if (ctx->logf)
+               fclose(ctx->logf);
 
-       if (show_version_only)
-               exit(0);
-       
-       check_mount();
-       
-       if (!preen && !nflag && !yflag) {
-               if (!isatty (0) || !isatty (1))
-                       die ("need terminal for interactive repairs");
-       }
-       sync_disks();
-       if (superblock && blocksize) {
-               retval = ext2fs_open(device_name, rwflag ? EXT2_FLAG_RW : 0,
-                                    superblock, blocksize, unix_io_manager,
-                                    &fs);
-       } else if (superblock) {
-               for (i=0; possible_block_sizes[i]; i++) {
-                       retval = ext2fs_open(device_name,
-                                            rwflag ? EXT2_FLAG_RW : 0,
-                                            superblock,
-                                            possible_block_sizes[i],
-                                            unix_io_manager, &fs);
-                       if (!retval)
-                               break;
-               }
-       } else 
-               retval = ext2fs_open(device_name, rwflag ? EXT2_FLAG_RW : 0,
-                                    0, 0, unix_io_manager, &fs);
-       if (retval) {
-               com_err(program_name, retval, "while trying to open %s",
-                       device_name);
-               printf("Couldn't find valid filesystem superblock.\n");
-               fatal_error(0);
+       if (ctx->problem_log_fn)
+               free(ctx->problem_log_fn);
+
+       if (ctx->problem_logf) {
+               fputs("</problem_log>\n", ctx->problem_logf);
+               fclose(ctx->problem_logf);
        }
-       /*
-        * If the user specified a specific superblock, presumably the
-        * master superblock has been trashed.  So we mark the
-        * superblock as dirty, so it can be written out.
-        */
-       if (superblock && rwflag)
-               ext2fs_mark_super_dirty(fs);
+       ext2fs_free_mem(&ctx);
+}
 
-       ehandler_init(fs->io);
+/*
+ * This function runs through the e2fsck passes and calls them all,
+ * returning restart, abort, or cancel as necessary...
+ */
+typedef void (*pass_t)(e2fsck_t ctx);
 
-       check_super_block(fs);
-       check_if_skip(fs);
-       if (bad_blocks_file)
-               read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
-       else if (cflag)
-               test_disk(fs);
+static pass_t e2fsck_passes[] = {
+       e2fsck_pass1, e2fsck_pass1e, e2fsck_pass2, e2fsck_pass3,
+       e2fsck_pass4, e2fsck_pass5, 0 };
 
-       /*
-        * Mark the system as valid, 'til proven otherwise
-        */
-       ext2fs_mark_valid(fs);
-       
-       pass1(fs);
-       pass2(fs);
-       pass3(fs);
-       pass4(fs);
-       pass5(fs);
+int e2fsck_run(e2fsck_t ctx)
+{
+       int     i;
+       pass_t  e2fsck_pass;
 
-#ifdef MTRACE
-       mtrace_print("Cleanup");
-#endif
-       if (ext2fs_test_changed(fs)) {
-               exit_value = FSCK_NONDESTRUCT;
-               if (!preen)
-                       printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
-                              device_name);
-               if (root_filesystem && !read_only_root) {
-                       printf("%s: ***** REBOOT LINUX *****\n", device_name);
-                       exit_value = FSCK_REBOOT;
-               }
+#ifdef HAVE_SETJMP_H
+       if (setjmp(ctx->abort_loc)) {
+               ctx->flags &= ~E2F_FLAG_SETJMP_OK;
+               return (ctx->flags & E2F_FLAG_RUN_RETURN);
        }
-       if (!ext2fs_test_valid(fs))
-               exit_value = FSCK_UNCORRECTED;
-       if (rwflag) {
-               if (ext2fs_test_valid(fs))
-                       fs->super->s_state = EXT2_VALID_FS;
-               else
-                       fs->super->s_state &= ~EXT2_VALID_FS;
-               fs->super->s_mnt_count = 0;
-               fs->super->s_lastcheck = time(NULL);
-               ext2fs_mark_super_dirty(fs);
+       ctx->flags |= E2F_FLAG_SETJMP_OK;
+#endif
+
+       for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
+               if (ctx->flags & E2F_FLAG_RUN_RETURN)
+                       break;
+               if (e2fsck_mmp_update(ctx->fs))
+                       fatal_error(ctx, 0);
+               e2fsck_pass(ctx);
+               if (ctx->progress)
+                       (void) (ctx->progress)(ctx, 0, 0, 0);
        }
-       show_stats(fs);
+       ctx->flags &= ~E2F_FLAG_SETJMP_OK;
 
-       write_bitmaps(fs);
-       ext2fs_close(fs);
-       sync_disks();
-       
-       if (tflag)
-               print_resource_track(&global_rtrack);
-       
-       return exit_value;
+       if (ctx->flags & E2F_FLAG_RUN_RETURN)
+               return (ctx->flags & E2F_FLAG_RUN_RETURN);
+       return 0;
 }