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/io.h"
47 const char * program_name = "badblocks";
49 int v_flag = 0; /* verbose */
50 int w_flag = 0; /* do r/w test */
51 int s_flag = 0; /* show progress of test */
53 static volatile void usage (void)
55 fprintf (stderr, "Usage: %s [-b block_size] [-o output_file] [-svw] device blocks_count\n [start_count]\n",
60 static unsigned long currently_testing = 0;
61 static unsigned long num_blocks = 0;
63 static void print_status(void)
65 fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
66 fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
70 static void alarm_intr (int alnum)
72 signal (SIGALRM, alarm_intr);
76 fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
77 fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
82 * Perform a test of a block; return the number of blocks readable/writeable.
84 static long do_test (int dev, char * buffer, int try, unsigned long block_size,
85 unsigned long current_block)
92 /* Seek to the correct loc. */
93 if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
94 SEEK_SET) != (ext2_loff_t) current_block * block_size)
95 com_err (program_name, errno, "during seek");
98 got = read (dev, buffer, try * block_size);
101 if (got & (block_size - 1))
103 "Weird value (%ld) in do_test: probably bugs\n",
109 static void flush_bufs (int dev, int sync)
112 #if !defined (BLKFLSBUF) && !defined (FDFLUSH)
116 fprintf (stderr, "Flushing buffers\n");
118 if (sync && fsync (dev) == -1)
119 com_err (program_name, errno, "during fsync");
122 ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */
125 ioctl (dev, FDFLUSH, 0); /* In case this is floppy */
129 static void test_ro (int dev, unsigned long blocks_count,
130 unsigned long block_size, FILE * out,
131 unsigned long from_count)
133 #define TEST_BUFFER_BLOCKS 16
138 blkbuf = malloc (TEST_BUFFER_BLOCKS * block_size);
141 com_err (program_name, ENOMEM, "while allocating buffers");
147 "Checking for bad blocks in read-only mode\n");
148 fprintf (stderr, "From block %lu to %lu\n", from_count, blocks_count);
150 try = TEST_BUFFER_BLOCKS;
151 currently_testing = from_count;
152 num_blocks = blocks_count;
153 if (s_flag || v_flag > 1) {
154 fprintf(stderr, "Checking for bad blocks (read-only test): ");
158 while (currently_testing < blocks_count)
160 if (currently_testing + try > blocks_count)
161 try = blocks_count - currently_testing;
162 got = do_test (dev, blkbuf, try, block_size, currently_testing);
163 currently_testing += got;
165 try = TEST_BUFFER_BLOCKS;
171 fprintf (out, "%lu\n", currently_testing++);
175 if (s_flag || v_flag > 1)
176 fprintf(stderr, "done \n");
181 static void test_rw (int dev, unsigned long blocks_count,
182 unsigned long block_size, FILE * out,
183 unsigned long from_count)
187 unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
189 buffer = malloc (2 * block_size);
192 com_err (program_name, ENOMEM, "while allocating buffers");
200 "Checking for bad blocks in read-write mode\n");
201 fprintf(stderr, "From block %lu to %lu\n",
202 from_count, blocks_count);
204 for (i = 0; i < sizeof (pattern); i++) {
205 memset (buffer, pattern[i], block_size);
207 fprintf (stderr, "Writing pattern 0x%08x: ",
209 num_blocks = blocks_count;
210 currently_testing = from_count;
211 if (s_flag && v_flag <= 1)
214 currently_testing < blocks_count;
217 if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
218 block_size, SEEK_SET) !=
219 (ext2_loff_t) currently_testing * block_size)
220 com_err (program_name, errno,
221 "during seek on block %d",
225 write (dev, buffer, block_size);
230 fprintf(stderr, "done \n");
233 fprintf (stderr, "Reading and comparing: ");
234 num_blocks = blocks_count;
235 currently_testing = from_count;
236 if (s_flag && v_flag <= 1)
239 currently_testing < blocks_count;
242 if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
243 block_size, SEEK_SET) !=
244 (ext2_loff_t) currently_testing * block_size)
245 com_err (program_name, errno,
246 "during seek on block %d",
250 if (read (dev, buffer + block_size, block_size) < block_size)
251 fprintf (out, "%ld\n", currently_testing);
252 else if (memcmp (buffer, buffer + block_size, block_size))
253 fprintf (out, "%ld\n", currently_testing);
258 fprintf(stderr, "done \n");
263 void main (int argc, char ** argv)
268 char * output_file = NULL;
270 unsigned long block_size = 1024;
271 unsigned long blocks_count, from_count;
274 setbuf(stdout, NULL);
275 setbuf(stderr, NULL);
277 program_name = *argv;
278 while ((c = getopt (argc, argv, "b:o:svw")) != EOF) {
281 block_size = strtoul (optarg, &tmp, 0);
282 if (*tmp || block_size > 4096) {
283 com_err (program_name, 0,
284 "bad block size - %s", optarg);
289 output_file = optarg;
304 if (optind > argc - 1)
306 device_name = argv[optind++];
307 if (optind > argc - 1)
309 blocks_count = strtoul (argv[optind], &tmp, 0);
312 com_err (program_name, 0, "bad blocks count - %s", argv[optind]);
315 if (++optind <= argc-1) {
316 from_count = strtoul (argv[optind], &tmp, 0);
317 } else from_count = 0;
318 if (from_count >= blocks_count) {
319 com_err (program_name, 0, "bad blocks range: %lu-%lu",
320 from_count, blocks_count);
323 dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
326 com_err (program_name, errno,"while trying to open %s",
330 if (output_file && strcmp (output_file, "-") != 0)
332 out = fopen (output_file, "w");
335 com_err (program_name, errno,"while trying to open %s",
343 test_rw (dev, blocks_count, block_size, out, from_count);
345 test_ro (dev, blocks_count, block_size, out, from_count);