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