2 * badblocks.c - Bad blocks checker
4 * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
5 * Laboratoire MASI, Institut Blaise Pascal
6 * Universite Pierre et Marie Curie (Paris VI)
8 * Copyright 1995, 1996, 1997 by Theodore Ts'o
10 * This file is based on the minix file system programs fsck and mkfs
11 * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi>
14 * This file may be redistributed under the terms of the GNU Public
21 * 93/05/26 - Creation from e2fsck
22 * 94/02/27 - Made a separate bad blocks checker
36 #include <sys/ioctl.h>
37 #include <sys/types.h>
44 #include "et/com_err.h"
45 #include "ext2fs/ext2_io.h"
47 const char * program_name = "badblocks";
48 const char * done_string = "done \n";
50 int v_flag = 0; /* verbose */
51 int w_flag = 0; /* do r/w test */
52 int s_flag = 0; /* show progress of test */
54 static void usage(void)
56 fprintf (stderr, "Usage: %s [-b block_size] [-o output_file] [-svw] device blocks_count\n [start_count]\n",
61 static unsigned long currently_testing = 0;
62 static unsigned long num_blocks = 0;
64 static void print_status(void)
66 fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
67 fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
71 static void alarm_intr (int alnum)
73 signal (SIGALRM, alarm_intr);
77 fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
78 fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
83 * Perform a test of a block; return the number of blocks readable/writeable.
85 static long do_test (int dev, char * buffer, int try, unsigned long block_size,
86 unsigned long current_block)
93 /* Seek to the correct loc. */
94 if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
95 SEEK_SET) != (ext2_loff_t) current_block * block_size)
96 com_err (program_name, errno, "during seek");
99 got = read (dev, buffer, try * block_size);
102 if (got & (block_size - 1))
104 "Weird value (%ld) in do_test: probably bugs\n",
110 static void flush_bufs (int dev, int sync)
113 #if !defined (BLKFLSBUF) && !defined (FDFLUSH)
117 fprintf (stderr, "Flushing buffers\n");
119 if (sync && fsync (dev) == -1)
120 com_err (program_name, errno, "during fsync");
123 ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */
126 ioctl (dev, FDFLUSH, 0); /* In case this is floppy */
130 static void test_ro (int dev, unsigned long blocks_count,
131 unsigned long block_size, FILE * out,
132 unsigned long from_count)
134 #define TEST_BUFFER_BLOCKS 16
139 blkbuf = malloc (TEST_BUFFER_BLOCKS * block_size);
142 com_err (program_name, ENOMEM, "while allocating buffers");
148 "Checking for bad blocks in read-only mode\n");
149 fprintf (stderr, "From block %lu to %lu\n", from_count, blocks_count);
151 try = TEST_BUFFER_BLOCKS;
152 currently_testing = from_count;
153 num_blocks = blocks_count;
154 if (s_flag || v_flag > 1) {
155 fprintf(stderr, "Checking for bad blocks (read-only test): ");
159 while (currently_testing < blocks_count)
161 if (currently_testing + try > blocks_count)
162 try = blocks_count - currently_testing;
163 got = do_test (dev, blkbuf, try, block_size, currently_testing);
164 currently_testing += got;
166 try = TEST_BUFFER_BLOCKS;
172 fprintf (out, "%lu\n", currently_testing++);
176 if (s_flag || v_flag > 1)
177 fprintf(stderr, done_string);
182 static void test_rw (int dev, unsigned long blocks_count,
183 unsigned long block_size, FILE * out,
184 unsigned long from_count)
188 unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
190 buffer = malloc (2 * block_size);
193 com_err (program_name, ENOMEM, "while allocating buffers");
201 "Checking for bad blocks in read-write mode\n");
202 fprintf(stderr, "From block %lu to %lu\n",
203 from_count, blocks_count);
205 for (i = 0; i < sizeof (pattern); i++) {
206 memset (buffer, pattern[i], block_size);
208 fprintf (stderr, "Writing pattern 0x%08x: ",
210 num_blocks = blocks_count;
211 currently_testing = from_count;
212 if (s_flag && v_flag <= 1)
215 currently_testing < blocks_count;
218 if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
219 block_size, SEEK_SET) !=
220 (ext2_loff_t) currently_testing * block_size)
221 com_err (program_name, errno,
222 "during seek on block %d",
226 write (dev, buffer, block_size);
231 fprintf(stderr, done_string);
234 fprintf (stderr, "Reading and comparing: ");
235 num_blocks = blocks_count;
236 currently_testing = from_count;
237 if (s_flag && v_flag <= 1)
240 currently_testing < blocks_count;
243 if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
244 block_size, SEEK_SET) !=
245 (ext2_loff_t) currently_testing * block_size)
246 com_err (program_name, errno,
247 "during seek on block %d",
251 if (read (dev, buffer + block_size, block_size) < block_size)
252 fprintf (out, "%ld\n", currently_testing);
253 else if (memcmp (buffer, buffer + block_size, block_size))
254 fprintf (out, "%ld\n", currently_testing);
259 fprintf(stderr, done_string);
264 int main (int argc, char ** argv)
269 char * output_file = NULL;
271 unsigned long block_size = 1024;
272 unsigned long blocks_count, from_count;
275 setbuf(stdout, NULL);
276 setbuf(stderr, NULL);
278 program_name = *argv;
279 while ((c = getopt (argc, argv, "b:o:svw")) != EOF) {
282 block_size = strtoul (optarg, &tmp, 0);
283 if (*tmp || block_size > 4096) {
284 com_err (program_name, 0,
285 "bad block size - %s", optarg);
290 output_file = optarg;
305 if (optind > argc - 1)
307 device_name = argv[optind++];
308 if (optind > argc - 1)
310 blocks_count = strtoul (argv[optind], &tmp, 0);
313 com_err (program_name, 0, "bad blocks count - %s", argv[optind]);
316 if (++optind <= argc-1) {
317 from_count = strtoul (argv[optind], &tmp, 0);
318 } else from_count = 0;
319 if (from_count >= blocks_count) {
320 com_err (program_name, 0, "bad blocks range: %lu-%lu",
321 from_count, blocks_count);
324 dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
327 com_err (program_name, errno,"while trying to open %s",
331 if (output_file && strcmp (output_file, "-") != 0)
333 out = fopen (output_file, "w");
336 com_err (program_name, errno,"while trying to open %s",
344 test_rw (dev, blocks_count, block_size, out, from_count);
346 test_ro (dev, blocks_count, block_size, out, from_count);