diff options
Diffstat (limited to 'e2fsck/badblocks.c')
-rw-r--r-- | e2fsck/badblocks.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/e2fsck/badblocks.c b/e2fsck/badblocks.c new file mode 100644 index 0000000..fec5f10 --- /dev/null +++ b/e2fsck/badblocks.c @@ -0,0 +1,142 @@ +/* + * badblocks.c --- replace/append bad blocks to the bad block inode + * + * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be + * redistributed under the terms of the GNU Public License. + */ + +#include "config.h" +#include <time.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#include <et/com_err.h> +#include "e2fsck.h" + +static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt, + void *priv_data); + + +static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk) +{ + printf(_("Bad block %u out of range; ignored.\n"), blk); + return; +} + +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]; + + e2fsck_read_bitmaps(ctx); + + /* + * Make sure the bad block inode is sane. If there are any + * illegal blocks, clear them. + */ + retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0, + check_bb_inode_blocks, 0); + if (retval) { + com_err("ext2fs_block_iterate", retval, "%s", + _("while sanity checking the bad blocks inode")); + goto fatal; + } + + /* + * If we're appending to the bad blocks inode, read in the + * current bad blocks. + */ + if (!replace_bad_blocks) { + retval = ext2fs_read_bb_inode(fs, &bb_list); + if (retval) { + com_err("ext2fs_read_bb_inode", retval, "%s", + _("while reading the bad blocks inode")); + goto fatal; + } + } + + /* + * Now read in the bad blocks from the file; if + * bad_blocks_file is null, then try to run the badblocks + * command. + */ + if (bad_blocks_file) { + f = fopen(bad_blocks_file, "r"); + if (!f) { + com_err("read_bad_blocks_file", errno, + _("while trying to open %s"), bad_blocks_file); + goto fatal; + } + } else { + sprintf(buf, "badblocks -b %d -X %s%s%s %llu", fs->blocksize, + (ctx->options & E2F_OPT_PREEN) ? "" : "-s ", + (ctx->options & E2F_OPT_WRITECHECK) ? "-n " : "", + fs->device_name, + (unsigned long long) ext2fs_blocks_count(fs->super)-1); + f = popen(buf, "r"); + if (!f) { + com_err("read_bad_blocks_file", errno, + _("while trying popen '%s'"), buf); + goto fatal; + } + } + retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block); + if (bad_blocks_file) + fclose(f); + else + pclose(f); + if (retval) { + com_err("ext2fs_read_bb_FILE", retval, "%s", + _("while reading in list of bad blocks from file")); + goto fatal; + } + + /* + * Finally, update the bad blocks from the bad_block_map + */ + printf("%s: Updating bad block inode.\n", ctx->device_name); + retval = ext2fs_update_bb_inode(fs, bb_list); + if (retval) { + com_err("ext2fs_update_bb_inode", retval, "%s", + _("while updating bad block inode")); + goto fatal; + } + + ext2fs_badblocks_list_free(bb_list); + return; + +fatal: + ctx->flags |= E2F_FLAG_ABORT; + if (bb_list) + ext2fs_badblocks_list_free(bb_list); + return; + +} + +static int check_bb_inode_blocks(ext2_filsys fs, + blk_t *block_nr, + int blockcnt EXT2FS_ATTR((unused)), + void *priv_data EXT2FS_ATTR((unused))) +{ + if (!*block_nr) + return 0; + + /* + * If the block number is outrageous, clear it and ignore it. + */ + if (*block_nr >= ext2fs_blocks_count(fs->super) || + *block_nr < fs->super->s_first_data_block) { + printf(_("Warning: illegal block %u found in bad block inode. " + "Cleared.\n"), *block_nr); + *block_nr = 0; + return BLOCK_CHANGED; + } + + return 0; +} + |