badblocks.c revision 45ff69ffeb700012a7c052f5e45882557a40be7e
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
17static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt,
18				 void *priv_data);
19
20
21static 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
27void 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
112fatal:
113	ctx->flags |= E2F_FLAG_ABORT;
114	return;
115
116}
117
118static int check_bb_inode_blocks(ext2_filsys fs,
119				 blk_t *block_nr,
120				 int blockcnt EXT2FS_ATTR((unused)),
121				 void *priv_data EXT2FS_ATTR((unused)))
122{
123	if (!*block_nr)
124		return 0;
125
126	/*
127	 * If the block number is outrageous, clear it and ignore it.
128	 */
129	if (*block_nr >= ext2fs_blocks_count(fs->super) ||
130	    *block_nr < fs->super->s_first_data_block) {
131		printf(_("Warning: illegal block %u found in bad block inode.  "
132			 "Cleared.\n"), *block_nr);
133		*block_nr = 0;
134		return BLOCK_CHANGED;
135	}
136
137	return 0;
138}
139
140