Whamcloud - gitweb
e2fsck, tune2fs: fix post-2038 support for s_lastcheck
[tools/e2fsprogs.git] / e2fsck / badblocks.c
index 6dff23d..fec5f10 100644 (file)
@@ -1,30 +1,52 @@
 /*
  * 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 void invalid_block(ext2_filsys fs, blk_t blk)
+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 %lu out of range; ignored.\n", blk);
+       printf(_("Bad block %u out of range; ignored.\n"), 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];
+
+       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;
+       }
 
-       read_bitmaps(fs);
-       
        /*
         * If we're appending to the bad blocks inode, read in the
         * current bad blocks.
@@ -32,95 +54,89 @@ void read_bad_blocks_file(ext2_filsys fs, const char *bad_blocks_file,
        if (!replace_bad_blocks) {
                retval = ext2fs_read_bb_inode(fs, &bb_list);
                if (retval) {
-                       com_err("ext2fs_read_bb_inode", retval,
-                               "while reading the bad blocks inode");
-                       fatal_error(0);
+                       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.
+        * Now read in the bad blocks from the file; if
+        * bad_blocks_file is null, then try to run the badblocks
+        * command.
         */
-       f = fopen(bad_blocks_file, "r");
-       if (!f) {
-               com_err("read_bad_blocks_file", errno,
-                       "while trying to open %s", bad_blocks_file);
-               fatal_error(0);
+       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);
-       fclose (f);
+       if (bad_blocks_file)
+               fclose(f);
+       else
+               pclose(f);
        if (retval) {
-               com_err("ext2fs_read_bb_FILE", retval,
-                       "while reading in list of bad blocks from file");
-               fatal_error(0);
+               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,
-                       "while updating bad block inode");
-               fatal_error(0);
+               com_err("ext2fs_update_bb_inode", retval, "%s",
+                       _("while updating bad block inode"));
+               goto fatal;
        }
 
-       badblocks_list_free(bb_list);
+       ext2fs_badblocks_list_free(bb_list);
        return;
+
+fatal:
+       ctx->flags |= E2F_FLAG_ABORT;
+       if (bb_list)
+               ext2fs_badblocks_list_free(bb_list);
+       return;
+
 }
 
-void test_disk(ext2_filsys fs)
+static int check_bb_inode_blocks(ext2_filsys fs,
+                                blk_t *block_nr,
+                                int blockcnt EXT2FS_ATTR((unused)),
+                                void *priv_data EXT2FS_ATTR((unused)))
 {
-       errcode_t       retval;
-       badblocks_list  bb_list = 0;
-       FILE            *f;
-       char            buf[1024];
+       if (!*block_nr)
+               return 0;
 
-       read_bitmaps(fs);
-       
        /*
-        * Always read in the current list of bad blocks.
+        * If the block number is outrageous, clear it and ignore it.
         */
-       retval = ext2fs_read_bb_inode(fs, &bb_list);
-       if (retval) {
-               com_err("ext2fs_read_bb_inode", retval,
-                       "while reading the bad blocks inode");
-               fatal_error(0);
-       }
-       
-       /*
-        * Now run the bad blocks program
-        */
-       sprintf(buf, "badblocks %s%s %ld", preen ? "" : "-s ",
-               fs->device_name,
-               fs->super->s_blocks_count);
-       if (verbose)
-               printf("Running command: %s\n", buf);
-       f = popen(buf, "r");
-       if (!f) {
-               com_err("popen", errno,
-                       "while trying to run %s", buf);
-               fatal_error(0);
-       }
-       retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
-       fclose (f);
-       if (retval) {
-               com_err("ext2fs_read_bb_FILE", retval,
-                       "while processing list of bad blocks from program");
-               fatal_error(0);
-       }
-       
-       /*
-        * Finally, update the bad blocks from the bad_block_map
-        */
-       retval = ext2fs_update_bb_inode(fs, bb_list);
-       if (retval) {
-               com_err("ext2fs_update_bb_inode", retval,
-                       "while updating bad block inode");
-               fatal_error(0);
+       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;
        }
 
-       badblocks_list_free(bb_list);
-       return;
+       return 0;
 }