]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - misc/badblocks.c
Many files:
[thirdparty/e2fsprogs.git] / misc / badblocks.c
CommitLineData
3839e657
TT
1/*
2 * badblocks.c - Bad blocks checker
3 *
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)
7 *
8 * This file is based on the minix file system programs fsck and mkfs
9 * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi>
10 *
11 * This file can be redistributed under the terms of the GNU General
12 * Public License
13 */
14
15/*
16 * History:
17 * 93/05/26 - Creation from e2fsck
18 * 94/02/27 - Made a separate bad blocks checker
19 */
20
21#include <errno.h>
22#include <fcntl.h>
23#include <getopt.h>
24#include <signal.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#include <sys/ioctl.h>
f3db3566 31#include <sys/types.h>
3839e657
TT
32
33#include <linux/fd.h>
34#include <linux/fs.h>
35
36#include "et/com_err.h"
f3db3566 37#include "ext2fs/io.h"
3839e657
TT
38
39const char * program_name = "badblocks";
40
41int v_flag = 0; /* verbose */
42int w_flag = 0; /* do r/w test */
43int s_flag = 0; /* show progress of test */
44
45static volatile void usage (void)
46{
f3db3566 47 fprintf (stderr, "Usage: %s [-b block_size] [-o output_file] [-svw] device blocks_count\n [start_count]\n",
3839e657
TT
48 program_name);
49 exit (1);
50}
51
52/*
53 * Perform a test of a block; return the number of blocks readable/writeable.
54 */
55static long do_test (int dev, char * buffer, int try, unsigned long block_size,
56 unsigned long current_block)
57{
58 long got;
59
60 /* Seek to the correct loc. */
f3db3566
TT
61 if (ext2_llseek (dev, (ext2_loff_t) current_block * block_size,
62 SEEK_SET) != (ext2_loff_t) current_block * block_size)
63 com_err (program_name, errno, "during seek");
3839e657
TT
64
65 /* Try the read */
66 got = read (dev, buffer, try * block_size);
67 if (got < 0)
68 got = 0;
69 if (got & (block_size - 1))
f3db3566
TT
70 fprintf (stderr,
71 "Weird value (%ld) in do_test: probably bugs\n",
72 got);
3839e657
TT
73 got /= block_size;
74 return got;
75}
76
77static unsigned long currently_testing = 0;
78static unsigned long num_blocks = 0;
79
80static void alarm_intr (int alnum)
81{
82 signal (SIGALRM, alarm_intr);
83 alarm(1);
84 if (!num_blocks)
85 return;
f3db3566
TT
86 fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
87 fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
3839e657
TT
88 fflush (stderr);
89}
90
91static void test_ro (int dev, unsigned long blocks_count,
f3db3566
TT
92 unsigned long block_size, FILE * out,
93 unsigned long from_count)
3839e657
TT
94{
95#define TEST_BUFFER_BLOCKS 16
96 char * blkbuf;
97 int try;
98 long got;
99
100 blkbuf = malloc (TEST_BUFFER_BLOCKS * block_size);
101 if (!blkbuf)
102 {
103 com_err (program_name, ENOMEM, "while allocating buffers");
104 exit (1);
105 }
106
107 if (v_flag)
108 fprintf (stderr, "Flushing buffers\n");
109 ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */
110 ioctl (dev, FDFLUSH, 0); /* In case this is floppy */
f3db3566
TT
111 if (v_flag) {
112 fprintf (stderr,
113 "Checking for bad blocks in read-only mode\n");
114 fprintf (stderr, "From block %lu to %lu\n", from_count, blocks_count);
115 }
3839e657 116 try = TEST_BUFFER_BLOCKS;
f3db3566 117 currently_testing = from_count;
3839e657
TT
118 num_blocks = blocks_count;
119 if (s_flag) {
120 fprintf(stderr, "Checking for bad blocks (read-only test): ");
121 alarm_intr(SIGALRM);
122 }
123 while (currently_testing < blocks_count)
124 {
125 if (currently_testing + try > blocks_count)
126 try = blocks_count - currently_testing;
127 got = do_test (dev, blkbuf, try, block_size, currently_testing);
128 currently_testing += got;
129 if (got == try) {
130 try = TEST_BUFFER_BLOCKS;
131 continue;
132 }
133 else
134 try = 1;
135 if (got == 0)
136 fprintf (out, "%lu\n", currently_testing++);
137 }
138 num_blocks = 0;
139 alarm(0);
140 if (s_flag)
f3db3566
TT
141 fprintf(stderr, "done \n");
142 fflush (stderr);
3839e657
TT
143 free (blkbuf);
144}
145
146static void test_rw (int dev, unsigned long blocks_count,
f3db3566
TT
147 unsigned long block_size, FILE * out,
148 unsigned long from_count)
3839e657
TT
149{
150 int i;
3839e657
TT
151 char * buffer;
152 unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
153
154 buffer = malloc (2 * block_size);
155 if (!buffer)
156 {
157 com_err (program_name, ENOMEM, "while allocating buffers");
158 exit (1);
159 }
160
161 if (v_flag)
162 fprintf (stderr, "Flushing buffers\n");
163 ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */
164 ioctl (dev, FDFLUSH, 0); /* In case this is floppy */
165 if (v_flag)
166 fprintf (stderr, "Checking for bad blocks in read-write mode\n");
167 for (i = 0; i < sizeof (pattern); i++)
168 {
169 memset (buffer, pattern[i], block_size);
f3db3566
TT
170 if (s_flag | v_flag)
171 fprintf (stderr, "Writing pattern 0x%08x: ",
3839e657 172 *((int *) buffer));
f3db3566
TT
173 num_blocks = blocks_count;
174 currently_testing = from_count;
175 if (s_flag)
176 alarm_intr(SIGALRM);
177 for (;
178 currently_testing < blocks_count;
179 currently_testing++)
3839e657 180 {
f3db3566
TT
181 if (ext2_llseek (dev, (ext2_loff_t) currently_testing *
182 block_size, SEEK_SET) !=
183 (ext2_loff_t) currently_testing * block_size)
3839e657 184 com_err (program_name, errno,
f3db3566
TT
185 "during seek on block %d",
186 currently_testing);
3839e657
TT
187 write (dev, buffer, block_size);
188 }
f3db3566
TT
189 num_blocks = 0;
190 alarm (0);
191 if (s_flag | v_flag)
192 fprintf(stderr, "done \n");
3839e657
TT
193 if (v_flag)
194 fprintf (stderr, "Flushing buffers\n");
195 if (fsync (dev) == -1)
196 com_err (program_name, errno, "during fsync");
197 ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */
198 ioctl (dev, FDFLUSH, 0); /* In case this is floppy */
f3db3566
TT
199 if (s_flag | v_flag)
200 fprintf (stderr, "Reading and comparing: ");
201 num_blocks = blocks_count;
202 currently_testing = from_count;
203 if (s_flag)
204 alarm_intr(SIGALRM);
205 for (;
206 currently_testing < blocks_count;
207 currently_testing++)
3839e657 208 {
f3db3566
TT
209 if (ext2_llseek (dev, (ext2_loff_t) currently_testing *
210 block_size, SEEK_SET) !=
211 (ext2_loff_t) currently_testing * block_size)
3839e657 212 com_err (program_name, errno,
f3db3566
TT
213 "during seek on block %d",
214 currently_testing);
3839e657 215 if (read (dev, buffer + block_size, block_size) < block_size)
f3db3566 216 fprintf (out, "%ld\n", currently_testing);
3839e657 217 else if (memcmp (buffer, buffer + block_size, block_size))
f3db3566 218 fprintf (out, "%ld\n", currently_testing);
3839e657 219 }
f3db3566
TT
220 num_blocks = 0;
221 alarm (0);
222 if (s_flag | v_flag)
223 fprintf(stderr, "done \n");
3839e657
TT
224 if (v_flag)
225 fprintf (stderr, "Flushing buffers\n");
226 ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */
227 ioctl (dev, FDFLUSH, 0); /* In case this is floppy */
228 }
229}
230
231void main (int argc, char ** argv)
232{
233 char c;
234 char * tmp;
235 char * device_name;
236 char * output_file = NULL;
237 FILE * out;
238 unsigned long block_size = 1024;
f3db3566 239 unsigned long blocks_count, from_count;
3839e657
TT
240 int dev;
241
242 setbuf(stdout, NULL);
243 setbuf(stderr, NULL);
244 if (argc && *argv)
245 program_name = *argv;
246 while ((c = getopt (argc, argv, "b:o:svw")) != EOF) {
247 switch (c) {
248 case 'b':
249 block_size = strtoul (optarg, &tmp, 0);
250 if (*tmp || block_size > 4096) {
251 com_err (program_name, 0,
252 "bad block size - %s", optarg);
253 exit (1);
254 }
255 break;
256 case 'o':
257 output_file = optarg;
258 break;
259 case 's':
260 s_flag = 1;
261 break;
262 case 'v':
263 v_flag = 1;
264 break;
265 case 'w':
266 w_flag = 1;
267 break;
268 default:
269 usage ();
270 }
271 }
272 if (optind > argc - 1)
273 usage ();
274 device_name = argv[optind++];
275 if (optind > argc - 1)
276 usage ();
277 blocks_count = strtoul (argv[optind], &tmp, 0);
278 if (*tmp)
279 {
280 com_err (program_name, 0, "bad blocks count - %s", argv[optind]);
281 exit (1);
282 }
f3db3566
TT
283 if (++optind <= argc-1) {
284 from_count = strtoul (argv[optind], &tmp, 0);
285 } else from_count = 0;
286 if (from_count >= blocks_count) {
287 com_err (program_name, 0, "bad blocks range: %lu-%lu",
288 from_count, blocks_count);
289 exit (1);
290 }
3839e657
TT
291 dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
292 if (dev == -1)
293 {
294 com_err (program_name, errno,"while trying to open %s",
295 device_name);
296 exit (1);
297 }
298 if (output_file && strcmp (output_file, "-") != 0)
299 {
300 out = fopen (output_file, "w");
301 if (out == NULL)
302 {
303 com_err (program_name, errno,"while trying to open %s",
304 device_name);
305 exit (1);
306 }
307 }
308 else
309 out = stdout;
310 if (w_flag)
f3db3566 311 test_rw (dev, blocks_count, block_size, out, from_count);
3839e657 312 else
f3db3566 313 test_ro (dev, blocks_count, block_size, out, from_count);
3839e657
TT
314 close (dev);
315 if (out != stdout)
316 fclose (out);
317}