1 /* 2 * badblocks.c --- replace/append bad blocks to the bad block inode 3 * 4 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be 5 * redistributed under the terms of the GNU Public License. 6 */ 7 8 #include "config.h" 9 #include <time.h> 10 #ifdef HAVE_ERRNO_H 11 #include <errno.h> 12 #endif 13 14 #include <et/com_err.h> 15 #include "e2fsck.h" 16 17 static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt, 18 void *priv_data); 19 20 21 static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk) 22 { 23 printf(_("Bad block %u out of range; ignored.\n"), blk); 24 return; 25 } 26 27 void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file, 28 int replace_bad_blocks) 29 { 30 ext2_filsys fs = ctx->fs; 31 errcode_t retval; 32 badblocks_list bb_list = 0; 33 FILE *f; 34 char buf[1024]; 35 36 e2fsck_read_bitmaps(ctx); 37 38 /* 39 * Make sure the bad block inode is sane. If there are any 40 * illegal blocks, clear them. 41 */ 42 retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0, 43 check_bb_inode_blocks, 0); 44 if (retval) { 45 com_err("ext2fs_block_iterate", retval, "%s", 46 _("while sanity checking the bad blocks inode")); 47 goto fatal; 48 } 49 50 /* 51 * If we're appending to the bad blocks inode, read in the 52 * current bad blocks. 53 */ 54 if (!replace_bad_blocks) { 55 retval = ext2fs_read_bb_inode(fs, &bb_list); 56 if (retval) { 57 com_err("ext2fs_read_bb_inode", retval, "%s", 58 _("while reading the bad blocks inode")); 59 goto fatal; 60 } 61 } 62 63 /* 64 * Now read in the bad blocks from the file; if 65 * bad_blocks_file is null, then try to run the badblocks 66 * command. 67 */ 68 if (bad_blocks_file) { 69 f = fopen(bad_blocks_file, "r"); 70 if (!f) { 71 com_err("read_bad_blocks_file", errno, 72 _("while trying to open %s"), bad_blocks_file); 73 goto fatal; 74 } 75 } else { 76 sprintf(buf, "badblocks -b %d -X %s%s%s %llu", fs->blocksize, 77 (ctx->options & E2F_OPT_PREEN) ? "" : "-s ", 78 (ctx->options & E2F_OPT_WRITECHECK) ? "-n " : "", 79 fs->device_name, ext2fs_blocks_count(fs->super)-1); 80 f = popen(buf, "r"); 81 if (!f) { 82 com_err("read_bad_blocks_file", errno, 83 _("while trying popen '%s'"), buf); 84 goto fatal; 85 } 86 } 87 retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block); 88 if (bad_blocks_file) 89 fclose(f); 90 else 91 pclose(f); 92 if (retval) { 93 com_err("ext2fs_read_bb_FILE", retval, "%s", 94 _("while reading in list of bad blocks from file")); 95 goto fatal; 96 } 97 98 /* 99 * Finally, update the bad blocks from the bad_block_map 100 */ 101 printf("%s: Updating bad block inode.\n", ctx->device_name); 102 retval = ext2fs_update_bb_inode(fs, bb_list); 103 if (retval) { 104 com_err("ext2fs_update_bb_inode", retval, "%s", 105 _("while updating bad block inode")); 106 goto fatal; 107 } 108 109 ext2fs_badblocks_list_free(bb_list); 110 return; 111 112 fatal: 113 ctx->flags |= E2F_FLAG_ABORT; 114 if (bb_list) 115 ext2fs_badblocks_list_free(bb_list); 116 return; 117 118 } 119 120 static int check_bb_inode_blocks(ext2_filsys fs, 121 blk_t *block_nr, 122 int blockcnt EXT2FS_ATTR((unused)), 123 void *priv_data EXT2FS_ATTR((unused))) 124 { 125 if (!*block_nr) 126 return 0; 127 128 /* 129 * If the block number is outrageous, clear it and ignore it. 130 */ 131 if (*block_nr >= ext2fs_blocks_count(fs->super) || 132 *block_nr < fs->super->s_first_data_block) { 133 printf(_("Warning: illegal block %u found in bad block inode. " 134 "Cleared.\n"), *block_nr); 135 *block_nr = 0; 136 return BLOCK_CHANGED; 137 } 138 139 return 0; 140 } 141 142