diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog index 9fceacde..efa67c35 100644 --- a/e2fsck/ChangeLog +++ b/e2fsck/ChangeLog @@ -1,3 +1,43 @@ +Fri Oct 3 13:40:03 1997 Theodore Ts'o + + * pass*.c, super.c: Massive changes to avoid using printf and + com_err routines. All diagnostic messages are now routed + through the fix_problem interface. + +Sat Sep 6 17:13:28 1997 Theodore Ts'o + + * pass2.c (check_dir_block): Check for duplicate '.' and '..' + entries. + + * problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and + PR_2_DUP_DOT_DOT. + +Tue Sep 2 09:04:51 1997 Theodore Ts'o + + * problem.c: Added new problem codes for some of the + superblock corruption checks, and for the pass header + messages. ("Pass 1: xxxxx") + + * util.c (print_resource_track): Now takes a description + argument. + +Mon Aug 25 10:23:13 1997 Theodore Ts'o + + * super.c, unix.c, e2fsck.c: New files to separate out the + operating-specific operations out from e2fsck.c. + e2fsck.c now contains the global e2fsck context management + routines, and super.c contains the "pass 0" initial + validation of the superblock and global block group + descriptors. + + * pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate + (nearly) all global variables and moved them to the e2fsck + context structure. + + * problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT, + PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, + PR_0_BLOCKS_PER_GROUP, PR_0_FIRST_DATA_BLOCK + Thu Aug 14 10:55:21 1997 Theodore Ts'o * message.c: Add compression for the word "Illegal" diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in index 24a9efb6..e16c12f3 100644 --- a/e2fsck/Makefile.in +++ b/e2fsck/Makefile.in @@ -52,17 +52,19 @@ PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) $(PROFILED_LIBUUI # #MCHECK= -DMCHECK -OBJS= e2fsck.o pass1.o pass1b.o pass2.o pass3.o pass4.o pass5.o \ - swapfs.o badblocks.o util.o dirinfo.o ehandler.o problem.o message.o \ - $(MTRACE_OBJ) +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 \ + problem.o message.o $(MTRACE_OBJ) -PROFILED_OBJS= profiled/e2fsck.o profiled/pass1.o profiled/pass1b.o \ +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 SRCS= $(srcdir)/e2fsck.c \ + $(srcdir)/super.c \ $(srcdir)/pass1.c \ $(srcdir)/pass1b.c \ $(srcdir)/pass2.c \ @@ -71,6 +73,7 @@ SRCS= $(srcdir)/e2fsck.c \ $(srcdir)/pass5.c \ $(srcdir)/badblocks.c \ $(srcdir)/util.c \ + $(srcdir)/unix.c \ $(srcdir)/dirinfo.c \ $(srcdir)/ehandler.c \ $(srcdir)/problem.c \ diff --git a/e2fsck/badblocks.c b/e2fsck/badblocks.c index e6ab4bcc..a9addf75 100644 --- a/e2fsck/badblocks.c +++ b/e2fsck/badblocks.c @@ -23,15 +23,16 @@ static void invalid_block(ext2_filsys fs, blk_t blk) return; } -void read_bad_blocks_file(ext2_filsys fs, const char *bad_blocks_file, +void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file, int replace_bad_blocks) { + ext2_filsys fs = ctx->fs; errcode_t retval; badblocks_list bb_list = 0; FILE *f; char buf[1024]; - read_bitmaps(fs); + read_bitmaps(ctx); /* * Make sure the bad block inode is sane. If there are any @@ -72,8 +73,8 @@ void read_bad_blocks_file(ext2_filsys fs, const char *bad_blocks_file, } } else { sprintf(buf, "badblocks -b %d %s%s %d", fs->blocksize, - preen ? "" : "-s ", fs->device_name, - fs->super->s_blocks_count); + (ctx->options & E2F_OPT_PREEN) ? "" : "-s ", + fs->device_name, fs->super->s_blocks_count); f = popen(buf, "r"); if (!f) { com_err("read_bad_blocks_file", errno, @@ -106,9 +107,9 @@ void read_bad_blocks_file(ext2_filsys fs, const char *bad_blocks_file, return; } -void test_disk(ext2_filsys fs) +void test_disk(e2fsck_t ctx) { - read_bad_blocks_file(fs, 0, 1); + read_bad_blocks_file(ctx, 0, 1); } static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt, diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c index 57390eee..592541b0 100644 --- a/e2fsck/e2fsck.c +++ b/e2fsck/e2fsck.c @@ -9,841 +9,117 @@ * %End-Header% */ -/* 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 :-). - */ - -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#include -#include -#include -#include -#include -#ifdef HAVE_GETOPT_H -#include -#endif -#include -#ifdef HAVE_ERRNO_H #include -#endif -#ifdef HAVE_MNTENT_H -#include -#endif -#include -#include #include "et/com_err.h" -#include "uuid/uuid.h" + #include "e2fsck.h" #include "problem.h" -#include "../version.h" -extern int isatty(int); - -const char * program_name = "e2fsck"; -const char * device_name = NULL; -const char * filesystem_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 swapfs = 0; -int normalize_swapfs = 0; -int inode_buffer_blocks = 0; -blk_t use_superblock; -blk_t superblock; -int blocksize = 0; -int verbose = 0; -int list = 0; -int debug = 0; -int force = 0; -int invalid_bitmaps = 0; -static int show_version_only = 0; - -static int replace_bad_blocks = 0; -static char *bad_blocks_file = 0; - -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; - -int *invalid_inode_bitmap; -int *invalid_block_bitmap; -int *invalid_inode_table; -int restart_e2fsck = 0; - -static void usage(NOARGS) +/* + * This function allocates an e2fsck context + */ +errcode_t e2fsck_allocate_context(e2fsck_t *ret) { - fprintf(stderr, - "Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n" - "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" - "\t\t[-l|-L bad_blocks_file] device\n", program_name); - exit(FSCK_USAGE); -} + e2fsck_t context; -static void show_stats(ext2_filsys fs) -{ - int inodes, inodes_used, blocks, blocks_used; - int dir_links; - int num_files, num_links; - int frag_percent; + context = malloc(sizeof(struct e2fsck_struct)); + if (!context) + return ENOMEM; - 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); + memset(context, 0, sizeof(struct e2fsck_struct)); - frag_percent = (10000 * fs_fragmented) / inodes_used; - frag_percent = (frag_percent + 5) / 10; - - if (!verbose) { - printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n", - device_name, inodes_used, inodes, - frag_percent / 10, frag_percent % 10, - blocks_used, blocks); - return; - } - printf ("\n%8d inode%s used (%d%%)\n", inodes_used, - (inodes_used != 1) ? "s" : "", - 100 * inodes_used / inodes); - printf ("%8d non-contiguous inodes (%0d.%d%%)\n", - fs_fragmented, frag_percent / 10, frag_percent % 10); - printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n", - fs_ind_count, fs_dind_count, fs_tind_count); - printf ("%8d block%s used (%d%%)\n" - "%8d bad block%s\n", blocks_used, - (blocks_used != 1) ? "s" : "", - 100 * blocks_used / blocks, fs_badblocks_count, - fs_badblocks_count != 1 ? "s" : ""); - printf ("\n%8d regular file%s\n" - "%8d director%s\n" - "%8d character device file%s\n" - "%8d block device file%s\n" - "%8d fifo%s\n" - "%8d link%s\n" - "%8d symbolic link%s (%d fast symbolic link%s)\n" - "%8d socket%s\n" - "--------\n" - "%8d 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" : ""); -} + context->process_inode_size = 256; -static void check_mount(NOARGS) -{ - errcode_t retval; - int mount_flags, cont, fd; - - retval = ext2fs_check_if_mounted(filesystem_name, &mount_flags); - if (retval) { - com_err("ext2fs_check_if_mount", retval, - "while determining whether %s is mounted.", - filesystem_name); - return; - } - if (!(mount_flags & EXT2_MF_MOUNTED)) - return; - -#if (defined(__linux__) && defined(HAVE_MNTENT_H)) - /* - * If the root is mounted read-only, then /etc/mtab is - * probably not correct; so we won't issue a warning based on - * it. - */ - fd = open(MOUNTED, O_RDWR); - if (fd < 0) { - if (errno == EROFS) - return; - } else - close(fd); -#endif - - if (!rwflag) { - printf("Warning! %s is mounted.\n", device_name); - return; - } - - printf("%s is mounted.\n\n", device_name); - printf("\a\a\a\aWARNING!!! Running e2fsck on a mounted filesystem " - "may cause\nSEVERE filesystem damage.\a\a\a\n\n"); - 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); - } - return; -} - -static void sync_disks(NOARGS) -{ - sync(); - sync(); - sleep(1); - sync(); -} - -static blk_t get_backup_sb(ext2_filsys fs) -{ - if (!fs || !fs->super) - return 8193; - return fs->super->s_blocks_per_group + 1; -} - -#define MIN_CHECK 1 -#define MAX_CHECK 2 - -static const char *corrupt_msg = -"\nThe superblock could not be read or does not describe a correct ext2\n" -"filesystem. If the device is valid and it really contains an ext2\n" -"filesystem (and not swap or ufs or something else), then the superblock\n" -"is corrupt, and you might try running e2fsck with an alternate superblock:\n" -" e2fsck -b %d \n\n"; - -static void check_super_value(ext2_filsys fs, const char *descr, - unsigned long value, int flags, - unsigned long min, unsigned long max) -{ - if (((flags & MIN_CHECK) && (value < min)) || - ((flags & MAX_CHECK) && (value > max))) { - printf("Corruption found in superblock. (%s = %lu).\n", - descr, value); - printf(corrupt_msg, get_backup_sb(fs)); - fatal_error(0); - } -} - -static void relocate_hint(ext2_filsys fs) -{ - static hint_issued = 0; - - /* - * Only issue the hint once, and only if we're using the - * primary superblocks. - */ - if (hint_issued || superblock) - return; - - printf("Note: if there is several inode or block bitmap blocks\n" - "which require relocation, or one part of the inode table\n" - "which must be moved, you may wish to try running e2fsck\n" - "with the '-b %d' option first. The problem may lie only\n" - "with the primary block group descriptor, and the backup\n" - "block group descriptor may be OK.\n\n", get_backup_sb(fs)); - hint_issued = 1; -} - - -static void check_super_block(ext2_filsys fs) -{ - blk_t first_block, last_block; - struct ext2fs_sb *s = (struct ext2fs_sb *) fs->super; - blk_t blocks_per_group = fs->super->s_blocks_per_group; - int i; - blk_t should_be; - errcode_t retval; - struct problem_context pctx; - - clear_problem_context(&pctx); - - /* - * Verify the super block constants... - */ - check_super_value(fs, "inodes_count", s->s_inodes_count, - MIN_CHECK, 1, 0); - check_super_value(fs, "blocks_count", s->s_blocks_count, - MIN_CHECK, 1, 0); - check_super_value(fs, "first_data_block", s->s_first_data_block, - MAX_CHECK, 0, s->s_blocks_count); - check_super_value(fs, "log_frag_size", s->s_log_frag_size, - MAX_CHECK, 0, 2); - check_super_value(fs, "log_block_size", s->s_log_block_size, - MIN_CHECK | MAX_CHECK, s->s_log_frag_size, - 2); - check_super_value(fs, "frags_per_group", s->s_frags_per_group, - MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s)); - check_super_value(fs, "blocks_per_group", s->s_blocks_per_group, - MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s)); - check_super_value(fs, "inodes_per_group", s->s_inodes_per_group, - MIN_CHECK, 1, 0); - check_super_value(fs, "r_blocks_count", s->s_r_blocks_count, - MAX_CHECK, 0, s->s_blocks_count); - - retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s), - &should_be); - if (retval) { - com_err("ext2fs_get_device_size", retval, - "while trying to check physical size of filesystem"); - fatal_error(0); - } - if (should_be < s->s_blocks_count) { - printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count); - printf("The physical size of the device is %d blocks\n", - should_be); - printf("Either the superblock or the partition table is likely to be corrupt!\n"); - preenhalt(fs); - if (ask("Abort", 1)) - fatal_error(0); - } - - if (s->s_log_block_size != s->s_log_frag_size) { - printf("Superblock block_size = %d, fragsize = %d.\n", - EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s)); - printf("This version of e2fsck does not support fragment " - "sizes different\n" - "from the block size.\n"); - fatal_error(0); - } - - should_be = s->s_frags_per_group / - (s->s_log_block_size - s->s_log_frag_size + 1); - if (s->s_blocks_per_group != should_be) { - printf("Superblock blocks_per_group = %u, should " - "have been %u\n", s->s_blocks_per_group, - should_be); - printf(corrupt_msg, get_backup_sb(fs)); - fatal_error(0); - } - - should_be = (s->s_log_block_size == 0) ? 1 : 0; - if (s->s_first_data_block != should_be) { - printf("Superblock first_data_block = %u, should " - "have been %u\n", s->s_first_data_block, - should_be); - printf(corrupt_msg, get_backup_sb(fs)); - fatal_error(0); - } - - /* - * Verify the group descriptors.... - */ - first_block = fs->super->s_first_data_block; - last_block = first_block + blocks_per_group; - - for (i = 0; i < fs->group_desc_count; i++) { - pctx.group = i; - - if (i == fs->group_desc_count - 1) - last_block = fs->super->s_blocks_count; - if ((fs->group_desc[i].bg_block_bitmap < first_block) || - (fs->group_desc[i].bg_block_bitmap >= last_block)) { - relocate_hint(fs); - pctx.blk = fs->group_desc[i].bg_block_bitmap; - if (fix_problem(fs, PR_0_BB_NOT_GROUP, &pctx)) { - fs->group_desc[i].bg_block_bitmap = 0; - invalid_block_bitmap[i]++; - invalid_bitmaps++; - } - } - if ((fs->group_desc[i].bg_inode_bitmap < first_block) || - (fs->group_desc[i].bg_inode_bitmap >= last_block)) { - relocate_hint(fs); - pctx.blk = fs->group_desc[i].bg_inode_bitmap; - if (fix_problem(fs, PR_0_IB_NOT_GROUP, &pctx)) { - fs->group_desc[i].bg_inode_bitmap = 0; - invalid_inode_bitmap[i]++; - invalid_bitmaps++; - } - } - 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)) { - relocate_hint(fs); - pctx.blk = fs->group_desc[i].bg_inode_table; - if (fix_problem(fs, PR_0_ITABLE_NOT_GROUP, &pctx)) { - fs->group_desc[i].bg_inode_table = 0; - invalid_inode_table[i]++; - invalid_bitmaps++; - } - } - first_block += fs->super->s_blocks_per_group; - last_block += fs->super->s_blocks_per_group; - } - /* - * If we have invalid bitmaps, set the error state of the - * filesystem. - */ - if (invalid_bitmaps && rwflag) { - fs->super->s_state &= ~EXT2_VALID_FS; - ext2fs_mark_super_dirty(fs); - } - - /* - * If the UUID field isn't assigned, assign it. - */ - if (rwflag && uuid_is_null(s->s_uuid)) { - if (preen) - printf("%s: Adding UUID to filesystem.\n", - device_name); - else - printf("Filesystem did not have a UUID; " - "generating one.\n\n"); - uuid_generate(s->s_uuid); - ext2fs_mark_super_dirty(fs); - } - return; + *ret = context; + 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. + * This function resets an e2fsck context; it is called when e2fsck + * needs to be restarted. */ -static void check_if_skip(ext2_filsys fs) +errcode_t e2fsck_reset_context(e2fsck_t ctx) { - const char *reason = NULL; - - if (force || bad_blocks_file || cflag || swapfs) - 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"; - else if ((fs->super->s_state & EXT2_VALID_FS) == 0) - reason = "was not cleanly unmounted"; - if (reason) { - printf("%s %s, check forced.\n", device_name, reason); - return; + 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->block_found_map) { + ext2fs_free_block_bitmap(ctx->block_found_map); + ctx->block_found_map = 0; + } + if (ctx->inode_link_info) { + ext2fs_free_icount(ctx->inode_link_info); + ctx->inode_link_info = 0; + } + if (ctx->fs->dblist) { + ext2fs_free_dblist(ctx->fs->dblist); + ctx->fs->dblist = 0; + } + free_dir_info(ctx->fs); + if (ctx->block_dup_map) { + ext2fs_free_block_bitmap(ctx->block_dup_map); + ctx->block_dup_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; } - printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name, - fs->super->s_inodes_count - fs->super->s_free_inodes_count, - fs->super->s_inodes_count, - fs->super->s_blocks_count - fs->super->s_free_blocks_count, - fs->super->s_blocks_count); - ext2fs_close(fs); - exit(FSCK_OK); -} -#define PATH_SET "PATH=/sbin" + /* + * Clear the array of invalid meta-data flags + */ + if (ctx->invalid_inode_bitmap_flag) { + free(ctx->invalid_inode_bitmap_flag); + ctx->invalid_inode_bitmap_flag = 0; + } + if (ctx->invalid_block_bitmap_flag) { + free(ctx->invalid_block_bitmap_flag); + ctx->invalid_block_bitmap_flag = 0; + } + if (ctx->invalid_inode_table_flag) { + free(ctx->invalid_inode_table_flag); + ctx->invalid_inode_table_flag = 0; + } -static void PRS(int argc, char *argv[]) -{ - int flush = 0; - char c; -#ifdef MTRACE - extern void *mallwatch; -#endif - char *oldpath = getenv("PATH"); + /* 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; - /* Update our PATH to include /sbin */ - if (oldpath) { - char *newpath; - - newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath)); - if (!newpath) - fatal_error("Couldn't malloc() newpath"); - strcpy (newpath, PATH_SET); - strcat (newpath, ":"); - strcat (newpath, oldpath); - putenv (newpath); - } else - putenv (PATH_SET); - - setbuf(stdout, NULL); - setbuf(stderr, NULL); - initialize_ext2_error_table(); + /* Reset the superblock to the user's requested value */ + ctx->superblock = ctx->use_superblock; - if (argc && *argv) - program_name = *argv; - while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != 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': - use_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': -#ifdef BLKFLSBUF - flush = 1; -#else - fatal_error ("-F not supported"); -#endif - 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 - case 'N': - device_name = optarg; - break; - case 's': - normalize_swapfs = 1; - case 'S': - swapfs = 1; - break; - default: - usage (); - } - if (show_version_only) - return; - if (optind != argc - 1) - usage (); - if (nflag && !bad_blocks_file && !cflag && !swapfs) - rwflag = 0; - filesystem_name = argv[optind]; - if (device_name == 0) - device_name = filesystem_name; - if (flush) { -#ifdef BLKFLSBUF - int fd = open(filesystem_name, O_RDONLY, 0); - - if (fd < 0) { - com_err("open", errno, "while opening %s for flushing", - filesystem_name); - exit(FSCK_ERROR); - } - if (ioctl(fd, BLKFLSBUF, 0) < 0) { - com_err("BLKFLSBUF", errno, "while trying to flush %s", - filesystem_name); - exit(FSCK_ERROR); - } - close(fd); -#else - fatal_error ("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); - } - } + return 0; } -static const char *my_ver_string = E2FSPROGS_VERSION; -static const char *my_ver_date = E2FSPROGS_DATE; - -int main (int argc, char *argv[]) +void e2fsck_free_context(e2fsck_t ctx) { - errcode_t retval = 0; - int exit_value = FSCK_OK; - int i; - ext2_filsys fs = 0; - io_manager io_ptr; - struct ext2fs_sb *s; - const char *lib_ver_date; - int my_ver, lib_ver; + if (!ctx) + return; -#ifdef MTRACE - mtrace(); -#endif -#ifdef MCHECK - mcheck(0); -#endif - my_ver = ext2fs_parse_version_string(my_ver_string); - lib_ver = ext2fs_get_library_version(0, &lib_ver_date); - if (my_ver > lib_ver) { - fprintf( stderr, "Error: ext2fs library version " - "out of date!\n"); - show_version_only++; - } + e2fsck_reset_context(ctx); - init_resource_track(&global_rtrack); - - PRS(argc, argv); - - if (!preen || show_version_only) - fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n", - my_ver_string, my_ver_date, EXT2FS_VERSION, - EXT2FS_DATE); - - if (show_version_only) { - fprintf(stderr, "\tUsing %s, %s\n", - error_message(EXT2_ET_BASE), lib_ver_date); - exit(0); - } - - check_mount(); - - if (!preen && !nflag && !yflag) { - if (!isatty (0) || !isatty (1)) - die ("need terminal for interactive repairs"); - } - superblock = use_superblock; -restart: -#if 1 - io_ptr = unix_io_manager; -#else - io_ptr = test_io_manager; - test_io_backing_manager = unix_io_manager; -#endif - sync_disks(); - if (superblock && blocksize) { - retval = ext2fs_open(filesystem_name, - rwflag ? EXT2_FLAG_RW : 0, - superblock, blocksize, io_ptr, &fs); - } else if (superblock) { - for (i=0; possible_block_sizes[i]; i++) { - retval = ext2fs_open(filesystem_name, - rwflag ? EXT2_FLAG_RW : 0, - superblock, - possible_block_sizes[i], - io_ptr, &fs); - if (!retval) - break; - } - } else - retval = ext2fs_open(filesystem_name, - rwflag ? EXT2_FLAG_RW : 0, - 0, 0, io_ptr, &fs); - if (!superblock && !preen && - ((retval == EXT2_ET_BAD_MAGIC) || - ((retval == 0) && ext2fs_check_desc(fs)))) { - if (!fs || (fs->group_desc_count > 1)) { - printf("%s trying backup blocks...\n", - retval ? "Couldn't find ext2 superblock," : - "Group descriptors look bad..."); - superblock = get_backup_sb(fs); - if (fs) - ext2fs_close(fs); - goto restart; - } - } - if (retval) { - com_err(program_name, retval, "while trying to open %s", - filesystem_name); - if (retval == EXT2_ET_REV_TOO_HIGH) - printf ("Get a newer version of e2fsck!\n"); - else if (retval == EXT2_ET_SHORT_READ) - printf ("Could this be a zero-length partition?\n"); - else if ((retval == EPERM) || (retval == EACCES)) - printf("You must have %s access to the " - "filesystem or be root\n", - rwflag ? "r/w" : "r/o"); - else if (retval == ENXIO) - printf("Possibly non-existent or swap device?\n"); - else - printf(corrupt_msg, get_backup_sb(fs)); - fatal_error(0); - } -#ifdef EXT2_CURRENT_REV - if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) { - com_err(program_name, EXT2_ET_REV_TOO_HIGH, - "while trying to open %s", - filesystem_name); - goto get_newer; - } -#endif - /* - * 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(program_name, EXT2_ET_UNSUPP_FEATURE, - "(%s)", filesystem_name); - get_newer: - printf ("Get a newer version of e2fsck!\n"); - fatal_error(0); - } - if (s->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) { - com_err(program_name, EXT2_ET_RO_UNSUPP_FEATURE, - "(%s)", filesystem_name); - goto get_newer; - } - - /* - * 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); - - /* - * Don't overwrite the backup superblock and block - * descriptors, until we're sure the filesystem is OK.... - */ - fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; - - ehandler_init(fs->io); - - invalid_inode_bitmap = allocate_memory(sizeof(int) * - fs->group_desc_count, - "invalid_inode_bitmap"); - invalid_block_bitmap = allocate_memory(sizeof(int) * - fs->group_desc_count, - "invalid_block_bitmap"); - invalid_inode_table = allocate_memory(sizeof(int) * - fs->group_desc_count, - "invalid_inode_table"); - - 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); - - if (normalize_swapfs) { - if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == - ext2fs_native_flag()) { - fprintf(stderr, "%s: Filesystem byte order " - "already normalized.\n", device_name); - fatal_error(0); - } - } - if (swapfs) - swap_filesys(fs); - - /* - * Mark the system as valid, 'til proven otherwise - */ - ext2fs_mark_valid(fs); - - retval = ext2fs_read_bb_inode(fs, &fs->badblocks); - if (retval) { - com_err(program_name, retval, - "while reading bad blocks inode"); - preenhalt(fs); - printf("This doesn't bode well, but we'll try to go on...\n"); - } - - pass1(fs); - free(invalid_inode_bitmap); - free(invalid_block_bitmap); - free(invalid_inode_table); - if (restart_e2fsck) { - ext2fs_close(fs); - printf("Restarting e2fsck from the beginning...\n"); - restart_e2fsck = 0; - superblock = use_superblock; - goto restart; - } - pass2(fs); - pass3(fs); - pass4(fs); - pass5(fs); - -#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; - } - } - if (ext2fs_test_valid(fs)) - fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; - else - exit_value = FSCK_UNCORRECTED; - if (rwflag) { - if (ext2fs_test_valid(fs)) { - if (!(fs->super->s_state & EXT2_VALID_FS)) - exit_value = FSCK_NONDESTRUCT; - 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); - } - show_stats(fs); - - write_bitmaps(fs); - ext2fs_close(fs); - sync_disks(); - - if (tflag) - print_resource_track(&global_rtrack); - - return exit_value; + free(ctx); } diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index c6dbd57d..27d703a0 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -44,12 +44,6 @@ */ #define E2FSCK_CURRENT_REV 1 -/* - * Inode count arrays - */ -extern ext2_icount_t inode_count; -extern ext2_icount_t inode_link_info; - /* * The directory information structure; stores directory information * collected in earlier passes, to avoid disk i/o in fetching the @@ -73,85 +67,110 @@ struct resource_track { }; /* - * Variables + * E2fsck options */ -extern const char * program_name; -extern const char * device_name; - -extern ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */ -extern ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */ -extern ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */ -extern ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */ - -extern ext2fs_block_bitmap block_found_map; /* Blocks which are in use */ -extern ext2fs_block_bitmap block_dup_map; /* Blocks which are used by more than once */ -extern ext2fs_block_bitmap block_illegal_map; /* Meta-data blocks */ - -extern const char *fix_msg[2]; /* Fixed or ignored! */ -extern const char *clear_msg[2]; /* Cleared or ignored! */ - -extern int *invalid_inode_bitmap; -extern int *invalid_block_bitmap; -extern int *invalid_inode_table; -extern int restart_e2fsck; - -/* Command line options */ -extern int nflag; -extern int yflag; -extern int tflag; -extern int preen; -extern int verbose; -extern int list; -extern int debug; -extern int force; - -extern int rwflag; - -extern int inode_buffer_blocks; -extern int process_inode_size; -extern int directory_blocks; - -extern int no_bad_inode; -extern int no_lpf; -extern int lpf_corrupted; - -/* Files counts */ -extern int fs_directory_count; -extern int fs_regular_count; -extern int fs_blockdev_count; -extern int fs_chardev_count; -extern int fs_links_count; -extern int fs_symlinks_count; -extern int fs_fast_symlinks_count; -extern int fs_fifo_count; -extern int fs_total_count; -extern int fs_badblocks_count; -extern int fs_sockets_count; -extern int fs_ind_count; -extern int fs_dind_count; -extern int fs_tind_count; -extern int fs_fragmented; - -extern struct resource_track global_rtrack; - -extern int invalid_bitmaps; +#define E2F_OPT_READONLY 0x0001 +#define E2F_OPT_PREEN 0x0002 +#define E2F_OPT_YES 0x0004 +#define E2F_OPT_NO 0x0008 +#define E2F_OPT_TIME 0x0010 +#define E2F_OPT_TIME2 0x0020 +#define E2F_OPT_CHECKBLOCKS 0x0040 +#define E2F_OPT_DEBUG 0x0080 /* - * For pass1_check_directory and pass1_get_blocks + * This is the global e2fsck structure. */ -extern ino_t stashed_ino; -extern struct ext2_inode *stashed_inode; +struct e2fsck_struct { + ext2_filsys fs; + const char *program_name; + const char *filesystem_name; + const char *device_name; + int options; + blk_t use_superblock; /* sb requested by user */ + blk_t superblock; /* sb used to open fs */ + + ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */ + ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */ + ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */ + ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */ + + ext2fs_block_bitmap block_found_map; /* Blocks which are in use */ + ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */ + ext2fs_block_bitmap block_illegal_map; /* Meta-data blocks */ + + /* + * Inode count arrays + */ + ext2_icount_t inode_count; + ext2_icount_t inode_link_info; + + /* + * Array of flags indicating whether an inode bitmap, block + * bitmap, or inode table is invalid + */ + int *invalid_inode_bitmap_flag; + int *invalid_block_bitmap_flag; + int *invalid_inode_table_flag; + int invalid_bitmaps; /* There are invalid bitmaps/itable */ + + /* + * For pass1_check_directory and pass1_get_blocks + */ + ino_t stashed_ino; + struct ext2_inode *stashed_inode; + + /* + * Tuning parameters + */ + int process_inode_size; + int inode_buffer_blocks; + + /* + * For timing purposes + */ + struct resource_track global_rtrack; + + /* File counts */ + int fs_directory_count; + int fs_regular_count; + int fs_blockdev_count; + int fs_chardev_count; + int fs_links_count; + int fs_symlinks_count; + int fs_fast_symlinks_count; + int fs_fifo_count; + int fs_total_count; + int fs_badblocks_count; + int fs_sockets_count; + int fs_ind_count; + int fs_dind_count; + int fs_tind_count; + int fs_fragmented; +}; + +typedef struct e2fsck_struct *e2fsck_t; + +/* + * Variables + */ +extern int restart_e2fsck; /* * Procedure declarations */ -extern void pass1(ext2_filsys fs); -extern void pass1_dupblocks(ext2_filsys fs, char *block_buf); -extern void pass2(ext2_filsys fs); -extern void pass3(ext2_filsys fs); -extern void pass4(ext2_filsys fs); -extern void pass5(ext2_filsys fs); +extern void pass1(e2fsck_t ctx); +extern void pass1_dupblocks(e2fsck_t ctx, char *block_buf); +extern void pass2(e2fsck_t ctx); +extern void pass3(e2fsck_t ctx); +extern void pass4(e2fsck_t ctx); +extern void pass5(e2fsck_t ctx); + +/* e2fsck.c */ +errcode_t e2fsck_allocate_context(e2fsck_t *ret); +errcode_t e2fsck_reset_context(e2fsck_t ctx); +void e2fsck_free_context(e2fsck_t ctx); /* pass1.c */ extern errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino); @@ -163,9 +182,9 @@ extern errcode_t pass1_write_inode(ext2_filsys fs, ino_t ino, extern int e2fsck_pass1_check_device_inode(struct ext2_inode *inode); /* badblock.c */ -extern void read_bad_blocks_file(ext2_filsys fs, const char *bad_blocks_file, +extern void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file, int replace_bad_blocks); -extern void test_disk(ext2_filsys fs); +extern void test_disk(e2fsck_t ctx); /* dirinfo.c */ extern void add_dir_info(ext2_filsys fs, ino_t ino, ino_t parent); @@ -178,18 +197,22 @@ extern struct dir_info *dir_info_iter(int *control); extern const char *ehandler_operation(const char *op); extern void ehandler_init(io_channel channel); +/* super.c */ +void check_super_block(e2fsck_t ctx); + /* swapfs.c */ -void swap_filesys(ext2_filsys fs); +void swap_filesys(e2fsck_t ctx); /* util.c */ extern void *allocate_memory(int size, const char *description); -extern int ask(const char * string, int def); +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(ext2_filsys fs); -extern void write_bitmaps(ext2_filsys fs); -extern void preenhalt(ext2_filsys fs); -extern void print_resource_track(struct resource_track *track); +extern void read_bitmaps(e2fsck_t ctx); +extern void write_bitmaps(e2fsck_t ctx); +extern void preenhalt(e2fsck_t ctx); +extern void print_resource_track(const char *desc, + struct resource_track *track); extern void init_resource_track(struct resource_track *track); extern int inode_has_valid_blocks(struct ext2_inode *inode); extern void e2fsck_read_inode(ext2_filsys fs, unsigned long ino, @@ -199,10 +222,11 @@ extern void e2fsck_write_inode(ext2_filsys fs, unsigned long ino, #ifdef MTRACE extern void mtrace_print(char *mesg); #endif +extern blk_t get_backup_sb(ext2_filsys fs); #define die(str) fatal_error(str) /* * pass3.c */ -extern int reconnect_file(ext2_filsys fs, ino_t inode); +extern int reconnect_file(e2fsck_t ctx, ino_t inode); diff --git a/e2fsck/ehandler.c b/e2fsck/ehandler.c index 131a0abb..b3707564 100644 --- a/e2fsck/ehandler.c +++ b/e2fsck/ehandler.c @@ -29,6 +29,10 @@ static errcode_t e2fsck_handle_read_error(io_channel channel, { int i; char *p; + ext2_filsys fs = channel->app_data; + e2fsck_t ctx; + + ctx = fs->private; /* * If more than one block was read, try reading each block @@ -51,8 +55,8 @@ static errcode_t e2fsck_handle_read_error(io_channel channel, else printf("Error reading block %lu (%s). ", block, error_message(error)); - preenhalt(NULL); - if (ask("Ignore error", 1)) + preenhalt(ctx); + if (ask(ctx, "Ignore error", 1)) return 0; return error; @@ -68,7 +72,11 @@ static errcode_t e2fsck_handle_write_error(io_channel channel, { int i; const char *p; + ext2_filsys fs = channel->app_data; + e2fsck_t ctx; + ctx = fs->private; + /* * If more than one block was written, try writing each block * separately. We could use the actual bytes read to figure @@ -91,8 +99,8 @@ static errcode_t e2fsck_handle_write_error(io_channel channel, else printf("Error writing block %lu (%s). ", block, error_message(error)); - preenhalt(NULL); - if (ask("Ignore error", 1)) + preenhalt(ctx); + if (ask(ctx, "Ignore error", 1)) return 0; return error; diff --git a/e2fsck/iscan.c b/e2fsck/iscan.c index d964b344..5a67b945 100644 --- a/e2fsck/iscan.c +++ b/e2fsck/iscan.c @@ -139,7 +139,7 @@ int main (int argc, char *argv[]) num_inodes++; } - print_resource_track(&global_rtrack); + print_resource_track(NULL, &global_rtrack); printf("%d inodes scanned.\n", num_inodes); exit(0); diff --git a/e2fsck/message.c b/e2fsck/message.c index b9f9dea1..673c4638 100644 --- a/e2fsck/message.c +++ b/e2fsck/message.c @@ -15,8 +15,11 @@ * * %b block number * %B integer + * %c block number * %di ->ino inode number * %dn ->name string + * %dr ->rec_len + * %dl ->name_len * %D inode number * %g integer * %i inode number @@ -29,6 +32,7 @@ * %If -> i_file_acl * %Id -> i_dir_acl * %j inode number + * %m * %N * %p ext2fs_get_pathname of directory * %P ext2fs_get_pathname of ->ino with as @@ -37,6 +41,8 @@ * %q ext2fs_get_pathname of directory * %Q ext2fs_get_pathname of directory with as * the containing directory. + * %s miscellaneous string + * %S backup superblock * * The following '@' expansions are supported: * @@ -49,12 +55,15 @@ * @d directory * @e entry * @E Entry '%Dn' in %p (%i) + * @f filesystem * @F for @i %i (%Q) is * @g group * @l lost+found * @L is a link * @u unattached * @r root inode + * @s should be + * @S superblock * @z zero-length */ @@ -90,6 +99,7 @@ static const char *abbrevs[] = { "ddirectory", "eentry", "E@e '%Dn' in %p (%i)", + "ffilesystem", "Ffor @i %i (%Q) is", "ggroup", "llost+found", @@ -97,6 +107,7 @@ static const char *abbrevs[] = { "uunattached", "rroot @i", "sshould be", + "Ssuper@b", "zzero-length", "@@", 0 @@ -145,8 +156,8 @@ static void print_pathname(ext2_filsys fs, ino_t dir, ino_t ino) * expansion; an @ expression can contain further '@' and '%' * expressions. */ -static _INLINE_ void expand_at_expression(ext2_filsys fs, char ch, - struct problem_context *ctx, +static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch, + struct problem_context *pctx, int *first) { const char **cpp, *str; @@ -162,7 +173,7 @@ static _INLINE_ void expand_at_expression(ext2_filsys fs, char ch, *first = 0; fputc(toupper(*str++), stdout); } - print_e2fsck_message(fs, str, ctx, *first); + print_e2fsck_message(ctx, str, pctx, *first); } else printf("@%c", ch); } @@ -242,6 +253,12 @@ static _INLINE_ void expand_dirent_expression(char ch, len = dirent->rec_len; printf("%.*s", dirent->name_len, dirent->name); break; + case 'r': + printf("%u", dirent->rec_len); + break; + case 'l': + printf("%u", dirent->name_len); + break; default: no_dirent: printf("%%D%c", ch); @@ -265,6 +282,9 @@ static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch, case 'B': printf("%d", ctx->blkcount); break; + case 'c': + printf("%u", ctx->blk2); + break; case 'd': printf("%lu", ctx->dir); break; @@ -277,6 +297,9 @@ static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch, case 'j': printf("%lu", ctx->ino2); break; + case 'm': + printf("%s", error_message(ctx->errcode)); + break; case 'N': printf("%u", ctx->num); break; @@ -293,6 +316,12 @@ static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch, case 'Q': print_pathname(fs, ctx->dir, ctx->ino); break; + case 'S': + printf("%d", get_backup_sb(fs)); + break; + case 's': + printf("%s", ctx->str); + break; default: no_context: printf("%%%c", ch); @@ -300,25 +329,26 @@ static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch, } } -void print_e2fsck_message(ext2_filsys fs, const char *msg, - struct problem_context *ctx, int first) +void print_e2fsck_message(e2fsck_t ctx, const char *msg, + struct problem_context *pctx, int first) { + ext2_filsys fs = ctx->fs; const char * cp; int i; for (cp = msg; *cp; cp++) { if (cp[0] == '@') { cp++; - expand_at_expression(fs, *cp, ctx, &first); + expand_at_expression(ctx, *cp, pctx, &first); } else if (cp[0] == '%' && cp[1] == 'I') { cp += 2; - expand_inode_expression(*cp, ctx); + expand_inode_expression(*cp, pctx); } else if (cp[0] == '%' && cp[1] == 'D') { cp += 2; - expand_dirent_expression(*cp, ctx); + expand_dirent_expression(*cp, pctx); } else if ((cp[0] == '%')) { cp++; - expand_percent_expression(fs, *cp, ctx); + expand_percent_expression(fs, *cp, pctx); } else { for (i=0; cp[i]; i++) if ((cp[i] == '@') || cp[i] == '%') diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 2f1d67e7..bd046d21 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -40,7 +40,6 @@ #include #endif -#include #include "e2fsck.h" #include "problem.h" @@ -50,47 +49,19 @@ #define _INLINE_ inline #endif -/* Files counts */ -int fs_directory_count = 0; -int fs_regular_count = 0; -int fs_blockdev_count = 0; -int fs_chardev_count = 0; -int fs_links_count = 0; -int fs_symlinks_count = 0; -int fs_fast_symlinks_count = 0; -int fs_fifo_count = 0; -int fs_total_count = 0; -int fs_badblocks_count = 0; -int fs_sockets_count = 0; -int fs_ind_count = 0; -int fs_dind_count = 0; -int fs_tind_count = 0; -int fs_fragmented = 0; - -ext2fs_inode_bitmap inode_used_map = 0; /* Inodes which are in use */ -ext2fs_inode_bitmap inode_bad_map = 0; /* Inodes which are bad in some way */ -ext2fs_inode_bitmap inode_dir_map = 0; /* Inodes which are directories */ -ext2fs_inode_bitmap inode_bb_map = 0; /* Inodes which are in bad blocks */ - -ext2fs_block_bitmap block_found_map = 0; -ext2fs_block_bitmap block_dup_map = 0; -ext2fs_block_bitmap block_illegal_map = 0; - -ext2_icount_t inode_link_info = 0; - static int process_block(ext2_filsys fs, blk_t *blocknr, int blockcnt, blk_t ref_blk, int ref_offset, void *private); static int process_bad_block(ext2_filsys fs, blk_t *block_nr, int blockcnt, blk_t ref_blk, int ref_offset, void *private); -static void check_blocks(ext2_filsys fs, struct problem_context *pctx, +static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, char *block_buf); -static void mark_table_blocks(ext2_filsys fs); -static void alloc_bad_map(ext2_filsys fs); -static void alloc_bb_map(ext2_filsys fs); -static void handle_fs_bad_blocks(ext2_filsys fs); -static void process_inodes(ext2_filsys fs, char *block_buf); +static void mark_table_blocks(e2fsck_t ctx); +static void alloc_bad_map(e2fsck_t ctx); +static void alloc_bb_map(e2fsck_t ctx); +static void handle_fs_bad_blocks(e2fsck_t ctx); +static void process_inodes(e2fsck_t ctx, char *block_buf); static int process_inode_cmp(const void *a, const void *b); static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, dgrp_t group, void * private); @@ -105,6 +76,7 @@ struct process_block_struct { blk_t previous_block; struct ext2_inode *inode; struct problem_context *pctx; + e2fsck_t ctx; }; struct process_inode_block { @@ -112,18 +84,11 @@ struct process_inode_block { struct ext2_inode inode; }; -/* - * For pass1_check_directory and pass1_get_blocks - */ -ino_t stashed_ino; -struct ext2_inode *stashed_inode; - /* * For the inodes to process list. */ static struct process_inode_block *inodes_to_process; static int process_inode_count; -int process_inode_size = 256; /* * Free all memory allocated by pass1 in preparation for restarting @@ -131,39 +96,7 @@ int process_inode_size = 256; */ static void unwind_pass1(ext2_filsys fs) { - ext2fs_free_inode_bitmap(inode_used_map); inode_used_map = 0; - ext2fs_free_inode_bitmap(inode_dir_map); inode_dir_map = 0; - ext2fs_free_block_bitmap(block_found_map); block_found_map = 0; - ext2fs_free_icount(inode_link_info); inode_link_info = 0; free(inodes_to_process);inodes_to_process = 0; - ext2fs_free_dblist(fs->dblist); fs->dblist = 0; - free_dir_info(fs); - if (block_dup_map) { - ext2fs_free_block_bitmap(block_dup_map); block_dup_map = 0; - } - if (inode_bb_map) { - ext2fs_free_inode_bitmap(inode_bb_map); inode_bb_map = 0; - } - if (inode_bad_map) { - ext2fs_free_inode_bitmap(inode_bad_map); inode_bad_map = 0; - } - - /* Clear statistic counters */ - fs_directory_count = 0; - fs_regular_count = 0; - fs_blockdev_count = 0; - fs_chardev_count = 0; - fs_links_count = 0; - fs_symlinks_count = 0; - fs_fast_symlinks_count = 0; - fs_fifo_count = 0; - fs_total_count = 0; - fs_badblocks_count = 0; - fs_sockets_count = 0; - fs_ind_count = 0; - fs_dind_count = 0; - fs_tind_count = 0; - fs_fragmented = 0; } /* @@ -180,21 +113,22 @@ int e2fsck_pass1_check_device_inode(struct ext2_inode *inode) return 1; } -void pass1(ext2_filsys fs) +void pass1(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; ino_t ino; struct ext2_inode inode; ext2_inode_scan scan; char *block_buf; - errcode_t retval; struct resource_track rtrack; unsigned char frag, fsize; struct problem_context pctx; init_resource_track(&rtrack); - - if (!preen) - printf("Pass 1: Checking inodes, blocks, and sizes\n"); + clear_problem_context(&pctx); + + if (!(ctx->options & E2F_OPT_PREEN)) + fix_problem(ctx, PR_1_PASS_HEADER, &pctx); #ifdef MTRACE mtrace_print("Pass 1"); @@ -203,85 +137,85 @@ void pass1(ext2_filsys fs) /* * Allocate bitmaps structures */ - retval = ext2fs_allocate_inode_bitmap(fs, "in-use inode map", - &inode_used_map); - if (retval) { - com_err("ext2fs_allocate_inode_bitmap", retval, - "while allocating inode_used_map"); + pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "in-use inode map", + &ctx->inode_used_map); + if (pctx.errcode) { + pctx.num = 1; + fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); fatal_error(0); } - retval = ext2fs_allocate_inode_bitmap(fs, "directory inode map", - &inode_dir_map); - if (retval) { - com_err("ext2fs_allocate_inode_bitmap", retval, - "while allocating inode_dir_map"); + pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "directory inode map", + &ctx->inode_dir_map); + if (pctx.errcode) { + pctx.num = 2; + fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); fatal_error(0); } - retval = ext2fs_allocate_block_bitmap(fs, "in-use block map", - &block_found_map); - if (retval) { - com_err("ext2fs_allocate_block_bitmap", retval, - "while allocating block_found_map"); + pctx.errcode = ext2fs_allocate_block_bitmap(fs, "in-use block map", + &ctx->block_found_map); + if (pctx.errcode) { + pctx.num = 1; + fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); fatal_error(0); } - retval = ext2fs_allocate_block_bitmap(fs, "illegal block map", - &block_illegal_map); - if (retval) { - com_err("ext2fs_allocate_block_bitmap", retval, - "while allocating block_illegal_map"); + pctx.errcode = ext2fs_allocate_block_bitmap(fs, "illegal block map", + &ctx->block_illegal_map); + if (pctx.errcode) { + pctx.num = 2; + fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); fatal_error(0); } - retval = ext2fs_create_icount2(fs, 0, 0, 0, &inode_link_info); - if (retval) { - com_err("ext2fs_create_icount", retval, - "while creating inode_link_info"); + pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0, + &ctx->inode_link_info); + if (pctx.errcode) { + fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx); fatal_error(0); } - inodes_to_process = allocate_memory(process_inode_size * + inodes_to_process = allocate_memory(ctx->process_inode_size * sizeof(struct process_inode_block), "array of inodes to process"); process_inode_count = 0; - retval = ext2fs_init_dblist(fs, 0); - if (retval) { - com_err(program_name, retval, - "while allocating directory block information"); + pctx.errcode = ext2fs_init_dblist(fs, 0); + if (pctx.errcode) { + fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx); fatal_error(0); } - mark_table_blocks(fs); + mark_table_blocks(ctx); block_buf = allocate_memory(fs->blocksize * 3, "block interate buffer"); fs->get_blocks = pass1_get_blocks; fs->check_directory = pass1_check_directory; fs->read_inode = pass1_read_inode; fs->write_inode = pass1_write_inode; ehandler_operation("doing inode scan"); - retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan); - if (retval) { - com_err(program_name, retval, "while opening inode scan"); + pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, + &scan); + if (pctx.errcode) { + fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); fatal_error(0); } ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0); - retval = ext2fs_get_next_inode(scan, &ino, &inode); - if (retval) { - com_err(program_name, retval, "while starting inode scan"); + pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode); + if (pctx.errcode) { + fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); fatal_error(0); } - stashed_inode = &inode; + ctx->stashed_inode = &inode; ext2fs_set_inode_callback(scan, scan_callback, block_buf); - clear_problem_context(&pctx); while (ino) { - stashed_ino = ino; - if (inode.i_links_count) - retval = ext2fs_icount_store(inode_link_info, ino, - inode.i_links_count); - if (retval) { - com_err("ext2fs_icount_fetch", retval, - "while adding inode %u", ino); - fatal_error(0); - } pctx.ino = ino; pctx.inode = &inode; + ctx->stashed_ino = ino; + if (inode.i_links_count) { + pctx.errcode = ext2fs_icount_store(ctx->inode_link_info, + ino, inode.i_links_count); + if (pctx.errcode) { + pctx.num = inode.i_links_count; + fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx); + fatal_error(0); + } + } if (ino == EXT2_BAD_INO) { struct process_block_struct pb; @@ -292,12 +226,14 @@ void pass1(ext2_filsys fs) pb.fragmented = 0; pb.inode = &inode; pb.pctx = &pctx; - retval = ext2fs_block_iterate2(fs, ino, 0, block_buf, - process_bad_block, &pb); - if (retval) - com_err(program_name, retval, "while calling e2fsc_block_interate in pass 1"); - - ext2fs_mark_inode_bitmap(inode_used_map, ino); + pb.ctx = ctx; + pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, + block_buf, process_bad_block, &pb); + if (pctx.errcode) { + fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx); + fatal_error(0); + } + ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); clear_problem_context(&pctx); goto next; } @@ -308,10 +244,10 @@ void pass1(ext2_filsys fs) * regnerated in pass #3. */ if (!LINUX_S_ISDIR(inode.i_mode)) { - if (fix_problem(fs, PR_1_ROOT_NO_DIR, &pctx)) { + if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) { inode.i_dtime = time(0); inode.i_links_count = 0; - ext2fs_icount_store(inode_link_info, + ext2fs_icount_store(ctx->inode_link_info, ino, 0); e2fsck_write_inode(fs, ino, &inode, "pass1"); @@ -327,7 +263,7 @@ void pass1(ext2_filsys fs) * as a special case. */ if (inode.i_dtime && inode.i_links_count) { - if (fix_problem(fs, PR_1_ROOT_DTIME, &pctx)) { + if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) { inode.i_dtime = 0; e2fsck_write_inode(fs, ino, &inode, "pass1"); @@ -335,22 +271,22 @@ void pass1(ext2_filsys fs) } } if (ino == EXT2_BOOT_LOADER_INO) { - ext2fs_mark_inode_bitmap(inode_used_map, ino); - check_blocks(fs, &pctx, block_buf); + ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); + check_blocks(ctx, &pctx, block_buf); goto next; } if ((ino != EXT2_ROOT_INO) && (ino < EXT2_FIRST_INODE(fs->super))) { - ext2fs_mark_inode_bitmap(inode_used_map, ino); + ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); if (inode.i_mode != 0) { - if (fix_problem(fs, + if (fix_problem(ctx, PR_1_RESERVED_BAD_MODE, &pctx)) { inode.i_mode = 0; e2fsck_write_inode(fs, ino, &inode, "pass1"); } } - check_blocks(fs, &pctx, block_buf); + check_blocks(ctx, &pctx, block_buf); goto next; } /* @@ -359,7 +295,7 @@ void pass1(ext2_filsys fs) */ if (!inode.i_links_count) { if (!inode.i_dtime && inode.i_mode) { - if (fix_problem(fs, + if (fix_problem(ctx, PR_1_ZERO_DTIME, &pctx)) { inode.i_dtime = time(0); e2fsck_write_inode(fs, ino, &inode, @@ -379,13 +315,13 @@ void pass1(ext2_filsys fs) * */ if (inode.i_dtime) { - if (fix_problem(fs, PR_1_SET_DTIME, &pctx)) { + if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) { inode.i_dtime = 0; e2fsck_write_inode(fs, ino, &inode, "pass1"); } } - ext2fs_mark_inode_bitmap(inode_used_map, ino); + ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); switch (fs->super->s_creator_os) { case EXT2_OS_LINUX: frag = inode.osd2.linux2.l_i_frag; @@ -405,45 +341,45 @@ void pass1(ext2_filsys fs) if (inode.i_faddr || frag || fsize || inode.i_file_acl || inode.i_dir_acl) { - if (!inode_bad_map) - alloc_bad_map(fs); - ext2fs_mark_inode_bitmap(inode_bad_map, ino); + if (!ctx->inode_bad_map) + alloc_bad_map(ctx); + ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino); } if (LINUX_S_ISDIR(inode.i_mode)) { - ext2fs_mark_inode_bitmap(inode_dir_map, ino); + ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); add_dir_info(fs, ino, 0); - fs_directory_count++; + ctx->fs_directory_count++; } else if (LINUX_S_ISREG (inode.i_mode)) - fs_regular_count++; + ctx->fs_regular_count++; else if (LINUX_S_ISCHR (inode.i_mode) && e2fsck_pass1_check_device_inode(&inode)) - fs_chardev_count++; + ctx->fs_chardev_count++; else if (LINUX_S_ISBLK (inode.i_mode) && e2fsck_pass1_check_device_inode(&inode)) - fs_blockdev_count++; + ctx->fs_blockdev_count++; else if (LINUX_S_ISLNK (inode.i_mode)) { - fs_symlinks_count++; + ctx->fs_symlinks_count++; if (!inode.i_blocks) { - fs_fast_symlinks_count++; + ctx->fs_fast_symlinks_count++; goto next; } } else if (LINUX_S_ISFIFO (inode.i_mode)) - fs_fifo_count++; + ctx->fs_fifo_count++; else if (LINUX_S_ISSOCK (inode.i_mode)) - fs_sockets_count++; + ctx->fs_sockets_count++; else { - if (!inode_bad_map) - alloc_bad_map(fs); - ext2fs_mark_inode_bitmap(inode_bad_map, ino); + if (!ctx->inode_bad_map) + alloc_bad_map(ctx); + ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino); } if (inode.i_block[EXT2_IND_BLOCK]) - fs_ind_count++; + ctx->fs_ind_count++; if (inode.i_block[EXT2_DIND_BLOCK]) - fs_dind_count++; + ctx->fs_dind_count++; if (inode.i_block[EXT2_TIND_BLOCK]) - fs_tind_count++; + ctx->fs_tind_count++; if (inode.i_block[EXT2_IND_BLOCK] || inode.i_block[EXT2_DIND_BLOCK] || inode.i_block[EXT2_TIND_BLOCK]) { @@ -451,43 +387,42 @@ void pass1(ext2_filsys fs) inodes_to_process[process_inode_count].inode = inode; process_inode_count++; } else - check_blocks(fs, &pctx, block_buf); + check_blocks(ctx, &pctx, block_buf); - if (process_inode_count >= process_inode_size) - process_inodes(fs, block_buf); + if (process_inode_count >= ctx->process_inode_size) + process_inodes(ctx, block_buf); next: - retval = ext2fs_get_next_inode(scan, &ino, &inode); - if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { - if (!inode_bb_map) - alloc_bb_map(fs); - ext2fs_mark_inode_bitmap(inode_bb_map, ino); - ext2fs_mark_inode_bitmap(inode_used_map, ino); + pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode); + if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { + if (!ctx->inode_bb_map) + alloc_bb_map(ctx); + ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino); + ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); goto next; } - if (retval) { - com_err(program_name, retval, - "while doing inode scan"); + if (pctx.errcode) { + fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); fatal_error(0); } } - process_inodes(fs, block_buf); + process_inodes(ctx, block_buf); ext2fs_close_inode_scan(scan); ehandler_operation(0); - if (invalid_bitmaps) - handle_fs_bad_blocks(fs); + if (ctx->invalid_bitmaps) + handle_fs_bad_blocks(ctx); if (restart_e2fsck) { unwind_pass1(fs); goto endit; } - if (block_dup_map) { - if (preen) { - printf("Duplicate or bad blocks in use!\n"); - preenhalt(fs); + if (ctx->block_dup_map) { + if (ctx->options & E2F_OPT_PREEN) { + clear_problem_context(&pctx); + fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx); } - pass1_dupblocks(fs, block_buf); + pass1_dupblocks(ctx, block_buf); } free(inodes_to_process); endit: @@ -497,13 +432,11 @@ endit: fs->write_inode = 0; free(block_buf); - ext2fs_free_block_bitmap(block_illegal_map); - block_illegal_map = 0; + ext2fs_free_block_bitmap(ctx->block_illegal_map); + ctx->block_illegal_map = 0; - if (tflag > 1) { - printf("Pass 1: "); - print_resource_track(&rtrack); - } + if (ctx->options & E2F_OPT_TIME2) + print_resource_track("Pass 1", &rtrack); } /* @@ -513,14 +446,14 @@ endit: static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, dgrp_t group, void * private) { - process_inodes(fs, (char *) private); + process_inodes((e2fsck_t) fs->private, (char *) private); return 0; } /* * Process the inodes in the "inodes to process" list. */ -static void process_inodes(ext2_filsys fs, char *block_buf) +static void process_inodes(e2fsck_t ctx, char *block_buf) { int i; struct ext2_inode *old_stashed_inode; @@ -533,24 +466,24 @@ static void process_inodes(ext2_filsys fs, char *block_buf) printf("begin process_inodes: "); #endif old_operation = ehandler_operation(0); - old_stashed_inode = stashed_inode; - old_stashed_ino = stashed_ino; + old_stashed_inode = ctx->stashed_inode; + old_stashed_ino = ctx->stashed_ino; qsort(inodes_to_process, process_inode_count, sizeof(struct process_inode_block), process_inode_cmp); clear_problem_context(&pctx); for (i=0; i < process_inode_count; i++) { - pctx.inode = stashed_inode = &inodes_to_process[i].inode; - pctx.ino = stashed_ino = inodes_to_process[i].ino; + pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode; + pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino; #if 0 printf("%u ", pctx.ino); #endif sprintf(buf, "reading indirect blocks of inode %lu", pctx.ino); ehandler_operation(buf); - check_blocks(fs, &pctx, block_buf); + check_blocks(ctx, &pctx, block_buf); } - stashed_inode = old_stashed_inode; - stashed_ino = old_stashed_ino; + ctx->stashed_inode = old_stashed_inode; + ctx->stashed_ino = old_stashed_ino; process_inode_count = 0; #if 0 printf("end process inodes\n"); @@ -572,15 +505,17 @@ static int process_inode_cmp(const void *a, const void *b) /* * This procedure will allocate the inode bad map table */ -static void alloc_bad_map(ext2_filsys fs) +static void alloc_bad_map(e2fsck_t ctx) { - errcode_t retval; + struct problem_context pctx; - retval = ext2fs_allocate_inode_bitmap(fs, "bad inode map", - &inode_bad_map); - if (retval) { - com_err("ext2fs_allocate_inode_bitmap", retval, - "while allocating inode_bad_map"); + clear_problem_context(&pctx); + + pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, "bad inode map", + &ctx->inode_bad_map); + if (pctx.errcode) { + pctx.num = 3; + fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); fatal_error(0); } } @@ -588,15 +523,17 @@ static void alloc_bad_map(ext2_filsys fs) /* * This procedure will allocate the inode "bb" (badblock) map table */ -static void alloc_bb_map(ext2_filsys fs) +static void alloc_bb_map(e2fsck_t ctx) { - errcode_t retval; + struct problem_context pctx; - retval = ext2fs_allocate_inode_bitmap(fs, "inode in bad block map", - &inode_bb_map); - if (retval) { - com_err("ext2fs_allocate_inode_bitmap", retval, - "while allocating inode in bad block map"); + clear_problem_context(&pctx); + pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, + "inode in bad block map", + &ctx->inode_bb_map); + if (pctx.errcode) { + pctx.num = 4; + fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); fatal_error(0); } } @@ -608,23 +545,27 @@ static void alloc_bb_map(ext2_filsys fs) * WARNING: Assumes checks have already been done to make sure block * is valid. This is true in both process_block and process_bad_block. */ -static _INLINE_ void mark_block_used(ext2_filsys fs, blk_t block) +static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block) { - errcode_t retval; + struct problem_context pctx; - if (ext2fs_fast_test_block_bitmap(block_found_map, block)) { - if (!block_dup_map) { - retval = ext2fs_allocate_block_bitmap(fs, - "multiply claimed block map", &block_dup_map); - if (retval) { - com_err("ext2fs_allocate_block_bitmap", retval, - "while allocating block_dup_map"); + clear_problem_context(&pctx); + + if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) { + if (!ctx->block_dup_map) { + pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs, + "multiply claimed block map", + &ctx->block_dup_map); + if (pctx.errcode) { + pctx.num = 3; + fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, + &pctx); fatal_error(0); } } - ext2fs_fast_mark_block_bitmap(block_dup_map, block); + ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block); } else { - ext2fs_fast_mark_block_bitmap(block_found_map, block); + ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block); } } @@ -632,11 +573,11 @@ static _INLINE_ void mark_block_used(ext2_filsys fs, blk_t block) * This subroutine is called on each inode to account for all of the * blocks used by that inode. */ -static void check_blocks(ext2_filsys fs, struct problem_context *pctx, +static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, char *block_buf) { + ext2_filsys fs = ctx->fs; struct process_block_struct pb; - errcode_t retval; ino_t ino = pctx->ino; struct ext2_inode *inode = pctx->inode; @@ -652,30 +593,26 @@ static void check_blocks(ext2_filsys fs, struct problem_context *pctx, pb.is_dir = LINUX_S_ISDIR(pctx->inode->i_mode); pb.inode = inode; pb.pctx = pctx; - retval = ext2fs_block_iterate2(fs, ino, + pb.ctx = ctx; + pctx->ino = ino; + pctx->errcode = ext2fs_block_iterate2(fs, ino, pb.is_dir ? BLOCK_FLAG_HOLE : 0, block_buf, process_block, &pb); - reset_problem_latch(PR_LATCH_BLOCK); - if (retval) - com_err(program_name, retval, - "while calling ext2fs_block_iterate in check_blocks"); + end_problem_latch(ctx, PR_LATCH_BLOCK); + if (pctx->errcode) + fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group) - fs_fragmented++; + ctx->fs_fragmented++; if (pb.clear) { e2fsck_read_inode(fs, ino, inode, "check_blocks"); - if (retval) { - com_err("check_blocks", retval, - "while reading to be cleared inode %d", ino); - fatal_error(0); - } inode->i_links_count = 0; - ext2fs_icount_store(inode_link_info, ino, 0); + ext2fs_icount_store(ctx->inode_link_info, ino, 0); inode->i_dtime = time(0); e2fsck_write_inode(fs, ino, inode, "check_blocks"); - ext2fs_unmark_inode_bitmap(inode_dir_map, ino); - ext2fs_unmark_inode_bitmap(inode_used_map, ino); + ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); + ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); /* * The inode was probably partially accounted for * before processing was aborted, so we need to @@ -692,14 +629,14 @@ static void check_blocks(ext2_filsys fs, struct problem_context *pctx, pb.num_blocks); #endif if (!pb.num_blocks && pb.is_dir) { - if (fix_problem(fs, PR_1_ZERO_LENGTH_DIR, pctx)) { + if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { inode->i_links_count = 0; - ext2fs_icount_store(inode_link_info, ino, 0); + ext2fs_icount_store(ctx->inode_link_info, ino, 0); inode->i_dtime = time(0); e2fsck_write_inode(fs, ino, inode, "check_blocks"); - ext2fs_unmark_inode_bitmap(inode_dir_map, ino); - ext2fs_unmark_inode_bitmap(inode_used_map, ino); - fs_directory_count--; + ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); + ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); + ctx->fs_directory_count--; pb.is_dir = 0; } } @@ -707,7 +644,7 @@ static void check_blocks(ext2_filsys fs, struct problem_context *pctx, (pb.last_block + 1) * fs->blocksize)) || (inode->i_size < pb.last_block * fs->blocksize)) { pctx->num = (pb.last_block+1) * fs->blocksize; - if (fix_problem(fs, PR_1_BAD_I_SIZE, pctx)) { + if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { inode->i_size = pctx->num; e2fsck_write_inode(fs, ino, inode, "check_blocks"); } @@ -715,7 +652,7 @@ static void check_blocks(ext2_filsys fs, struct problem_context *pctx, } if (pb.num_blocks != inode->i_blocks) { pctx->num = pb.num_blocks; - if (fix_problem(fs, PR_1_BAD_I_BLOCKS, pctx)) { + if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { inode->i_blocks = pb.num_blocks; e2fsck_write_inode(fs, ino, inode, "check_blocks"); } @@ -790,10 +727,11 @@ int process_block(ext2_filsys fs, blk_t blk = *block_nr; int ret_code = 0; int problem = 0; - errcode_t retval; + e2fsck_t ctx; p = (struct process_block_struct *) private; pctx = p->pctx; + ctx = p->ctx; if (blk == 0) { if (p->is_dir == 0) { @@ -801,9 +739,11 @@ int process_block(ext2_filsys fs, * Should never happen, since only directories * get called with BLOCK_FLAG_HOLE */ +#if DEBUG_E2FSCK printf("process_block() called with blk == 0, " "blockcnt=%d, inode %lu???\n", blockcnt, p->ino); +#endif return 0; } if (blockcnt < 0) @@ -846,18 +786,19 @@ int process_block(ext2_filsys fs, if (problem) { p->num_illegal_blocks++; if (!p->suppress && (p->num_illegal_blocks % 12) == 0) { - if (fix_problem(fs, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) { + if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) { p->clear = 1; return BLOCK_ABORT; } - if (ask("Suppress messages", 0)) { + if (ask(ctx, "Suppress messages", 0)) { p->suppress = 1; - suppress_latch_group(PR_LATCH_BLOCK, 1); + set_latch_flags(PR_LATCH_BLOCK, + PRL_SUPPRESS, 0); } } pctx->blk = blk; pctx->blkcount = blockcnt; - if (fix_problem(fs, problem, pctx)) { + if (fix_problem(ctx, problem, pctx)) { blk = *block_nr = 0; ret_code = BLOCK_CHANGED; goto mark_dir; @@ -867,51 +808,34 @@ int process_block(ext2_filsys fs, pctx->blkcount = -1; } - mark_block_used(fs, blk); + mark_block_used(ctx, blk); p->num_blocks++; if (blockcnt >= 0) p->last_block = blockcnt; mark_dir: if (p->is_dir && (blockcnt >= 0)) { - retval = ext2fs_add_dir_block(fs->dblist, p->ino, - blk, blockcnt); - if (retval) { - com_err(program_name, retval, - "while adding to directory block list"); + pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino, + blk, blockcnt); + if (pctx->errcode) { + pctx->blk = blk; + pctx->num = blockcnt; + fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); fatal_error(0); } } return ret_code; } -static void bad_block_indirect(ext2_filsys fs, blk_t blk) +static void bad_block_indirect(e2fsck_t ctx, blk_t blk) { - printf("Bad block %u used as bad block indirect block?!?\n", blk); - preenhalt(fs); - printf("\nThis inconsistency can not be fixed with " - "e2fsck; to fix it, use\n" - """dumpe2fs -b"" to dump out the bad block " - "list and ""e2fsck -L filename""\n" - "to read it back in again.\n"); - if (ask("Continue", 0)) - return; - fatal_error(0); -} + struct problem_context pctx; -static int bad_primary_block(ext2_filsys fs, blk_t *block_nr) -{ - printf("\nIf the block is really bad, the filesystem can not be " - "fixed.\n"); - preenhalt(fs); - printf("You can clear the this block from the bad block list\n"); - printf("and hope that block is really OK, but there are no " - "guarantees.\n\n"); - if (ask("Clear (and hope for the best)", 1)) { - *block_nr = 0; - return 1; - } - ext2fs_unmark_valid(fs); - return 0; + clear_problem_context(&pctx); + /* + * Prompt to see if we should continue or not. + */ + if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, &pctx)) + fatal_error(0); } int process_bad_block(ext2_filsys fs, @@ -926,20 +850,21 @@ int process_bad_block(ext2_filsys fs, int first_block; int i; struct problem_context *pctx; + e2fsck_t ctx; if (!blk) return 0; p = (struct process_block_struct *) private; + ctx = p->ctx; pctx = p->pctx; pctx->blk = blk; pctx->blkcount = blockcnt; - if ((blk < fs->super->s_first_data_block) || (blk >= fs->super->s_blocks_count)) { - if (fix_problem(fs, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) { + if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) { *block_nr = 0; return BLOCK_CHANGED; } else @@ -947,24 +872,24 @@ int process_bad_block(ext2_filsys fs, } if (blockcnt < 0) { - if (ext2fs_test_block_bitmap(block_found_map, blk)) - bad_block_indirect(fs, blk); + if (ext2fs_test_block_bitmap(ctx->block_found_map, blk)) + bad_block_indirect(ctx, blk); else - mark_block_used(fs, blk); + mark_block_used(ctx, blk); return 0; } #if 0 printf ("DEBUG: Marking %u as bad.\n", blk); #endif - fs_badblocks_count++; + ctx->fs_badblocks_count++; /* * If the block is not used, then mark it as used and return. * If it is already marked as found, this must mean that * there's an overlap between the filesystem table blocks * (bitmaps and inode table) and the bad block list. */ - if (!ext2fs_test_block_bitmap(block_found_map, blk)) { - ext2fs_mark_block_bitmap(block_found_map, blk); + if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) { + ext2fs_mark_block_bitmap(ctx->block_found_map, blk); return 0; } /* @@ -974,46 +899,45 @@ int process_bad_block(ext2_filsys fs, for (i = 0; i < fs->group_desc_count; i++ ) { pctx->group = i; + pctx->blk = blk; if (blk == first_block) { if (i == 0) { - printf("The primary superblock (%u) is " - "on the bad block list.\n", blk); - if (bad_primary_block(fs, block_nr)) + if (fix_problem(ctx, + PR_1_BAD_PRIMARY_SUPERBLOCK, + pctx)) { + *block_nr = 0; return BLOCK_CHANGED; + } return 0; } - if (!preen) - printf("Warning: Group %d's superblock " - "(%u) is bad.\n", i, blk); + fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx); return 0; } if ((blk > first_block) && (blk <= first_block + fs->desc_blocks)) { if (i == 0) { - printf("Block %u in the primary group " - "descriptors is on the bad block " - "list\n", blk); - if (bad_primary_block(fs, block_nr)) + pctx->blk = *block_nr; + if (fix_problem(ctx, + PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) { + *block_nr = 0; return BLOCK_CHANGED; + } return 0; } - if (!preen) - printf("Warning: Group %d's copy of the " - "group descriptors has a bad " - "block (%u).\n", i, blk); + fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx); return 0; } if (blk == fs->group_desc[i].bg_block_bitmap) { - if (fix_problem(fs, PR_1_BB_BAD_BLOCK, pctx)) { - invalid_block_bitmap[i]++; - invalid_bitmaps++; + if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) { + ctx->invalid_block_bitmap_flag[i]++; + ctx->invalid_bitmaps++; } return 0; } if (blk == fs->group_desc[i].bg_inode_bitmap) { - if (fix_problem(fs, PR_1_IB_BAD_BLOCK, pctx)) { - invalid_inode_bitmap[i]++; - invalid_bitmaps++; + if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) { + ctx->invalid_inode_bitmap_flag[i]++; + ctx->invalid_bitmaps++; } return 0; } @@ -1035,62 +959,69 @@ int process_bad_block(ext2_filsys fs, */ if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) || p->inode->i_block[EXT2_DIND_BLOCK]) { - bad_block_indirect(fs, blk); + bad_block_indirect(ctx, blk); return 0; } - - printf("Programming error? block #%u claimed for no reason " - "in process_bad_block.\n", blk); + + pctx->group = -1; + + /* Warn user that the block wasn't claimed */ + fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx); + return 0; } -static void new_table_block(ext2_filsys fs, blk_t first_block, int group, +static void new_table_block(e2fsck_t ctx, blk_t first_block, int group, const char *name, int num, blk_t *new_block) { - errcode_t retval; + ext2_filsys fs = ctx->fs; blk_t old_block = *new_block; int i; char *buf; - - retval = ext2fs_get_free_blocks(fs, first_block, + struct problem_context pctx; + + clear_problem_context(&pctx); + + pctx.group = group; + pctx.blk = old_block; + pctx.str = name; + + pctx.errcode = ext2fs_get_free_blocks(fs, first_block, first_block + fs->super->s_blocks_per_group, - num, block_found_map, new_block); - if (retval) { - printf("Could not allocate %d block(s) for %s: %s\n", - num, name, error_message(retval)); + num, ctx->block_found_map, new_block); + if (pctx.errcode) { + pctx.num = num; + fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx); ext2fs_unmark_valid(fs); return; } buf = malloc(fs->blocksize); if (!buf) { - printf("Could not allocate block buffer for relocating %s\n", - name); + fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx); ext2fs_unmark_valid(fs); return; } ext2fs_mark_super_dirty(fs); - printf("Relocating group %d's %s ", group, name); - if (old_block) - printf("from %u ", old_block); - printf("to %u...\n", *new_block); + pctx.blk2 = *new_block; + fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO : + PR_1_RELOC_TO), &pctx); + pctx.blk2 = 0; for (i = 0; i < num; i++) { - ext2fs_mark_block_bitmap(block_found_map, (*new_block)+i); + pctx.blk = i; + ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i); if (old_block) { - retval = io_channel_read_blk(fs->io, old_block + i, - 1, buf); - if (retval) - printf("Warning: could not read block %u " - "of %s: %s\n", - old_block + i, name, - error_message(retval)); + pctx.errcode = io_channel_read_blk(fs->io, + old_block + i, 1, buf); + if (pctx.errcode) + fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx); } else memset(buf, 0, fs->blocksize); - retval = io_channel_write_blk(fs->io, (*new_block) + i, + pctx.blk = (*new_block) + i; + pctx.errcode = io_channel_write_blk(fs->io, pctx.blk, 1, buf); - if (retval) - printf("Warning: could not write block %u for %s: %s\n", - (*new_block) + i, name, error_message(retval)); + if (pctx.errcode) + fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx); } free(buf); } @@ -1102,37 +1033,39 @@ static void new_table_block(ext2_filsys fs, blk_t first_block, int group, * out, so we can try to allocate new block(s) to replace the bad * blocks. */ -static void handle_fs_bad_blocks(ext2_filsys fs) +static void handle_fs_bad_blocks(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; int i; int first_block = fs->super->s_first_data_block; for (i = 0; i < fs->group_desc_count; i++) { - if (invalid_block_bitmap[i]) { - new_table_block(fs, first_block, i, "block bitmap", 1, - &fs->group_desc[i].bg_block_bitmap); + if (ctx->invalid_block_bitmap_flag[i]) { + new_table_block(ctx, first_block, i, "block bitmap", + 1, &fs->group_desc[i].bg_block_bitmap); } - if (invalid_inode_bitmap[i]) { - new_table_block(fs, first_block, i, "inode bitmap", 1, - &fs->group_desc[i].bg_inode_bitmap); + if (ctx->invalid_inode_bitmap_flag[i]) { + new_table_block(ctx, first_block, i, "inode bitmap", + 1, &fs->group_desc[i].bg_inode_bitmap); } - if (invalid_inode_table[i]) { - new_table_block(fs, first_block, i, "inode table", + if (ctx->invalid_inode_table_flag[i]) { + new_table_block(ctx, first_block, i, "inode table", fs->inode_blocks_per_group, &fs->group_desc[i].bg_inode_table); restart_e2fsck++; } first_block += fs->super->s_blocks_per_group; } - invalid_bitmaps = 0; + ctx->invalid_bitmaps = 0; } /* * This routine marks all blocks which are used by the superblock, * group descriptors, inode bitmaps, and block bitmaps. */ -static void mark_table_blocks(ext2_filsys fs) +static void mark_table_blocks(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; blk_t block, b; int i,j; struct problem_context pctx; @@ -1147,16 +1080,17 @@ static void mark_table_blocks(ext2_filsys fs) /* * Mark this group's copy of the superblock */ - ext2fs_mark_block_bitmap(block_found_map, block); - ext2fs_mark_block_bitmap(block_illegal_map, block); + ext2fs_mark_block_bitmap(ctx->block_found_map, block); + ext2fs_mark_block_bitmap(ctx->block_illegal_map, + block); /* * Mark this group's copy of the descriptors */ for (j = 0; j < fs->desc_blocks; j++) { - ext2fs_mark_block_bitmap(block_found_map, + ext2fs_mark_block_bitmap(ctx->block_found_map, block + j + 1); - ext2fs_mark_block_bitmap(block_illegal_map, + ext2fs_mark_block_bitmap(ctx->block_illegal_map, block + j + 1); } } @@ -1168,18 +1102,18 @@ static void mark_table_blocks(ext2_filsys fs) for (j = 0, b = fs->group_desc[i].bg_inode_table; j < fs->inode_blocks_per_group; j++, b++) { - if (ext2fs_test_block_bitmap(block_found_map, + if (ext2fs_test_block_bitmap(ctx->block_found_map, b)) { pctx.blk = b; - if (fix_problem(fs, + if (fix_problem(ctx, PR_1_ITABLE_CONFLICT, &pctx)) { - invalid_inode_table[i]++; - invalid_bitmaps++; + ctx->invalid_inode_table_flag[i]++; + ctx->invalid_bitmaps++; } } else { - ext2fs_mark_block_bitmap(block_found_map, + ext2fs_mark_block_bitmap(ctx->block_found_map, b); - ext2fs_mark_block_bitmap(block_illegal_map, + ext2fs_mark_block_bitmap(ctx->block_illegal_map, b); } } @@ -1189,17 +1123,17 @@ static void mark_table_blocks(ext2_filsys fs) * Mark block used for the block bitmap */ if (fs->group_desc[i].bg_block_bitmap) { - if (ext2fs_test_block_bitmap(block_found_map, + if (ext2fs_test_block_bitmap(ctx->block_found_map, fs->group_desc[i].bg_block_bitmap)) { pctx.blk = fs->group_desc[i].bg_block_bitmap; - if (fix_problem(fs, PR_1_BB_CONFLICT, &pctx)) { - invalid_block_bitmap[i]++; - invalid_bitmaps++; + if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) { + ctx->invalid_block_bitmap_flag[i]++; + ctx->invalid_bitmaps++; } } else { - ext2fs_mark_block_bitmap(block_found_map, + ext2fs_mark_block_bitmap(ctx->block_found_map, fs->group_desc[i].bg_block_bitmap); - ext2fs_mark_block_bitmap(block_illegal_map, + ext2fs_mark_block_bitmap(ctx->block_illegal_map, fs->group_desc[i].bg_block_bitmap); } @@ -1208,17 +1142,17 @@ static void mark_table_blocks(ext2_filsys fs) * Mark block used for the inode bitmap */ if (fs->group_desc[i].bg_inode_bitmap) { - if (ext2fs_test_block_bitmap(block_found_map, + if (ext2fs_test_block_bitmap(ctx->block_found_map, fs->group_desc[i].bg_inode_bitmap)) { pctx.blk = fs->group_desc[i].bg_inode_bitmap; - if (fix_problem(fs, PR_1_IB_CONFLICT, &pctx)) { - invalid_inode_bitmap[i]++; - invalid_bitmaps++; + if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) { + ctx->invalid_inode_bitmap_flag[i]++; + ctx->invalid_bitmaps++; } } else { - ext2fs_mark_block_bitmap(block_found_map, + ext2fs_mark_block_bitmap(ctx->block_found_map, fs->group_desc[i].bg_inode_bitmap); - ext2fs_mark_block_bitmap(block_illegal_map, + ext2fs_mark_block_bitmap(ctx->block_illegal_map, fs->group_desc[i].bg_inode_bitmap); } } @@ -1234,41 +1168,45 @@ static void mark_table_blocks(ext2_filsys fs) */ errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks) { + e2fsck_t ctx = fs->private; int i; - if (ino != stashed_ino) + if (ino != ctx->stashed_ino) return EXT2_ET_CALLBACK_NOTHANDLED; for (i=0; i < EXT2_N_BLOCKS; i++) - blocks[i] = stashed_inode->i_block[i]; + blocks[i] = ctx->stashed_inode->i_block[i]; return 0; } errcode_t pass1_read_inode(ext2_filsys fs, ino_t ino, struct ext2_inode *inode) { - if (ino != stashed_ino) + e2fsck_t ctx = fs->private; + + if (ino != ctx->stashed_ino) return EXT2_ET_CALLBACK_NOTHANDLED; - *inode = *stashed_inode; + *inode = *ctx->stashed_inode; return 0; } errcode_t pass1_write_inode(ext2_filsys fs, ino_t ino, struct ext2_inode *inode) { - if (ino == stashed_ino) - *stashed_inode = *inode; + e2fsck_t ctx = fs->private; + + if (ino == ctx->stashed_ino) + *ctx->stashed_inode = *inode; return EXT2_ET_CALLBACK_NOTHANDLED; } errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino) { - if (ino == stashed_ino) { - if (!LINUX_S_ISDIR(stashed_inode->i_mode)) - return ENOTDIR; - return 0; - } - printf("INTERNAL ERROR: pass1_check_directory: unexpected inode #%lu\n", - ino); - printf("\t(was expecting %lu)\n", stashed_ino); - exit(FSCK_ERROR); + e2fsck_t ctx = fs->private; + + if (ino != ctx->stashed_ino) + return EXT2_ET_CALLBACK_NOTHANDLED; + + if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode)) + return ENOTDIR; + return 0; } diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c index 0edefdea..30c59245 100644 --- a/e2fsck/pass1b.c +++ b/e2fsck/pass1b.c @@ -89,12 +89,12 @@ struct dup_inode { static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr, int blockcnt, void *private); -static void delete_file(ext2_filsys fs, struct dup_inode *dp, +static void delete_file(e2fsck_t ctx, struct dup_inode *dp, char *block_buf); -static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf); -static void pass1b(ext2_filsys fs, char *block_buf); -static void pass1c(ext2_filsys fs, char *block_buf); -static void pass1d(ext2_filsys fs, char *block_buf); +static int clone_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf); +static void pass1b(e2fsck_t ctx, char *block_buf); +static void pass1c(e2fsck_t ctx, char *block_buf); +static void pass1d(e2fsck_t ctx, char *block_buf); static struct dup_block *dup_blk = 0; static struct dup_inode *dup_ino = 0; @@ -105,30 +105,32 @@ static ext2fs_inode_bitmap inode_dup_map; /* * Main procedure for handling duplicate blocks */ -void pass1_dupblocks(ext2_filsys fs, char *block_buf) +void pass1_dupblocks(e2fsck_t ctx, char *block_buf) { - errcode_t retval; + ext2_filsys fs = ctx->fs; struct dup_block *p, *q, *next_p, *next_q; struct dup_inode *r, *next_r; + struct problem_context pctx; + + clear_problem_context(&pctx); - retval = ext2fs_allocate_inode_bitmap(fs, + pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "multiply claimed inode map", &inode_dup_map); - if (retval) { - com_err("ext2fs_allocate_inode_bitmap", retval, - "while allocating inode_dup_map"); + if (pctx.errcode) { + fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx); fatal_error(0); } - pass1b(fs, block_buf); - pass1c(fs, block_buf); - pass1d(fs, block_buf); + pass1b(ctx, block_buf); + pass1c(ctx, block_buf); + pass1d(ctx, block_buf); /* * Time to free all of the accumulated data structures that we * don't need anymore. */ - ext2fs_free_inode_bitmap(inode_dup_map); inode_dup_map = 0; - ext2fs_free_block_bitmap(block_dup_map); block_dup_map = 0; + ext2fs_free_inode_bitmap(inode_dup_map); inode_dup_map = 0; + ext2fs_free_block_bitmap(ctx->block_dup_map); ctx->block_dup_map = 0; for (p = dup_blk; p; p = next_p) { next_p = p->next_block; for (q = p; q; q = next_q) { @@ -148,34 +150,42 @@ void pass1_dupblocks(ext2_filsys fs, char *block_buf) struct process_block_struct { ino_t ino; int dup_blocks; + e2fsck_t ctx; + struct problem_context *pctx; }; -void pass1b(ext2_filsys fs, char *block_buf) +void pass1b(e2fsck_t ctx, char *block_buf) { + ext2_filsys fs = ctx->fs; ino_t ino; struct ext2_inode inode; ext2_inode_scan scan; errcode_t retval; struct process_block_struct pb; struct dup_inode *dp; + struct problem_context pctx; + + clear_problem_context(&pctx); - printf("Duplicate blocks found... invoking duplicate block passes.\n"); - printf("Pass 1B: Rescan for duplicate/bad blocks\n"); - retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan); - if (retval) { - com_err(program_name, retval, "while opening inode scan"); + fix_problem(ctx, PR_1B_PASS_HEADER, &pctx); + pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, + &scan); + if (pctx.errcode) { + fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx); fatal_error(0); } - retval = ext2fs_get_next_inode(scan, &ino, &inode); - if (retval) { - com_err(program_name, retval, "while starting inode scan"); + pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode); + if (pctx.errcode) { + fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx); fatal_error(0); } - stashed_inode = &inode; + ctx->stashed_inode = &inode; + pb.ctx = ctx; + pb.pctx = &pctx; while (ino) { - stashed_ino = ino; + pctx.ino = ctx->stashed_ino = ino; if ((ino != EXT2_BAD_INO) && - (!ext2fs_test_inode_bitmap(inode_used_map, ino) || + (!ext2fs_test_inode_bitmap(ctx->inode_used_map, ino) || !ext2fs_inode_has_valid_blocks(&inode))) goto next; @@ -184,8 +194,7 @@ void pass1b(ext2_filsys fs, char *block_buf) retval = ext2fs_block_iterate(fs, ino, 0, block_buf, process_pass1b_block, &pb); if (pb.dup_blocks) { - if (ino != EXT2_BAD_INO) - printf("\n"); + end_problem_latch(ctx, PR_LATCH_DBLOCK); dp = allocate_memory(sizeof(struct dup_inode), "duplicate inode record"); dp->ino = ino; @@ -198,16 +207,15 @@ void pass1b(ext2_filsys fs, char *block_buf) dup_inode_count++; } if (retval) - com_err(program_name, retval, + com_err(ctx->program_name, retval, "while calling ext2fs_block_iterate in pass1b"); next: - retval = ext2fs_get_next_inode(scan, &ino, &inode); - if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) + pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode); + if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) goto next; - if (retval) { - com_err(program_name, retval, - "while doing inode scan"); + if (pctx.errcode) { + fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx); fatal_error(0); } } @@ -224,21 +232,21 @@ int process_pass1b_block(ext2_filsys fs, struct process_block_struct *p; struct dup_block *dp, *q, *r; int i; + e2fsck_t ctx; if (!*block_nr) return 0; p = (struct process_block_struct *) private; + ctx = p->ctx; - if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) { + if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) { /* OK, this is a duplicate block */ if (p->ino != EXT2_BAD_INO) { - if (!p->dup_blocks) - printf("Duplicate/bad block(s) in inode %lu:", - p->ino); - printf(" %u", *block_nr); + p->pctx->blk = *block_nr; + fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx); } p->dup_blocks++; - ext2fs_mark_block_bitmap(block_dup_map, *block_nr); + 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"); @@ -314,13 +322,17 @@ static int search_dirent_proc(ino_t dir, int entry, } -void pass1c(ext2_filsys fs, char *block_buf) +void pass1c(e2fsck_t ctx, char *block_buf) { + ext2_filsys fs = ctx->fs; struct dup_inode *p; int inodes_left = dup_inode_count; struct search_dir_struct sd; + struct problem_context pctx; - printf("Pass 1C: Scan directories for inodes with dup blocks.\n"); + clear_problem_context(&pctx); + + fix_problem(ctx, PR_1C_PASS_HEADER, &pctx); /* * First check to see if any of the inodes with dup blocks is @@ -344,23 +356,25 @@ void pass1c(ext2_filsys fs, char *block_buf) search_dirent_proc, &sd); } -static void pass1d(ext2_filsys fs, char *block_buf) +static void pass1d(e2fsck_t ctx, char *block_buf) { + ext2_filsys fs = ctx->fs; struct dup_inode *p, *s; struct dup_block *q, *r; ino_t *shared; int shared_len; int i; - errcode_t retval; int file_ok; int meta_data = 0; struct problem_context pctx; - - printf("Pass 1D: Reconciling duplicate blocks\n"); - read_bitmaps(fs); - printf("(There are %d inodes containing duplicate/bad blocks.)\n\n", - dup_inode_count); + clear_problem_context(&pctx); + + fix_problem(ctx, PR_1D_PASS_HEADER, &pctx); + 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"); for (p = dup_ino; p; p = p->next) { @@ -385,7 +399,7 @@ static void pass1d(ext2_filsys fs, char *block_buf) continue; if (q->num_bad > 1) file_ok = 0; - if (ext2fs_test_block_bitmap(block_illegal_map, + if (ext2fs_test_block_bitmap(ctx->block_illegal_map, q->block)) { file_ok = 0; meta_data = 1; @@ -412,18 +426,17 @@ static void pass1d(ext2_filsys fs, char *block_buf) /* * Report the inode that we are working on */ - clear_problem_context(&pctx); pctx.inode = &p->inode; pctx.ino = p->ino; pctx.dir = p->dir; pctx.blkcount = p->num_dupblocks; pctx.num = meta_data ? shared_len+1 : shared_len; - fix_problem(fs, PR_1B_DUP_FILE, &pctx); + fix_problem(ctx, PR_1D_DUP_FILE, &pctx); pctx.blkcount = 0; pctx.num = 0; if (meta_data) - fix_problem(fs, PR_1B_SHARE_METADATA, &pctx); + fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx); for (i = 0; i < shared_len; i++) { for (s = dup_ino; s; s = s->next) @@ -437,28 +450,23 @@ static void pass1d(ext2_filsys fs, char *block_buf) pctx.inode = &s->inode; pctx.ino = s->ino; pctx.dir = s->dir; - fix_problem(fs, PR_1B_DUP_FILE_LIST, &pctx); + fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx); } if (file_ok) { - printf("Duplicated blocks already reassigned or cloned.\n\n"); + fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx); continue; } - - if (ask("Clone duplicate/bad blocks", 1)) { - retval = clone_file(fs, p, block_buf); - if (retval) - printf("Couldn't clone file: %s\n", - error_message(retval)); - else { - printf("\n"); + if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) { + pctx.errcode = clone_file(ctx, p, block_buf); + if (pctx.errcode) + fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx); + else continue; - } } - if (ask("Delete file", 1)) - delete_file(fs, p, block_buf); + if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx)) + delete_file(ctx, p, block_buf); else ext2fs_unmark_valid(fs); - printf("\n"); } free(shared); } @@ -468,40 +476,46 @@ static int delete_file_block(ext2_filsys fs, int blockcnt, void *private) { + struct process_block_struct *pb = private; struct dup_block *p; + e2fsck_t ctx; + + ctx = pb->ctx; if (!*block_nr) return 0; - if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) { + if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) { for (p = dup_blk; p; p = p->next_block) if (p->block == *block_nr) break; if (p) { p->num_bad--; if (p->num_bad == 1) - ext2fs_unmark_block_bitmap(block_dup_map, + ext2fs_unmark_block_bitmap(ctx->block_dup_map, *block_nr); } else com_err("delete_file_block", 0, "internal error; can't find dup_blk for %d\n", *block_nr); } else { - ext2fs_unmark_block_bitmap(block_found_map, *block_nr); + ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr); ext2fs_unmark_block_bitmap(fs->block_map, *block_nr); } return 0; } -static void delete_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf) +static void delete_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf) { + ext2_filsys fs = ctx->fs; errcode_t retval; struct process_block_struct pb; struct ext2_inode inode; pb.ino = dp->ino; pb.dup_blocks = dp->num_dupblocks; + pb.ctx = ctx; retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf, delete_file_block, &pb); @@ -509,10 +523,10 @@ static void delete_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf) com_err("delete_file", retval, "while calling ext2fs_block_iterate for inode %d", dp->ino); - ext2fs_unmark_inode_bitmap(inode_used_map, dp->ino); - ext2fs_unmark_inode_bitmap(inode_dir_map, dp->ino); - if (inode_bad_map) - ext2fs_unmark_inode_bitmap(inode_bad_map, dp->ino); + ext2fs_unmark_inode_bitmap(ctx->inode_used_map, dp->ino); + ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, dp->ino); + if (ctx->inode_bad_map) + ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, dp->ino); ext2fs_unmark_inode_bitmap(fs->inode_map, dp->ino); ext2fs_mark_ib_dirty(fs); ext2fs_mark_bb_dirty(fs); @@ -526,6 +540,7 @@ struct clone_struct { errcode_t errcode; ino_t dir; char *buf; + e2fsck_t ctx; }; static int clone_file_block(ext2_filsys fs, @@ -537,16 +552,19 @@ static int clone_file_block(ext2_filsys fs, blk_t new_block; errcode_t retval; struct clone_struct *cs = (struct clone_struct *) private; + e2fsck_t ctx; + ctx = cs->ctx; + if (!*block_nr) return 0; - if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) { + if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) { for (p = dup_blk; p; p = p->next_block) if (p->block == *block_nr) break; if (p) { - retval = ext2fs_new_block(fs, 0, block_found_map, + retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &new_block); if (retval) { cs->errcode = retval; @@ -574,10 +592,10 @@ static int clone_file_block(ext2_filsys fs, } p->num_bad--; if (p->num_bad == 1) - ext2fs_unmark_block_bitmap(block_dup_map, + ext2fs_unmark_block_bitmap(ctx->block_dup_map, *block_nr); *block_nr = new_block; - ext2fs_mark_block_bitmap(block_found_map, + ext2fs_mark_block_bitmap(ctx->block_found_map, new_block); ext2fs_mark_block_bitmap(fs->block_map, new_block); return BLOCK_CHANGED; @@ -589,18 +607,20 @@ static int clone_file_block(ext2_filsys fs, return 0; } -static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf) +static int clone_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf) { + ext2_filsys fs = ctx->fs; errcode_t retval; struct clone_struct cs; cs.errcode = 0; - cs.buf = malloc(fs->blocksize); cs.dir = 0; + cs.ctx = ctx; + cs.buf = malloc(fs->blocksize); if (!cs.buf) return ENOMEM; - if (ext2fs_test_inode_bitmap(inode_dir_map, dp->ino)) + if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dp->ino)) cs.dir = dp->ino; retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf, @@ -620,8 +640,3 @@ static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf) } return 0; } - - - - - diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index 2c52944a..bcd8aa2f 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -40,23 +40,19 @@ * - The inode_bad_map bitmap */ -#include "et/com_err.h" - #include "e2fsck.h" #include "problem.h" /* * Keeps track of how many times an inode is referenced. */ -ext2_icount_t inode_count = 0; - -static void deallocate_inode(ext2_filsys fs, ino_t ino, +static void deallocate_inode(e2fsck_t ctx, ino_t ino, char* block_buf); -static int process_bad_inode(ext2_filsys fs, ino_t dir, ino_t ino); +static int process_bad_inode(e2fsck_t ctx, ino_t dir, ino_t ino); static int check_dir_block(ext2_filsys fs, struct ext2_db_entry *dir_blocks_info, void *private); -static int allocate_dir_block(ext2_filsys fs, +static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info, char *buf, struct problem_context *pctx); static int update_dir_block(ext2_filsys fs, @@ -67,30 +63,33 @@ static int update_dir_block(ext2_filsys fs, struct check_dir_struct { char *buf; struct problem_context pctx; + e2fsck_t ctx; }; -void pass2(ext2_filsys fs) +void pass2(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; char *buf; struct resource_track rtrack; struct dir_info *dir; - errcode_t retval; - ino_t size; struct check_dir_struct cd; init_resource_track(&rtrack); + clear_problem_context(&cd.pctx); + #ifdef MTRACE mtrace_print("Pass 2"); #endif - if (!preen) - printf("Pass 2: Checking directory structure\n"); - retval = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT, - 0, inode_link_info, &inode_count); - if (retval) { - com_err("ext2fs_create_icount", retval, - "while creating inode_count"); + if (!(ctx->options & E2F_OPT_PREEN)) + fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx); + + cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT, + 0, ctx->inode_link_info, + &ctx->inode_count); + if (cd.pctx.errcode) { + fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx); fatal_error(0); } buf = allocate_memory(fs->blocksize, "directory scan buffer"); @@ -105,33 +104,31 @@ void pass2(ext2_filsys fs) dir->parent = EXT2_ROOT_INO; cd.buf = buf; - clear_problem_context(&cd.pctx); + cd.ctx = ctx; - retval = ext2fs_dblist_iterate(fs->dblist, check_dir_block, &cd); - if (retval) { - com_err("ext2fs_dblist_iterate", retval, - "while iterating through dblist"); + cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block, + &cd); + if (cd.pctx.errcode) { + fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx); fatal_error(0); } free(buf); ext2fs_free_dblist(fs->dblist); - if (inode_bad_map) { - ext2fs_free_inode_bitmap(inode_bad_map); - inode_bad_map = 0; - } - if (tflag > 1) { - printf("Pass 2: "); - print_resource_track(&rtrack); + if (ctx->inode_bad_map) { + ext2fs_free_inode_bitmap(ctx->inode_bad_map); + ctx->inode_bad_map = 0; } + if (ctx->options & E2F_OPT_TIME2) + print_resource_track("Pass 2", &rtrack); } /* * Make sure the first entry in the directory is '.', and that the * directory entry is sane. */ -static int check_dot(ext2_filsys fs, +static int check_dot(e2fsck_t ctx, struct ext2_dir_entry *dirent, ino_t ino, struct problem_context *pctx) { @@ -150,7 +147,7 @@ static int check_dot(ext2_filsys fs, problem = PR_2_DOT_NULL_TERM; if (problem) { - if (fix_problem(fs, problem, pctx)) { + if (fix_problem(ctx, problem, pctx)) { if (dirent->rec_len < 12) dirent->rec_len = 12; dirent->inode = ino; @@ -162,7 +159,7 @@ static int check_dot(ext2_filsys fs, } } if (dirent->inode != ino) { - if (fix_problem(fs, PR_2_BAD_INODE_DOT, pctx)) { + if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) { dirent->inode = ino; status = 1; } @@ -170,9 +167,9 @@ static int check_dot(ext2_filsys fs, if (dirent->rec_len > 12) { new_len = dirent->rec_len - 12; if (new_len > 12) { - preenhalt(fs); + preenhalt(ctx); if (created || - ask("Directory entry for '.' is big. Split", 1)) { + ask(ctx, "Directory entry for '.' is big. Split", 1)) { nextdir = (struct ext2_dir_entry *) ((char *) dirent + 12); dirent->rec_len = 12; @@ -191,7 +188,7 @@ static int check_dot(ext2_filsys fs, * directory entry is sane. We do not check the inode number of '..' * here; this gets done in pass 3. */ -static int check_dotdot(ext2_filsys fs, +static int check_dotdot(e2fsck_t ctx, struct ext2_dir_entry *dirent, struct dir_info *dir, struct problem_context *pctx) { @@ -207,7 +204,7 @@ static int check_dotdot(ext2_filsys fs, problem = PR_2_DOT_DOT_NULL_TERM; if (problem) { - if (fix_problem(fs, problem, pctx)) { + if (fix_problem(ctx, problem, pctx)) { if (dirent->rec_len < 12) dirent->rec_len = 12; /* @@ -232,7 +229,7 @@ static int check_dotdot(ext2_filsys fs, * Check to make sure a directory entry doesn't contain any illegal * characters. */ -static int check_name(ext2_filsys fs, +static int check_name(e2fsck_t ctx, struct ext2_dir_entry *dirent, ino_t dir_ino, struct problem_context *pctx) { @@ -243,7 +240,7 @@ static int check_name(ext2_filsys fs, for ( i = 0; i < dirent->name_len; i++) { if (dirent->name[i] == '/' || dirent->name[i] == '\0') { if (fixup < 0) { - fixup = fix_problem(fs, PR_2_BAD_NAME, pctx); + fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx); } if (fixup) { dirent->name[i] = '.'; @@ -262,19 +259,23 @@ static int check_dir_block(ext2_filsys fs, struct ext2_dir_entry *dirent; int offset = 0; int dir_modified = 0; - errcode_t retval; int dot_state; blk_t block_nr = db->blk; ino_t ino = db->ino; __u16 links; struct check_dir_struct *cd = private; - char *buf = cd->buf; + char *buf; + e2fsck_t ctx; + int problem; + + buf = cd->buf; + ctx = cd->ctx; /* * Make sure the inode is still in use (could have been * deleted in the duplicate/bad blocks pass. */ - if (!(ext2fs_test_inode_bitmap(inode_used_map, ino))) + if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))) return 0; cd->pctx.ino = ino; @@ -285,7 +286,7 @@ static int check_dir_block(ext2_filsys fs, cd->pctx.num = 0; if (db->blk == 0) { - if (allocate_dir_block(fs, db, buf, &cd->pctx)) + if (allocate_dir_block(ctx, db, buf, &cd->pctx)) return 0; block_nr = db->blk; } @@ -300,14 +301,16 @@ static int check_dir_block(ext2_filsys fs, db->blockcnt, ino); #endif - retval = ext2fs_read_dir_block(fs, block_nr, buf); - if (retval) { - com_err(program_name, retval, - "while reading directory block %d", block_nr); + 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); + memset(buf, 0, fs->blocksize); } do { dot_state++; + problem = 0; dirent = (struct ext2_dir_entry *) (buf + offset); cd->pctx.dirent = dirent; cd->pctx.num = offset; @@ -315,7 +318,7 @@ static int check_dir_block(ext2_filsys fs, (dirent->rec_len < 8) || ((dirent->rec_len % 4) != 0) || ((dirent->name_len+8) > dirent->rec_len)) { - if (fix_problem(fs, PR_2_DIR_CORRUPTED, &cd->pctx)) { + if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) { dirent->rec_len = fs->blocksize - offset; dirent->name_len = 0; dirent->inode = 0; @@ -323,28 +326,27 @@ static int check_dir_block(ext2_filsys fs, } else return DIRENT_ABORT; } - if (dirent->name_len > EXT2_NAME_LEN) { - if (fix_problem(fs, PR_2_FILENAME_LONG, &cd->pctx)) { + if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) { dirent->name_len = EXT2_NAME_LEN; dir_modified++; } } if (dot_state == 1) { - if (check_dot(fs, dirent, ino, &cd->pctx)) + if (check_dot(ctx, dirent, ino, &cd->pctx)) dir_modified++; } else if (dot_state == 2) { dir = get_dir_info(ino); if (!dir) { - printf("Internal error: couldn't find dir_info for %lu\n", - ino); + fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx); fatal_error(0); } - if (check_dotdot(fs, dirent, dir, &cd->pctx)) + if (check_dotdot(ctx, dirent, dir, &cd->pctx)) dir_modified++; } else if (dirent->inode == ino) { - if (fix_problem(fs, PR_2_LINK_DOT, &cd->pctx)) { + problem = PR_2_LINK_DOT; + if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) { dirent->inode = 0; dir_modified++; goto next; @@ -353,44 +355,66 @@ static int check_dir_block(ext2_filsys fs, if (!dirent->inode) goto next; - if (check_name(fs, dirent, ino, &cd->pctx)) - dir_modified++; - /* * Make sure the inode listed is a legal one. */ if (((dirent->inode != EXT2_ROOT_INO) && (dirent->inode < EXT2_FIRST_INODE(fs->super))) || (dirent->inode > fs->super->s_inodes_count)) { - if (fix_problem(fs, PR_2_BAD_INO, &cd->pctx)) { - dirent->inode = 0; - dir_modified++; - goto next; - } - } - - /* - * If the inode is unused, offer to clear it. - */ - if (!(ext2fs_test_inode_bitmap(inode_used_map, + problem = PR_2_BAD_INO; + } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, dirent->inode))) { - if (fix_problem(fs, PR_2_UNUSED_INODE, &cd->pctx)) { - dirent->inode = 0; - dir_modified++; - goto next; - } + /* + * If the inode is unused, offer to clear it. + */ + problem = PR_2_UNUSED_INODE; + } else if (ctx->inode_bb_map && + (ext2fs_test_inode_bitmap(ctx->inode_bb_map, + dirent->inode))) { + /* + * If the inode is in a bad block, offer to + * clear it. + */ + problem = PR_2_BB_INODE; + } else if ((dot_state > 2) && + (dirent->name_len == 1) && + (dirent->name[0] == '.')) { + /* + * If there's a '.' entry in anything other + * than the first directory entry, it's a + * duplicate entry that should be removed. + */ + problem = PR_2_DUP_DOT; + } else if ((dot_state > 2) && + (dirent->name_len == 2) && + (dirent->name[0] == '.') && + (dirent->name[1] == '.')) { + /* + * If there's a '..' entry in anything other + * than the second directory entry, it's a + * duplicate entry that should be removed. + */ + problem = PR_2_DUP_DOT_DOT; + } else if ((dot_state > 2) && + (dirent->inode == EXT2_ROOT_INO)) { + /* + * Don't allow links to the root directory. + * We check this specially to make sure we + * catch this error case even if the root + * directory hasn't been created yet. + */ + problem = PR_2_LINK_ROOT; } - /* - * If the inode is in a bad block, offer to clear it. - */ - if (inode_bb_map && - (ext2fs_test_inode_bitmap(inode_bb_map, - dirent->inode))) { - if (fix_problem(fs, PR_2_BB_INODE, &cd->pctx)) { + if (problem) { + if (fix_problem(ctx, problem, &cd->pctx)) { dirent->inode = 0; dir_modified++; goto next; + } else { + ext2fs_unmark_valid(fs); + if (problem == PR_2_BAD_INO) + goto next; } } @@ -400,30 +424,19 @@ static int check_dir_block(ext2_filsys fs, * (We wait until now so that we can display the * pathname to the user.) */ - if (inode_bad_map && - ext2fs_test_inode_bitmap(inode_bad_map, + if (ctx->inode_bad_map && + ext2fs_test_inode_bitmap(ctx->inode_bad_map, dirent->inode)) { - if (process_bad_inode(fs, ino, dirent->inode)) { + if (process_bad_inode(ctx, ino, dirent->inode)) { dirent->inode = 0; dir_modified++; goto next; } } - /* - * Don't allow links to the root directory. We check - * this specially to make sure we catch this error - * case even if the root directory hasn't been created - * yet. - */ - if ((dot_state > 2) && (dirent->inode == EXT2_ROOT_INO)) { - if (fix_problem(fs, PR_2_LINK_ROOT, &cd->pctx)) { - dirent->inode = 0; - dir_modified++; - goto next; - } - } - + if (check_name(ctx, dirent, ino, &cd->pctx)) + dir_modified++; + /* * If this is a directory, then mark its parent in its * dir_info structure. If the parent field is already @@ -432,17 +445,17 @@ static int check_dir_block(ext2_filsys fs, * and ask the user if he/she wants to clear this one. */ if ((dot_state > 2) && - (ext2fs_test_inode_bitmap(inode_dir_map, + (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode))) { subdir = get_dir_info(dirent->inode); if (!subdir) { - printf("INTERNAL ERROR: missing dir %u\n", - dirent->inode); + cd->pctx.ino = dirent->inode; + fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx); fatal_error(0); } if (subdir->parent) { cd->pctx.ino2 = subdir->parent; - if (fix_problem(fs, PR_2_LINK_DIR, + if (fix_problem(ctx, PR_2_LINK_DIR, &cd->pctx)) { dirent->inode = 0; dir_modified++; @@ -453,10 +466,11 @@ static int check_dir_block(ext2_filsys fs, subdir->parent = ino; } - ext2fs_icount_increment(inode_count, dirent->inode, &links); + ext2fs_icount_increment(ctx->inode_count, dirent->inode, + &links); if (links > 1) - fs_links_count++; - fs_total_count++; + ctx->fs_links_count++; + ctx->fs_total_count++; next: offset += dirent->rec_len; } while (offset < fs->blocksize); @@ -464,15 +478,17 @@ static int check_dir_block(ext2_filsys fs, printf("\n"); #endif if (offset != fs->blocksize) { - printf("Final rec_len is %d, should be %d\n", - dirent->rec_len, - dirent->rec_len - fs->blocksize + offset); + cd->pctx.num = dirent->rec_len - fs->blocksize + offset; + if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) { + dirent->rec_len = cd->pctx.num; + dir_modified++; + } } if (dir_modified) { - retval = ext2fs_write_dir_block(fs, block_nr, buf); - if (retval) { - com_err(program_name, retval, - "while writing directory block %d", block_nr); + 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); } ext2fs_mark_changed(fs); } @@ -488,9 +504,11 @@ static int deallocate_inode_block(ext2_filsys fs, int blockcnt, void *private) { + e2fsck_t ctx = (e2fsck_t) private; + if (!*block_nr) return 0; - ext2fs_unmark_block_bitmap(block_found_map, *block_nr); + ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr); ext2fs_unmark_block_bitmap(fs->block_map, *block_nr); return 0; } @@ -498,26 +516,29 @@ static int deallocate_inode_block(ext2_filsys fs, /* * This fuction deallocates an inode */ -static void deallocate_inode(ext2_filsys fs, ino_t ino, +static void deallocate_inode(e2fsck_t ctx, ino_t ino, char* block_buf) { - errcode_t retval; + ext2_filsys fs = ctx->fs; struct ext2_inode inode; - - ext2fs_icount_store(inode_link_info, ino, 0); + struct problem_context pctx; + + ext2fs_icount_store(ctx->inode_link_info, ino, 0); e2fsck_read_inode(fs, ino, &inode, "deallocate_inode"); inode.i_links_count = 0; inode.i_dtime = time(0); e2fsck_write_inode(fs, ino, &inode, "deallocate_inode"); + clear_problem_context(&pctx); + pctx.ino = ino; /* * Fix up the bitmaps... */ - read_bitmaps(fs); - ext2fs_unmark_inode_bitmap(inode_used_map, ino); - ext2fs_unmark_inode_bitmap(inode_dir_map, ino); - if (inode_bad_map) - ext2fs_unmark_inode_bitmap(inode_bad_map, ino); + 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) + ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino); ext2fs_unmark_inode_bitmap(fs->inode_map, ino); ext2fs_mark_ib_dirty(fs); @@ -525,16 +546,17 @@ static void deallocate_inode(ext2_filsys fs, ino_t ino, return; ext2fs_mark_bb_dirty(fs); - retval = ext2fs_block_iterate(fs, ino, 0, block_buf, - deallocate_inode_block, 0); - if (retval) - com_err("deallocate_inode", retval, - "while calling ext2fs_block_iterate for inode %d", - ino); + pctx.errcode = ext2fs_block_iterate(fs, ino, 0, block_buf, + deallocate_inode_block, ctx); + if (pctx.errcode) { + fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx); + fatal_error(0); + } } -static int process_bad_inode(ext2_filsys fs, ino_t dir, ino_t ino) +static int process_bad_inode(e2fsck_t ctx, ino_t dir, ino_t ino) { + ext2_filsys fs = ctx->fs; struct ext2_inode inode; int inode_modified = 0; unsigned char *frag, *fsize; @@ -551,31 +573,31 @@ static int process_bad_inode(ext2_filsys fs, ino_t dir, ino_t ino) !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(fs, PR_2_BAD_MODE, &pctx)) { - deallocate_inode(fs, ino, 0); + if (fix_problem(ctx, PR_2_BAD_MODE, &pctx)) { + deallocate_inode(ctx, ino, 0); return 1; } } if (LINUX_S_ISCHR(inode.i_mode) && !e2fsck_pass1_check_device_inode(&inode)) { - if (fix_problem(fs, PR_2_BAD_CHAR_DEV, &pctx)) { - deallocate_inode(fs, ino, 0); + if (fix_problem(ctx, PR_2_BAD_CHAR_DEV, &pctx)) { + deallocate_inode(ctx, ino, 0); return 1; } } if (LINUX_S_ISBLK(inode.i_mode) && !e2fsck_pass1_check_device_inode(&inode)) { - if (fix_problem(fs, PR_2_BAD_BLOCK_DEV, &pctx)) { - deallocate_inode(fs, ino, 0); + if (fix_problem(ctx, PR_2_BAD_BLOCK_DEV, &pctx)) { + deallocate_inode(ctx, ino, 0); return 1; } } if (inode.i_faddr && - fix_problem(fs, PR_2_FADDR_ZERO, &pctx)) { + fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) { inode.i_faddr = 0; inode_modified++; } @@ -598,7 +620,7 @@ static int process_bad_inode(ext2_filsys fs, ino_t dir, ino_t ino) } if (frag && *frag) { pctx.num = *frag; - if (fix_problem(fs, PR_2_FRAG_ZERO, &pctx)) { + if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) { *frag = 0; inode_modified++; } @@ -606,7 +628,7 @@ static int process_bad_inode(ext2_filsys fs, ino_t dir, ino_t ino) } if (fsize && *fsize) { pctx.num = *fsize; - if (fix_problem(fs, PR_2_FSIZE_ZERO, &pctx)) { + if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) { *fsize = 0; inode_modified++; } @@ -614,12 +636,12 @@ static int process_bad_inode(ext2_filsys fs, ino_t dir, ino_t ino) } if (inode.i_file_acl && - fix_problem(fs, PR_2_FILE_ACL_ZERO, &pctx)) { + fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) { inode.i_file_acl = 0; inode_modified++; } if (inode.i_dir_acl && - fix_problem(fs, PR_2_DIR_ACL_ZERO, &pctx)) { + fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) { inode.i_dir_acl = 0; inode_modified++; } @@ -635,34 +657,34 @@ static int process_bad_inode(ext2_filsys fs, ino_t dir, ino_t ino) * a "hole" in it, or if a directory has a illegal block number * that was zeroed out and now needs to be replaced. */ -static int allocate_dir_block(ext2_filsys fs, +static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db, char *buf, struct problem_context *pctx) { + ext2_filsys fs = ctx->fs; blk_t blk; char *block; struct ext2_inode inode; - errcode_t retval; - if (fix_problem(fs, PR_2_DIRECTORY_HOLE, pctx) == 0) + if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0) return 1; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ - read_bitmaps(fs); + read_bitmaps(ctx); /* * First, find a free block */ - retval = ext2fs_new_block(fs, 0, block_found_map, &blk); - if (retval) { - com_err("allocate_dir_block", retval, - "while trying to fill a hole in a directory inode"); + pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); + if (pctx->errcode) { + pctx->str = "ext2fs_new_block"; + fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); return 1; } - ext2fs_mark_block_bitmap(block_found_map, blk); + ext2fs_mark_block_bitmap(ctx->block_found_map, blk); ext2fs_mark_block_bitmap(fs->block_map, blk); ext2fs_mark_bb_dirty(fs); @@ -670,22 +692,22 @@ static int allocate_dir_block(ext2_filsys fs, * Now let's create the actual data block for the inode */ if (db->blockcnt) - retval = ext2fs_new_dir_block(fs, 0, 0, &block); + pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block); else - retval = ext2fs_new_dir_block(fs, db->ino, EXT2_ROOT_INO, - &block); + pctx->errcode = ext2fs_new_dir_block(fs, db->ino, + EXT2_ROOT_INO, &block); - if (retval) { - com_err("allocate_dir_block", retval, - "while creating new directory block"); + if (pctx->errcode) { + pctx->str = "ext2fs_new_dir_block"; + fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); return 1; } - retval = ext2fs_write_dir_block(fs, blk, block); + pctx->errcode = ext2fs_write_dir_block(fs, blk, block); free(block); - if (retval) { - com_err("allocate_dir_block", retval, - "while writing an empty directory block"); + if (pctx->errcode) { + pctx->str = "ext2fs_write_dir_block"; + fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); return 1; } @@ -702,11 +724,11 @@ static int allocate_dir_block(ext2_filsys fs, * Finally, update the block pointers for the inode */ db->blk = blk; - retval = ext2fs_block_iterate(fs, db->ino, BLOCK_FLAG_HOLE, + pctx->errcode = ext2fs_block_iterate(fs, db->ino, BLOCK_FLAG_HOLE, 0, update_dir_block, db); - if (retval) { - com_err("allocate_dir_block", retval, - "while calling ext2fs_block_iterate"); + if (pctx->errcode) { + pctx->str = "ext2fs_block_iterate"; + fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); return 1; } diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c index 2f97aa4c..7d7c6495 100644 --- a/e2fsck/pass3.c +++ b/e2fsck/pass3.c @@ -37,18 +37,17 @@ #ifdef HAVE_ERRNO_H #include #endif -#include "et/com_err.h" #include "e2fsck.h" #include "problem.h" -static void check_root(ext2_filsys fs); -static void check_directory(ext2_filsys fs, struct dir_info *dir, +static void check_root(e2fsck_t ctx); +static void check_directory(e2fsck_t ctx, struct dir_info *dir, struct problem_context *pctx); -static ino_t get_lost_and_found(ext2_filsys fs); -static void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent); -static errcode_t adjust_inode_count(ext2_filsys fs, ino_t ino, int adj); -static errcode_t expand_directory(ext2_filsys fs, ino_t dir); +static ino_t get_lost_and_found(e2fsck_t ctx); +static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ino_t parent); +static errcode_t adjust_inode_count(e2fsck_t ctx, ino_t ino, int adj); +static errcode_t expand_directory(e2fsck_t ctx, ino_t dir); static ino_t lost_and_found = 0; static int bad_lost_and_found = 0; @@ -56,120 +55,120 @@ static int bad_lost_and_found = 0; static ext2fs_inode_bitmap inode_loop_detect; static ext2fs_inode_bitmap inode_done_map; -void pass3(ext2_filsys fs) +void pass3(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; int i; - errcode_t retval; struct resource_track rtrack; struct problem_context pctx; struct dir_info *dir; init_resource_track(&rtrack); + clear_problem_context(&pctx); + #ifdef MTRACE mtrace_print("Pass 3"); #endif - if (!preen) - printf("Pass 3: Checking directory connectivity\n"); + if (!(ctx->options & E2F_OPT_PREEN)) + fix_problem(ctx, PR_3_PASS_HEADER, &pctx); /* * Allocate some bitmaps to do loop detection. */ - retval = ext2fs_allocate_inode_bitmap(fs, - "inode loop detection bitmap", - &inode_loop_detect); - if (retval) { - com_err("ext2fs_allocate_inode_bitmap", retval, - "while allocating inode_loop_detect"); + pctx.errcode = ext2fs_allocate_inode_bitmap(fs, + "inode loop detection bitmap", &inode_loop_detect); + if (pctx.errcode) { + pctx.num = 1; + fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx); fatal_error(0); } - retval = ext2fs_allocate_inode_bitmap(fs, "inode done bitmap", - &inode_done_map); - if (retval) { - com_err("ext2fs_allocate_inode_bitmap", retval, - "while allocating inode_done_map"); + pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "inode done bitmap", + &inode_done_map); + if (pctx.errcode) { + pctx.num = 2; + fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx); fatal_error(0); } - if (tflag) { - printf("Peak memory: "); - print_resource_track(&global_rtrack); - } + if (ctx->options & E2F_OPT_TIME) + print_resource_track("Peak memory", &ctx->global_rtrack); - check_root(fs); + check_root(ctx); ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO); - clear_problem_context(&pctx); for (i=0; (dir = dir_info_iter(&i)) != 0;) { - if (ext2fs_test_inode_bitmap(inode_dir_map, dir->ino)) - check_directory(fs, dir, &pctx); + if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino)) + check_directory(ctx, dir, &pctx); } free_dir_info(fs); ext2fs_free_inode_bitmap(inode_loop_detect); ext2fs_free_inode_bitmap(inode_done_map); - if (tflag > 1) { - printf("Pass 3: "); - print_resource_track(&rtrack); - } + if (ctx->options & E2F_OPT_TIME2) + print_resource_track("Pass 3", &rtrack); } /* * This makes sure the root inode is present; if not, we ask if the * user wants us to create it. Not creating it is a fatal error. */ -static void check_root(ext2_filsys fs) +static void check_root(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; blk_t blk; - errcode_t retval; struct ext2_inode inode; char * block; + struct problem_context pctx; - if (ext2fs_test_inode_bitmap(inode_used_map, EXT2_ROOT_INO)) { + clear_problem_context(&pctx); + + if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) { /* * If the root inode is a directory, die here. The * user must have answered 'no' in pass1 when we * offered to clear it. */ - if (!(ext2fs_test_inode_bitmap(inode_dir_map, EXT2_ROOT_INO))) + if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map, + EXT2_ROOT_INO))) fatal_error("Root inode not directory"); return; } - if (!fix_problem(fs, PR_3_NO_ROOT_INODE, 0)) + if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) fatal_error("Cannot proceed without a root inode."); - read_bitmaps(fs); + read_bitmaps(ctx); /* * First, find a free block */ - retval = ext2fs_new_block(fs, 0, block_found_map, &blk); - if (retval) { - com_err("ext2fs_new_block", retval, - "while trying to create root directory"); + pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); + if (pctx.errcode) { + pctx.str = "ext2fs_new_block"; + fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); fatal_error(0); } - ext2fs_mark_block_bitmap(block_found_map, blk); + ext2fs_mark_block_bitmap(ctx->block_found_map, blk); ext2fs_mark_block_bitmap(fs->block_map, blk); ext2fs_mark_bb_dirty(fs); /* * Now let's create the actual data block for the inode */ - retval = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, - &block); - if (retval) { - com_err("ext2fs_new_dir_block", retval, - "while creating new root directory"); + pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, + &block); + if (pctx.errcode) { + pctx.str = "ext2fs_new_dir_block"; + fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); fatal_error(0); } - retval = ext2fs_write_dir_block(fs, blk, block); - if (retval) { - com_err("ext2fs_write_dir_block", retval, - "while writing the root directory block"); + pctx.errcode = ext2fs_write_dir_block(fs, blk, block); + if (pctx.errcode) { + pctx.str = "ext2fs_write_dir_block"; + fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); fatal_error(0); } free(block); @@ -188,10 +187,10 @@ static void check_root(ext2_filsys fs) /* * Write out the inode. */ - retval = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode); - if (retval) { - com_err("ext2fs_write_inode", retval, - "While trying to create /lost+found"); + pctx.errcode = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode); + if (pctx.errcode) { + pctx.str = "ext2fs_write_inode"; + fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); fatal_error(0); } @@ -199,11 +198,11 @@ static void check_root(ext2_filsys fs) * Miscellaneous bookkeeping... */ add_dir_info(fs, EXT2_ROOT_INO, EXT2_ROOT_INO); - ext2fs_icount_store(inode_count, EXT2_ROOT_INO, 2); - ext2fs_icount_store(inode_link_info, EXT2_ROOT_INO, 2); + ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2); + ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2); - ext2fs_mark_inode_bitmap(inode_used_map, EXT2_ROOT_INO); - ext2fs_mark_inode_bitmap(inode_dir_map, EXT2_ROOT_INO); + ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO); + ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO); ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO); ext2fs_mark_ib_dirty(fs); } @@ -216,9 +215,10 @@ static void check_root(ext2_filsys fs) * a loop, we treat that as a disconnected directory and offer to * reparent it to lost+found. */ -static void check_directory(ext2_filsys fs, struct dir_info *dir, +static void check_directory(e2fsck_t ctx, struct dir_info *dir, struct problem_context *pctx) { + ext2_filsys fs = ctx->fs; struct dir_info *p = dir; ext2fs_clear_inode_bitmap(inode_loop_detect); @@ -258,12 +258,12 @@ static void check_directory(ext2_filsys fs, struct dir_info *dir, * inode; offer to reconnect it to lost+found. */ pctx->ino = p->ino; - if (fix_problem(fs, PR_3_UNCONNECTED_DIR, pctx)) { - if (reconnect_file(fs, p->ino)) + if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) { + if (reconnect_file(ctx, p->ino)) ext2fs_unmark_valid(fs); else { p->parent = lost_and_found; - fix_dotdot(fs, p, lost_and_found); + fix_dotdot(ctx, p, lost_and_found); } } @@ -276,8 +276,8 @@ check_dot_dot: pctx->ino = dir->ino; pctx->ino2 = dir->dotdot; pctx->dir = dir->parent; - if (fix_problem(fs, PR_3_BAD_DOT_DOT, pctx)) - fix_dotdot(fs, dir, dir->parent); + if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx)) + fix_dotdot(ctx, dir, dir->parent); } } @@ -285,56 +285,61 @@ check_dot_dot: * This routine gets the lost_and_found inode, making it a directory * if necessary */ -ino_t get_lost_and_found(ext2_filsys fs) +ino_t get_lost_and_found(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; ino_t ino; blk_t blk; errcode_t retval; struct ext2_inode inode; char * block; const char name[] = "lost+found"; + struct problem_context pctx; + clear_problem_context(&pctx); + retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (!retval) return ino; - if (retval != ENOENT) - printf("Error while trying to find /lost+found: %s", - error_message(retval)); - if (!fix_problem(fs, PR_3_NO_LF_DIR, 0)) + if (retval != ENOENT) { + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); + } + if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ - read_bitmaps(fs); + read_bitmaps(ctx); /* * First, find a free block */ - retval = ext2fs_new_block(fs, 0, block_found_map, &blk); + retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); if (retval) { - com_err("ext2fs_new_block", retval, - "while trying to create /lost+found directory"); + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } - ext2fs_mark_block_bitmap(block_found_map, blk); + ext2fs_mark_block_bitmap(ctx->block_found_map, blk); ext2fs_mark_block_bitmap(fs->block_map, blk); ext2fs_mark_bb_dirty(fs); /* * Next find a free inode. */ - retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040755, inode_used_map, - &ino); + retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040755, + ctx->inode_used_map, &ino); if (retval) { - com_err("ext2fs_new_inode", retval, - "while trying to create /lost+found directory"); + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } - ext2fs_mark_inode_bitmap(inode_used_map, ino); - ext2fs_mark_inode_bitmap(inode_dir_map, ino); + ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); + ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); ext2fs_mark_inode_bitmap(fs->inode_map, ino); ext2fs_mark_ib_dirty(fs); @@ -343,16 +348,16 @@ ino_t get_lost_and_found(ext2_filsys fs) */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { - com_err("ext2fs_new_dir_block", retval, - "while creating new directory block"); + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block(fs, blk, block); free(block); if (retval) { - com_err("ext2fs_write_dir_block", retval, - "while writing the directory block for /lost+found"); + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } @@ -370,18 +375,19 @@ ino_t get_lost_and_found(ext2_filsys fs) /* * Next, write out the inode. */ - retval = ext2fs_write_inode(fs, ino, &inode); - if (retval) { - com_err("ext2fs_write_inode", retval, - "While trying to create /lost+found"); + pctx.errcode = ext2fs_write_inode(fs, ino, &inode); + if (pctx.errcode) { + pctx.str = "ext2fs_write_inode"; + fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Finally, create the directory link */ - retval = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, 0); - if (retval) { - com_err("ext2fs_link", retval, "While creating /lost+found"); + pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, 0); + if (pctx.errcode) { + pctx.str = "ext2fs_link"; + fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } @@ -389,9 +395,9 @@ ino_t get_lost_and_found(ext2_filsys fs) * Miscellaneous bookkeeping that needs to be kept straight. */ add_dir_info(fs, ino, EXT2_ROOT_INO); - adjust_inode_count(fs, EXT2_ROOT_INO, +1); - ext2fs_icount_store(inode_count, ino, 2); - ext2fs_icount_store(inode_link_info, ino, 2); + adjust_inode_count(ctx, EXT2_ROOT_INO, +1); + ext2fs_icount_store(ctx->inode_count, ino, 2); + ext2fs_icount_store(ctx->inode_link_info, ino, 2); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif @@ -401,44 +407,45 @@ ino_t get_lost_and_found(ext2_filsys fs) /* * This routine will connect a file to lost+found */ -int reconnect_file(ext2_filsys fs, ino_t inode) +int reconnect_file(e2fsck_t ctx, ino_t inode) { + ext2_filsys fs = ctx->fs; errcode_t retval; char name[80]; - + struct problem_context pctx; + + clear_problem_context(&pctx); + pctx.ino = inode; + + if (!bad_lost_and_found && !lost_and_found) { + lost_and_found = get_lost_and_found(ctx); + if (!lost_and_found) + bad_lost_and_found++; + } if (bad_lost_and_found) { - printf("Bad or nonexistent /lost+found. Cannot reconnect.\n"); + fix_problem(ctx, PR_3_NO_LPF, &pctx); return 1; } - if (!lost_and_found) { - lost_and_found = get_lost_and_found(fs); - if (!lost_and_found) { - printf("Bad or nonexistent /lost+found. Cannot reconnect.\n"); - bad_lost_and_found++; - return 1; - } - } - + sprintf(name, "#%lu", inode); retval = ext2fs_link(fs, lost_and_found, name, inode, 0); if (retval == EXT2_ET_DIR_NO_SPACE) { - if (!fix_problem(fs, PR_3_EXPAND_LF_DIR, 0)) + if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx)) return 1; - retval = expand_directory(fs, lost_and_found); + retval = expand_directory(ctx, lost_and_found); if (retval) { - printf("Could not expand /lost+found: %s\n", - error_message(retval)); + pctx.errcode = retval; + fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx); return 1; } retval = ext2fs_link(fs, lost_and_found, name, inode, 0); } if (retval) { - printf("Could not reconnect %lu: %s\n", inode, - error_message(retval)); + pctx.errcode = retval; + fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx); return 1; } - - adjust_inode_count(fs, inode, +1); + adjust_inode_count(ctx, inode, +1); return 0; } @@ -446,8 +453,9 @@ int reconnect_file(ext2_filsys fs, ino_t inode) /* * Utility routine to adjust the inode counts on an inode. */ -static errcode_t adjust_inode_count(ext2_filsys fs, ino_t ino, int adj) +static errcode_t adjust_inode_count(e2fsck_t ctx, ino_t ino, int adj) { + ext2_filsys fs = ctx->fs; errcode_t retval; struct ext2_inode inode; @@ -465,11 +473,11 @@ static errcode_t adjust_inode_count(ext2_filsys fs, ino_t ino, int adj) inode.i_links_count += adj; if (adj == 1) { - ext2fs_icount_increment(inode_count, ino, 0); - ext2fs_icount_increment(inode_link_info, ino, 0); + ext2fs_icount_increment(ctx->inode_count, ino, 0); + ext2fs_icount_increment(ctx->inode_link_info, ino, 0); } else { - ext2fs_icount_decrement(inode_count, ino, 0); - ext2fs_icount_decrement(inode_link_info, ino, 0); + ext2fs_icount_decrement(ctx->inode_count, ino, 0); + ext2fs_icount_decrement(ctx->inode_link_info, ino, 0); } @@ -487,6 +495,7 @@ struct fix_dotdot_struct { ext2_filsys fs; ino_t parent; int done; + e2fsck_t ctx; }; static int fix_dotdot_proc(struct ext2_dir_entry *dirent, @@ -497,35 +506,42 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent, { struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) private; errcode_t retval; + struct problem_context pctx; if (dirent->name_len != 2) return 0; if (strncmp(dirent->name, "..", 2)) return 0; - - retval = adjust_inode_count(fp->fs, dirent->inode, -1); - if (retval) - printf("Error while adjusting inode count on inode %u\n", - dirent->inode); - retval = adjust_inode_count(fp->fs, fp->parent, 1); - if (retval) - printf("Error while adjusting inode count on inode %lu\n", - fp->parent); + clear_problem_context(&pctx); + + retval = adjust_inode_count(fp->ctx, dirent->inode, -1); + if (retval) { + pctx.errcode = retval; + fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); + } + retval = adjust_inode_count(fp->ctx, fp->parent, 1); + if (retval) { + pctx.errcode = retval; + fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); + } dirent->inode = fp->parent; fp->done++; return DIRENT_ABORT | DIRENT_CHANGED; } -static void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent) +static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ino_t parent) { + ext2_filsys fs = ctx->fs; errcode_t retval; struct fix_dotdot_struct fp; + struct problem_context pctx; fp.fs = fs; fp.parent = parent; fp.done = 0; + fp.ctx = ctx; #if 0 printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent); @@ -534,9 +550,11 @@ static void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent) retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY, 0, fix_dotdot_proc, &fp); if (retval || !fp.done) { - printf("Couldn't fix parent of inode %lu: %s\n\n", - dir->ino, retval ? error_message(retval) : - "Couldn't find parent direntory entry"); + clear_problem_context(&pctx); + pctx.ino = dir->ino; + pctx.errcode = retval; + fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR : + PR_3_FIX_PARENT_NOFIND, &pctx); ext2fs_unmark_valid(fs); } dir->dotdot = parent; @@ -552,6 +570,7 @@ static void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent) struct expand_dir_struct { int done; errcode_t err; + e2fsck_t ctx; }; static int expand_dir_proc(ext2_filsys fs, @@ -564,12 +583,16 @@ static int expand_dir_proc(ext2_filsys fs, static blk_t last_blk = 0; char *block; errcode_t retval; + e2fsck_t ctx; + + ctx = es->ctx; if (*blocknr) { last_blk = *blocknr; return 0; } - retval = ext2fs_new_block(fs, last_blk, block_found_map, &new_blk); + retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map, + &new_blk); if (retval) { es->err = retval; return BLOCK_ABORT; @@ -596,7 +619,7 @@ static int expand_dir_proc(ext2_filsys fs, } free(block); *blocknr = new_blk; - ext2fs_mark_block_bitmap(block_found_map, new_blk); + ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk); ext2fs_mark_block_bitmap(fs->block_map, new_blk); ext2fs_mark_bb_dirty(fs); if (es->done) @@ -605,8 +628,9 @@ static int expand_dir_proc(ext2_filsys fs, return BLOCK_CHANGED; } -static errcode_t expand_directory(ext2_filsys fs, ino_t dir) +static errcode_t expand_directory(e2fsck_t ctx, ino_t dir) { + ext2_filsys fs = ctx->fs; errcode_t retval; struct expand_dir_struct es; struct ext2_inode inode; @@ -620,6 +644,7 @@ static errcode_t expand_directory(ext2_filsys fs, ino_t dir) es.done = 0; es.err = 0; + es.ctx = ctx; retval = ext2fs_block_iterate(fs, dir, BLOCK_FLAG_APPEND, 0, expand_dir_proc, &es); @@ -643,6 +668,3 @@ static errcode_t expand_directory(ext2_filsys fs, ino_t dir) return 0; } - - - diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c index 627b5548..f5784cfd 100644 --- a/e2fsck/pass4.c +++ b/e2fsck/pass4.c @@ -22,8 +22,9 @@ * This subroutine returns 1 then the caller shouldn't bother with the * rest of the pass 4 tests. */ -static int disconnect_inode(ext2_filsys fs, ino_t i) +static int disconnect_inode(e2fsck_t ctx, ino_t i) { + ext2_filsys fs = ctx->fs; struct ext2_inode inode; struct problem_context pctx; @@ -37,8 +38,8 @@ static int disconnect_inode(ext2_filsys fs, ino_t i) /* * This is a zero-length file; prompt to delete it... */ - if (fix_problem(fs, PR_4_ZERO_LEN_INODE, &pctx)) { - ext2fs_icount_store(inode_link_info, i, 0); + if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) { + ext2fs_icount_store(ctx->inode_link_info, i, 0); inode.i_links_count = 0; inode.i_dtime = time(0); e2fsck_write_inode(fs, i, &inode, @@ -46,9 +47,9 @@ static int disconnect_inode(ext2_filsys fs, ino_t i) /* * Fix up the bitmaps... */ - read_bitmaps(fs); - ext2fs_unmark_inode_bitmap(inode_used_map, i); - ext2fs_unmark_inode_bitmap(inode_dir_map, i); + 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); ext2fs_mark_ib_dirty(fs); return 0; @@ -58,8 +59,8 @@ static int disconnect_inode(ext2_filsys fs, ino_t i) /* * Prompt to reconnect. */ - if (fix_problem(fs, PR_4_UNATTACHED_INODE, &pctx)) { - if (reconnect_file(fs, i)) + if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) { + if (reconnect_file(ctx, i)) ext2fs_unmark_valid(fs); } else { /* @@ -74,8 +75,9 @@ static int disconnect_inode(ext2_filsys fs, ino_t i) } -void pass4(ext2_filsys fs) +void pass4(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; ino_t i; struct ext2_inode inode; struct resource_track rtrack; @@ -88,52 +90,50 @@ void pass4(ext2_filsys fs) mtrace_print("Pass 4"); #endif - if (!preen) - printf("Pass 4: Checking reference counts\n"); clear_problem_context(&pctx); + + if (!(ctx->options & E2F_OPT_PREEN)) + fix_problem(ctx, PR_4_PASS_HEADER, &pctx); + for (i=1; i <= fs->super->s_inodes_count; i++) { if (i == EXT2_BAD_INO || (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super))) continue; - if (!(ext2fs_test_inode_bitmap(inode_used_map, i)) || - (inode_bb_map && - ext2fs_test_inode_bitmap(inode_bb_map, i))) + if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) || + (ctx->inode_bb_map && + ext2fs_test_inode_bitmap(ctx->inode_bb_map, i))) continue; - ext2fs_icount_fetch(inode_link_info, i, &link_count); - ext2fs_icount_fetch(inode_count, i, &link_counted); + ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); + ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); if (link_counted == 0) { - if (disconnect_inode(fs, i)) + if (disconnect_inode(ctx, i)) continue; - ext2fs_icount_fetch(inode_link_info, i, &link_count); - ext2fs_icount_fetch(inode_count, i, &link_counted); + ext2fs_icount_fetch(ctx->inode_link_info, i, + &link_count); + ext2fs_icount_fetch(ctx->inode_count, i, + &link_counted); } if (link_counted != link_count) { e2fsck_read_inode(fs, i, &inode, "pass4"); pctx.ino = i; pctx.inode = &inode; if (link_count != inode.i_links_count) { - printf("WARNING: PROGRAMMING BUG IN E2FSCK!\n"); - printf("\tOR SOME BONEHEAD (YOU) IS CHECKING " - "A MOUNTED (LIVE) FILESYSTEM.\n"); - printf("inode_link_info[%ld] is %u, " - "inode.i_links_count is %d. " - "They should be the same!\n", - i, link_count, - inode.i_links_count); + pctx.num = link_count; + fix_problem(ctx, + PR_4_INCONSISTENT_COUNT, &pctx); } pctx.num = link_counted; - if (fix_problem(fs, PR_4_BAD_REF_COUNT, &pctx)) { + if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) { inode.i_links_count = link_counted; e2fsck_write_inode(fs, i, &inode, "pass4"); } } } - ext2fs_free_icount(inode_link_info); inode_link_info = 0; - ext2fs_free_icount(inode_count); inode_count = 0; - ext2fs_free_inode_bitmap(inode_bb_map); - if (tflag > 1) { - printf("Pass 4: "); - print_resource_track(&rtrack); - } + ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; + 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->options & E2F_OPT_TIME2) + print_resource_track("Pass 4", &rtrack); } diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c index def492a9..499c92ce 100644 --- a/e2fsck/pass5.c +++ b/e2fsck/pass5.c @@ -10,21 +10,18 @@ * */ -#include "et/com_err.h" - #include "e2fsck.h" +#include "problem.h" -static void check_block_bitmaps(ext2_filsys fs); -static void check_inode_bitmaps(ext2_filsys fs); -static void check_inode_end(ext2_filsys fs); -static void check_block_end(ext2_filsys fs); +static void check_block_bitmaps(e2fsck_t ctx); +static void check_inode_bitmaps(e2fsck_t ctx); +static void check_inode_end(e2fsck_t ctx); +static void check_block_end(e2fsck_t ctx); -static int do_fix = -1; -static const char *fix_question = "Fix summary information"; - -void pass5(ext2_filsys fs) +void pass5(e2fsck_t ctx) { struct resource_track rtrack; + struct problem_context pctx; #ifdef MTRACE mtrace_print("Pass 5"); @@ -32,28 +29,32 @@ void pass5(ext2_filsys fs) init_resource_track(&rtrack); - if (!preen) - printf("Pass 5: Checking group summary information\n"); + clear_problem_context(&pctx); - read_bitmaps(fs); + if (!(ctx->options & E2F_OPT_PREEN)) + fix_problem(ctx, PR_5_PASS_HEADER, &pctx); - check_block_bitmaps(fs); - check_inode_bitmaps(fs); - check_inode_end(fs); - check_block_end(fs); + read_bitmaps(ctx); - ext2fs_free_inode_bitmap(inode_used_map); - ext2fs_free_inode_bitmap(inode_dir_map); - ext2fs_free_block_bitmap(block_found_map); + check_block_bitmaps(ctx); + check_inode_bitmaps(ctx); + check_inode_end(ctx); + check_block_end(ctx); - if (tflag > 1) { - printf("Pass 5: "); - print_resource_track(&rtrack); - } + ext2fs_free_inode_bitmap(ctx->inode_used_map); + ctx->inode_used_map = 0; + ext2fs_free_inode_bitmap(ctx->inode_dir_map); + ctx->inode_dir_map = 0; + ext2fs_free_block_bitmap(ctx->block_found_map); + ctx->block_found_map = 0; + + if (ctx->options & E2F_OPT_TIME2) + print_resource_track("Pass 5", &rtrack); } -static void check_block_bitmaps(ext2_filsys fs) +static void check_block_bitmaps(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; blk_t i; int *free_array; int group = 0; @@ -61,21 +62,25 @@ static void check_block_bitmaps(ext2_filsys fs) int free_blocks = 0; int group_free = 0; int actual, bitmap; - const char *print_header = "Block bitmap differences:"; + struct problem_context pctx; + int problem, fixit; + errcode_t retval; + clear_problem_context(&pctx); free_array = allocate_memory(fs->group_desc_count * sizeof(int), "free block count array"); if ((fs->super->s_first_data_block < - ext2fs_get_block_bitmap_start(block_found_map)) || + ext2fs_get_block_bitmap_start(ctx->block_found_map)) || (fs->super->s_blocks_count-1 > - ext2fs_get_block_bitmap_end(block_found_map))) { - printf("PROGRAMMING ERROR: filesystem endpoints (%d, %d)\n\t" - "don't match block_found_map endpoints (%d, %d).\n", - fs->super->s_first_data_block, - fs->super->s_blocks_count -1, - ext2fs_get_block_bitmap_start(block_found_map), - ext2fs_get_block_bitmap_end(block_found_map)); + ext2fs_get_block_bitmap_end(ctx->block_found_map))) { + pctx.num = 1; + pctx.blk = fs->super->s_first_data_block; + pctx.blk2 = fs->super->s_blocks_count -1; + pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map); + pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map); + fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); + /* fatal */ fatal_error(0); } @@ -83,56 +88,40 @@ static void check_block_bitmaps(ext2_filsys fs) ext2fs_get_block_bitmap_start(fs->block_map)) || (fs->super->s_blocks_count-1 > ext2fs_get_block_bitmap_end(fs->block_map))) { - printf("PROGRAMMING ERROR: filesystem endpoints (%d, %d)\n\t" - "don't match fs->block_map endpoints (%d, %d).\n", - fs->super->s_first_data_block, - fs->super->s_blocks_count -1, - ext2fs_get_block_bitmap_start(fs->block_map), - ext2fs_get_block_bitmap_end(fs->block_map)); + pctx.num = 2; + pctx.blk = fs->super->s_first_data_block; + pctx.blk2 = fs->super->s_blocks_count -1; + pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map); + pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map); + fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); + /* fatal */ fatal_error(0); } - +redo_counts: for (i = fs->super->s_first_data_block; i < fs->super->s_blocks_count; i++) { - actual = ext2fs_fast_test_block_bitmap(block_found_map, i); + actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i); bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i); if (actual == bitmap) goto do_counts; - - if (do_fix < 0) - do_fix = ask(fix_question, 1); - if (!preen && print_header) { - printf(print_header); - print_header = 0; - } + if (!actual && bitmap) { /* * Block not used, but marked in use in the bitmap. */ - if (!preen) - printf(" -%u", i); - if (do_fix) - ext2fs_unmark_block_bitmap(fs->block_map, - i); + problem = PR_5_UNUSED_BLOCK; } else { /* * Block used, but not marked in use in the bitmap. */ - if (!preen) - printf(" +%u", i); - if (do_fix) - ext2fs_mark_block_bitmap(fs->block_map, - i); + problem = PR_5_BLOCK_USED; } - if (do_fix) { - ext2fs_mark_bb_dirty(fs); - bitmap = actual; - } else - ext2fs_unmark_valid(fs); - + pctx.blk = i; + fix_problem(ctx, problem, &pctx); + do_counts: if (!bitmap) { group_free++; @@ -147,18 +136,30 @@ static void check_block_bitmaps(ext2_filsys fs) group_free = 0; } } - if (!print_header) - printf(". %s\n", fix_msg[do_fix]); + fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP); + if (fixit == 1) { + ext2fs_free_block_bitmap(fs->block_map); + retval = ext2fs_copy_bitmap(ctx->block_found_map, + &fs->block_map); + /* XXX check retval --- should never fail! */ + ext2fs_set_bitmap_padding(fs->block_map); + ext2fs_mark_bb_dirty(fs); + + /* Redo the counts */ + blocks = 0; free_blocks = 0; group_free = 0; group = 0; + memset(free_array, 0, fs->group_desc_count * sizeof(int)); + goto redo_counts; + } else if (fixit == 0) + ext2fs_unmark_valid(fs); + for (i = 0; i < fs->group_desc_count; i++) { if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) { - if (do_fix < 0) - do_fix = ask(fix_question, 1); - if (!preen) - printf("Free blocks count wrong for " - "group %u (%u, counted=%d). %s\n", i, - fs->group_desc[i].bg_free_blocks_count, - free_array[i], fix_msg[do_fix]); - if (do_fix) { + pctx.group = i; + pctx.blk = fs->group_desc[i].bg_free_blocks_count; + pctx.blk2 = free_array[i]; + + if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP, + &pctx)) { fs->group_desc[i].bg_free_blocks_count = free_array[i]; ext2fs_mark_super_dirty(fs); @@ -167,14 +168,11 @@ static void check_block_bitmaps(ext2_filsys fs) } } if (free_blocks != fs->super->s_free_blocks_count) { - if (do_fix < 0) - do_fix = ask(fix_question, 1); - if (!preen) - printf("Free blocks count wrong " - "(%u, counted=%d). %s\n", - fs->super->s_free_blocks_count, free_blocks, - fix_msg[do_fix]); - if (do_fix) { + pctx.group = 0; + pctx.blk = fs->super->s_free_blocks_count; + pctx.blk2 = free_blocks; + + if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) { fs->super->s_free_blocks_count = free_blocks; ext2fs_mark_super_dirty(fs); } else @@ -183,8 +181,9 @@ static void check_block_bitmaps(ext2_filsys fs) free(free_array); } -static void check_inode_bitmaps(ext2_filsys fs) +static void check_inode_bitmaps(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; ino_t i; int free_inodes = 0; int group_free = 0; @@ -194,77 +193,70 @@ static void check_inode_bitmaps(ext2_filsys fs) int *free_array; int *dir_array; int actual, bitmap; - const char *print_header = "Inode bitmap differences:"; + errcode_t retval; + struct problem_context pctx; + int problem, fixit; + clear_problem_context(&pctx); free_array = allocate_memory(fs->group_desc_count * sizeof(int), "free inode count array"); dir_array = allocate_memory(fs->group_desc_count * sizeof(int), "directory count array"); - if ((1 < ext2fs_get_inode_bitmap_start(inode_used_map)) || + if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) || (fs->super->s_inodes_count > - ext2fs_get_inode_bitmap_end(inode_used_map))) { - printf("PROGRAMMING ERROR: filesystem inode endpoints (%d, %d)\n\t" - "don't match inode_used_map endpoints (%d, %d).\n", - 1, fs->super->s_inodes_count, - ext2fs_get_inode_bitmap_start(inode_used_map), - ext2fs_get_inode_bitmap_end(inode_used_map)); + ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) { + pctx.num = 3; + pctx.blk = 1; + pctx.blk2 = fs->super->s_inodes_count; + pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map); + pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map); + fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); + /* fatal */ fatal_error(0); } if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) || (fs->super->s_inodes_count > ext2fs_get_inode_bitmap_end(fs->inode_map))) { - printf("PROGRAMMING ERROR: filesystem inode endpoints (%d, %d)\n\t" - "don't match fs->inode_map endpoints (%d, %d).\n", - 1, fs->super->s_inodes_count, - ext2fs_get_inode_bitmap_start(fs->inode_map), - ext2fs_get_inode_bitmap_end(fs->inode_map)); + pctx.num = 4; + pctx.blk = 1; + pctx.blk2 = fs->super->s_inodes_count; + pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map); + pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map); + fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); + /* fatal */ fatal_error(0); } +redo_counts: for (i = 1; i <= fs->super->s_inodes_count; i++) { - actual = ext2fs_fast_test_inode_bitmap(inode_used_map, i); + actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i); bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i); if (actual == bitmap) goto do_counts; - if (do_fix < 0) - do_fix = ask(fix_question, 1); - if (!preen && print_header) { - printf(print_header); - print_header = 0; - } if (!actual && bitmap) { /* * Inode wasn't used, but marked in bitmap */ - if (!preen) - printf(" -%lu", i); - if (do_fix) - ext2fs_unmark_inode_bitmap(fs->inode_map, i); - } else if (actual && !bitmap) { + problem = PR_5_UNUSED_INODE; + } else /* if (actual && !bitmap) */ { /* * Inode used, but not in bitmap */ - if (!preen) - printf (" +%lu", i); - if (do_fix) - ext2fs_mark_inode_bitmap(fs->inode_map, i); + problem = PR_5_INODE_USED; } - if (do_fix) { - ext2fs_mark_ib_dirty(fs); - bitmap = actual; - } else - ext2fs_unmark_valid(fs); - + pctx.ino = i; + fix_problem(ctx, problem, &pctx); + do_counts: if (!bitmap) { group_free++; free_inodes++; } else { - if (ext2fs_test_inode_bitmap(inode_dir_map, i)) + if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i)) dirs_count++; } inodes++; @@ -278,19 +270,31 @@ do_counts: dirs_count = 0; } } - if (!print_header) - printf(". %s\n", fix_msg[do_fix]); + fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP); + if (fixit == 1) { + ext2fs_free_inode_bitmap(fs->inode_map); + retval = ext2fs_copy_bitmap(ctx->inode_used_map, + &fs->inode_map); + /* XXX check retval --- should never fail! */ + ext2fs_set_bitmap_padding(fs->inode_map); + ext2fs_mark_ib_dirty(fs); + + /* redo counts */ + inodes = 0; free_inodes = 0; group_free = 0; + dirs_count = 0; group = 0; + memset(free_array, 0, fs->group_desc_count * sizeof(int)); + memset(dir_array, 0, fs->group_desc_count * sizeof(int)); + goto redo_counts; + } else if (fixit == 0) + ext2fs_unmark_valid(fs); for (i = 0; i < fs->group_desc_count; i++) { if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) { - if (do_fix < 0) - do_fix = ask(fix_question, 1); - if (!preen) - printf ("Free inodes count wrong for " - "group #%lu (%u, counted=%d). %s\n", i, - fs->group_desc[i].bg_free_inodes_count, - free_array[i], fix_msg[do_fix]); - if (do_fix) { + pctx.group = i; + pctx.ino = fs->group_desc[i].bg_free_inodes_count; + pctx.ino2 = free_array[i]; + if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP, + &pctx)) { fs->group_desc[i].bg_free_inodes_count = free_array[i]; ext2fs_mark_super_dirty(fs); @@ -298,14 +302,12 @@ do_counts: ext2fs_unmark_valid(fs); } if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) { - if (do_fix < 0) - do_fix = ask(fix_question, 1); - if (!preen) - printf ("Directories count wrong for " - "group #%lu (%u, counted=%d). %s\n", i, - fs->group_desc[i].bg_used_dirs_count, - dir_array[i], fix_msg[do_fix]); - if (do_fix) { + pctx.group = i; + pctx.ino = fs->group_desc[i].bg_used_dirs_count; + pctx.ino2 = dir_array[i]; + + if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP, + &pctx)) { fs->group_desc[i].bg_used_dirs_count = dir_array[i]; ext2fs_mark_super_dirty(fs); @@ -314,14 +316,11 @@ do_counts: } } if (free_inodes != fs->super->s_free_inodes_count) { - if (do_fix < 0) - do_fix = ask(fix_question, 1); - if (!preen) - printf("Free inodes count wrong " - "(%u, counted=%d). %s\n", - fs->super->s_free_inodes_count, free_inodes, - fix_msg[do_fix]); - if (do_fix) { + pctx.group = -1; + pctx.ino = fs->super->s_free_inodes_count; + pctx.ino2 = free_inodes; + + if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) { fs->super->s_free_inodes_count = free_inodes; ext2fs_mark_super_dirty(fs); } else @@ -331,17 +330,20 @@ do_counts: free(dir_array); } -static void check_inode_end(ext2_filsys fs) +static void check_inode_end(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; ino_t end, save_inodes_count, i; - errcode_t retval; + struct problem_context pctx; + + clear_problem_context(&pctx); end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count; - retval = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end, - &save_inodes_count); - if (retval) { - com_err("check_inode_end", retval, - "while trying to fudge end of inode bitmap"); + pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end, + &save_inodes_count); + if (pctx.errcode) { + pctx.num = 1; + fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); fatal_error(0); } if (save_inodes_count == end) @@ -349,8 +351,7 @@ static void check_inode_end(ext2_filsys fs) for (i = save_inodes_count + 1; i <= end; i++) { if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) { - printf("Padding at end of inode bitmap is not set. "); - if (ask("Fix", 1)) { + if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) { for (i = save_inodes_count + 1; i <= end; i++) ext2fs_mark_inode_bitmap(fs->inode_map, i); @@ -361,27 +362,30 @@ static void check_inode_end(ext2_filsys fs) } } - retval = ext2fs_fudge_inode_bitmap_end(fs->inode_map, - save_inodes_count, 0); - if (retval) { - com_err("check_inode_end", retval, - "while trying to fudge end of inode bitmap back"); + pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, + save_inodes_count, 0); + if (pctx.errcode) { + pctx.num = 2; + fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); fatal_error(0); } } -static void check_block_end(ext2_filsys fs) +static void check_block_end(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; blk_t end, save_blocks_count, i; - errcode_t retval; + struct problem_context pctx; + + clear_problem_context(&pctx); end = fs->block_map->start + (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1; - retval = ext2fs_fudge_block_bitmap_end(fs->block_map, end, - &save_blocks_count); - if (retval) { - com_err("check_block_end", retval, - "while trying to fudge end of block bitmap"); + pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end, + &save_blocks_count); + if (pctx.errcode) { + pctx.num = 3; + fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); fatal_error(0); } if (save_blocks_count == end) @@ -389,9 +393,7 @@ static void check_block_end(ext2_filsys fs) for (i = save_blocks_count + 1; i <= end; i++) { if (!ext2fs_test_block_bitmap(fs->block_map, i)) { - printf("Padding at end of block bitmap is not set. "); - - if (ask("Fix", 1)) { + if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) { for (i = save_blocks_count + 1; i < end; i++) ext2fs_mark_block_bitmap(fs->block_map, i); @@ -402,12 +404,14 @@ static void check_block_end(ext2_filsys fs) } } - retval = ext2fs_fudge_block_bitmap_end(fs->block_map, - save_blocks_count, 0); - if (retval) { - com_err("check_block_end", retval, - "while trying to fudge end of block bitmap back"); + pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, + save_blocks_count, 0); + if (pctx.errcode) { + pctx.num = 4; + fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); fatal_error(0); } } + + diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 512e2c69..eae98b11 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -19,71 +19,152 @@ #include "problem.h" -#define PROMPT_FIX 0 -#define PROMPT_CLEAR 1 -#define PROMPT_RELOCATE 2 -#define PROMPT_ALLOCATE 3 -#define PROMPT_EXPAND 4 -#define PROMPT_CONNECT 5 -#define PROMPT_CREATE 6 -#define PROMPT_SALVAGE 7 -#define PROMPT_TRUNCATE 8 -#define PROMPT_CLEAR_INODE 9 +#define PROMPT_NONE 0 +#define PROMPT_FIX 1 +#define PROMPT_CLEAR 2 +#define PROMPT_RELOCATE 3 +#define PROMPT_ALLOCATE 4 +#define PROMPT_EXPAND 5 +#define PROMPT_CONNECT 6 +#define PROMPT_CREATE 7 +#define PROMPT_SALVAGE 8 +#define PROMPT_TRUNCATE 9 +#define PROMPT_CLEAR_INODE 10 +#define PROMPT_ABORT 11 +#define PROMPT_SPLIT 12 +#define PROMPT_CONTINUE 13 +#define PROMPT_CLONE 14 +#define PROMPT_DELETE 15 /* * These are the prompts which are used to ask the user if they want * to fix a problem. */ static const char *prompt[] = { - "Fix", /* 0 */ - "Clear", /* 1 */ - "Relocate", /* 2 */ - "Allocate", /* 3 */ - "Expand", /* 4 */ - "Connect to /lost+found", /* 5 */ - "Create", /* 6 */ - "Salvage", /* 7 */ - "Truncate", /* 8 */ - "Clear inode" /* 9 */ - }; + "(no prompt)", /* 0 */ + "Fix", /* 1 */ + "Clear", /* 2 */ + "Relocate", /* 3 */ + "Allocate", /* 4 */ + "Expand", /* 5 */ + "Connect to /lost+found", /* 6 */ + "Create", /* 7 */ + "Salvage", /* 8 */ + "Truncate", /* 9 */ + "Clear inode", /* 10 */ + "Abort", /* 11 */ + "Split", /* 12 */ + "Continue", /* 13 */ + "Clone duplicate/bad blocks", /* 14 */ + "Delete file", /* 15 */ +}; /* * These messages are printed when we are preen mode and we will be * automatically fixing the problem. */ static const char *preen_msg[] = { - "FIXED", /* 0 */ - "CLEARED", /* 1 */ - "RELOCATED", /* 2 */ - "ALLOCATED", /* 3 */ - "EXPANDED", /* 4 */ - "RECONNECTED", /* 5 */ - "CREATED", /* 6 */ - "SALVAGED", /* 7 */ - "TRUNCATED", /* 8 */ - "INODE CLEARED" /* 9 */ + "(NONE)", /* 0 */ + "FIXED", /* 1 */ + "CLEARED", /* 2 */ + "RELOCATED", /* 3 */ + "ALLOCATED", /* 4 */ + "EXPANDED", /* 5 */ + "RECONNECTED", /* 6 */ + "CREATED", /* 7 */ + "SALVAGED", /* 8 */ + "TRUNCATED", /* 9 */ + "INODE CLEARED", /* 10 */ + "ABORTED", /* 11 */ + "SPLIT", /* 12 */ + "CONTINUING", /* 13 */ + "DUPLICATE/BAD BLOCKS CLONED", /* 14 */ + "FILE DELETED", /* 15 */ }; -static struct e2fsck_problem problem_table[] = { +static const struct e2fsck_problem problem_table[] = { /* Pre-Pass 1 errors */ /* Block bitmap not in group */ { PR_0_BB_NOT_GROUP, "@b @B for @g %g is not in @g. (@b %b)\n", - PROMPT_RELOCATE, 0 }, + PROMPT_RELOCATE, PR_LATCH_RELOC }, /* Inode bitmap not in group */ { PR_0_IB_NOT_GROUP, "@i @B for @g %g is not in @g. (@b %b)\n", - PROMPT_RELOCATE, 0 }, + PROMPT_RELOCATE, PR_LATCH_RELOC }, /* Inode table not in group */ { PR_0_ITABLE_NOT_GROUP, "@i table for @g %g is not in @g. (@b %b)\n" "WARNING: SEVERE DATA LOSS POSSIBLE.\n", - PROMPT_RELOCATE, 0 }, + PROMPT_RELOCATE, PR_LATCH_RELOC }, + + /* Superblock corrupt */ + { PR_0_SB_CORRUPT, + "\nThe @S could not be read or does not describe a correct ext2\n" + "@f. If the device is valid and it really contains an ext2\n" + "@f (and not swap or ufs or something else), then the @S\n" + "is corrupt, and you might try running e2fsck with an alternate @S:\n" + " e2fsck -b %S \n\n", + PROMPT_NONE, PR_FATAL }, + + /* Filesystem size is wrong */ + { PR_0_FS_SIZE_WRONG, + "The @f size (according to the @S) is %b @bs\n" + "The physical size of the device is %c @bs\n" + "Either the @S or the partition table is likely to be corrupt!\n", + PROMPT_ABORT, 0 }, + + /* Fragments not supported */ + { PR_0_NO_FRAGMENTS, + "@S @b_size = %b, fragsize = %c.\n" + "This version of e2fsck does not support fragment sizes different\n" + "from the @b size.\n", + PROMPT_NONE, PR_FATAL }, + + /* Bad blocks_per_group */ + { PR_0_BLOCKS_PER_GROUP, + "@S @bs_per_group = %b, should have been %c\n", + PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT }, + + /* Bad first_data_block */ + { PR_0_FIRST_DATA_BLOCK, + "@S first_data_@b = %b, should have been %c\n", + PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT }, + /* Adding UUID to filesystem */ + { PR_0_ADD_UUID, + "@f did not have a UUID; generating one.\n\n", + PROMPT_NONE, 0 }, + + /* Relocate hint */ + { PR_0_RELOCATE_HINT, + "Note: if there is several inode or block bitmap blocks\n" + "which require relocation, or one part of the inode table\n" + "which must be moved, you may wish to try running e2fsck\n" + "with the '-b %S' option first. The problem may lie only\n" + "with the primary block group descriptor, and the backup\n" + "block group descriptor may be OK.\n\n", + PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE }, + + /* Miscellaneous superblock corruption */ + { PR_0_MISC_CORRUPT_SUPER, + "Corruption found in @S. (%s = %N).\n", + PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT }, + + /* Error determing physical device size of filesystem */ + { PR_0_GETSIZE_ERROR, + "Error determining size of the physical device: %m\n", + PROMPT_NONE, PR_FATAL }, + /* Pass 1 errors */ + /* Pass 1: Checking inodes, blocks, and sizes */ + { PR_1_PASS_HEADER, + "Pass 1: Checking @is, @bs, and sizes\n", + PROMPT_NONE, 0 }, + /* Root directory is not an inode */ { PR_1_ROOT_NO_DIR, "@r is not a @d. ", PROMPT_CLEAR, 0 }, @@ -141,12 +222,12 @@ static struct e2fsck_problem problem_table[] = { /* Inode has incorrect i_size */ { PR_1_BAD_I_SIZE, "@i %i, i_size is %Is, @s %N. ", - PROMPT_FIX, PR_PREEN_OK }, + PROMPT_FIX, PR_PREEN_OK }, /* Inode has incorrect i_blocks */ { PR_1_BAD_I_BLOCKS, - "@i %i, i_blocks is %Ib, @s %N. ", - PROMPT_FIX, PR_PREEN_OK }, + "@i %i, i_@bs is %Ib, @s %N. ", + PROMPT_FIX, PR_PREEN_OK }, /* Illegal block number in inode */ { PR_1_ILLEGAL_BLOCK_NUM, @@ -155,7 +236,7 @@ static struct e2fsck_problem problem_table[] = { /* Block number overlaps fs metadata */ { PR_1_BLOCK_OVERLAPS_METADATA, - "@b #%B (%b) overlaps filesystem metadata in @i %i. ", + "@b #%B (%b) overlaps @f metadata in @i %i. ", PROMPT_CLEAR, PR_LATCH_BLOCK }, /* Inode has illegal blocks (latch question) */ @@ -178,26 +259,230 @@ static struct e2fsck_problem problem_table[] = { "Bad @b @i has illegal @b(s). ", PROMPT_CLEAR, 0 }, + /* Duplicate or bad blocks in use! */ + { PR_1_DUP_BLOCKS_PREENSTOP, + "Duplicate or bad @b in use!\n", + PROMPT_NONE, 0 }, + + /* Bad block used as bad block indirect block */ + { PR_1_BBINODE_BAD_METABLOCK, + "Bad @b %b used as bad @b indirect @b?!?\n", + PROMPT_NONE, PR_AFTER_CODE, PR_1_BBINODE_BAD_METABLOCK_PROMPT }, + + /* Inconsistency can't be fixed prompt */ + { PR_1_BBINODE_BAD_METABLOCK_PROMPT, + "\nThis inconsistency can not be fixed with e2fsck; to fix it, use\n" + """dumpe2fs -b"" to dump out the bad @b " + "list and ""e2fsck -L filename""\n" + "to read it back in again.\n", + PROMPT_CONTINUE, PR_PREEN_NOMSG }, + + /* Bad primary block */ + { PR_1_BAD_PRIMARY_BLOCK, + "\nIf the @b is really bad, the @f can not be fixed.\n", + PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT }, + + /* Bad primary block prompt */ + { PR_1_BAD_PRIMARY_BLOCK_PROMPT, + "You can clear the this @b (and hope for the best) from the\n" + "bad @b list and hope that @b is really OK, but there are no\n" + "guarantees.\n\n", + PROMPT_CLEAR, PR_PREEN_NOMSG }, + + /* Bad primary superblock */ + { PR_1_BAD_PRIMARY_SUPERBLOCK, + "The primary @S (%b) is on the bad @b list.\n", + PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK }, + + /* 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", + PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK }, + + /* Bad superblock in group */ + { PR_1_BAD_SUPERBLOCK, + "Warning: Group %g's @S (%b) is bad.\n", + PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Bad block group descriptors in group */ + { PR_1_BAD_GROUP_DESCRIPTORS, + "Warning: Group %d's copy of the @g descriptors has a bad " + "@b (%b).\n", + PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Block claimed for no reason */ + { PR_1_PROGERR_CLAIMED_BLOCK, + "Programming error? @b #%b claimed for no reason in " + "process_bad_@b.\n", + PROMPT_NONE, PR_PREEN_OK }, + + /* Could not allocate blocks for relocating metadata */ + { PR_1_RELOC_BLOCK_ALLOCATE, + "Could not allocate %N @b(s) for %s: %m\n", + PROMPT_NONE, PR_PREEN_OK }, + + /* Could not allocate memory during relocation process */ + { PR_1_RELOC_MEMORY_ALLOCATE, + "Could not allocate @b buffer for relocating %s\n", + PROMPT_NONE, PR_PREEN_OK }, + + /* Relocating metadata group information from X to Y */ + { PR_1_RELOC_FROM_TO, + "Relocating @g %g's %s from %b to %c...\n", + PROMPT_NONE, PR_PREEN_OK }, + + /* Relocating metatdata group information to X */ + { PR_1_RELOC_TO, + "Relocating @g %g's %s to %c...\n", + PROMPT_NONE, PR_PREEN_OK }, + + /* Block read error during relocation process */ + { PR_1_RELOC_READ_ERR, + "Warning: could not read @b %b of %s: %m\n", + PROMPT_NONE, PR_PREEN_OK }, + + /* Block write error during relocation process */ + { PR_1_RELOC_WRITE_ERR, + "Warning: could not write @b %b for %s: %m\n", + PROMPT_NONE, PR_PREEN_OK }, + + /* Error allocating inode bitmap */ + { PR_1_ALLOCATE_IBITMAP_ERROR, + "Error allocating @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", + PROMPT_NONE, PR_FATAL }, + + /* Error allocating icount structure */ + { PR_1_ALLOCATE_ICOUNT, + "Error allocating icount link information: %m\n", + PROMPT_NONE, PR_FATAL }, + + /* Error allocating dbcount */ + { PR_1_ALLOCATE_DBCOUNT, + "Error allocating directory @b array: %m\n", + PROMPT_NONE, PR_FATAL }, + + /* Error while scanning inodes */ + { PR_1_ISCAN_ERROR, + "Error while scanning inodes (%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", + 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", + PROMPT_NONE, PR_FATAL }, + + /* Error while storing directory block information */ + { PR_1_ADD_DBLOCK, + "Error storing dir block 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", + PROMPT_NONE, PR_FATAL }, + /* Pass 1b errors */ + /* Pass 1B: Rescan for duplicate/bad blocks */ + { PR_1B_PASS_HEADER, + "Duplicate @bs found... invoking duplicate @b passes.\n" + "Pass 1B: Rescan for duplicate/bad @bs\n", + PROMPT_NONE, 0 }, + + /* Duplicate/bad block(s) header */ + { PR_1B_DUP_BLOCK_HEADER, + "Duplicate/bad @b(s) in @i %i:", + PROMPT_NONE, 0 }, + + /* Duplicate/bad block(s) in inode */ + { PR_1B_DUP_BLOCK, + " %b", + PROMPT_NONE, PR_LATCH_DBLOCK }, + + /* Duplicate/bad block(s) end */ + { PR_1B_DUP_BLOCK_END, + "\n", + PROMPT_NONE, 0 }, + + /* Error while scanning inodes */ + { PR_1B_ISCAN_ERROR, + "Error while scanning inodes (%i): %m\n", + PROMPT_NONE, PR_FATAL }, + + /* Error allocating inode bitmap */ + { PR_1B_ALLOCATE_IBITMAP_ERROR, + "Error allocating @i @B (inode_dup_map): %m\n", + PROMPT_NONE, PR_FATAL }, + + + /* Pass 1C: Scan directories for inodes with dup blocks. */ + { PR_1C_PASS_HEADER, + "Pass 1C: Scan directories for @is with dup @bs.\n", + PROMPT_NONE, 0 }, + + + /* Pass 1D: Reconciling duplicate blocks */ + { PR_1D_PASS_HEADER, + "Pass 1D: Reconciling duplicate @bs\n", + PROMPT_NONE, 0 }, + /* File has duplicate blocks */ - { PR_1B_DUP_FILE, + { PR_1D_DUP_FILE, "File %Q (@i #%i, mod time %IM) \n" " has %B duplicate @b(s), shared with %N file(s):\n", - PROMPT_FIX, PR_MSG_ONLY }, + PROMPT_NONE, 0 }, /* List of files sharing duplicate blocks */ - { PR_1B_DUP_FILE_LIST, + { PR_1D_DUP_FILE_LIST, "\t%Q (@i #%i, mod time %IM)\n", - PROMPT_FIX, PR_MSG_ONLY }, + PROMPT_NONE, 0 }, /* File sharing blocks with filesystem metadata */ - { PR_1B_SHARE_METADATA, - "\t\n", - PROMPT_FIX, PR_MSG_ONLY }, + { PR_1D_SHARE_METADATA, + "\t<@f metadata>\n", + PROMPT_NONE, 0 }, + + /* Report of how many duplicate/bad inodes */ + { PR_1D_NUM_DUP_INODES, + "(There are %N @is containing duplicate/bad @bs.)\n\n", + PROMPT_NONE, 0 }, + + /* Duplicated blocks already reassigned or cloned. */ + { PR_1D_DUP_BLOCKS_DEALT, + "Duplicated @bs already reassigned or cloned.\n\n", + PROMPT_NONE, 0 }, + + /* Clone duplicate/bad blocks? */ + { PR_1D_CLONE_QUESTION, + "", PROMPT_CLONE, PR_NO_OK }, + + /* Delete file? */ + { PR_1D_DELETE_QUESTION, + "", PROMPT_DELETE, 0 }, + + /* Couldn't clone file (error) */ + { PR_1D_CLONE_ERROR, + "Couldn't clone file: %m\n", PROMPT_NONE, 0 }, /* Pass 2 errors */ + /* Pass 2: Checking directory structure */ + { PR_2_PASS_HEADER, + "Pass 2: Checking @d structure\n", + PROMPT_NONE, 0 }, + /* Bad inode number for '.' */ { PR_2_BAD_INODE_DOT, "Bad @i number for '.' in @d @i %i.\n", @@ -323,8 +608,64 @@ static struct e2fsck_problem problem_table[] = { "@i %i (%Q) is an @I @b device.\n", PROMPT_CLEAR, 0 }, - /* Pass 3 errors */ + /* Duplicate '.' entry */ + { PR_2_DUP_DOT, + "@E is duplicate '.' @e.\n", + PROMPT_FIX, 0 }, + /* Duplicate '..' entry */ + { PR_2_DUP_DOT_DOT, + "@E is duplicate '..' @e.\n", + PROMPT_FIX, 0 }, + + /* Internal error: couldn't find dir_info */ + { PR_2_NO_DIRINFO, + "Internal error: couldn't find dir_info for %i.\n", + PROMPT_NONE, PR_FATAL }, + + /* Final rec_len is wrong */ + { PR_2_FINAL_RECLEN, + "@E has rec_len of %dr, should be %N.\n", + PROMPT_FIX, 0 }, + + /* Error allocating icount structure */ + { PR_2_ALLOCATE_ICOUNT, + "Error allocating icount structure: %m\n", + PROMPT_NONE, PR_FATAL }, + + /* Error iterating over directory blocks */ + { PR_2_DBLIST_ITERATE, + "Error interating over directory blocks: %m\n", + PROMPT_NONE, PR_FATAL }, + + /* Error reading directory block */ + { PR_2_READ_DIRBLOCK, + "Error reading directory block %b (inode %i): %m\n", + PROMPT_CONTINUE, 0 }, + + /* Error writing directory block */ + { PR_2_WRITE_DIRBLOCK, + "Error writing directory block %b (inode %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", + PROMPT_NONE, 0 }, + + /* Error deallocating inode */ + { PR_2_DEALLOC_INODE, + "Error deallocating inode %i: %m\n", + PROMPT_NONE, PR_FATAL }, + + + /* Pass 3 errors */ + + /* Pass 3: Checking directory connectivity */ + { PR_3_PASS_HEADER, + "Pass 3: Checking @d connectivity\n", + PROMPT_NONE, 0 }, + /* Root inode not allocated */ { PR_3_NO_ROOT_INODE, "@r not allocated. ", @@ -350,8 +691,83 @@ static struct e2fsck_problem problem_table[] = { "'..' in %Q (%i) is %P (%j), @s %q (%d).\n", PROMPT_FIX, 0 }, + /* Bad or non-existent /lost+found. Cannot reconnect */ + { PR_3_NO_LPF, + "Bad or non-existent /@l. Cannot reconnect\n", + PROMPT_NONE, 0 }, + + /* Could not expand /lost+found */ + { PR_3_CANT_EXPAND_LPF, + "Could not expand /@l: %m\n", + PROMPT_NONE, 0 }, + + /* Could not reconnect inode */ + { PR_3_CANT_RECONNECT, + "Could not reconnect %i: %m\n", + PROMPT_NONE, 0 }, + + /* Error while trying to find /lost+found */ + { PR_3_ERR_FIND_LPF, + "Error while trying to find /@l: %m\n", + PROMPT_NONE, 0 }, + + /* Error in ext2fs_new_block while creating /lost+found */ + { PR_3_ERR_LPF_NEW_BLOCK, + "ext2fs_new_@b: %m while trying to create /@l @d\n", + PROMPT_NONE, 0 }, + + /* Error in ext2fs_new_inode while creating /lost+found */ + { PR_3_ERR_LPF_NEW_INODE, + "ext2fs_new_@i: %m while trying to create /@l @d\n", + PROMPT_NONE, 0 }, + + /* Error in ext2fs_new_dir_block while creating /lost+found */ + { PR_3_ERR_LPF_NEW_DIR_BLOCK, + "ext2fs_new_dir_@b: %m while creating new @d @b\n", + PROMPT_NONE, 0 }, + + /* Error while writing directory block for /lost+found */ + { PR_3_ERR_LPF_WRITE_BLOCK, + "ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n", + PROMPT_NONE, 0 }, + + /* Error while adjusting inode count */ + { PR_3_ADJUST_INODE, + "Error while adjusting @i count on @i %i\n", + PROMPT_NONE, 0 }, + + /* Couldn't fix parent directory -- error */ + { PR_3_FIX_PARENT_ERR, + "Couldn't fix parent of @i %i: %m\n\n", + PROMPT_NONE, 0 }, + + /* Couldn't fix parent directory -- couldn't find it */ + { PR_3_FIX_PARENT_NOFIND, + "Couldn't fix parent of @i %i: Couldn't find parent @d entry\n\n", + PROMPT_NONE, 0 }, + + /* Error allocating inode bitmap */ + { PR_3_ALLOCATE_IBITMAP_ERROR, + "Error allocating @i @B (%N): %m\n", + PROMPT_NONE, PR_FATAL }, + + /* Error creating root directory */ + { PR_3_CREATE_ROOT_ERROR, + "Error creating root @d (%s): %m\n", + PROMPT_NONE, PR_FATAL }, + + /* Error creating lost and found directory */ + { PR_3_CREATE_LPF_ERROR, + "Error creating /@l @d (%s): %m\n", + PROMPT_NONE, PR_FATAL }, + /* Pass 4 errors */ + /* Pass 4: Checking reference counts */ + { PR_4_PASS_HEADER, + "Pass 4: Checking reference counts\n", + PROMPT_NONE, 0 }, + /* Unattached zero-length inode */ { PR_4_ZERO_LEN_INODE, "@u @z @i %i. ", @@ -366,7 +782,107 @@ static struct e2fsck_problem problem_table[] = { { PR_4_BAD_REF_COUNT, "@i %i ref count is %Il, @s %N. ", PROMPT_FIX, PR_PREEN_OK }, - + + { PR_4_INCONSISTENT_COUNT, + "WARNING: PROGRAMMING BUG IN E2FSCK!\n" + "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n" + "@i_link_info[%i] is %N, @i.i_links_count is %Il. " + "They should be the same!\n", + PROMPT_NONE, 0 }, + + /* Pass 5 errors */ + + /* Pass 5: Checking group summary information */ + { PR_5_PASS_HEADER, + "Pass 5: Checking @g summary information\n", + PROMPT_NONE, 0 }, + + /* Padding at end of inode bitmap is not set. */ + { PR_5_INODE_BMAP_PADDING, + "Padding at end of @i @B is not set. ", + PROMPT_FIX, PR_PREEN_OK }, + + /* Padding at end of block bitmap is not set. */ + { PR_5_BLOCK_BMAP_PADDING, + "Padding at end of @b @B is not set. ", + PROMPT_FIX, PR_PREEN_OK }, + + /* Block bitmap differences header */ + { PR_5_BLOCK_BITMAP_HEADER, + "@b @B differences: ", + PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG}, + + /* Block not used, but marked in bitmap */ + { PR_5_UNUSED_BLOCK, + " -%b", + PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Block used, but not marked used in bitmap */ + { PR_5_BLOCK_USED, + " +%b", + PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Block bitmap differences end */ + { PR_5_BLOCK_BITMAP_END, + "\n", + PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Inode bitmap differences header */ + { PR_5_INODE_BITMAP_HEADER, + "@i @B differences: ", + PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Inode not used, but marked in bitmap */ + { PR_5_UNUSED_INODE, + " -%i", + PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Inode used, but not marked used in bitmap */ + { PR_5_INODE_USED, + " +%i", + PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Inode bitmap differences end */ + { PR_5_INODE_BITMAP_END, + "\n", + PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Free inodes count for group wrong */ + { PR_5_FREE_INODE_COUNT_GROUP, + "Free @is count wrong for @g #%g (%i, counted=%j).\n", + PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Directories count for group wrong */ + { PR_5_FREE_DIR_COUNT_GROUP, + "Directories count wrong for @g #%g (%i, counted=%j).\n", + PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Free inodes count wrong */ + { PR_5_FREE_INODE_COUNT, + "Free @is count wrong (%i, counted=%j).\n", + PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Free blocks count for group wrong */ + { PR_5_FREE_BLOCK_COUNT_GROUP, + "Free @bs count wrong for @g #%g (%b, counted=%c).\n", + PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Free blocks count wrong */ + { PR_5_FREE_BLOCK_COUNT, + "Free @bs count wrong (%b, counted=%c).\n", + PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, + + /* Programming error: bitmap endpoints don't match */ + { PR_5_BMAP_ENDPOINTS, + "PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't " + "match calculated @B endpoints (%i, %j)\n", + PROMPT_NONE, PR_FATAL }, + + /* Internal error: fudging end of bitmap */ + { PR_5_FUDGE_BITMAP_ERROR, + "Internal error: fudging end of bitmap (%N)\n", + PROMPT_NONE, PR_FATAL }, + { 0 } }; @@ -376,14 +892,17 @@ static struct e2fsck_problem problem_table[] = { * question for the set of problems, and all of the associated * problems will be either fixed or not fixed. */ -char pr_latch[7]; /* Latch flags register */ -char pr_suppress[7]; /* Latch groups which are suppressed */ -int latch_question[7] = { - PR_1_INODE_BLOCK_LATCH, - PR_1_INODE_BBLOCK_LATCH +static struct latch_descr pr_latch_info[] = { + { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 }, + { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 }, + { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END }, + { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END }, + { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 }, + { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END }, + { -1, 0, 0 }, }; -static struct e2fsck_problem *find_problem(int code) +static const struct e2fsck_problem *find_problem(int code) { int i; @@ -394,15 +913,53 @@ static struct e2fsck_problem *find_problem(int code) return 0; } -void reset_problem_latch(int mask) +static struct latch_descr *find_latch(int code) { - pr_latch[PR_LATCH(mask)] = 0; - pr_suppress[PR_LATCH(mask)] = 0; + int i; + + for (i=0; pr_latch_info[i].latch_code >= 0; i++) { + if (pr_latch_info[i].latch_code == code) + return &pr_latch_info[i]; + } + return 0; } -void suppress_latch_group(int mask, int value) +int end_problem_latch(e2fsck_t ctx, int mask) { - pr_suppress[PR_LATCH(mask)] = value; + struct latch_descr *ldesc; + struct problem_context pctx; + int answer = -1; + + ldesc = find_latch(mask); + if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) { + clear_problem_context(&pctx); + answer = fix_problem(ctx, ldesc->end_message, &pctx); + } + ldesc->flags &= ~(PRL_VARIABLE); + return answer; +} + +int set_latch_flags(int mask, int setflags, int clearflags) +{ + struct latch_descr *ldesc; + + ldesc = find_latch(mask); + if (!ldesc) + return -1; + ldesc->flags |= setflags; + ldesc->flags &= ~clearflags; + return 0; +} + +int get_latch_flags(int mask, int *value) +{ + struct latch_descr *ldesc; + + ldesc = find_latch(mask); + if (!ldesc) + return -1; + *value = ldesc->flags; + return 0; } void clear_problem_context(struct problem_context *ctx) @@ -412,11 +969,13 @@ void clear_problem_context(struct problem_context *ctx) ctx->group = -1; } -int fix_problem(ext2_filsys fs, int code, struct problem_context *ctx) +int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx) { - struct e2fsck_problem *ptr; - int def_yn, answer; - int latch; + ext2_filsys fs = ctx->fs; + const struct e2fsck_problem *ptr; + struct latch_descr *ldesc = 0; + const char *message; + int def_yn, answer, ans; int print_answer = 0; int suppress = 0; @@ -432,45 +991,72 @@ int fix_problem(ext2_filsys fs, int code, struct problem_context *ctx) * latch question, if it exists */ if (ptr->flags & PR_LATCH_MASK) { - latch = PR_LATCH(ptr->flags); - if (latch_question[latch] && !pr_latch[latch]) - pr_latch[latch] = fix_problem(fs, - latch_question[latch], - ctx) + 1; - if (pr_suppress[latch]) + ldesc = find_latch(ptr->flags & PR_LATCH_MASK); + if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) { + ans = fix_problem(ctx, ldesc->question, pctx); + if (ans == 1) + ldesc->flags |= PRL_YES; + if (ans == 0) + ldesc->flags |= PRL_NO; + ldesc->flags |= PRL_LATCHED; + } + if (ldesc->flags & PRL_SUPPRESS) suppress++; } - + if ((ptr->flags & PR_PREEN_NOMSG) && + (ctx->options & E2F_OPT_PREEN)) + suppress++; if (!suppress) { - if (preen) - printf("%s: ", device_name); - print_e2fsck_message(fs, ptr->e2p_description, ctx, 1); + message = ptr->e2p_description; + if (ctx->options & E2F_OPT_PREEN) { + printf("%s: ", ctx->device_name); +#if 0 + if (ptr->e2p_preen_msg) + message = ptr->e2p_preen_msg; +#endif + } + print_e2fsck_message(ctx, message, pctx, 1); } - if (!(ptr->flags & PR_PREEN_OK)) - preenhalt(fs); + if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE)) + preenhalt(ctx); - if (ptr->flags & PR_MSG_ONLY) - return 1; - - if (preen) { - answer = def_yn; - print_answer = 1; - } else if (ptr->flags & PR_LATCH_MASK) { - latch = PR_LATCH(ptr->flags); - if (!pr_latch[latch]) - pr_latch[latch] = - ask(prompt[(int) ptr->prompt], def_yn) + 1; + if (ptr->flags & PR_FATAL) + fatal_error(0); + + if (ptr->prompt == PROMPT_NONE) { + if (ptr->flags & PR_NOCOLLATE) + answer = -1; else - print_answer = 1; - answer = pr_latch[latch] - 1; - } else - answer = ask(prompt[(int) ptr->prompt], def_yn); - if (!answer && !(ptr->flags & PR_NO_OK)) - ext2fs_unmark_valid(fs); + answer = def_yn; + } else { + if (ctx->options & E2F_OPT_PREEN) { + answer = def_yn; + if (!(ptr->flags & PR_PREEN_NOMSG)) + print_answer = 1; + } else if ((ptr->flags & PR_LATCH_MASK) && + (ldesc->flags & (PRL_YES | PRL_NO))) { + if (!suppress) + print_answer = 1; + if (ldesc->flags & PRL_YES) + answer = 1; + else + answer = 0; + } else + answer = ask(ctx, prompt[(int) ptr->prompt], def_yn); + if (!answer && !(ptr->flags & PR_NO_OK)) + ext2fs_unmark_valid(fs); - if (print_answer) - printf("%s.\n", - answer ? preen_msg[(int) ptr->prompt] : "IGNORED"); + if (print_answer) + printf("%s.\n", answer ? + preen_msg[(int) ptr->prompt] : "IGNORED"); + } + + if (ptr->flags & PR_AFTER_CODE) + (void) fix_problem(ctx, ptr->second_code, pctx); + + if (ptr->prompt == PROMPT_ABORT) + fatal_error(0); + return answer; } diff --git a/e2fsck/problem.h b/e2fsck/problem.h index 5e1fd9ba..3fbbb2ad 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -9,26 +9,43 @@ * %End-Header% */ +typedef __u32 problem_t; + struct problem_context { + errcode_t errcode; ino_t ino, ino2, dir; struct ext2_inode *inode; struct ext2_dir_entry *dirent; - blk_t blk; + blk_t blk, blk2; int blkcount, group; __u32 num; + const char *str; }; struct e2fsck_problem { - int e2p_code; + 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 @@ -38,9 +55,23 @@ struct e2fsck_problem { #define PR_LATCH_MASK 0x0070 /* Latch mask */ #define PR_LATCH_BLOCK 0x0010 /* Latch for illegal blocks (pass 1) */ #define PR_LATCH_BBLOCK 0x0020 /* Latch for bad block inode blocks (pass 1) */ +#define PR_LATCH_IBITMAP 0x0030 /* Latch for pass 5 inode bitmap proc. */ +#define PR_LATCH_BBITMAP 0x0040 /* Latch for pass 5 inode bitmap proc. */ +#define PR_LATCH_RELOC 0x0050 /* Latch for superblock relocate hint */ +#define PR_LATCH_DBLOCK 0x0060 /* Latch for pass 1b dup block headers */ #define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1) +/* + * Latch group descriptor flags + */ +#define PRL_YES 0x0001 /* Answer yes */ +#define PRL_NO 0x0002 /* Answer no */ +#define PRL_LATCHED 0x0004 /* The latch group is latched */ +#define PRL_SUPPRESS 0x0008 /* Suppress all latch group questions */ + +#define PRL_VARIABLE 0x000f /* All the flags that need to be reset */ + /* * Pre-Pass 1 errors */ @@ -54,84 +85,234 @@ struct e2fsck_problem { /* Inode table not in group */ #define PR_0_ITABLE_NOT_GROUP 0x000003 +/* Superblock corrupt */ +#define PR_0_SB_CORRUPT 0x000004 + +/* Filesystem size is wrong */ +#define PR_0_FS_SIZE_WRONG 0x000005 + +/* Fragments not supported */ +#define PR_0_NO_FRAGMENTS 0x000006 + +/* Bad blocks_per_group */ +#define PR_0_BLOCKS_PER_GROUP 0x000007 + +/* Bad first_data_block */ +#define PR_0_FIRST_DATA_BLOCK 0x000008 + +/* Adding UUID to filesystem */ +#define PR_0_ADD_UUID 0x000009 + +/* Relocate hint */ +#define PR_0_RELOCATE_HINT 0x00000A + +/* Miscellaneous superblock corruption */ +#define PR_0_MISC_CORRUPT_SUPER 0x00000B + +/* Error determing physical device size of filesystem */ +#define PR_0_GETSIZE_ERROR 0x00000C + /* * Pass 1 errors */ +/* Pass 1: Checking inodes, blocks, and sizes */ +#define PR_1_PASS_HEADER 0x010000 + /* Root directory is not an inode */ -#define PR_1_ROOT_NO_DIR 0x010001 +#define PR_1_ROOT_NO_DIR 0x010001 /* Root directory has dtime set */ -#define PR_1_ROOT_DTIME 0x010002 +#define PR_1_ROOT_DTIME 0x010002 /* Reserved inode has bad mode */ -#define PR_1_RESERVED_BAD_MODE 0x010003 +#define PR_1_RESERVED_BAD_MODE 0x010003 /* Deleted inode has zero dtime */ -#define PR_1_ZERO_DTIME 0x010004 +#define PR_1_ZERO_DTIME 0x010004 /* Inode in use, but dtime set */ -#define PR_1_SET_DTIME 0x010005 +#define PR_1_SET_DTIME 0x010005 /* Zero-length directory */ -#define PR_1_ZERO_LENGTH_DIR 0x010006 +#define PR_1_ZERO_LENGTH_DIR 0x010006 /* Block bitmap conflicts with some other fs block */ -#define PR_1_BB_CONFLICT 0x010007 +#define PR_1_BB_CONFLICT 0x010007 /* Inode bitmap conflicts with some other fs block */ -#define PR_1_IB_CONFLICT 0x010008 +#define PR_1_IB_CONFLICT 0x010008 /* Inode table conflicts with some other fs block */ -#define PR_1_ITABLE_CONFLICT 0x010009 +#define PR_1_ITABLE_CONFLICT 0x010009 /* Block bitmap is on a bad block */ -#define PR_1_BB_BAD_BLOCK 0x01000A +#define PR_1_BB_BAD_BLOCK 0x01000A /* Inode bitmap is on a bad block */ -#define PR_1_IB_BAD_BLOCK 0x01000B +#define PR_1_IB_BAD_BLOCK 0x01000B /* Inode has incorrect i_size */ -#define PR_1_BAD_I_SIZE 0x01000C +#define PR_1_BAD_I_SIZE 0x01000C /* Inode has incorrect i_blocks */ -#define PR_1_BAD_I_BLOCKS 0x01000D +#define PR_1_BAD_I_BLOCKS 0x01000D /* Illegal block number in inode */ -#define PR_1_ILLEGAL_BLOCK_NUM 0x01000E +#define PR_1_ILLEGAL_BLOCK_NUM 0x01000E /* Block number overlaps fs metadata */ #define PR_1_BLOCK_OVERLAPS_METADATA 0x01000F /* Inode has illegal blocks (latch question) */ -#define PR_1_INODE_BLOCK_LATCH 0x010010 +#define PR_1_INODE_BLOCK_LATCH 0x010010 /* Too many bad blocks in inode */ -#define PR_1_TOO_MANY_BAD_BLOCKS 0x010011 +#define PR_1_TOO_MANY_BAD_BLOCKS 0x010011 /* Illegal block number in bad block inode */ -#define PR_1_BB_ILLEGAL_BLOCK_NUM 0x010012 +#define PR_1_BB_ILLEGAL_BLOCK_NUM 0x010012 /* Bad block inode has illegal blocks (latch question) */ -#define PR_1_INODE_BBLOCK_LATCH 0x010013 +#define PR_1_INODE_BBLOCK_LATCH 0x010013 + +/* Duplicate or bad blocks in use! */ +#define PR_1_DUP_BLOCKS_PREENSTOP 0x010014 + +/* Bad block used as bad block indirect block */ +#define PR_1_BBINODE_BAD_METABLOCK 0x010015 + +/* Inconsistency can't be fixed prompt */ +#define PR_1_BBINODE_BAD_METABLOCK_PROMPT 0x010016 + +/* Bad primary block */ +#define PR_1_BAD_PRIMARY_BLOCK 0x0100017 + +/* Bad primary block prompt */ +#define PR_1_BAD_PRIMARY_BLOCK_PROMPT 0x0100018 + +/* Bad primary superblock */ +#define PR_1_BAD_PRIMARY_SUPERBLOCK 0x0100019 + +/* Bad primary block group descriptors */ +#define PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR 0x010001A + +/* Bad superblock in group */ +#define PR_1_BAD_SUPERBLOCK 0x010001B + +/* Bad block group descriptors in group */ +#define PR_1_BAD_GROUP_DESCRIPTORS 0x010001C + +/* Block claimed for no reason */ +#define PR_1_PROGERR_CLAIMED_BLOCK 0x010001D + +/* Could not allocate blocks for relocating metadata */ +#define PR_1_RELOC_BLOCK_ALLOCATE 0x010001E + +/* Could not allocate memory during relocation process */ +#define PR_1_RELOC_MEMORY_ALLOCATE 0x010001F + +/* Relocating metadata group information from X to Y */ +#define PR_1_RELOC_FROM_TO 0x0100020 + +/* Relocating metatdata group information to X */ +#define PR_1_RELOC_TO 0x0100021 + +/* Block read error during relocation process */ +#define PR_1_RELOC_READ_ERR 0x0100022 + +/* Block write error during relocation process */ +#define PR_1_RELOC_WRITE_ERR 0x0100023 + +/* Error allocating inode bitmap */ +#define PR_1_ALLOCATE_IBITMAP_ERROR 0x0100024 + +/* Error allocating block bitmap */ +#define PR_1_ALLOCATE_BBITMAP_ERROR 0x0100025 + +/* Error allocating icount structure */ +#define PR_1_ALLOCATE_ICOUNT 0x0100026 + +/* Error allocating dbcount */ +#define PR_1_ALLOCATE_DBCOUNT 0x0100027 + +/* Error while scanning inodes */ +#define PR_1_ISCAN_ERROR 0x0100028 + +/* Error while iterating over blocks */ +#define PR_1_BLOCK_ITERATE 0x0100029 + +/* Error while storing inode count information */ +#define PR_1_ICOUNT_STORE 0x010002A + +/* Error while storing directory block information */ +#define PR_1_ADD_DBLOCK 0x010002B + +/* Error while reading inode (for clearing) */ +#define PR_1_READ_INODE 0x010002C + /* * Pass 1b errors */ +/* Pass 1B: Rescan for duplicate/bad blocks */ +#define PR_1B_PASS_HEADER 0x011000 + +/* Duplicate/bad block(s) header */ +#define PR_1B_DUP_BLOCK_HEADER 0x011001 + +/* Duplicate/bad block(s) in inode */ +#define PR_1B_DUP_BLOCK 0x011002 + +/* Duplicate/bad block(s) end */ +#define PR_1B_DUP_BLOCK_END 0x011003 + +/* Error while scanning inodes */ +#define PR_1B_ISCAN_ERROR 0x011004 + +/* Error allocating inode bitmap */ +#define PR_1B_ALLOCATE_IBITMAP_ERROR 0x011005 + + +/* Pass 1C: Scan directories for inodes with dup blocks. */ +#define PR_1C_PASS_HEADER 0x012000 + + +/* Pass 1D: Reconciling duplicate blocks */ +#define PR_1D_PASS_HEADER 0x013000 + /* File has duplicate blocks */ -#define PR_1B_DUP_FILE 0x011001 +#define PR_1D_DUP_FILE 0x013001 /* List of files sharing duplicate blocks */ -#define PR_1B_DUP_FILE_LIST 0x011002 +#define PR_1D_DUP_FILE_LIST 0x013002 /* File sharing blocks with filesystem metadata */ -#define PR_1B_SHARE_METADATA 0x011003 +#define PR_1D_SHARE_METADATA 0x013003 +/* Report of how many duplicate/bad inodes */ +#define PR_1D_NUM_DUP_INODES 0x013004 + +/* Duplicated blocks already reassigned or cloned. */ +#define PR_1D_DUP_BLOCKS_DEALT 0x013005 + +/* Clone duplicate/bad blocks? */ +#define PR_1D_CLONE_QUESTION 0x013006 + +/* Delete file? */ +#define PR_1D_DELETE_QUESTION 0x013007 + +/* Couldn't clone file (error) */ +#define PR_1D_CLONE_ERROR 0x013008 + /* * Pass 2 errors */ +/* Pass 2: Checking directory structure */ +#define PR_2_PASS_HEADER 0x020000 + /* Bad inode number for '.' */ #define PR_2_BAD_INODE_DOT 0x020001 @@ -207,30 +388,107 @@ struct e2fsck_problem { /* Illegal block device in inode */ #define PR_2_BAD_BLOCK_DEV 0x020019 +/* Duplicate '.' entry */ +#define PR_2_DUP_DOT 0x02001A + +/* Duplicate '..' entry */ +#define PR_2_DUP_DOT_DOT 0x02001B + +/* Internal error: couldn't find dir_info */ +#define PR_2_NO_DIRINFO 0x02001C + +/* Final rec_len is wrong */ +#define PR_2_FINAL_RECLEN 0x02001D + +/* Error allocating icount structure */ +#define PR_2_ALLOCATE_ICOUNT 0x02001E + +/* Error iterating over directory blocks */ +#define PR_2_DBLIST_ITERATE 0x02001F + +/* Error reading directory block */ +#define PR_2_READ_DIRBLOCK 0x020020 + +/* Error writing directory block */ +#define PR_2_WRITE_DIRBLOCK 0x020021 + +/* Error allocating new directory block */ +#define PR_2_ALLOC_DIRBOCK 0x020022 + +/* Error deallocating inode */ +#define PR_2_DEALLOC_INODE 0x020023 + /* * Pass 3 errors */ +/* Pass 3: Checking directory connectivity */ +#define PR_3_PASS_HEADER 0x030000 + /* Root inode not allocated */ -#define PR_3_NO_ROOT_INODE 0x030001 +#define PR_3_NO_ROOT_INODE 0x030001 /* No room in lost+found */ -#define PR_3_EXPAND_LF_DIR 0x030002 +#define PR_3_EXPAND_LF_DIR 0x030002 /* Unconnected directory inode */ -#define PR_3_UNCONNECTED_DIR 0x030003 +#define PR_3_UNCONNECTED_DIR 0x030003 /* /lost+found not found */ -#define PR_3_NO_LF_DIR 0x030004 +#define PR_3_NO_LF_DIR 0x030004 /* .. entry is incorrect */ -#define PR_3_BAD_DOT_DOT 0x030005 +#define PR_3_BAD_DOT_DOT 0x030005 +/* Bad or non-existent /lost+found. Cannot reconnect */ +#define PR_3_NO_LPF 0x030006 + +/* Could not expand /lost+found */ +#define PR_3_CANT_EXPAND_LPF 0x030007 + +/* Could not reconnect inode */ +#define PR_3_CANT_RECONNECT 0x030008 + +/* Error while trying to find /lost+found */ +#define PR_3_ERR_FIND_LPF 0x030009 + +/* Error in ext2fs_new_block while creating /lost+found */ +#define PR_3_ERR_LPF_NEW_BLOCK 0x03000A + +/* Error in ext2fs_new_inode while creating /lost+found */ +#define PR_3_ERR_LPF_NEW_INODE 0x03000B + +/* Error in ext2fs_new_dir_block while creating /lost+found */ +#define PR_3_ERR_LPF_NEW_DIR_BLOCK 0x03000C + +/* Error while writing directory block for /lost+found */ +#define PR_3_ERR_LPF_WRITE_BLOCK 0x03000D + +/* Error while adjusting inode count */ +#define PR_3_ADJUST_INODE 0x03000E + +/* Couldn't fix parent directory -- error */ +#define PR_3_FIX_PARENT_ERR 0x03000F + +/* Couldn't fix parent directory -- couldn't find it */ +#define PR_3_FIX_PARENT_NOFIND 0x030010 + +/* Error allocating inode bitmap */ +#define PR_3_ALLOCATE_IBITMAP_ERROR 0x030011 + +/* Error creating root directory */ +#define PR_3_CREATE_ROOT_ERROR 0x030012 + +/* Error creating lost and found directory */ +#define PR_3_CREATE_LPF_ERROR 0x030013 /* * Pass 4 errors */ +/* Pass 4: Checking reference counts */ +#define PR_4_PASS_HEADER 0x040000 + /* Unattached zero-length inode */ #define PR_4_ZERO_LEN_INODE 0x040001 @@ -240,19 +498,77 @@ struct e2fsck_problem { /* Inode ref count wrong */ #define PR_4_BAD_REF_COUNT 0x040003 +/* Inconsistent inode count information cached */ +#define PR_4_INCONSISTENT_COUNT 0x040004 + /* * Pass 5 errors */ +/* Pass 5: Checking group summary information */ +#define PR_5_PASS_HEADER 0x050000 + +/* Padding at end of inode bitmap is not set. */ +#define PR_5_INODE_BMAP_PADDING 0x050001 + +/* Padding at end of block bitmap is not set. */ +#define PR_5_BLOCK_BMAP_PADDING 0x050002 + +/* Block bitmap differences header */ +#define PR_5_BLOCK_BITMAP_HEADER 0x050003 + +/* Block not used, but marked in bitmap */ +#define PR_5_UNUSED_BLOCK 0x050004 + +/* Block used, but not marked used in bitmap */ +#define PR_5_BLOCK_USED 0x050005 + +/* Block bitmap differences end */ +#define PR_5_BLOCK_BITMAP_END 0x050006 + +/* Inode bitmap differences header */ +#define PR_5_INODE_BITMAP_HEADER 0x050007 + +/* Inode not used, but marked in bitmap */ +#define PR_5_UNUSED_INODE 0x050008 + +/* Inode used, but not marked used in bitmap */ +#define PR_5_INODE_USED 0x050009 + +/* Inode bitmap differences end */ +#define PR_5_INODE_BITMAP_END 0x05000A + +/* Free inodes count for group wrong */ +#define PR_5_FREE_INODE_COUNT_GROUP 0x05000B + +/* Directories count for group wrong */ +#define PR_5_FREE_DIR_COUNT_GROUP 0x05000C + +/* Free inodes count wrong */ +#define PR_5_FREE_INODE_COUNT 0x05000D + +/* Free blocks count for group wrong */ +#define PR_5_FREE_BLOCK_COUNT_GROUP 0x05000E + +/* Free blocks count wrong */ +#define PR_5_FREE_BLOCK_COUNT 0x05000F + +/* Programming error: bitmap endpoints don't match */ +#define PR_5_BMAP_ENDPOINTS 0x050010 + +/* Internal error: fudging end of bitmap */ +#define PR_5_FUDGE_BITMAP_ERROR 0x050011 + /* * Function declarations */ -int fix_problem(ext2_filsys fs, int code, struct problem_context *ctx); -void reset_problem_latch(int mask); -void suppress_latch_group(int mask, int value); +int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx); +int end_problem_latch(e2fsck_t ctx, int mask); +int set_latch_flags(int mask, int setflags, int clearflags); +int get_latch_flags(int mask, int *value); void clear_problem_context(struct problem_context *ctx); /* message.c */ -void print_e2fsck_message(ext2_filsys fs, const char *msg, - struct problem_context *ctx, int first); +void print_e2fsck_message(e2fsck_t ctx, const char *msg, + struct problem_context *pctx, int first); diff --git a/e2fsck/scantest.c b/e2fsck/scantest.c index 29d1e888..f82e67f9 100644 --- a/e2fsck/scantest.c +++ b/e2fsck/scantest.c @@ -72,7 +72,7 @@ static __inline__ float timeval_subtract(struct timeval *tv1, ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000); } -void print_resource_track(struct resource_track *track) +static void print_resource_track(struct resource_track *track) { struct rusage r; struct timeval time_end; diff --git a/e2fsck/super.c b/e2fsck/super.c new file mode 100644 index 00000000..d6a0c980 --- /dev/null +++ b/e2fsck/super.c @@ -0,0 +1,204 @@ +/* + * e2fsck.c - superblock checks + * + * 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 +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif +#include +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_MNTENT_H +#include +#endif +#include +#include + +#include "uuid/uuid.h" +#include "e2fsck.h" +#include "problem.h" +#include "../version.h" + +#define MIN_CHECK 1 +#define MAX_CHECK 2 + +static void check_super_value(e2fsck_t ctx, const char *descr, + unsigned long value, int flags, + unsigned long min, unsigned long max) +{ + struct problem_context pctx; + + if (((flags & MIN_CHECK) && (value < min)) || + ((flags & MAX_CHECK) && (value > max))) { + clear_problem_context(&pctx); + pctx.num = value; + pctx.str = descr; + fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx); + fatal_error(0); /* never get here! */ + } +} + +void check_super_block(e2fsck_t ctx) +{ + ext2_filsys fs = ctx->fs; + blk_t first_block, last_block; + struct ext2fs_sb *s = (struct ext2fs_sb *) fs->super; + blk_t blocks_per_group = fs->super->s_blocks_per_group; + int i; + 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"); + + clear_problem_context(&pctx); + + /* + * Verify the super block constants... + */ + check_super_value(ctx, "inodes_count", s->s_inodes_count, + MIN_CHECK, 1, 0); + check_super_value(ctx, "blocks_count", s->s_blocks_count, + MIN_CHECK, 1, 0); + check_super_value(ctx, "first_data_block", s->s_first_data_block, + MAX_CHECK, 0, s->s_blocks_count); + check_super_value(ctx, "log_frag_size", s->s_log_frag_size, + MAX_CHECK, 0, 2); + check_super_value(ctx, "log_block_size", s->s_log_block_size, + MIN_CHECK | MAX_CHECK, s->s_log_frag_size, + 2); + check_super_value(ctx, "frags_per_group", s->s_frags_per_group, + MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s)); + check_super_value(ctx, "blocks_per_group", s->s_blocks_per_group, + MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s)); + check_super_value(ctx, "inodes_per_group", s->s_inodes_per_group, + MIN_CHECK, 1, 0); + 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); + fatal_error(0); + } + 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)) + fatal_error(0); + } + + if (s->s_log_block_size != s->s_log_frag_size) { + pctx.blk = EXT2_BLOCK_SIZE(s); + pctx.blk2 = EXT2_FRAG_SIZE(s); + fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx); + fatal_error(0); + } + + should_be = s->s_frags_per_group / + (s->s_log_block_size - s->s_log_frag_size + 1); + if (s->s_blocks_per_group != should_be) { + pctx.blk = s->s_blocks_per_group; + pctx.blk2 = should_be; + fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx); + fatal_error(0); + } + + should_be = (s->s_log_block_size == 0) ? 1 : 0; + if (s->s_first_data_block != should_be) { + pctx.blk = s->s_first_data_block; + pctx.blk2 = should_be; + fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx); + fatal_error(0); + } + + /* + * Verify the group descriptors.... + */ + first_block = fs->super->s_first_data_block; + last_block = first_block + blocks_per_group; + + for (i = 0; i < fs->group_desc_count; i++) { + pctx.group = i; + + if (i == fs->group_desc_count - 1) + last_block = fs->super->s_blocks_count; + if ((fs->group_desc[i].bg_block_bitmap < first_block) || + (fs->group_desc[i].bg_block_bitmap >= last_block)) { + pctx.blk = fs->group_desc[i].bg_block_bitmap; + if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx)) { + fs->group_desc[i].bg_block_bitmap = 0; + ctx->invalid_block_bitmap_flag[i]++; + ctx->invalid_bitmaps++; + } + } + if ((fs->group_desc[i].bg_inode_bitmap < first_block) || + (fs->group_desc[i].bg_inode_bitmap >= last_block)) { + pctx.blk = fs->group_desc[i].bg_inode_bitmap; + if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx)) { + fs->group_desc[i].bg_inode_bitmap = 0; + ctx->invalid_inode_bitmap_flag[i]++; + ctx->invalid_bitmaps++; + } + } + 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)) { + pctx.blk = fs->group_desc[i].bg_inode_table; + if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx)) { + fs->group_desc[i].bg_inode_table = 0; + ctx->invalid_inode_table_flag[i]++; + ctx->invalid_bitmaps++; + } + } + first_block += fs->super->s_blocks_per_group; + last_block += fs->super->s_blocks_per_group; + } + /* + * If we have invalid bitmaps, set the error state of the + * filesystem. + */ + if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) { + fs->super->s_state &= ~EXT2_VALID_FS; + ext2fs_mark_super_dirty(fs); + } + + /* + * If the UUID field isn't assigned, assign it. + */ + if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(s->s_uuid)) { + clear_problem_context(&pctx); + if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) { + uuid_generate(s->s_uuid); + ext2fs_mark_super_dirty(fs); + } + } + return; +} + diff --git a/e2fsck/swapfs.c b/e2fsck/swapfs.c index a317cc78..64d4775a 100644 --- a/e2fsck/swapfs.c +++ b/e2fsck/swapfs.c @@ -102,8 +102,9 @@ static void swap_inode_blocks(ext2_filsys fs, ino_t ino, char *block_buf, } } -static void swap_inodes(ext2_filsys fs) +static void swap_inodes(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; int i, group; ino_t ino = 1; char *buf, *block_buf; @@ -135,8 +136,8 @@ static void swap_inodes(ext2_filsys fs) inode = (struct ext2_inode *) buf; for (i=0; i < fs->super->s_inodes_per_group; i++, ino++, inode++) { - stashed_ino = ino; - stashed_inode = inode; + ctx->stashed_ino = ino; + ctx->stashed_inode = inode; if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ) ext2fs_swap_inode(fs, inode, inode, 0); @@ -173,13 +174,14 @@ static void swap_inodes(ext2_filsys fs) fs->get_blocks = 0; } -void swap_filesys(ext2_filsys fs) +void swap_filesys(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; struct resource_track rtrack; init_resource_track(&rtrack); - if (!preen) + if (!(ctx->options & E2F_OPT_PREEN)) printf("Pass 0: Doing byte-swap of filesystem\n"); #ifdef MTRACE @@ -190,7 +192,7 @@ void swap_filesys(ext2_filsys fs) fprintf(stderr, "%s: the filesystem must be freshly " "checked using fsck\n" "and not mounted before trying to " - "byte-swap it.\n", device_name); + "byte-swap it.\n", ctx->device_name); fatal_error(0); } if (fs->flags & EXT2_FLAG_SWAP_BYTES) { @@ -201,17 +203,15 @@ void swap_filesys(ext2_filsys fs) fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ; fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE; } - swap_inodes(fs); + swap_inodes(ctx); if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE) fs->flags |= EXT2_FLAG_SWAP_BYTES; fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ| EXT2_FLAG_SWAP_BYTES_WRITE); ext2fs_flush(fs); - if (tflag > 1) { - printf("Byte swap: "); - print_resource_track(&rtrack); - } + if (ctx->options & E2F_OPT_TIME2) + print_resource_track("Byte swap", &rtrack); } diff --git a/e2fsck/unix.c b/e2fsck/unix.c new file mode 100644 index 00000000..7bc0963c --- /dev/null +++ b/e2fsck/unix.c @@ -0,0 +1,651 @@ +/* + * unix.c - The unix-specific code for e2fsck + * + * 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 +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif +#include +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_MNTENT_H +#include +#endif +#include +#include + +#include "et/com_err.h" +#include "e2fsck.h" +#include "problem.h" +#include "../version.h" + +extern int isatty(int); + +/* Command line options */ +static int blocksize = 0; +static int swapfs = 0; +static int normalize_swapfs = 0; +static int cflag = 0; /* check disk */ +static int show_version_only = 0; +static int force = 0; +static int verbose = 0; + +static int replace_bad_blocks = 0; +static char *bad_blocks_file = 0; + +static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0}; + +static int root_filesystem = 0; +static int read_only_root = 0; + +int restart_e2fsck = 0; + +static void usage(e2fsck_t ctx) +{ + fprintf(stderr, + "Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n" + "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" + "\t\t[-l|-L bad_blocks_file] device\n", ctx->program_name); + exit(FSCK_USAGE); +} + +static void show_stats(e2fsck_t ctx) +{ + ext2_filsys fs = ctx->fs; + int inodes, inodes_used, blocks, blocks_used; + int dir_links; + int num_files, num_links; + int frag_percent; + + dir_links = 2 * ctx->fs_directory_count - 1; + num_files = ctx->fs_total_count - dir_links; + num_links = ctx->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); + + frag_percent = (10000 * ctx->fs_fragmented) / inodes_used; + frag_percent = (frag_percent + 5) / 10; + + if (!verbose) { + printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n", + ctx->device_name, inodes_used, inodes, + frag_percent / 10, frag_percent % 10, + blocks_used, blocks); + return; + } + printf ("\n%8d inode%s used (%d%%)\n", inodes_used, + (inodes_used != 1) ? "s" : "", + 100 * inodes_used / inodes); + printf ("%8d non-contiguous inodes (%0d.%d%%)\n", + ctx->fs_fragmented, frag_percent / 10, frag_percent % 10); + printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n", + ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count); + printf ("%8d block%s used (%d%%)\n" + "%8d bad block%s\n", blocks_used, + (blocks_used != 1) ? "s" : "", + 100 * blocks_used / blocks, ctx->fs_badblocks_count, + ctx->fs_badblocks_count != 1 ? "s" : ""); + printf ("\n%8d regular file%s\n" + "%8d director%s\n" + "%8d character device file%s\n" + "%8d block device file%s\n" + "%8d fifo%s\n" + "%8d link%s\n" + "%8d symbolic link%s (%d fast symbolic link%s)\n" + "%8d socket%s\n" + "--------\n" + "%8d file%s\n", + ctx->fs_regular_count, + (ctx->fs_regular_count != 1) ? "s" : "", + ctx->fs_directory_count, + (ctx->fs_directory_count != 1) ? "ies" : "y", + ctx->fs_chardev_count, + (ctx->fs_chardev_count != 1) ? "s" : "", + ctx->fs_blockdev_count, + (ctx->fs_blockdev_count != 1) ? "s" : "", + ctx->fs_fifo_count, + (ctx->fs_fifo_count != 1) ? "s" : "", + ctx->fs_links_count - dir_links, + ((ctx->fs_links_count - dir_links) != 1) ? "s" : "", + ctx->fs_symlinks_count, + (ctx->fs_symlinks_count != 1) ? "s" : "", + ctx->fs_fast_symlinks_count, + (ctx->fs_fast_symlinks_count != 1) ? "s" : "", + ctx->fs_sockets_count, (ctx->fs_sockets_count != 1) ? "s" : "", + ctx->fs_total_count - dir_links, + ((ctx->fs_total_count - dir_links) != 1) ? "s" : ""); +} + +static void check_mount(e2fsck_t ctx) +{ + errcode_t retval; + int mount_flags, cont, fd; + + retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags); + if (retval) { + com_err("ext2fs_check_if_mount", retval, + "while determining whether %s is mounted.", + ctx->filesystem_name); + return; + } + if (!(mount_flags & EXT2_MF_MOUNTED)) + return; + +#if (defined(__linux__) && defined(HAVE_MNTENT_H)) + /* + * If the root is mounted read-only, then /etc/mtab is + * probably not correct; so we won't issue a warning based on + * it. + */ + fd = open(MOUNTED, O_RDWR); + if (fd < 0) { + if (errno == EROFS) + return; + } else + close(fd); +#endif + + if (ctx->options & E2F_OPT_READONLY) { + printf("Warning! %s is mounted.\n", ctx->device_name); + return; + } + + 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"); + 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); + } + return; +} + +static void sync_disks(NOARGS) +{ + sync(); + sync(); + sleep(1); + sync(); +} + +/* + * 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(e2fsck_t ctx) +{ + ext2_filsys fs = ctx->fs; + const char *reason = NULL; + + if (force || bad_blocks_file || cflag || swapfs) + 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"; + else if ((fs->super->s_state & EXT2_VALID_FS) == 0) + reason = "was not cleanly unmounted"; + if (reason) { + printf("%s %s, check forced.\n", ctx->device_name, reason); + return; + } + printf("%s: clean, %d/%d files, %d/%d blocks\n", ctx->device_name, + fs->super->s_inodes_count - fs->super->s_free_inodes_count, + fs->super->s_inodes_count, + fs->super->s_blocks_count - fs->super->s_free_blocks_count, + fs->super->s_blocks_count); + ext2fs_close(fs); + exit(FSCK_OK); +} + + +#define PATH_SET "PATH=/sbin" + +static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) +{ + int flush = 0; + char c; +#ifdef MTRACE + extern void *mallwatch; +#endif + char *oldpath = getenv("PATH"); + e2fsck_t ctx; + errcode_t retval; + + retval = e2fsck_allocate_context(&ctx); + if (retval) + return retval; + + *ret_ctx = ctx; + + /* Update our PATH to include /sbin */ + if (oldpath) { + char *newpath; + + newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath)); + if (!newpath) + fatal_error("Couldn't malloc() newpath"); + strcpy (newpath, PATH_SET); + strcat (newpath, ":"); + strcat (newpath, oldpath); + putenv (newpath); + } else + putenv (PATH_SET); + + setbuf(stdout, NULL); + setbuf(stderr, NULL); + initialize_ext2_error_table(); + + if (argc && *argv) + ctx->program_name = *argv; + else + ctx->program_name = "e2fsck"; + while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF) + switch (c) { + case 'p': + case 'a': + ctx->options |= E2F_OPT_PREEN; + ctx->options &= ~(E2F_OPT_YES|E2F_OPT_NO); + break; + case 'n': + ctx->options |= E2F_OPT_NO; + ctx->options &= ~(E2F_OPT_YES|E2F_OPT_PREEN); + break; + case 'y': + ctx->options |= E2F_OPT_YES; + ctx->options &= ~(E2F_OPT_PREEN|E2F_OPT_NO); + break; + case 't': + if (ctx->options & E2F_OPT_TIME) + ctx->options |= E2F_OPT_TIME2; + else + ctx->options |= E2F_OPT_TIME; + break; + case 'c': + cflag++; + ctx->options |= E2F_OPT_CHECKBLOCKS; + break; + case 'r': + /* What we do by default, anyway! */ + break; + case 'b': + ctx->use_superblock = atoi(optarg); + break; + case 'B': + blocksize = atoi(optarg); + break; + case 'I': + ctx->inode_buffer_blocks = atoi(optarg); + break; + case 'P': + ctx->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': + ctx->options |= E2F_OPT_DEBUG; + break; + case 'f': + force = 1; + break; + case 'F': +#ifdef BLKFLSBUF + flush = 1; +#else + fatal_error ("-F not supported"); +#endif + 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 + case 'N': + ctx->device_name = optarg; + break; + case 's': + normalize_swapfs = 1; + case 'S': + swapfs = 1; + break; + default: + usage(ctx); + } + if (show_version_only) + return 0; + if (optind != argc - 1) + usage(ctx); + if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file && + !cflag && !swapfs) + ctx->options |= E2F_OPT_READONLY; + ctx->filesystem_name = argv[optind]; + if (ctx->device_name == 0) + ctx->device_name = ctx->filesystem_name; + if (flush) { +#ifdef BLKFLSBUF + int fd = open(ctx->filesystem_name, O_RDONLY, 0); + + if (fd < 0) { + com_err("open", errno, "while opening %s for flushing", + ctx->filesystem_name); + exit(FSCK_ERROR); + } + if (ioctl(fd, BLKFLSBUF, 0) < 0) { + com_err("BLKFLSBUF", errno, "while trying to flush %s", + ctx->filesystem_name); + exit(FSCK_ERROR); + } + close(fd); +#else + fatal_error ("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); + } + } + return 0; +} + +static const char *my_ver_string = E2FSPROGS_VERSION; +static const char *my_ver_date = E2FSPROGS_DATE; + +int main (int argc, char *argv[]) +{ + errcode_t retval = 0; + int exit_value = FSCK_OK; + int i; + ext2_filsys fs = 0; + io_manager io_ptr; + struct ext2fs_sb *s; + const char *lib_ver_date; + int my_ver, lib_ver; + e2fsck_t ctx; + struct problem_context pctx; + int flags; + + clear_problem_context(&pctx); +#ifdef MTRACE + mtrace(); +#endif +#ifdef MCHECK + mcheck(0); +#endif + my_ver = ext2fs_parse_version_string(my_ver_string); + lib_ver = ext2fs_get_library_version(0, &lib_ver_date); + if (my_ver > lib_ver) { + fprintf( stderr, "Error: ext2fs library version " + "out of date!\n"); + show_version_only++; + } + + retval = PRS(argc, argv, &ctx); + if (retval) { + com_err("e2fsck", retval, + "while trying to initialize program"); + exit(1); + } + + init_resource_track(&ctx->global_rtrack); + + if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) + fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n", + my_ver_string, my_ver_date, EXT2FS_VERSION, + EXT2FS_DATE); + + if (show_version_only) { + fprintf(stderr, "\tUsing %s, %s\n", + error_message(EXT2_ET_BASE), lib_ver_date); + exit(0); + } + + check_mount(ctx); + + if (!(ctx->options & E2F_OPT_PREEN) && + !(ctx->options & E2F_OPT_NO) && + !(ctx->options & E2F_OPT_YES)) { + if (!isatty (0) || !isatty (1)) + die ("need terminal for interactive repairs"); + } + ctx->superblock = ctx->use_superblock; +restart: +#if 1 + io_ptr = unix_io_manager; +#else + io_ptr = test_io_manager; + test_io_backing_manager = unix_io_manager; +#endif + sync_disks(); + flags = (ctx->options & E2F_OPT_READONLY) ? 0 : EXT2_FLAG_RW; + if (ctx->superblock && blocksize) { + retval = ext2fs_open(ctx->filesystem_name, flags, + ctx->superblock, blocksize, io_ptr, &fs); + } else if (ctx->superblock) { + for (i=0; possible_block_sizes[i]; i++) { + retval = ext2fs_open(ctx->filesystem_name, flags, + ctx->superblock, + possible_block_sizes[i], + io_ptr, &fs); + if (!retval) + break; + } + } else + retval = ext2fs_open(ctx->filesystem_name, flags, + 0, 0, io_ptr, &fs); + if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) && + ((retval == EXT2_ET_BAD_MAGIC) || + ((retval == 0) && ext2fs_check_desc(fs)))) { + if (!fs || (fs->group_desc_count > 1)) { + printf("%s trying backup blocks...\n", + retval ? "Couldn't find ext2 superblock," : + "Group descriptors look bad..."); + ctx->superblock = get_backup_sb(fs); + if (fs) + ext2fs_close(fs); + goto restart; + } + } + if (retval) { + com_err(ctx->program_name, retval, "while trying to open %s", + ctx->filesystem_name); + if (retval == EXT2_ET_REV_TOO_HIGH) + printf ("Get a newer version of e2fsck!\n"); + else if (retval == EXT2_ET_SHORT_READ) + printf ("Could this be a zero-length partition?\n"); + else if ((retval == EPERM) || (retval == EACCES)) + printf("You must have %s access to the " + "filesystem or be root\n", + (ctx->options & E2F_OPT_READONLY) ? + "r/o" : "r/w"); + else if (retval == ENXIO) + printf("Possibly non-existent or swap device?\n"); + else + fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); + fatal_error(0); + } + ctx->fs = fs; + fs->private = ctx; +#ifdef EXT2_CURRENT_REV + if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) { + com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH, + "while trying to open %s", + ctx->filesystem_name); + goto get_newer; + } +#endif + /* + * 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, + "(%s)", ctx->filesystem_name); + get_newer: + printf ("Get a newer version of e2fsck!\n"); + fatal_error(0); + } + if (s->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) { + com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE, + "(%s)", ctx->filesystem_name); + goto get_newer; + } + + /* + * 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 (ctx->superblock && + !(ctx->options & E2F_OPT_READONLY)) + ext2fs_mark_super_dirty(fs); + + /* + * Don't overwrite the backup superblock and block + * descriptors, until we're sure the filesystem is OK.... + */ + fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; + + ehandler_init(fs->io); + + if (ctx->superblock) + set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0); + check_super_block(ctx); + 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 (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); + } + } + if (swapfs) + swap_filesys(ctx); + + /* + * Mark the system as valid, 'til proven otherwise + */ + ext2fs_mark_valid(fs); + + retval = ext2fs_read_bb_inode(fs, &fs->badblocks); + if (retval) { + com_err(ctx->program_name, retval, + "while reading bad blocks inode"); + preenhalt(ctx); + printf("This doesn't bode well, but we'll try to go on...\n"); + } + + pass1(ctx); + if (restart_e2fsck) { + ext2fs_close(fs); + printf("Restarting e2fsck from the beginning...\n"); + restart_e2fsck = 0; + retval = e2fsck_reset_context(ctx); + if (retval) { + com_err(ctx->program_name, retval, + "while resetting context"); + exit(1); + } + goto restart; + } + pass2(ctx); + pass3(ctx); + pass4(ctx); + pass5(ctx); + +#ifdef MTRACE + mtrace_print("Cleanup"); +#endif + if (ext2fs_test_changed(fs)) { + exit_value = FSCK_NONDESTRUCT; + if (!(ctx->options & E2F_OPT_PREEN)) + printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n", + ctx->device_name); + if (root_filesystem && !read_only_root) { + printf("%s: ***** REBOOT LINUX *****\n", + ctx->device_name); + exit_value = FSCK_REBOOT; + } + } + if (ext2fs_test_valid(fs)) + fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; + else + exit_value = FSCK_UNCORRECTED; + if (!(ctx->options & E2F_OPT_READONLY)) { + if (ext2fs_test_valid(fs)) { + if (!(fs->super->s_state & EXT2_VALID_FS)) + exit_value = FSCK_NONDESTRUCT; + 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); + } + show_stats(ctx); + + write_bitmaps(ctx); + ext2fs_close(fs); + sync_disks(); + + if (ctx->options & E2F_OPT_TIME) + print_resource_track(NULL, &ctx->global_rtrack); + + e2fsck_free_context(ctx); + + return exit_value; +} diff --git a/e2fsck/util.c b/e2fsck/util.c index 24f77d26..879e7baa 100644 --- a/e2fsck/util.c +++ b/e2fsck/util.c @@ -20,12 +20,10 @@ #include #include -const char * fix_msg[2] = { "IGNORED", "FIXED" }; - void fatal_error (const char *msg) { if (msg) - fprintf (stderr, "%s: %s\n", program_name, msg); + fprintf (stderr, "e2fsck: %s\n", msg); exit(FSCK_ERROR); } @@ -46,7 +44,6 @@ void *allocate_memory(int size, const char *description) return ret; } - int ask_yn(const char * string, int def) { int c; @@ -91,31 +88,32 @@ int ask_yn(const char * string, int def) return def; } -int ask (const char * string, int def) +int ask (e2fsck_t ctx, const char * string, int def) { - if (nflag) { + if (ctx->options & E2F_OPT_NO) { printf ("%s? no\n\n", string); return 0; } - if (yflag) { + if (ctx->options & E2F_OPT_YES) { printf ("%s? yes\n\n", string); return 1; } - if (preen) { + if (ctx->options & E2F_OPT_PREEN) { printf ("%s? %s\n\n", string, def ? "yes" : "no"); return def; } return ask_yn(string, def); } -void read_bitmaps(ext2_filsys fs) +void read_bitmaps(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; errcode_t retval; - if (invalid_bitmaps) { - com_err(program_name, 0, + if (ctx->invalid_bitmaps) { + com_err(ctx->program_name, 0, "read_bitmaps: illegal bitmap block(s) for %s", - device_name); + ctx->device_name); fatal_error(0); } @@ -123,15 +121,16 @@ void read_bitmaps(ext2_filsys fs) retval = ext2fs_read_bitmaps(fs); ehandler_operation(0); if (retval) { - com_err(program_name, retval, + com_err(ctx->program_name, retval, "while retrying to read bitmaps for %s", - device_name); + ctx->device_name); fatal_error(0); } } -void write_bitmaps(ext2_filsys fs) +void write_bitmaps(e2fsck_t ctx) { + ext2_filsys fs = ctx->fs; errcode_t retval; if (ext2fs_test_bb_dirty(fs)) { @@ -139,9 +138,9 @@ void write_bitmaps(ext2_filsys fs) retval = ext2fs_write_block_bitmap(fs); ehandler_operation(0); if (retval) { - com_err(program_name, retval, + com_err(ctx->program_name, retval, "while retrying to write block bitmaps for %s", - device_name); + ctx->device_name); fatal_error(0); } } @@ -151,21 +150,23 @@ void write_bitmaps(ext2_filsys fs) retval = ext2fs_write_inode_bitmap(fs); ehandler_operation(0); if (retval) { - com_err(program_name, retval, + com_err(ctx->program_name, retval, "while retrying to write inode bitmaps for %s", - device_name); + ctx->device_name); fatal_error(0); } } } -void preenhalt(ext2_filsys fs) +void preenhalt(e2fsck_t ctx) { - if (!preen) + ext2_filsys fs = ctx->fs; + + if (!(ctx->options & E2F_OPT_PREEN)) return; fprintf(stderr, "\n\n%s: UNEXPECTED INCONSISTENCY; " "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n", - device_name); + ctx->device_name); if (fs != NULL) { fs->super->s_state |= EXT2_ERROR_FS; ext2fs_mark_super_dirty(fs); @@ -183,6 +184,9 @@ void init_resource_track(struct resource_track *track) track->brk_start = sbrk(0); gettimeofday(&track->time_start, 0); #ifdef HAVE_GETRUSAGE +#ifdef solaris + memcpy(&r, 0, sizeof(struct rusage)); +#endif getrusage(RUSAGE_SELF, &r); track->user_start = r.ru_utime; track->system_start = r.ru_stime; @@ -205,7 +209,7 @@ static _INLINE_ float timeval_subtract(struct timeval *tv1, ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000); } -void print_resource_track(struct resource_track *track) +void print_resource_track(const char *desc, struct resource_track *track) { #ifdef HAVE_GETRUSAGE struct rusage r; @@ -213,6 +217,10 @@ void print_resource_track(struct resource_track *track) struct timeval time_end; gettimeofday(&time_end, 0); + + if (desc) + printf("%s :", desc); + #ifdef HAVE_GETRUSAGE getrusage(RUSAGE_SELF, &r); @@ -265,4 +273,10 @@ void mtrace_print(char *mesg) } #endif +blk_t get_backup_sb(ext2_filsys fs) +{ + if (!fs || !fs->super) + return 8193; + return fs->super->s_blocks_per_group + 1; +} diff --git a/tests/f_badbblocks/expect.1 b/tests/f_badbblocks/expect.1 index 208543fa..d64e745f 100644 --- a/tests/f_badbblocks/expect.1 +++ b/tests/f_badbblocks/expect.1 @@ -13,11 +13,15 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: +50 +Fix? yes + +Free blocks count wrong for group #0 (78, counted=77). +Fix? yes + +Free blocks count wrong (78, counted=77). +Fix? yes -Block bitmap differences: +50. FIXED -Free blocks count wrong for group 0 (78, counted=77). FIXED -Free blocks count wrong (78, counted=77). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 11/32 files (0.0% non-contiguous), 23/100 blocks diff --git a/tests/f_baddir/expect.1 b/tests/f_baddir/expect.1 index f8f02558..375a2bf9 100644 --- a/tests/f_baddir/expect.1 +++ b/tests/f_baddir/expect.1 @@ -36,12 +36,18 @@ Pass 4: Checking reference counts Inode 12 ref count is 1, should be 2. Fix? yes Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: -22 +Fix? yes + +Free blocks count wrong (74, counted=75). +Fix? yes + +Inode bitmap differences: -13 +Fix? yes + +Directories count wrong for group #0 (5, counted=4). +Fix? yes -Block bitmap differences: -22. FIXED -Free blocks count wrong (74, counted=75). FIXED -Inode bitmap differences: -13. FIXED -Directories count wrong for group #0 (5, counted=4). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 14/32 files (0.0% non-contiguous), 25/100 blocks diff --git a/tests/f_baddotdir/expect.1 b/tests/f_baddotdir/expect.1 index 77b8f8cf..e24aa94f 100644 --- a/tests/f_baddotdir/expect.1 +++ b/tests/f_baddotdir/expect.1 @@ -47,10 +47,12 @@ Fix? yes Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (70, counted=71). +Fix? yes + +Free blocks count wrong (70, counted=71). +Fix? yes -Free blocks count wrong for group 0 (70, counted=71). FIXED -Free blocks count wrong (70, counted=71). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 18/32 files (0.0% non-contiguous), 29/100 blocks diff --git a/tests/f_badinode/expect.1 b/tests/f_badinode/expect.1 index 67120d09..29af17ba 100644 --- a/tests/f_badinode/expect.1 +++ b/tests/f_badinode/expect.1 @@ -20,13 +20,21 @@ Clear? yes Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: -25 +Fix? yes + +Free blocks count wrong for group #0 (76, counted=77). +Fix? yes + +Free blocks count wrong (76, counted=77). +Fix? yes + +Free inodes count wrong for group #0 (17, counted=20). +Fix? yes + +Free inodes count wrong (17, counted=20). +Fix? yes -Block bitmap differences: -25. FIXED -Free blocks count wrong for group 0 (76, counted=77). FIXED -Free blocks count wrong (76, counted=77). FIXED -Free inodes count wrong for group #0 (17, counted=20). FIXED -Free inodes count wrong (17, counted=20). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 12/32 files (0.0% non-contiguous), 23/100 blocks diff --git a/tests/f_badprimary/expect.1 b/tests/f_badprimary/expect.1 index bca07d2b..eb498ff5 100644 --- a/tests/f_badprimary/expect.1 +++ b/tests/f_badprimary/expect.1 @@ -4,18 +4,20 @@ Pass 1: Checking inodes, blocks, and sizes The primary superblock (1) is on the bad block list. If the block is really bad, the filesystem can not be fixed. -You can clear the this block from the bad block list -and hope that block is really OK, but there are no guarantees. +You can clear the this block (and hope for the best) from the +bad block list and hope that block is really OK, but there are no +guarantees. -Clear (and hope for the best)? yes +Clear? yes Block 2 in the primary group descriptors is on the bad block list If the block is really bad, the filesystem can not be fixed. -You can clear the this block from the bad block list -and hope that block is really OK, but there are no guarantees. +You can clear the this block (and hope for the best) from the +bad block list and hope that block is really OK, but there are no +guarantees. -Clear (and hope for the best)? yes +Clear? yes Pass 2: Checking directory structure Pass 3: Checking directory connectivity diff --git a/tests/f_badroot/expect.1 b/tests/f_badroot/expect.1 index cd73a334..187c49a4 100644 --- a/tests/f_badroot/expect.1 +++ b/tests/f_badroot/expect.1 @@ -23,13 +23,21 @@ Connect to /lost+found? yes Inode 12 ref count is 2, should be 1. Fix? yes Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (77, counted=76). +Fix? yes + +Free blocks count wrong (77, counted=76). +Fix? yes + +Free inodes count wrong for group #0 (20, counted=19). +Fix? yes + +Directories count wrong for group #0 (2, counted=3). +Fix? yes + +Free inodes count wrong (20, counted=19). +Fix? yes -Free blocks count wrong for group 0 (77, counted=76). FIXED -Free blocks count wrong (77, counted=76). FIXED -Free inodes count wrong for group #0 (20, counted=19). FIXED -Directories count wrong for group #0 (2, counted=3). FIXED -Free inodes count wrong (20, counted=19). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 13/32 files (0.0% non-contiguous), 24/100 blocks diff --git a/tests/f_badtable/expect.1 b/tests/f_badtable/expect.1 index 11bbc970..5cb96176 100644 --- a/tests/f_badtable/expect.1 +++ b/tests/f_badtable/expect.1 @@ -16,15 +16,27 @@ Pass 4: Checking reference counts Inode 2 ref count is 3, should be 2. Fix? yes Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 +Fix? yes + +Free blocks count wrong for group #0 (78, counted=88). +Fix? yes + +Free blocks count wrong (78, counted=88). +Fix? yes + +Inode bitmap differences: +12 +13 +14 +15 +16 +25 +26 +27 +28 +29 +30 +31 +32 +Fix? yes + +Free inodes count wrong for group #0 (21, counted=8). +Fix? yes + +Directories count wrong for group #0 (2, counted=1). +Fix? yes + +Free inodes count wrong (21, counted=8). +Fix? yes -Block bitmap differences: -11 -12 -13 -14 -15 -16 -17 -18 -19 -20. FIXED -Free blocks count wrong for group 0 (78, counted=88). FIXED -Free blocks count wrong (78, counted=88). FIXED -Inode bitmap differences: +12 +13 +14 +15 +16 +25 +26 +27 +28 +29 +30 +31 +32. FIXED -Free inodes count wrong for group #0 (21, counted=8). FIXED -Directories count wrong for group #0 (2, counted=1). FIXED -Free inodes count wrong (21, counted=8). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 24/32 files (0.0% non-contiguous), 12/100 blocks diff --git a/tests/f_bbfile/expect.1 b/tests/f_bbfile/expect.1 index 8dcbc4f5..6ffed264 100644 --- a/tests/f_bbfile/expect.1 +++ b/tests/f_bbfile/expect.1 @@ -18,28 +18,29 @@ File /termcap (inode #12, mod time Sun Jan 2 08:29:13 1994) (inode #1, mod time Sun Jul 17 00:47:58 1994) Clone duplicate/bad blocks? yes - File /lost+found (inode #11, mod time Sun Jan 2 08:28:40 1994) has 12 duplicate block(s), shared with 1 file(s): (inode #1, mod time Sun Jul 17 00:47:58 1994) Clone duplicate/bad blocks? yes - File / (inode #2, mod time Sun Jan 2 08:29:13 1994) has 1 duplicate block(s), shared with 1 file(s): (inode #1, mod time Sun Jul 17 00:47:58 1994) Clone duplicate/bad blocks? yes - Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: +43 +Fix? yes + +Free blocks count wrong for group #0 (57, counted=41). +Fix? yes + +Free blocks count wrong (57, counted=41). +Fix? yes -Block bitmap differences: +43. FIXED -Free blocks count wrong for group 0 (57, counted=41). FIXED -Free blocks count wrong (57, counted=41). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 12/32 files (0.0% non-contiguous), 59/100 blocks diff --git a/tests/f_bbinode/expect.1 b/tests/f_bbinode/expect.1 index 91de7461..0a3ab107 100644 --- a/tests/f_bbinode/expect.1 +++ b/tests/f_bbinode/expect.1 @@ -27,14 +27,24 @@ Clear? yes Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: -83 +Fix? yes + +Free blocks count wrong for group #0 (1962, counted=1965). +Fix? yes + +Free blocks count wrong (1962, counted=1965). +Fix? yes + +Inode bitmap differences: +41 +42 +43 +44 +45 +46 +47 +48 +Fix? yes + +Free inodes count wrong for group #0 (485, counted=477). +Fix? yes + +Free inodes count wrong (485, counted=477). +Fix? yes -Block bitmap differences: -83. FIXED -Free blocks count wrong for group 0 (1962, counted=1965). FIXED -Free blocks count wrong (1962, counted=1965). FIXED -Inode bitmap differences: +41 +42 +43 +44 +45 +46 +47 +48. FIXED -Free inodes count wrong for group #0 (485, counted=477). FIXED -Free inodes count wrong (485, counted=477). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 35/512 files (0.0% non-contiguous), 83/2048 blocks diff --git a/tests/f_bitmaps/expect.1 b/tests/f_bitmaps/expect.1 index 9b15ea2b..715984d4 100644 --- a/tests/f_bitmaps/expect.1 +++ b/tests/f_bitmaps/expect.1 @@ -5,10 +5,12 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: +12 -20 +41 -50 +Fix? yes + +Inode bitmap differences: +11 -15 +Fix? yes -Block bitmap differences: +12 -20 +41 -50. FIXED -Inode bitmap differences: +11 -15. FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 11/32 files (9.1% non-contiguous), 22/100 blocks diff --git a/tests/f_dup/expect.1 b/tests/f_dup/expect.1 index 082c5454..8375b4ed 100644 --- a/tests/f_dup/expect.1 +++ b/tests/f_dup/expect.1 @@ -14,7 +14,6 @@ File /motd (inode #13, mod time Tue Sep 21 03:19:20 1993) /termcap (inode #12, mod time Tue Sep 21 03:19:14 1993) Clone duplicate/bad blocks? yes - File /termcap (inode #12, mod time Tue Sep 21 03:19:14 1993) has 2 duplicate block(s), shared with 1 file(s): /motd (inode #13, mod time Tue Sep 21 03:19:20 1993) @@ -24,10 +23,12 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (44, counted=60). +Fix? yes + +Free blocks count wrong (62, counted=60). +Fix? yes -Free blocks count wrong for group 0 (44, counted=60). FIXED -Free blocks count wrong (62, counted=60). FIXED Padding at end of block bitmap is not set. Fix? yes diff --git a/tests/f_dup2/expect.1 b/tests/f_dup2/expect.1 index f9962952..ff5d30ac 100644 --- a/tests/f_dup2/expect.1 +++ b/tests/f_dup2/expect.1 @@ -15,14 +15,12 @@ File /pass1.c (inode #14, mod time Tue Sep 21 04:28:37 1993) /motd (inode #13, mod time Tue Sep 21 03:19:20 1993) Clone duplicate/bad blocks? yes - File /motd (inode #13, mod time Tue Sep 21 03:19:20 1993) has 4 duplicate block(s), shared with 2 file(s): /pass1.c (inode #14, mod time Tue Sep 21 04:28:37 1993) /termcap (inode #12, mod time Tue Sep 21 03:19:14 1993) Clone duplicate/bad blocks? yes - File /termcap (inode #12, mod time Tue Sep 21 03:19:14 1993) has 2 duplicate block(s), shared with 1 file(s): /motd (inode #13, mod time Tue Sep 21 03:19:20 1993) @@ -32,10 +30,12 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (8, counted=22). +Fix? yes + +Free blocks count wrong (26, counted=22). +Fix? yes -Free blocks count wrong for group 0 (8, counted=22). FIXED -Free blocks count wrong (26, counted=22). FIXED Padding at end of block bitmap is not set. Fix? yes diff --git a/tests/f_dupfsblks/expect.1 b/tests/f_dupfsblks/expect.1 index 1adda3b3..1249f395 100644 --- a/tests/f_dupfsblks/expect.1 +++ b/tests/f_dupfsblks/expect.1 @@ -13,7 +13,6 @@ File /foo (inode #12, mod time Thu Apr 28 17:57:53 1994) Clone duplicate/bad blocks? yes - Pass 2: Checking directory structure Directory inode 12, block 1, offset 0: directory corrupted Salvage? yes @@ -27,10 +26,12 @@ Salvage? yes Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (77, counted=74). +Fix? yes + +Free blocks count wrong (77, counted=74). +Fix? yes -Free blocks count wrong for group 0 (77, counted=74). FIXED -Free blocks count wrong (77, counted=74). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 12/32 files (8.3% non-contiguous), 26/100 blocks diff --git a/tests/f_dupsuper/expect.1 b/tests/f_dupsuper/expect.1 index 61603bff..6fff1c05 100644 --- a/tests/f_dupsuper/expect.1 +++ b/tests/f_dupsuper/expect.1 @@ -13,14 +13,13 @@ File /termcap (inode #12, mod time Sun Jan 2 08:29:13 1994) Clone duplicate/bad blocks? yes - Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: -29 -30 -31 +Fix? yes -Block bitmap differences: -29 -30 -31. FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 12/32 files (8.3% non-contiguous), 39/100 blocks diff --git a/tests/f_end-bitmap/expect.1 b/tests/f_end-bitmap/expect.1 index f2beea62..87e2fd64 100644 --- a/tests/f_end-bitmap/expect.1 +++ b/tests/f_end-bitmap/expect.1 @@ -5,9 +5,9 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (44, counted=63). +Fix? yes -Free blocks count wrong for group 0 (44, counted=63). FIXED Padding at end of block bitmap is not set. Fix? yes diff --git a/tests/f_expand/expect.1 b/tests/f_expand/expect.1 index 86aba903..e8fffdb3 100644 --- a/tests/f_expand/expect.1 +++ b/tests/f_expand/expect.1 @@ -518,13 +518,21 @@ Connect to /lost+found? yes Inode 111 ref count is 2, should be 1. Fix? yes Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (56, counted=55). +Fix? yes + +Free blocks count wrong (56, counted=55). +Fix? yes + +Free inodes count wrong for group #0 (89, counted=88). +Fix? yes + +Directories count wrong for group #0 (2, counted=3). +Fix? yes + +Free inodes count wrong (89, counted=88). +Fix? yes -Free blocks count wrong for group 0 (56, counted=55). FIXED -Free blocks count wrong (56, counted=55). FIXED -Free inodes count wrong for group #0 (89, counted=88). FIXED -Directories count wrong for group #0 (2, counted=3). FIXED -Free inodes count wrong (89, counted=88). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 112/200 files (0.0% non-contiguous), 145/200 blocks diff --git a/tests/f_illbbitmap/expect.1 b/tests/f_illbbitmap/expect.1 index d22dbf2a..0d20dec6 100644 --- a/tests/f_illbbitmap/expect.1 +++ b/tests/f_illbbitmap/expect.1 @@ -16,11 +16,11 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +Fix? yes -Block bitmap differences: +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21. FIXED -Inode bitmap differences: -12 -13 -14 -15 -16 -17 -18 -19 -20 -21. FIXED -Padding at end of block bitmap is not set. Fix? yes +Inode bitmap differences: -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 +Fix? yes test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** diff --git a/tests/f_illibitmap/expect.1 b/tests/f_illibitmap/expect.1 index 4e4d996c..b2ffc360 100644 --- a/tests/f_illibitmap/expect.1 +++ b/tests/f_illibitmap/expect.1 @@ -16,9 +16,9 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Inode bitmap differences: +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +Fix? yes -Inode bitmap differences: +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11. FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 11/32 files (0.0% non-contiguous), 22/100 blocks diff --git a/tests/f_illitable/expect.1 b/tests/f_illitable/expect.1 index e0af316e..aef002c4 100644 --- a/tests/f_illitable/expect.1 +++ b/tests/f_illitable/expect.1 @@ -23,15 +23,27 @@ Root inode not allocated. Allocate? yes Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 +Fix? yes + +Free blocks count wrong for group #0 (78, counted=90). +Fix? yes + +Free blocks count wrong (78, counted=90). +Fix? yes + +Inode bitmap differences: -11 +Fix? yes + +Free inodes count wrong for group #0 (21, counted=22). +Fix? yes + +Directories count wrong for group #0 (2, counted=1). +Fix? yes + +Free inodes count wrong (21, counted=22). +Fix? yes -Block bitmap differences: -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21. FIXED -Free blocks count wrong for group 0 (78, counted=90). FIXED -Free blocks count wrong (78, counted=90). FIXED -Inode bitmap differences: -11. FIXED -Free inodes count wrong for group #0 (21, counted=22). FIXED -Directories count wrong for group #0 (2, counted=1). FIXED -Free inodes count wrong (21, counted=22). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 10/32 files (0.0% non-contiguous), 10/100 blocks diff --git a/tests/f_lotsbad/expect.1 b/tests/f_lotsbad/expect.1 index fd491d50..8a0f06a3 100644 --- a/tests/f_lotsbad/expect.1 +++ b/tests/f_lotsbad/expect.1 @@ -25,14 +25,24 @@ Entry 'termcap' in / (2) has deleted/unused inode 12. Clear? yes Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -44 -45 +Fix? yes + +Free blocks count wrong for group #0 (41, counted=58). +Fix? yes + +Free blocks count wrong (41, counted=58). +Fix? yes + +Inode bitmap differences: -12 +Fix? yes + +Free inodes count wrong for group #0 (20, counted=21). +Fix? yes + +Free inodes count wrong (20, counted=21). +Fix? yes -Block bitmap differences: -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -44 -45. FIXED -Free blocks count wrong for group 0 (41, counted=58). FIXED -Free blocks count wrong (41, counted=58). FIXED -Inode bitmap differences: -12. FIXED -Free inodes count wrong for group #0 (20, counted=21). FIXED -Free inodes count wrong (20, counted=21). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 11/32 files (0.0% non-contiguous), 42/100 blocks diff --git a/tests/f_lpf/expect.1 b/tests/f_lpf/expect.1 index 3803029a..83261fcd 100644 --- a/tests/f_lpf/expect.1 +++ b/tests/f_lpf/expect.1 @@ -24,16 +24,26 @@ Connect to /lost+found? yes Inode 15 ref count is 2, should be 1. Fix? yes Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: +22 +23 +49 +57 +58 +Fix? yes -Block bitmap differences: +22 +23 +49 +57 +58. FIXED -Free blocks count wrong for group 0 (25, counted=33). FIXED -Free blocks count wrong (39, counted=33). FIXED -Inode bitmap differences: +13. FIXED -Free inodes count wrong for group #0 (2, counted=0). FIXED -Directories count wrong for group #0 (1, counted=2). FIXED -Free inodes count wrong (2, counted=0). FIXED -Padding at end of block bitmap is not set. Fix? yes +Free blocks count wrong for group #0 (25, counted=33). +Fix? yes + +Free blocks count wrong (39, counted=33). +Fix? yes + +Inode bitmap differences: +13 +Fix? yes + +Free inodes count wrong for group #0 (2, counted=0). +Fix? yes + +Directories count wrong for group #0 (1, counted=2). +Fix? yes + +Free inodes count wrong (2, counted=0). +Fix? yes test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** diff --git a/tests/f_messy_inode/expect.1 b/tests/f_messy_inode/expect.1 index 32b2a15c..ae5f52ac 100644 --- a/tests/f_messy_inode/expect.1 +++ b/tests/f_messy_inode/expect.1 @@ -24,11 +24,15 @@ Clear? yes Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: -43 -44 -45 -46 -47 -48 -49 +Fix? yes + +Free blocks count wrong for group #0 (68, counted=75). +Fix? yes + +Free blocks count wrong (68, counted=75). +Fix? yes -Block bitmap differences: -43 -44 -45 -46 -47 -48 -49. FIXED -Free blocks count wrong for group 0 (68, counted=75). FIXED -Free blocks count wrong (68, counted=75). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 29/32 files (3.4% non-contiguous), 25/100 blocks diff --git a/tests/f_misstable/expect.1 b/tests/f_misstable/expect.1 index 83514548..5e774613 100644 --- a/tests/f_misstable/expect.1 +++ b/tests/f_misstable/expect.1 @@ -21,15 +21,27 @@ Pass 4: Checking reference counts Inode 2 ref count is 8, should be 4. Fix? yes Pass 5: Checking group summary information -Fix summary information? yes +Block bitmap differences: -8385 -8386 -8387 -8388 -8389 -8390 -8391 -8392 -8393 -8394 -8395 -8396 -8397 -8398 -8399 -8400 -8401 -8402 -8403 -8404 -8405 +Fix? yes + +Free blocks count wrong for group #0 (7987, counted=7984). +Fix? yes + +Free blocks count wrong (11602, counted=11599). +Fix? yes + +Inode bitmap differences: -1505 -1506 -1507 -1508 -1509 -1510 -1511 -1512 -1513 -1514 -1515 -1516 +Fix? yes + +Free inodes count wrong for group #0 (1493, counted=1489). +Fix? yes + +Directories count wrong for group #0 (2, counted=3). +Fix? yes + +Free inodes count wrong (2997, counted=2993). +Fix? yes -Block bitmap differences: -8385 -8386 -8387 -8388 -8389 -8390 -8391 -8392 -8393 -8394 -8395 -8396 -8397 -8398 -8399 -8400 -8401 -8402 -8403 -8404 -8405. FIXED -Free blocks count wrong for group 0 (7987, counted=7984). FIXED -Free blocks count wrong (11602, counted=11599). FIXED -Inode bitmap differences: -1505 -1506 -1507 -1508 -1509 -1510 -1511 -1512 -1513 -1514 -1515 -1516. FIXED -Free inodes count wrong for group #0 (1493, counted=1489). FIXED -Directories count wrong for group #0 (2, counted=3). FIXED -Free inodes count wrong (2997, counted=2993). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 15/3008 files (0.0% non-contiguous), 401/12000 blocks diff --git a/tests/f_noroot/expect.1 b/tests/f_noroot/expect.1 index cef02279..cc90d93a 100644 --- a/tests/f_noroot/expect.1 +++ b/tests/f_noroot/expect.1 @@ -27,13 +27,21 @@ Inode 12 ref count is 4, should be 3. Fix? yes Unattached zero-length inode 15. Clear? yes Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (75, counted=74). +Fix? yes + +Free blocks count wrong (75, counted=74). +Fix? yes + +Free inodes count wrong for group #0 (17, counted=16). +Fix? yes + +Directories count wrong for group #0 (4, counted=5). +Fix? yes + +Free inodes count wrong (17, counted=16). +Fix? yes -Free blocks count wrong for group 0 (75, counted=74). FIXED -Free blocks count wrong (75, counted=74). FIXED -Free inodes count wrong for group #0 (17, counted=16). FIXED -Directories count wrong for group #0 (4, counted=5). FIXED -Free inodes count wrong (17, counted=16). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 16/32 files (0.0% non-contiguous), 26/100 blocks diff --git a/tests/f_overfsblks/expect.1 b/tests/f_overfsblks/expect.1 index d0f47ebd..a38b9142 100644 --- a/tests/f_overfsblks/expect.1 +++ b/tests/f_overfsblks/expect.1 @@ -9,9 +9,9 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Inode bitmap differences: -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 +Fix? yes -Inode bitmap differences: -12 -13 -14 -15 -16 -17 -18 -19 -20 -21. FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 11/32 files (0.0% non-contiguous), 22/100 blocks diff --git a/tests/f_preen/expect.2 b/tests/f_preen/expect.2 index 9d30709d..a7f6ce10 100644 --- a/tests/f_preen/expect.2 +++ b/tests/f_preen/expect.2 @@ -3,15 +3,27 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (8042, counted=7614). +Fix? yes + +Free blocks count wrong for group #1 (170, counted=169). +Fix? yes + +Free blocks count wrong (8212, counted=7783). +Fix? yes + +Free inodes count wrong for group #0 (1053, counted=1052). +Fix? yes + +Free inodes count wrong for group #1 (1064, counted=1063). +Fix? yes + +Directories count wrong for group #1 (0, counted=1). +Fix? yes + +Free inodes count wrong (2117, counted=2115). +Fix? yes -Free blocks count wrong for group 0 (8042, counted=7614). FIXED -Free blocks count wrong for group 1 (170, counted=169). FIXED -Free blocks count wrong (8212, counted=7783). FIXED -Free inodes count wrong for group #0 (1053, counted=1052). FIXED -Free inodes count wrong for group #1 (1064, counted=1063). FIXED -Directories count wrong for group #1 (0, counted=1). FIXED -Free inodes count wrong (2117, counted=2115). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 13/2128 files (0.0% non-contiguous), 717/8500 blocks diff --git a/tests/f_zero_group/expect.1 b/tests/f_zero_group/expect.1 index c066e8c4..20796198 100644 --- a/tests/f_zero_group/expect.1 +++ b/tests/f_zero_group/expect.1 @@ -4,12 +4,18 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (7987, counted=7982). +Fix? yes + +Free blocks count wrong (11602, counted=11597). +Fix? yes + +Free inodes count wrong for group #0 (1493, counted=1488). +Fix? yes + +Free inodes count wrong (2997, counted=2992). +Fix? yes -Free blocks count wrong for group 0 (7987, counted=7982). FIXED -Free blocks count wrong (11602, counted=11597). FIXED -Free inodes count wrong for group #0 (1493, counted=1488). FIXED -Free inodes count wrong (2997, counted=2992). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 16/3008 files (0.0% non-contiguous), 403/12000 blocks diff --git a/tests/f_zero_super/expect.1 b/tests/f_zero_super/expect.1 index ff9e1b3b..a7a6b480 100644 --- a/tests/f_zero_super/expect.1 +++ b/tests/f_zero_super/expect.1 @@ -4,12 +4,18 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -Fix summary information? yes +Free blocks count wrong for group #0 (7987, counted=7982). +Fix? yes + +Free blocks count wrong (11602, counted=11597). +Fix? yes + +Free inodes count wrong for group #0 (1493, counted=1488). +Fix? yes + +Free inodes count wrong (2997, counted=2992). +Fix? yes -Free blocks count wrong for group 0 (7987, counted=7982). FIXED -Free blocks count wrong (11602, counted=11597). FIXED -Free inodes count wrong for group #0 (1493, counted=1488). FIXED -Free inodes count wrong (2997, counted=2992). FIXED test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 16/3008 files (0.0% non-contiguous), 403/12000 blocks