badblocks.c revision 54c637d4d29af3e6365779f8b12976abe95a4753
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * badblocks.c		- Bad blocks checker
33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Copyright (C) 1992, 1993, 1994  Remy Card <card@masi.ibp.fr>
53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *                                 Laboratoire MASI, Institut Blaise Pascal
63839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *                                 Universite Pierre et Marie Curie (Paris VI)
73839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
8dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o
9879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Copyright 1999 by David Beattie
1019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This file is based on the minix file system programs fsck and mkfs
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi>
1319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
1419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
1519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
1619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License.
1719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * History:
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 93/05/26	- Creation from e2fsck
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 94/02/27	- Made a separate bad blocks checker
24879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * 99/06/30...99/07/26 - Added non-destructive write-testing,
25dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o *                       configurable blocks-at-once parameter,
26dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * 			 loading of badblocks list to avoid testing
27dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * 			 blocks known to be bad, multiple passes to
28dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * 			 make sure that no new blocks are added to the
29dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * 			 list.  (Work done by David Beattie)
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <errno.h>
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
34a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef HAVE_GETOPT_H
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <getopt.h>
36373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'o#else
37373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'oextern char *optarg;
38373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'oextern int optind;
39a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <signal.h>
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdlib.h>
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
45879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include <setjmp.h>
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/ioctl.h>
48f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h>
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "et/com_err.h"
51d40259fd552d942903f2fd0b426c75a5c2516017Theodore Ts'o#include "ext2fs/ext2_io.h"
5254c637d4d29af3e6365779f8b12976abe95a4753Theodore Ts'o#include "ext2fs/ext2_fs.h"
53879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include "ext2fs/ext2fs.h"
54d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#include "nls-enable.h"
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oconst char * program_name = "badblocks";
578f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'oconst char * done_string = N_("done                        \n");
583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
594d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int v_flag = 0;			/* verbose */
604d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int w_flag = 0;			/* do r/w test: 0=no, 1=yes,
614d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o					 * 2=non-destructive */
624d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int s_flag = 0;			/* show progress of test */
63981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic int force = 0;			/* force check of mounted device */
644d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
658820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void usage(void)
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
67cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	fprintf(stderr, _("Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnf]\n [-c blocks_at_once] [-p num_passes] device [last_block [start_count]]\n"),
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 program_name);
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	exit (1);
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long currently_testing = 0;
7319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long num_blocks = 0;
74879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_list bb_list = NULL;
75879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic FILE *out;
76879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic blk_t next_bad = 0;
77879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_iterate bb_iter = NULL;
7819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
79dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o/*
80dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * This routine reports a new bad block.  If the bad block has already
81dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * been seen before, then it returns 0; otherwise it returns 1.
82dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o */
83dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic int bb_output (unsigned long bad)
84879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
85879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
86879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
87dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	if (ext2fs_badblocks_list_test(bb_list, bad))
88dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		return 0;
89dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o
90879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	fprintf (out, "%lu\n", bad);
91879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
92879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_add (bb_list, bad);
93879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
94879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "adding to in-memory bad block list");
95879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
96879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
97879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
98879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* kludge:
99879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   increment the iteration through the bb_list if
100879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   an element was just added before the current iteration
101879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   position.  This should not cause next_bad to change. */
102879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (bb_iter && bad < next_bad)
103879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
104dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	return 1;
105879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
106879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1078820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void print_status(void)
10819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
10919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
11019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
11119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
11219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
11319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
114981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void alarm_intr(int alnum)
11519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
11619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	signal (SIGALRM, alarm_intr);
11719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	alarm(1);
11819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!num_blocks)
11919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return;
12019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
12119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
12219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
12319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
12419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
125879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void *terminate_addr = NULL;
126879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
127981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void terminate_intr(int signo)
128879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
129879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (terminate_addr)
130879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		longjmp(terminate_addr,1);
131879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	exit(1);
132879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
133879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
134981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void capture_terminate(jmp_buf term_addr)
135879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
136879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	terminate_addr = term_addr;
137879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGHUP, terminate_intr);
138879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGINT, terminate_intr);
139879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGPIPE, terminate_intr);
140879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGTERM, terminate_intr);
141879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR1, terminate_intr);
142879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR2, terminate_intr);
143879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
144879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1458820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void uncapture_terminate(void)
1464d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o{
1474d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	terminate_addr = NULL;
1484d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGHUP, SIG_DFL);
1494d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGINT, SIG_DFL);
1504d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGPIPE, SIG_DFL);
1514d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGTERM, SIG_DFL);
1524d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR1, SIG_DFL);
1534d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR2, SIG_DFL);
1544d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o}
1554d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
1563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
157879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a read of a sequence of blocks; return the number of blocks
158879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially read.
1593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
160dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic long do_read (int dev, char * buffer, int try, int block_size,
1613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		     unsigned long current_block)
1623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
1643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
16519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag > 1)
16619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		print_status();
16719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
1683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Seek to the correct loc. */
16919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
170f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
171d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
1723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Try the read */
1743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got = read (dev, buffer, try * block_size);
1753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (got < 0)
1763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		got = 0;
1779f10a7b31e57288093930fc9565102409eeac6e9Theodore Ts'o	if (got & 511)
178d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Weird value (%ld) in do_read\n"), got);
179879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got /= block_size;
180879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return got;
181879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
182879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
183879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o/*
184879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a write of a sequence of blocks; return the number of blocks
185879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially written.
186879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o */
187dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic long do_write (int dev, char * buffer, int try, int block_size,
188879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long current_block)
189879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
190879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	long got;
191879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
192879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag > 1)
193879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		print_status();
194879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
195879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Seek to the correct loc. */
196879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
197879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
198d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
199879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
200879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Try the write */
201879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got = write (dev, buffer, try * block_size);
202879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got < 0)
203879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = 0;
204879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got & 511)
205879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fprintf (stderr,
206879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 "Weird value (%ld) in do_write\n", got);
2073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got /= block_size;
2083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return got;
2093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
211879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic int host_dev;
212879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
2134d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'ostatic void flush_bufs(void)
214a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o{
2154d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	errcode_t	retval;
216a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
2174d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	retval = ext2fs_sync_device(host_dev, 1);
2184d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	if (retval)
2194d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		com_err(program_name, retval, _("during ext2fs_sync_device"));
220a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o}
221a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
222cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'ostatic unsigned int test_ro (int dev, unsigned long last_block,
223dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
224dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
2253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * blkbuf;
2273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int try;
2283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
229879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
230879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
2313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
232879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
233879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
234d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
235d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
236879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
237879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
238879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
239879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
240879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
241879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
242879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	blkbuf = malloc (blocks_at_once * block_size);
2433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!blkbuf)
2443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
245d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
2463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
2473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2484d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	flush_bufs();
249f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (v_flag) {
250d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    fprintf(stderr, _("Checking for bad blocks in read-only mode\n"));
251d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    fprintf (stderr, _("From block %lu to %lu\n"), from_count,
252cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		     last_block);
253f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
254879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	try = blocks_at_once;
255f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	currently_testing = from_count;
256cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	num_blocks = last_block;
25719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1) {
258d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr,
259d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			_("Checking for bad blocks (read-only test): "));
26019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (v_flag <= 1)
26119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			alarm_intr(SIGALRM);
2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
263cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	while (currently_testing < last_block)
2643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
265879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (next_bad) {
266879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (currently_testing == next_bad) {
267879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
268879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
269879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				currently_testing++;
270879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				continue;
271879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
272879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			else if (currently_testing + try > next_bad)
273879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				try = next_bad - currently_testing;
274879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
275cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		if (currently_testing + try > last_block)
276cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o			try = last_block - currently_testing;
277879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = do_read (dev, blkbuf, try, block_size, currently_testing);
2783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		currently_testing += got;
2793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (got == try) {
280879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			try = blocks_at_once;
2813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			continue;
2823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
2833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		else
2843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = 1;
285879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (got == 0) {
286dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			bb_count += bb_output(currently_testing++);
287879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = 0;
2903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	alarm(0);
29119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1)
2928f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'o		fprintf(stderr, _(done_string));
293879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
294f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	fflush (stderr);
2953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free (blkbuf);
296879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
297879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
298879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
299879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
3003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
302cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'ostatic unsigned int test_rw (int dev, unsigned long last_block,
303dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
304dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
3053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int i;
3073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * buffer;
3088820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o	static unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
309879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
3103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	buffer = malloc (2 * block_size);
3123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!buffer)
3133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
314d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
3153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
3163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3184d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	flush_bufs();
319a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
32019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag) {
32119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		fprintf(stderr,
322d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			_("Checking for bad blocks in read-write mode\n"));
323d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("From block %lu to %lu\n"),
324cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o			 from_count, last_block);
32519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
32619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	for (i = 0; i < sizeof (pattern); i++) {
3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset (buffer, pattern[i], block_size);
328f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
329d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf (stderr, _("Writing pattern 0x%08x: "),
3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				 *((int *) buffer));
331cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		num_blocks = last_block;
332f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
33319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
334f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
335f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
336cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		     currently_testing < last_block;
337f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
3383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
33919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
340f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
341f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
3423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
343d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("during seek on block %d"),
344f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
34519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
34619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			write (dev, buffer, block_size);
3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
349f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
350f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
351f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
3528f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'o			fprintf(stderr, _(done_string));
3534d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		flush_bufs();
354f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
355d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf (stderr, _("Reading and comparing: "));
356cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		num_blocks = last_block;
357f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
35819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
359f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
360f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
361cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		     currently_testing < last_block;
362f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
36419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
365f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
366f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
3673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
368d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("during seek on block %d"),
369f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
37019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
37119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
372dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			if ((read (dev, buffer + block_size, block_size)
3734d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			     != block_size) ||
374dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			    memcmp(buffer, buffer + block_size, block_size))
3754d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				bb_count += bb_output(currently_testing);
3763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
377f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
378f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
379f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
3808f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'o			fprintf(stderr, _(done_string));
3814d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		flush_bufs();
3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
383879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
384879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
385879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
386879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
387d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'ostruct saved_blk_record {
388d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	blk_t	block;
389d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	int	num;
390d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o};
391d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
392cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'ostatic unsigned int test_nd (int dev, unsigned long last_block,
393dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
394dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
395879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
396dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
397879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * ptr;
398dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int try, i;
399a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	long got, used2, written, save_currently_testing;
400d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	struct saved_blk_record *test_record;
401a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	/* This is static to prevent being clobbered by the longjmp */
402a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	static int num_saved;
403879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	jmp_buf terminate_env;
404879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
405a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	long buf_used;
406a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	unsigned int bb_count;
407879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
408879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
409879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
410dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		com_err (program_name, errcode,
411d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
412879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
413879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
414879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
415879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
416879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
417879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
418879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	blkbuf = malloc (3 * blocks_at_once * block_size);
419d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	test_record = malloc (blocks_at_once*sizeof(struct saved_blk_record));
420d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	if (!blkbuf || !test_record) {
421d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err(program_name, ENOMEM, _("while allocating buffers"));
422879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
423879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
424d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	num_saved = 0;
425879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
426879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* inititalize the test data randomly: */
427879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
428d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf (stderr, _("Initializing random test data\n"));
429879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
430879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	for(ptr = blkbuf + blocks_at_once * block_size;
431dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	    ptr < blkbuf + 2 * blocks_at_once * block_size;
432dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	    ++ptr) {
433879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		(*ptr) = random() % (1 << sizeof(char));
434879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
435879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
4364d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	flush_bufs();
437879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
438879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	    fprintf (stderr,
439d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		     _("Checking for bad blocks in non-destructive read-write mode\n"));
440cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	    fprintf (stderr, _("From block %lu to %lu\n"), from_count, last_block);
441879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
442879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (s_flag || v_flag > 1) {
443d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Checking for bad blocks (non-destructive read-write test): "));
444879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag <= 1)
445879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			alarm_intr(SIGALRM);
446879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
4474d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	if (setjmp(terminate_env)) {
4484d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
4494d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * Abnormal termination by a signal is handled here.
4504d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
451a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		signal (SIGALRM, SIG_IGN);
452a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		fprintf(stderr, _("\nInterrupt caught, cleaning up\n"));
453879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
454d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		save_ptr = blkbuf;
455d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		for (i=0; i < num_saved; i++) {
456d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			do_write(dev, save_ptr, test_record[i].num,
457d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				 block_size, test_record[i].block);
458d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			save_ptr += test_record[i].num * block_size;
459d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		}
460879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fflush (out);
461dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		exit(1);
462879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
4634d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
4644d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	/* set up abend handler */
4654d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	capture_terminate(terminate_env);
4664d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
467d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	buf_used = 0;
468a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	bb_count = 0;
469d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	save_ptr = blkbuf;
4704d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	test_ptr = blkbuf + (blocks_at_once * block_size);
4714d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	currently_testing = from_count;
472cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	num_blocks = last_block;
4734d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
474cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	while (currently_testing < last_block) {
4754d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		try = blocks_at_once - buf_used;
4764d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (next_bad) {
4774d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (currently_testing == next_bad) {
4784d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
4794d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
480d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				currently_testing++;
481d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				goto check_for_more;
4824d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			}
4834d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			else if (currently_testing + try > next_bad)
4844d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				try = next_bad - currently_testing;
4854d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		}
486cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		if (currently_testing + try > last_block)
487cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o			try = last_block - currently_testing;
4884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		got = do_read (dev, save_ptr, try, block_size,
4894d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			       currently_testing);
490d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		if (got == 0) {
491d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			/* First block must have been bad. */
492d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			bb_count += bb_output(currently_testing++);
493d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			goto check_for_more;
494d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		}
4954d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
496d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		/*
497d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		 * Note the fact that we've saved this much data
498d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		 * *before* we overwrite it with test data
499d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		 */
500d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		test_record[num_saved].block = currently_testing;
501d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		test_record[num_saved].num = got;
502d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		num_saved++;
503d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
504d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		/* Write the test data */
505d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		written = do_write (dev, test_ptr, got, block_size,
506d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				    currently_testing);
507d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		if (written != got)
508d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			com_err (program_name, errno,
5094d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				 _("during test data write, block %lu"),
510d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				 currently_testing + written);
5114d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5124d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		buf_used += got;
5134d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		save_ptr += got * block_size;
5144d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		test_ptr += got * block_size;
5154d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		currently_testing += got;
5164d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (got != try)
5174d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			bb_count += bb_output(currently_testing++);
5184d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
519d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	check_for_more:
5204d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
5214d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * If there's room for more blocks to be tested this
5224d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * around, and we're not done yet testing the disk, go
5234d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * back and get some more blocks.
5244d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
5254d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if ((buf_used != blocks_at_once) &&
526cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		    (currently_testing < last_block))
5274d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			continue;
5284d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5294d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		flush_bufs();
530a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		save_currently_testing = currently_testing;
5314d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5324d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
5334d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * for each contiguous block that we read into the
5344d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * buffer (and wrote test data into afterwards), read
5354d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * it back (looping if necessary, to get past newly
5364d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * discovered unreadable blocks, of which there should
5374d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * be none, but with a hard drive which is unreliable,
5384d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * it has happened), and compare with the test data
5394d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * that was written; output to the bad block list if
5404d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * it doesn't match.
5414d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
5424d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		used2 = 0;
5434d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		save_ptr = blkbuf;
5444d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		test_ptr = blkbuf + (blocks_at_once * block_size);
5454d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		read_ptr = blkbuf + (2 * blocks_at_once * block_size);
546d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		try = 0;
5474d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
548d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		while (1) {
549d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			if (try == 0) {
550d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				if (used2 >= num_saved)
551d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o					break;
552d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				currently_testing = test_record[used2].block;
553d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				try = test_record[used2].num;
554d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				used2++;
555d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			}
556d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
5574d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			got = do_read (dev, read_ptr, try,
5584d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				       block_size, currently_testing);
5594d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5604d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			/* test the comparison between all the
5614d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			   blocks successfully read  */
5624d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			for (i = 0; i < got; ++i)
5634d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				if (memcmp (test_ptr+i*block_size,
5644d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o					    read_ptr+i*block_size, block_size))
5654d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o					bb_count += bb_output(currently_testing + i);
5664d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (got < try) {
5674d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				bb_count += bb_output(currently_testing + got);
5684d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				got++;
5694d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			}
5704d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5714d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			/* when done, write back original data */
5724d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			do_write (dev, save_ptr, got, block_size,
5734d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				  currently_testing);
5744d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5754d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			currently_testing += got;
5764d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			save_ptr += got * block_size;
5774d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_ptr += got * block_size;
5784d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			read_ptr += got * block_size;
5794d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			try -= got;
5804d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		}
5814d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5824d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/* empty the buffer so it can be reused */
583d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		num_saved = 0;
5844d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		buf_used = 0;
585d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		save_ptr = blkbuf;
586d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		test_ptr = blkbuf + (blocks_at_once * block_size);
587a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		currently_testing = save_currently_testing;
5884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	}
5894d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	num_blocks = 0;
5904d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	alarm(0);
5914d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	uncapture_terminate();
5924d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	if (s_flag || v_flag > 1)
5934d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		fprintf(stderr, _(done_string));
594879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
595dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	fflush(stderr);
596dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	free(blkbuf);
597d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	free(test_record);
598879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
599879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
600879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
601879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
6023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
604981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void check_mount(char *device_name)
605981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o{
606981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	errcode_t	retval;
607981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	int		mount_flags;
608981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
609981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	retval = ext2fs_check_if_mounted(device_name, &mount_flags);
610981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (retval) {
611981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		com_err("ext2fs_check_if_mount", retval,
612981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			_("while determining whether %s is mounted."),
613981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			device_name);
614981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		return;
615981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
616981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (!(mount_flags & EXT2_MF_MOUNTED))
617981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		return;
618981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
619981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	fprintf(stderr, _("%s is mounted; "), device_name);
620981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (force) {
621981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		fprintf(stderr, _("badblocks forced anyway.  "
622981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			"Hope /etc/mtab is incorrect.\n"));
623981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		return;
624981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
625981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	fprintf(stderr, _("it's not safe to run badblocks!\n"));
626981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	exit(1);
627981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o}
628981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
629981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
63000e5433eb5e9f70f485968b809fdcf297d7fe7b9Theodore Ts'oint main (int argc, char ** argv)
6313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
632519149fb458b0fa69c10fecd83fae42e838cf01dTheodore Ts'o	int c;
6333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * tmp;
6343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * device_name;
635879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * host_device_name = NULL;
636879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * input_file = NULL;
6373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * output_file = NULL;
638879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	FILE * in = NULL;
639dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int block_size = 1024;
640879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned long blocks_at_once = 16;
641cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	blk_t last_block, from_count;
642879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int num_passes = 0;
643879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int passes_clean = 0;
6443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int dev;
645879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
6468820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o	unsigned int (*test_func)(int, unsigned long,
6478820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o				  int, unsigned long,
6488820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o				  unsigned long);
6493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stdout, NULL);
6513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stderr, NULL);
652d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#ifdef ENABLE_NLS
653d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	setlocale(LC_MESSAGES, "");
654d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
655d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	textdomain(NLS_CAT_NAME);
656d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#endif
6574d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	test_func = test_ro;
6584d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o
6593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (argc && *argv)
6603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		program_name = *argv;
661a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	while ((c = getopt (argc, argv, "b:fi:o:svwnc:p:h:")) != EOF) {
6623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		switch (c) {
6633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'b':
6643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			block_size = strtoul (optarg, &tmp, 0);
6653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (*tmp || block_size > 4096) {
6663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, 0,
667d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("bad block size - %s"), optarg);
6683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				exit (1);
6693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
6703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
671981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		case 'f':
672981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			force++;
673981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			break;
674879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'i':
675879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			input_file = optarg;
676879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
6773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'o':
6783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			output_file = optarg;
6793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 's':
6813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			s_flag = 1;
6823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'v':
68419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			v_flag++;
6853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'w':
6874d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
6884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				usage();
6894d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_rw;
6904d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			w_flag = 1;
691879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
692879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'n':
6934d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
6944d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				usage();
6954d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_nd;
696879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			w_flag = 2;
697879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
698879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'c':
699879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			blocks_at_once = strtoul (optarg, &tmp, 0);
700879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
701879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
702879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 "bad simultaneous block count - %s", optarg);
703879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
704879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
705879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
706879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'p':
707879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			num_passes = strtoul (optarg, &tmp, 0);
708879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
709879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
710879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				    "bad number of clean passes - %s", optarg);
711879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
712879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
713879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
714879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'h':
715879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			host_device_name = optarg;
7163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
7173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		default:
718818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o			usage();
7193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
7203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
7213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
722818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
7233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	device_name = argv[optind++];
72435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind > argc - 1) {
72535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		errcode = ext2fs_get_device_size(device_name,
72635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o						 block_size,
727cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o						 &last_block);
72835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode == EXT2_ET_UNIMPLEMENTED) {
72935964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err(program_name, 0,
73035964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("Couldn't determine device size; you "
73135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				  "must specify\nthe size manually\n"));
73235964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
73335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
73435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode) {
73535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err(program_name, errcode,
73635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("while trying to determine device size"));
73735964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
73835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
73935964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	} else {
740cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		last_block = strtoul (argv[optind], &tmp, 0);
74135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (*tmp) {
74235964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err (program_name, 0, _("bad blocks count - %s"),
74335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				 argv[optind]);
74435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit (1);
74535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
74635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		optind++;
7473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
74835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind <= argc-1) {
749f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		from_count = strtoul (argv[optind], &tmp, 0);
750a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		if (*tmp) {
751a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o			com_err (program_name, 0, _("bad starting block - %s"),
752a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o				 argv[optind]);
753a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o			exit (1);
754a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		}
755f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	} else from_count = 0;
756cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	if (from_count >= last_block) {
757d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    com_err (program_name, 0, _("bad blocks range: %lu-%lu"),
758cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		     from_count, last_block);
759f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    exit (1);
760f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
761981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (w_flag)
762981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		check_mount(device_name);
763981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
7643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
7653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dev == -1)
7663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
767d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("while trying to open %s"),
7683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 device_name);
7693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
7703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
771879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (host_device_name) {
772879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = open (host_device_name, O_RDONLY);
773879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (host_dev == -1)
774879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		{
775d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
776d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
777d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 host_device_name);
778879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			exit (1);
779879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
780879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} else
781879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = dev;
782879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (input_file)
783879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (strcmp (input_file, "-") == 0)
784879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = stdin;
785879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		else {
786879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = fopen (input_file, "r");
787879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (in == NULL)
788879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			{
789d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				com_err (program_name, errno,
790d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("while trying to open %s"),
791879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 input_file);
792879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
793879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
794879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
7953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (output_file && strcmp (output_file, "-") != 0)
7963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
7973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = fopen (output_file, "w");
7983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (out == NULL)
7993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
800d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
801d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
802879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				 output_file);
8033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			exit (1);
8043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
8053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
8063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
8073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = stdout;
808879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
809879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_create(&bb_list,0);
810879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
811d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
812d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("creating in-memory bad blocks list"));
813879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
814879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
815879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
816879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (in) {
817879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		for(;;) {
818a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o			switch(fscanf (in, "%u\n", &next_bad)) {
819879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case 0:
820879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					com_err (program_name, 0, "input file - bad format");
821879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					exit (1);
822879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case EOF:
823879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					break;
824879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				default:
825879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
826879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					if (errcode) {
827d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o						com_err (program_name, errcode, _("adding to in-memory bad block list"));
828879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						exit (1);
829879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					}
830879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					continue;
831879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
832879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
833879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
834879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
835879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (in != stdin)
836879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			fclose (in);
837879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
838879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
839879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
840879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		unsigned int bb_count;
841879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
842cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		bb_count = test_func(dev, last_block, block_size,
8434d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				     from_count, blocks_at_once);
8444d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (bb_count)
8454d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			passes_clean = 0;
8464d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		else
8474d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			++passes_clean;
8484d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
849879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag)
850d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf(stderr,
851d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				_("Pass completed, %u bad blocks found.\n"),
852d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				bb_count);
853879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
854879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (passes_clean < num_passes);
855879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
8563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	close (dev);
8573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (out != stdout)
8583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fclose (out);
859879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return 0;
8603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
861d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o
862