Whamcloud - gitweb
Many files:
[tools/e2fsprogs.git] / e2fsck / badblocks.c
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 <time.h>
9 #ifdef HAVE_ERRNO_H
10 #include <errno.h>
11 #endif
12
13 #include <et/com_err.h>
14 #include "e2fsck.h"
15
16 static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt,
17                                  void *private);
18
19
20 static void invalid_block(ext2_filsys fs, blk_t blk)
21 {
22         printf("Bad block %u out of range; ignored.\n", blk);
23         return;
24 }
25
26 void read_bad_blocks_file(ext2_filsys fs, const char *bad_blocks_file,
27                           int replace_bad_blocks)
28 {
29         errcode_t       retval;
30         badblocks_list  bb_list = 0;
31         FILE            *f;
32         char            buf[1024];
33
34         read_bitmaps(fs);
35
36         /*
37          * Make sure the bad block inode is sane.  If there are any
38          * illegal blocks, clear them.
39          */
40         retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0,
41                                       check_bb_inode_blocks, 0);
42         if (retval) {
43                 com_err("ext2fs_block_iterate", retval,
44                         "while sanity checking the bad blocks inode");
45                 fatal_error(0);
46         }
47         
48         /*
49          * If we're appending to the bad blocks inode, read in the
50          * current bad blocks.
51          */
52         if (!replace_bad_blocks) {
53                 retval = ext2fs_read_bb_inode(fs, &bb_list);
54                 if (retval) {
55                         com_err("ext2fs_read_bb_inode", retval,
56                                 "while reading the bad blocks inode");
57                         fatal_error(0);
58                 }
59         }
60         
61         /*
62          * Now read in the bad blocks from the file; if
63          * bad_blocks_file is null, then try to run the badblocks
64          * command.
65          */
66         if (bad_blocks_file) {
67                 f = fopen(bad_blocks_file, "r");
68                 if (!f) {
69                         com_err("read_bad_blocks_file", errno,
70                                 "while trying to open %s", bad_blocks_file);
71                         fatal_error(0);
72                 }
73         } else {
74                 sprintf(buf, "badblocks %s%s %d", preen ? "" : "-s ",
75                         fs->device_name,
76                         fs->super->s_blocks_count);
77                 f = popen(buf, "r");
78                 if (!f) {
79                         com_err("read_bad_blocks_file", errno,
80                                 "while trying popen '%s'", buf);
81                         fatal_error(0);
82                 }
83         }
84         retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
85         if (bad_blocks_file) 
86                 fclose(f);
87         else
88                 pclose(f);
89         if (retval) {
90                 com_err("ext2fs_read_bb_FILE", retval,
91                         "while reading in list of bad blocks from file");
92                 fatal_error(0);
93         }
94         
95         /*
96          * Finally, update the bad blocks from the bad_block_map
97          */
98         retval = ext2fs_update_bb_inode(fs, bb_list);
99         if (retval) {
100                 com_err("ext2fs_update_bb_inode", retval,
101                         "while updating bad block inode");
102                 fatal_error(0);
103         }
104
105         badblocks_list_free(bb_list);
106         return;
107 }
108
109 void test_disk(ext2_filsys fs)
110 {
111         read_bad_blocks_file(fs, 0, 1);
112 }
113
114 static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt,
115                                  void *private)
116 {
117         if (!*block_nr)
118                 return 0;
119
120         /*
121          * If the block number is outrageous, clear it and ignore it.
122          */
123         if (*block_nr >= fs->super->s_blocks_count ||
124             *block_nr < fs->super->s_first_data_block) {
125                 printf("Warning illegal block %u found in bad block inode.  Cleared.\n", *block_nr);
126                 *block_nr = 0;
127                 return BLOCK_CHANGED;
128         }
129
130         return 0;
131 }
132