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, 1998, 1999 by Theodore Ts'o
9 * Copyright 1999 by David Beattie
11 * This file is based on the minix file system programs fsck and mkfs
12 * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi>
15 * This file may be redistributed under the terms of the GNU Public
22 * 93/05/26 - Creation from e2fsck
23 * 94/02/27 - Made a separate bad blocks checker
24 * 99/06/30...99/07/26 - Added non-destructive write-testing,
25 * configurable blocks-at-once parameter,
26 * loading of badblocks list to avoid testing
27 * blocks known to be bad, multiple passes to
28 * make sure that no new blocks are added to the
29 * list. (Work done by David Beattie)
32 #define _GNU_SOURCE /* for O_DIRECT */
51 #include <sys/ioctl.h>
52 #include <sys/types.h>
54 #include "et/com_err.h"
55 #include "ext2fs/ext2_io.h"
56 #include "ext2fs/ext2_fs.h"
57 #include "ext2fs/ext2fs.h"
58 #include "nls-enable.h"
60 const char * program_name
= "badblocks";
61 const char * done_string
= N_("done \n");
63 static int v_flag
= 0; /* verbose */
64 static int w_flag
= 0; /* do r/w test: 0=no, 1=yes,
65 * 2=non-destructive */
66 static int s_flag
= 0; /* show progress of test */
67 static int force
= 0; /* force check of mounted device */
68 static int t_flag
= 0; /* number of test patterns */
69 static int t_max
= 0; /* allocated test patterns */
70 static unsigned int *t_patts
= NULL
; /* test patterns */
71 static int current_O_DIRECT
= 0; /* Current status of O_DIRECT flag */
72 static int exclusive_ok
= 0;
76 unsigned int sys_page_size
= 4096;
78 static void usage(void)
80 fprintf(stderr
, _("Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnf]\n [-c blocks_at_once] [-p num_passes] [-t test_pattern [-t test_pattern [...]]]\n device [last_block [start_block]]\n"),
85 static void exclusive_usage(void)
88 _("%s: The -n and -w options are mutually exclusive.\n\n"),
93 static blk_t currently_testing
= 0;
94 static blk_t num_blocks
= 0;
95 static ext2_badblocks_list bb_list
= NULL
;
97 static blk_t next_bad
= 0;
98 static ext2_badblocks_iterate bb_iter
= NULL
;
100 static void *allocate_buffer(size_t size
)
104 #ifdef HAVE_POSIX_MEMALIGN
105 if (posix_memalign(&ret
, sys_page_size
, size
) < 0)
109 ret
= memalign(sys_page_size
, size
);
113 #endif /* HAVE_VALLOC */
114 #endif /* HAVE_MEMALIGN */
115 #endif /* HAVE_POSIX_MEMALIGN */
124 * This routine reports a new bad block. If the bad block has already
125 * been seen before, then it returns 0; otherwise it returns 1.
127 static int bb_output (blk_t bad
)
131 if (ext2fs_badblocks_list_test(bb_list
, bad
))
134 fprintf(out
, "%lu\n", (unsigned long) bad
);
137 errcode
= ext2fs_badblocks_list_add (bb_list
, bad
);
139 com_err (program_name
, errcode
, "adding to in-memory bad block list");
144 increment the iteration through the bb_list if
145 an element was just added before the current iteration
146 position. This should not cause next_bad to change. */
147 if (bb_iter
&& bad
< next_bad
)
148 ext2fs_badblocks_list_iterate (bb_iter
, &next_bad
);
152 static void print_status(void)
154 fprintf(stderr
, "%15lu/%15lu", (unsigned long) currently_testing
,
155 (unsigned long) num_blocks
);
156 fputs("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", stderr
);
160 static void alarm_intr(int alnum
EXT2FS_ATTR((unused
)))
162 signal (SIGALRM
, alarm_intr
);
169 static void *terminate_addr
= NULL
;
171 static void terminate_intr(int signo
EXT2FS_ATTR((unused
)))
174 longjmp(terminate_addr
,1);
178 static void capture_terminate(jmp_buf term_addr
)
180 terminate_addr
= term_addr
;
181 signal (SIGHUP
, terminate_intr
);
182 signal (SIGINT
, terminate_intr
);
183 signal (SIGPIPE
, terminate_intr
);
184 signal (SIGTERM
, terminate_intr
);
185 signal (SIGUSR1
, terminate_intr
);
186 signal (SIGUSR2
, terminate_intr
);
189 static void uncapture_terminate(void)
191 terminate_addr
= NULL
;
192 signal (SIGHUP
, SIG_DFL
);
193 signal (SIGINT
, SIG_DFL
);
194 signal (SIGPIPE
, SIG_DFL
);
195 signal (SIGTERM
, SIG_DFL
);
196 signal (SIGUSR1
, SIG_DFL
);
197 signal (SIGUSR2
, SIG_DFL
);
200 static void set_o_direct(int dev
, unsigned char *buffer
, size_t size
,
204 int new_flag
= O_DIRECT
;
207 if ((((unsigned long) buffer
& (sys_page_size
- 1)) != 0) ||
208 ((size
& (sys_page_size
- 1)) != 0) ||
209 ((current_block
& ((sys_page_size
>> 9)-1)) != 0))
212 if (new_flag
!= current_O_DIRECT
) {
213 /* printf("%s O_DIRECT\n", new_flag ? "Setting" : "Clearing"); */
214 flag
= fcntl(dev
, F_GETFL
);
216 flag
= (flag
& ~O_DIRECT
) | new_flag
;
217 fcntl(dev
, F_SETFL
, flag
);
219 current_O_DIRECT
= new_flag
;
225 static void pattern_fill(unsigned char *buffer
, unsigned int pattern
,
229 unsigned char bpattern
[sizeof(pattern
)], *ptr
;
231 if (pattern
== (unsigned int) ~0) {
232 for (ptr
= buffer
; ptr
< buffer
+ n
; ptr
++) {
233 (*ptr
) = random() % (1 << (8 * sizeof(char)));
236 fputs(_("Testing with random pattern: "), stderr
);
239 for (i
= 0; i
< sizeof(bpattern
); i
++) {
242 bpattern
[i
] = pattern
& 0xFF;
243 pattern
= pattern
>> 8;
246 for (ptr
= buffer
, i
= nb
; ptr
< buffer
+ n
; ptr
++) {
253 if (s_flag
| v_flag
) {
254 fputs(_("Testing with pattern 0x"), stderr
);
255 for (i
= 0; i
<= nb
; i
++)
256 fprintf(stderr
, "%02x", buffer
[i
]);
263 * Perform a read of a sequence of blocks; return the number of blocks
264 * successfully sequentially read.
266 static int do_read (int dev
, unsigned char * buffer
, int try, int block_size
,
271 set_o_direct(dev
, buffer
, try * block_size
, current_block
);
276 /* Seek to the correct loc. */
277 if (ext2fs_llseek (dev
, (ext2_loff_t
) current_block
* block_size
,
278 SEEK_SET
) != (ext2_loff_t
) current_block
* block_size
)
279 com_err (program_name
, errno
, _("during seek"));
282 got
= read (dev
, buffer
, try * block_size
);
286 fprintf(stderr
, _("Weird value (%ld) in do_read\n"), got
);
292 * Perform a write of a sequence of blocks; return the number of blocks
293 * successfully sequentially written.
295 static int do_write(int dev
, unsigned char * buffer
, int try, int block_size
,
296 unsigned long current_block
)
300 set_o_direct(dev
, buffer
, try * block_size
, current_block
);
305 /* Seek to the correct loc. */
306 if (ext2fs_llseek (dev
, (ext2_loff_t
) current_block
* block_size
,
307 SEEK_SET
) != (ext2_loff_t
) current_block
* block_size
)
308 com_err (program_name
, errno
, _("during seek"));
311 got
= write (dev
, buffer
, try * block_size
);
315 fprintf(stderr
, "Weird value (%ld) in do_write\n", got
);
322 static void flush_bufs(void)
326 retval
= ext2fs_sync_device(host_dev
, 1);
328 com_err(program_name
, retval
, _("during ext2fs_sync_device"));
331 static unsigned int test_ro (int dev
, blk_t last_block
,
332 int block_size
, blk_t from_count
,
333 unsigned int blocks_at_once
)
335 unsigned char * blkbuf
;
338 unsigned int bb_count
= 0;
341 errcode
= ext2fs_badblocks_list_iterate_begin(bb_list
,&bb_iter
);
343 com_err (program_name
, errcode
,
344 _("while beginning bad block list iteration"));
348 ext2fs_badblocks_list_iterate (bb_iter
, &next_bad
);
349 } while (next_bad
&& next_bad
< from_count
);
352 blkbuf
= allocate_buffer((blocks_at_once
+ 1) * block_size
);
354 blkbuf
= allocate_buffer(blocks_at_once
* block_size
);
358 com_err (program_name
, ENOMEM
, _("while allocating buffers"));
362 fprintf (stderr
, _("Checking blocks %lu to %lu\n"),
363 (unsigned long) from_count
,
364 (unsigned long) last_block
- 1);
367 fputs(_("Checking for bad blocks in read-only mode\n"), stderr
);
368 pattern_fill(blkbuf
+ blocks_at_once
* block_size
,
369 t_patts
[0], block_size
);
372 try = blocks_at_once
;
373 currently_testing
= from_count
;
374 num_blocks
= last_block
- 1;
375 if (!t_flag
&& (s_flag
|| v_flag
)) {
376 fputs(_("Checking for bad blocks (read-only test): "), stderr
);
380 while (currently_testing
< last_block
)
383 if (currently_testing
== next_bad
) {
384 /* fprintf (out, "%lu\n", nextbad); */
385 ext2fs_badblocks_list_iterate (bb_iter
, &next_bad
);
389 else if (currently_testing
+ try > next_bad
)
390 try = next_bad
- currently_testing
;
392 if (currently_testing
+ try > last_block
)
393 try = last_block
- currently_testing
;
394 got
= do_read (dev
, blkbuf
, try, block_size
, currently_testing
);
396 /* test the comparison between all the
397 blocks successfully read */
399 for (i
= 0; i
< got
; ++i
)
400 if (memcmp (blkbuf
+i
*block_size
,
401 blkbuf
+blocks_at_once
*block_size
,
403 bb_count
+= bb_output(currently_testing
+ i
);
405 currently_testing
+= got
;
407 try = blocks_at_once
;
408 /* recover page-aligned offset for O_DIRECT */
409 if ( (blocks_at_once
>= sys_page_size
>> 9)
410 && (currently_testing
% (sys_page_size
>> 9)!= 0))
411 try -= (sys_page_size
>> 9)
413 % (sys_page_size
>> 9));
419 bb_count
+= bb_output(currently_testing
++);
424 if (s_flag
|| v_flag
)
425 fputs(_(done_string
), stderr
);
430 ext2fs_badblocks_list_iterate_end(bb_iter
);
435 static unsigned int test_rw (int dev
, blk_t last_block
,
436 int block_size
, blk_t from_count
,
437 unsigned int blocks_at_once
)
439 unsigned char *buffer
, *read_buffer
;
440 const unsigned int patterns
[] = {0xaa, 0x55, 0xff, 0x00};
441 const unsigned int *pattern
;
442 int i
, try, got
, nr_pattern
, pat_idx
;
443 unsigned int bb_count
= 0;
445 buffer
= allocate_buffer(2 * blocks_at_once
* block_size
);
446 read_buffer
= buffer
+ blocks_at_once
* block_size
;
449 com_err (program_name
, ENOMEM
, _("while allocating buffers"));
456 fputs(_("Checking for bad blocks in read-write mode\n"),
458 fprintf(stderr
, _("From block %lu to %lu\n"),
459 (unsigned long) from_count
,
460 (unsigned long) last_block
);
467 nr_pattern
= sizeof(patterns
) / sizeof(patterns
[0]);
469 for (pat_idx
= 0; pat_idx
< nr_pattern
; pat_idx
++) {
470 pattern_fill(buffer
, pattern
[pat_idx
],
471 blocks_at_once
* block_size
);
472 num_blocks
= last_block
- 1;
473 currently_testing
= from_count
;
474 if (s_flag
&& v_flag
<= 1)
477 try = blocks_at_once
;
478 while (currently_testing
< last_block
) {
479 if (currently_testing
+ try > last_block
)
480 try = last_block
- currently_testing
;
481 got
= do_write(dev
, buffer
, try, block_size
,
486 currently_testing
+= got
;
488 try = blocks_at_once
;
489 /* recover page-aligned offset for O_DIRECT */
490 if ( (blocks_at_once
>= sys_page_size
>> 9)
491 && (currently_testing
%
492 (sys_page_size
>> 9)!= 0))
493 try -= (sys_page_size
>> 9)
495 % (sys_page_size
>> 9));
500 bb_count
+= bb_output(currently_testing
++);
507 fputs(_(done_string
), stderr
);
510 fputs(_("Reading and comparing: "), stderr
);
511 num_blocks
= last_block
;
512 currently_testing
= from_count
;
513 if (s_flag
&& v_flag
<= 1)
516 try = blocks_at_once
;
517 while (currently_testing
< last_block
) {
518 if (currently_testing
+ try > last_block
)
519 try = last_block
- currently_testing
;
520 got
= do_read (dev
, read_buffer
, try, block_size
,
523 bb_count
+= bb_output(currently_testing
++);
526 for (i
=0; i
< got
; i
++) {
527 if (memcmp(read_buffer
+ i
* block_size
,
528 buffer
+ i
* block_size
,
530 bb_count
+= bb_output(currently_testing
+i
);
532 currently_testing
+= got
;
533 /* recover page-aligned offset for O_DIRECT */
534 if ( (blocks_at_once
>= sys_page_size
>> 9)
535 && (currently_testing
% (sys_page_size
>> 9)!= 0))
536 try = blocks_at_once
- (sys_page_size
>> 9)
538 % (sys_page_size
>> 9));
540 try = blocks_at_once
;
548 fputs(_(done_string
), stderr
);
551 uncapture_terminate();
556 struct saved_blk_record
{
561 static unsigned int test_nd (int dev
, blk_t last_block
,
562 int block_size
, blk_t from_count
,
563 unsigned int blocks_at_once
)
565 unsigned char *blkbuf
, *save_ptr
, *test_ptr
, *read_ptr
;
566 unsigned char *test_base
, *save_base
, *read_base
;
568 const unsigned int patterns
[] = { ~0 };
569 const unsigned int *pattern
;
570 int nr_pattern
, pat_idx
;
571 int got
, used2
, written
;
572 blk_t save_currently_testing
;
573 struct saved_blk_record
*test_record
;
574 /* This is static to prevent being clobbered by the longjmp */
575 static int num_saved
;
576 jmp_buf terminate_env
;
578 unsigned long buf_used
;
579 static unsigned int bb_count
;
582 errcode
= ext2fs_badblocks_list_iterate_begin(bb_list
,&bb_iter
);
584 com_err (program_name
, errcode
,
585 _("while beginning bad block list iteration"));
589 ext2fs_badblocks_list_iterate (bb_iter
, &next_bad
);
590 } while (next_bad
&& next_bad
< from_count
);
592 blkbuf
= allocate_buffer(3 * blocks_at_once
* block_size
);
593 test_record
= malloc (blocks_at_once
*sizeof(struct saved_blk_record
));
594 if (!blkbuf
|| !test_record
) {
595 com_err(program_name
, ENOMEM
, _("while allocating buffers"));
600 test_base
= blkbuf
+ (blocks_at_once
* block_size
);
601 read_base
= blkbuf
+ (2 * blocks_at_once
* block_size
);
607 fputs(_("Checking for bad blocks in non-destructive read-write mode\n"), stderr
);
608 fprintf (stderr
, _("From block %lu to %lu\n"),
609 (unsigned long) from_count
, (unsigned long) last_block
);
611 if (s_flag
|| v_flag
> 1) {
612 fputs(_("Checking for bad blocks (non-destructive read-write test)\n"), stderr
);
614 if (setjmp(terminate_env
)) {
616 * Abnormal termination by a signal is handled here.
618 signal (SIGALRM
, SIG_IGN
);
619 fputs(_("\nInterrupt caught, cleaning up\n"), stderr
);
621 save_ptr
= save_base
;
622 for (i
=0; i
< num_saved
; i
++) {
623 do_write(dev
, save_ptr
, test_record
[i
].num
,
624 block_size
, test_record
[i
].block
);
625 save_ptr
+= test_record
[i
].num
* block_size
;
631 /* set up abend handler */
632 capture_terminate(terminate_env
);
639 nr_pattern
= sizeof(patterns
) / sizeof(patterns
[0]);
641 for (pat_idx
= 0; pat_idx
< nr_pattern
; pat_idx
++) {
642 pattern_fill(test_base
, pattern
[pat_idx
],
643 blocks_at_once
* block_size
);
647 save_ptr
= save_base
;
648 test_ptr
= test_base
;
649 currently_testing
= from_count
;
650 num_blocks
= last_block
- 1;
651 if (s_flag
&& v_flag
<= 1)
654 while (currently_testing
< last_block
) {
655 got
= try = blocks_at_once
- buf_used
;
657 if (currently_testing
== next_bad
) {
658 /* fprintf (out, "%lu\n", nextbad); */
659 ext2fs_badblocks_list_iterate (bb_iter
, &next_bad
);
663 else if (currently_testing
+ try > next_bad
)
664 try = next_bad
- currently_testing
;
666 if (currently_testing
+ try > last_block
)
667 try = last_block
- currently_testing
;
668 got
= do_read (dev
, save_ptr
, try, block_size
,
671 /* First block must have been bad. */
672 bb_count
+= bb_output(currently_testing
++);
677 * Note the fact that we've saved this much data
678 * *before* we overwrite it with test data
680 test_record
[num_saved
].block
= currently_testing
;
681 test_record
[num_saved
].num
= got
;
684 /* Write the test data */
685 written
= do_write (dev
, test_ptr
, got
, block_size
,
688 com_err (program_name
, errno
,
689 _("during test data write, block %lu"),
690 (unsigned long) currently_testing
+
694 save_ptr
+= got
* block_size
;
695 test_ptr
+= got
* block_size
;
696 currently_testing
+= got
;
698 bb_count
+= bb_output(currently_testing
++);
702 * If there's room for more blocks to be tested this
703 * around, and we're not done yet testing the disk, go
704 * back and get some more blocks.
706 if ((buf_used
!= blocks_at_once
) &&
707 (currently_testing
< last_block
))
711 save_currently_testing
= currently_testing
;
714 * for each contiguous block that we read into the
715 * buffer (and wrote test data into afterwards), read
716 * it back (looping if necessary, to get past newly
717 * discovered unreadable blocks, of which there should
718 * be none, but with a hard drive which is unreliable,
719 * it has happened), and compare with the test data
720 * that was written; output to the bad block list if
724 save_ptr
= save_base
;
725 test_ptr
= test_base
;
726 read_ptr
= read_base
;
731 if (used2
>= num_saved
)
733 currently_testing
= test_record
[used2
].block
;
734 try = test_record
[used2
].num
;
738 got
= do_read (dev
, read_ptr
, try,
739 block_size
, currently_testing
);
741 /* test the comparison between all the
742 blocks successfully read */
743 for (i
= 0; i
< got
; ++i
)
744 if (memcmp (test_ptr
+i
*block_size
,
745 read_ptr
+i
*block_size
, block_size
))
746 bb_count
+= bb_output(currently_testing
+ i
);
748 bb_count
+= bb_output(currently_testing
+ got
);
752 /* write back original data */
753 do_write (dev
, save_ptr
, got
,
754 block_size
, currently_testing
);
755 save_ptr
+= got
* block_size
;
757 currently_testing
+= got
;
758 test_ptr
+= got
* block_size
;
759 read_ptr
+= got
* block_size
;
763 /* empty the buffer so it can be reused */
766 save_ptr
= save_base
;
767 test_ptr
= test_base
;
768 currently_testing
= save_currently_testing
;
772 if (s_flag
|| v_flag
> 1)
773 fputs(_(done_string
), stderr
);
777 uncapture_terminate();
782 ext2fs_badblocks_list_iterate_end(bb_iter
);
787 static void check_mount(char *device_name
)
792 retval
= ext2fs_check_if_mounted(device_name
, &mount_flags
);
794 com_err("ext2fs_check_if_mount", retval
,
795 _("while determining whether %s is mounted."),
799 if (mount_flags
& EXT2_MF_MOUNTED
) {
800 fprintf(stderr
, _("%s is mounted; "), device_name
);
802 fputs(_("badblocks forced anyway. "
803 "Hope /etc/mtab is incorrect.\n"), stderr
);
807 fputs(_("it's not safe to run badblocks!\n"), stderr
);
811 if ((mount_flags
& EXT2_MF_BUSY
) && !exclusive_ok
) {
812 fprintf(stderr
, _("%s is apparently in use by the system; "),
815 fputs(_("badblocks forced anyway.\n"), stderr
);
817 goto abort_badblocks
;
823 * This function will convert a string to an unsigned long, printing
824 * an error message if it fails, and returning success or failure in err.
826 static unsigned int parse_uint(const char *str
, const char *descr
)
831 ret
= strtoul(str
, &tmp
, 0);
832 if (*tmp
|| errno
|| (ret
> UINT_MAX
) ||
833 (ret
== ULONG_MAX
&& errno
== ERANGE
)) {
834 com_err (program_name
, 0, _("invalid %s - %s"), descr
, str
);
840 int main (int argc
, char ** argv
)
844 char * host_device_name
= NULL
;
845 char * input_file
= NULL
;
846 char * output_file
= NULL
;
848 int block_size
= 1024;
849 unsigned int blocks_at_once
= 64;
850 blk_t last_block
, from_count
;
852 int passes_clean
= 0;
855 unsigned int pattern
;
856 unsigned int (*test_func
)(int, blk_t
,
862 setbuf(stdout
, NULL
);
863 setbuf(stderr
, NULL
);
865 setlocale(LC_MESSAGES
, "");
866 setlocale(LC_CTYPE
, "");
867 bindtextdomain(NLS_CAT_NAME
, LOCALEDIR
);
868 textdomain(NLS_CAT_NAME
);
870 srandom((unsigned int)time(NULL
)); /* simple randomness is enough */
873 /* Determine the system page size if possible */
875 #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
876 #define _SC_PAGESIZE _SC_PAGE_SIZE
879 sysval
= sysconf(_SC_PAGESIZE
);
881 sys_page_size
= sysval
;
882 #endif /* _SC_PAGESIZE */
883 #endif /* HAVE_SYSCONF */
886 program_name
= *argv
;
887 while ((c
= getopt (argc
, argv
, "b:fi:o:svwnc:p:h:t:X")) != EOF
) {
890 block_size
= parse_uint(optarg
, "block size");
891 if (block_size
> 4096) {
892 com_err (program_name
, 0,
893 _("bad block size - %s"), optarg
);
904 output_file
= optarg
;
925 blocks_at_once
= parse_uint(optarg
, "blocks at once");
928 num_passes
= parse_uint(optarg
,
929 "number of clean passes");
932 host_device_name
= optarg
;
935 if (t_flag
+ 1 > t_max
) {
936 unsigned int *t_patts_new
;
938 t_patts_new
= realloc(t_patts
, t_max
+ T_INC
);
940 com_err(program_name
, ENOMEM
,
941 _("can't allocate memory for "
942 "test_pattern - %s"),
946 t_patts
= t_patts_new
;
949 if (!strcmp(optarg
, "r") || !strcmp(optarg
,"random")) {
950 t_patts
[t_flag
++] = ~0;
952 pattern
= parse_uint(optarg
, "test pattern");
953 if (pattern
== (unsigned int) ~0)
955 t_patts
[t_flag
++] = pattern
;
967 com_err(program_name
, 0,
968 _("Maximum of one test_pattern may be specified "
969 "in read-only mode"));
972 if (t_patts
&& (t_patts
[0] == (unsigned int) ~0)) {
973 com_err(program_name
, 0,
974 _("Random test_pattern is not allowed "
975 "in read-only mode"));
979 if (optind
> argc
- 1)
981 device_name
= argv
[optind
++];
982 if (optind
> argc
- 1) {
983 errcode
= ext2fs_get_device_size(device_name
,
986 if (errcode
== EXT2_ET_UNIMPLEMENTED
) {
987 com_err(program_name
, 0,
988 _("Couldn't determine device size; you "
989 "must specify\nthe size manually\n"));
993 com_err(program_name
, errcode
,
994 _("while trying to determine device size"));
999 last_block
= parse_uint(argv
[optind
], "last block");
1000 printf("last_block = %d (%s)\n", last_block
, argv
[optind
]);
1004 if (optind
<= argc
-1) {
1006 from_count
= parse_uint(argv
[optind
], "start block");
1007 printf("from_count = %d\n", from_count
);
1008 } else from_count
= 0;
1009 if (from_count
>= last_block
) {
1010 com_err (program_name
, 0, _("invalid starting block (%lu): must be less than %lu"),
1011 (unsigned long) from_count
, (unsigned long) last_block
);
1015 check_mount(device_name
);
1017 open_flag
= w_flag
? O_RDWR
: O_RDONLY
;
1018 dev
= open (device_name
, open_flag
);
1020 com_err (program_name
, errno
, _("while trying to open %s"),
1024 if (host_device_name
) {
1025 host_dev
= open (host_device_name
, open_flag
);
1026 if (host_dev
== -1) {
1027 com_err (program_name
, errno
,
1028 _("while trying to open %s"),
1035 if (strcmp (input_file
, "-") == 0)
1038 in
= fopen (input_file
, "r");
1041 com_err (program_name
, errno
,
1042 _("while trying to open %s"),
1048 if (output_file
&& strcmp (output_file
, "-") != 0)
1050 out
= fopen (output_file
, "w");
1053 com_err (program_name
, errno
,
1054 _("while trying to open %s"),
1062 errcode
= ext2fs_badblocks_list_create(&bb_list
,0);
1064 com_err (program_name
, errcode
,
1065 _("while creating in-memory bad blocks list"));
1071 switch(fscanf (in
, "%u\n", &next_bad
)) {
1073 com_err (program_name
, 0, "input file - bad format");
1078 errcode
= ext2fs_badblocks_list_add(bb_list
,next_bad
);
1080 com_err (program_name
, errcode
, _("while adding to in-memory bad block list"));
1093 unsigned int bb_count
;
1095 bb_count
= test_func(dev
, last_block
, block_size
,
1096 from_count
, blocks_at_once
);
1104 _("Pass completed, %u bad blocks found.\n"),
1107 } while (passes_clean
< num_passes
);