badblocks.c revision f56f32b0a505e34712c8b8fb908dffb616743726
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
321c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#define _GNU_SOURCE /* for O_DIRECT */
331c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <errno.h>
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
36a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef HAVE_GETOPT_H
373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <getopt.h>
38373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'o#else
39373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'oextern char *optarg;
40373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'oextern int optind;
41a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <signal.h>
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdlib.h>
453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
47879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include <setjmp.h>
486d40f568cdec7d654691e6eed61cf5a32e918c03Theodore Ts'o#include <time.h>
495267a520bb7887b146f05ffa8726664afbb6c3c2Theodore Ts'o#include <limits.h>
503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
51edf261f6f859ed0ff3c16803ab61a78373089ad8Iustin Pop#include <sys/time.h>
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/ioctl.h>
53f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h>
5479e62409b3a247e258d9e9206484ed8f193a183eEric Sandeen#include <sys/time.h>
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "et/com_err.h"
57d40259fd552d942903f2fd0b426c75a5c2516017Theodore Ts'o#include "ext2fs/ext2_io.h"
5854c637d4d29af3e6365779f8b12976abe95a4753Theodore Ts'o#include "ext2fs/ext2_fs.h"
59879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include "ext2fs/ext2fs.h"
60d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#include "nls-enable.h"
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oconst char * program_name = "badblocks";
63f63978aff759325b542de7134ab659c79dc47496Theodore Ts'oconst char * done_string = N_("done                                \n");
643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
654d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int v_flag = 0;			/* verbose */
664d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int w_flag = 0;			/* do r/w test: 0=no, 1=yes,
674d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o					 * 2=non-destructive */
684d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int s_flag = 0;			/* show progress of test */
69981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic int force = 0;			/* force check of mounted device */
70849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'ostatic int t_flag = 0;			/* number of test patterns */
71849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'ostatic int t_max = 0;			/* allocated test patterns */
72e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'ostatic unsigned int *t_patts = NULL;	/* test patterns */
731c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'ostatic int current_O_DIRECT = 0;	/* Current status of O_DIRECT flag */
74f63978aff759325b542de7134ab659c79dc47496Theodore Ts'ostatic int exclusive_ok = 0;
75931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Popstatic unsigned int max_bb = 0;		/* Abort test if more than this number of bad blocks has been encountered */
76264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Popstatic unsigned int d_flag = 0;		/* delay factor between reads */
771c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
78849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o#define T_INC 32
794d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
80acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ounsigned int sys_page_size = 4096;
811c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
828820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void usage(void)
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
84f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	fprintf(stderr, _("Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnf]\n [-c blocks_at_once] [-p num_passes] [-e max_bad_blocks] [-d delay_factor_between_reads] [-t test_pattern [-t test_pattern [...]]]\n device [last_block [first_block]]\n"),
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 program_name);
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	exit (1);
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
89d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'ostatic void exclusive_usage(void)
90d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o{
91d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o	fprintf(stderr,
92017a76ee39356ecb13911d666a152f2a4856cbbbTheodore Ts'o		_("%s: The -n and -w options are mutually exclusive.\n\n"),
93017a76ee39356ecb13911d666a152f2a4856cbbbTheodore Ts'o		program_name);
94017a76ee39356ecb13911d666a152f2a4856cbbbTheodore Ts'o	exit(1);
95d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o}
96d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o
97acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic blk_t currently_testing = 0;
98acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic blk_t num_blocks = 0;
99879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_list bb_list = NULL;
100879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic FILE *out;
101879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic blk_t next_bad = 0;
102879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_iterate bb_iter = NULL;
10319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
1041c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'ostatic void *allocate_buffer(size_t size)
1051c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o{
1061c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	void	*ret = 0;
1071c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
1081c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_POSIX_MEMALIGN
1091c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (posix_memalign(&ret, sys_page_size, size) < 0)
1101c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		ret = 0;
1111c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#else
1121c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_MEMALIGN
1131c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	ret = memalign(sys_page_size, size);
1141c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#else
1151c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_VALLOC
1161c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	ret = valloc(size);
1171c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_VALLOC */
1181c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_MEMALIGN */
1191c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_POSIX_MEMALIGN */
1201c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
1211c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (!ret)
1221c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		ret = malloc(size);
1231c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
1241c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	return ret;
1251c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o}
1261c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
127dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o/*
128dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * This routine reports a new bad block.  If the bad block has already
129dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * been seen before, then it returns 0; otherwise it returns 1.
130dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o */
131acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic int bb_output (blk_t bad)
132879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
133879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
134879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
135dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	if (ext2fs_badblocks_list_test(bb_list, bad))
136dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		return 0;
137dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o
138acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	fprintf(out, "%lu\n", (unsigned long) bad);
139cc4f98ed2deeaca33244fd77386e7d76917a3d30Theodore Ts'o	fflush(out);
140879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
141879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_add (bb_list, bad);
142879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
143879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "adding to in-memory bad block list");
144879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
145879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
146879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
147879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* kludge:
148879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   increment the iteration through the bb_list if
149879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   an element was just added before the current iteration
150879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   position.  This should not cause next_bad to change. */
151879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (bb_iter && bad < next_bad)
152879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
153dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	return 1;
154879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
155879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1568820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void print_status(void)
15719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
158acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	fprintf(stderr, "%15lu/%15lu", (unsigned long) currently_testing,
159acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o		(unsigned long) num_blocks);
160c76564a8784c3c44a6a0516e0fc40f10ec6221edTheodore Ts'o	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);
16119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
16219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
16319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
164544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void alarm_intr(int alnum EXT2FS_ATTR((unused)))
16519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
16619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	signal (SIGALRM, alarm_intr);
16719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	alarm(1);
16819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!num_blocks)
16919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return;
170c76564a8784c3c44a6a0516e0fc40f10ec6221edTheodore Ts'o	print_status();
17119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
17219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
173879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void *terminate_addr = NULL;
174879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
175544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void terminate_intr(int signo EXT2FS_ATTR((unused)))
176879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
177879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (terminate_addr)
178879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		longjmp(terminate_addr,1);
179879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	exit(1);
180879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
181879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
182981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void capture_terminate(jmp_buf term_addr)
183879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
184879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	terminate_addr = term_addr;
185879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGHUP, terminate_intr);
186879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGINT, terminate_intr);
187879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGPIPE, terminate_intr);
188879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGTERM, terminate_intr);
189879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR1, terminate_intr);
190879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR2, terminate_intr);
191879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
192879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1938820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void uncapture_terminate(void)
1944d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o{
1954d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	terminate_addr = NULL;
1964d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGHUP, SIG_DFL);
1974d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGINT, SIG_DFL);
1984d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGPIPE, SIG_DFL);
1994d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGTERM, SIG_DFL);
2004d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR1, SIG_DFL);
2014d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR2, SIG_DFL);
2024d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o}
2034d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
2041f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'ostatic void set_o_direct(int dev, unsigned char *buffer, size_t size,
205acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			 blk_t current_block)
2061c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o{
2071c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef O_DIRECT
2081c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int new_flag = O_DIRECT;
2091c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int flag;
2101c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
2111c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if ((((unsigned long) buffer & (sys_page_size - 1)) != 0) ||
2121f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o	    ((size & (sys_page_size - 1)) != 0) ||
2131f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o	    ((current_block & ((sys_page_size >> 9)-1)) != 0))
2141c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		new_flag = 0;
2151c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
2161c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (new_flag != current_O_DIRECT) {
217dc058719dfca9b35baec3208932702d39a502d3aTheodore Ts'o	     /* printf("%s O_DIRECT\n", new_flag ? "Setting" : "Clearing"); */
2181c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		flag = fcntl(dev, F_GETFL);
2191c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		if (flag > 0) {
2201c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			flag = (flag & ~O_DIRECT) | new_flag;
2211c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			fcntl(dev, F_SETFL, flag);
2221c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		}
2231c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		current_O_DIRECT = new_flag;
2241c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	}
2251c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif
2261c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o}
2271c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
2281c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
229e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'ostatic void pattern_fill(unsigned char *buffer, unsigned int pattern,
23084c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			 size_t n)
231849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o{
232544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	i, nb;
23384c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o	unsigned char	bpattern[sizeof(pattern)], *ptr;
234849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
235e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	if (pattern == (unsigned int) ~0) {
236849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		for (ptr = buffer; ptr < buffer + n; ptr++) {
237849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			(*ptr) = random() % (1 << (8 * sizeof(char)));
238849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
239849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (s_flag | v_flag)
240544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(_("Testing with random pattern: "), stderr);
241849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
242849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		bpattern[0] = 0;
243849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		for (i = 0; i < sizeof(bpattern); i++) {
244849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (pattern == 0)
245849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				break;
246849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			bpattern[i] = pattern & 0xFF;
247849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			pattern = pattern >> 8;
248849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
249849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nb = i ? (i-1) : 0;
250849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		for (ptr = buffer, i = nb; ptr < buffer + n; ptr++) {
251544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			*ptr = bpattern[i];
252544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if (i == 0)
253849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				i = nb;
254544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			else
255544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				i--;
256849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
25784c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o		if (s_flag | v_flag) {
258544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(_("Testing with pattern 0x"), stderr);
25984c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			for (i = 0; i <= nb; i++)
26084c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				fprintf(stderr, "%02x", buffer[i]);
261544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(": ", stderr);
26284c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o		}
263849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
264849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o}
265849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
2663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
267879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a read of a sequence of blocks; return the number of blocks
268879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially read.
2693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
270acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic int do_read (int dev, unsigned char * buffer, int try, int block_size,
271acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o		    blk_t current_block)
2723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
274264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	struct timeval tv1, tv2;
275264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop#define NANOSEC (1000000000L)
276264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop#define MILISEC (1000L)
2773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2781f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o	set_o_direct(dev, buffer, try * block_size, current_block);
2791c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
28019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag > 1)
28119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		print_status();
28219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
2833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Seek to the correct loc. */
28419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
285f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
286d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
2873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Try the read */
289264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	if (d_flag)
290edf261f6f859ed0ff3c16803ab61a78373089ad8Iustin Pop		gettimeofday(&tv1, NULL);
2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got = read (dev, buffer, try * block_size);
292264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	if (d_flag)
293edf261f6f859ed0ff3c16803ab61a78373089ad8Iustin Pop		gettimeofday(&tv2, NULL);
2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (got < 0)
2953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		got = 0;
2969f10a7b31e57288093930fc9565102409eeac6e9Theodore Ts'o	if (got & 511)
297d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Weird value (%ld) in do_read\n"), got);
298879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got /= block_size;
299264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	if (d_flag && got == try) {
300264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		struct timespec ts;
301264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		ts.tv_sec = tv2.tv_sec - tv1.tv_sec;
302264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		ts.tv_nsec = (tv2.tv_usec - tv1.tv_usec) * MILISEC;
303264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		if (ts.tv_nsec < 0) {
304264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			ts.tv_nsec += NANOSEC;
305264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			ts.tv_sec -= 1;
306264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		}
307264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		/* increase/decrease the sleep time based on d_flag value */
308264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		ts.tv_sec = ts.tv_sec * d_flag / 100;
309264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		ts.tv_nsec = ts.tv_nsec * d_flag / 100;
310264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		if (ts.tv_nsec > NANOSEC) {
311264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			ts.tv_sec += ts.tv_nsec / NANOSEC;
312264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			ts.tv_nsec %= NANOSEC;
313264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		}
314264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		if (ts.tv_sec || ts.tv_nsec)
315264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			nanosleep(&ts, NULL);
316264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	}
317879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return got;
318879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
319879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
320879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o/*
321879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a write of a sequence of blocks; return the number of blocks
322879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially written.
323879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o */
324acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic int do_write(int dev, unsigned char * buffer, int try, int block_size,
325acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o		    unsigned long current_block)
326879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
327879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	long got;
328879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
3291f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o	set_o_direct(dev, buffer, try * block_size, current_block);
3301c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
331879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag > 1)
332879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		print_status();
333879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
334879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Seek to the correct loc. */
335879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
336879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
337d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
338879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
339879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Try the write */
340879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got = write (dev, buffer, try * block_size);
341879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got < 0)
342879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = 0;
343879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got & 511)
344544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fprintf(stderr, "Weird value (%ld) in do_write\n", got);
3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got /= block_size;
3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return got;
3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
349879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic int host_dev;
350879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
3514d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'ostatic void flush_bufs(void)
352a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o{
3534d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	errcode_t	retval;
354a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
3554d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	retval = ext2fs_sync_device(host_dev, 1);
3564d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	if (retval)
3574d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		com_err(program_name, retval, _("during ext2fs_sync_device"));
358a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o}
359a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
360acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic unsigned int test_ro (int dev, blk_t last_block,
361f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			     int block_size, blk_t first_block,
362acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			     unsigned int blocks_at_once)
3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
36448e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o	unsigned char * blkbuf;
3653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int try;
366acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	int got;
367879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
368879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
3693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
370879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
371879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
372d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
373d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
374879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
375879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
376879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
377879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
378f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	} while (next_bad && next_bad < first_block);
379879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
380849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
3811c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		blkbuf = allocate_buffer((blocks_at_once + 1) * block_size);
382849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
3831c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		blkbuf = allocate_buffer(blocks_at_once * block_size);
384849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!blkbuf)
3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
387d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
3883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
390f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (v_flag) {
391acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o		fprintf (stderr, _("Checking blocks %lu to %lu\n"),
392f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			 (unsigned long) first_block,
393acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			 (unsigned long) last_block - 1);
394f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
395849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
396544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks in read-only mode\n"), stderr);
397849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern_fill(blkbuf + blocks_at_once * block_size,
398849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			     t_patts[0], block_size);
399849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
400849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	flush_bufs();
401879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	try = blocks_at_once;
402f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	currently_testing = first_block;
4038938ce64dca50d7d0f47f45fdc886de4f0939f0bTheodore Ts'o	num_blocks = last_block - 1;
404849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (!t_flag && (s_flag || v_flag)) {
405544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks (read-only test): "), stderr);
40619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (v_flag <= 1)
40719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			alarm_intr(SIGALRM);
4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
409cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	while (currently_testing < last_block)
4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
411931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop		if (max_bb && bb_count >= max_bb) {
412931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			if (s_flag || v_flag) {
413931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				fputs(_("Too many bad blocks, aborting test\n"), stderr);
414931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			}
415931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			break;
416931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop		}
417879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (next_bad) {
418879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (currently_testing == next_bad) {
419879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
420879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
421879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				currently_testing++;
422879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				continue;
423879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
424879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			else if (currently_testing + try > next_bad)
425879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				try = next_bad - currently_testing;
426879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
427cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		if (currently_testing + try > last_block)
428cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o			try = last_block - currently_testing;
429879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = do_read (dev, blkbuf, try, block_size, currently_testing);
430849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (t_flag) {
431849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/* test the comparison between all the
432849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			   blocks successfully read  */
433849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			int i;
434849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			for (i = 0; i < got; ++i)
435849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (memcmp (blkbuf+i*block_size,
436849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					    blkbuf+blocks_at_once*block_size,
437849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					    block_size))
438849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					bb_count += bb_output(currently_testing + i);
439849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		currently_testing += got;
4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (got == try) {
442879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			try = blocks_at_once;
4431f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			/* recover page-aligned offset for O_DIRECT */
444acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			if ( (blocks_at_once >= sys_page_size >> 9)
4451f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			     && (currently_testing % (sys_page_size >> 9)!= 0))
4461f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				try -= (sys_page_size >> 9)
4471f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					- (currently_testing
4481f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					   % (sys_page_size >> 9));
4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			continue;
4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		else
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = 1;
453879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (got == 0) {
454dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			bb_count += bb_output(currently_testing++);
455879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = 0;
4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	alarm(0);
459849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (s_flag || v_flag)
4603ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o		fputs(_(done_string), stderr);
461879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
462f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	fflush (stderr);
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free (blkbuf);
464879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
465879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
466879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
467879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
470acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic unsigned int test_rw (int dev, blk_t last_block,
471f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			     int block_size, blk_t first_block,
472acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			     unsigned int blocks_at_once)
4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4741c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	unsigned char *buffer, *read_buffer;
475e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	const unsigned int patterns[] = {0xaa, 0x55, 0xff, 0x00};
476e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	const unsigned int *pattern;
4771c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int i, try, got, nr_pattern, pat_idx;
478879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
4793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4801c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	buffer = allocate_buffer(2 * blocks_at_once * block_size);
4811c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	read_buffer = buffer + blocks_at_once * block_size;
4821c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
4831c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (!buffer) {
484d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
4853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4884d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	flush_bufs();
489a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
49019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag) {
491544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks in read-write mode\n"),
492544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		      stderr);
493d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("From block %lu to %lu\n"),
494f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			(unsigned long) first_block,
495f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			(unsigned long) last_block - 1);
49619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
497849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
498849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = t_patts;
499849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = t_flag;
500849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
501849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = patterns;
502849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
503849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
504849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
5051c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		pattern_fill(buffer, pattern[pat_idx],
5061c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			     blocks_at_once * block_size);
5078938ce64dca50d7d0f47f45fdc886de4f0939f0bTheodore Ts'o		num_blocks = last_block - 1;
508f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		currently_testing = first_block;
50919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
510f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
5111c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
5121c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		try = blocks_at_once;
5131c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		while (currently_testing < last_block) {
514931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			if (max_bb && bb_count >= max_bb) {
515931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				if (s_flag || v_flag) {
516931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop					fputs(_("Too many bad blocks, aborting test\n"), stderr);
517931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				}
518931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				break;
519931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			}
5201c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (currently_testing + try > last_block)
5211c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = last_block - currently_testing;
5221c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			got = do_write(dev, buffer, try, block_size,
5231c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					currently_testing);
52419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
52519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
5261c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
5271c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			currently_testing += got;
5281c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (got == try) {
5291c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = blocks_at_once;
5301f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				/* recover page-aligned offset for O_DIRECT */
531acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o				if ( (blocks_at_once >= sys_page_size >> 9)
5321f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				     && (currently_testing %
5331f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					 (sys_page_size >> 9)!= 0))
5341f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					try -= (sys_page_size >> 9)
5351f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o						- (currently_testing
5361f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o						   % (sys_page_size >> 9));
5371c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				continue;
5381c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			} else
5391c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = 1;
5401c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (got == 0) {
5411c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				bb_count += bb_output(currently_testing++);
5421c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			}
5433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
5441c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
545f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
546f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
547f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
5483ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o			fputs(_(done_string), stderr);
5494d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		flush_bufs();
550f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
551544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(_("Reading and comparing: "), stderr);
552cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		num_blocks = last_block;
553f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		currently_testing = first_block;
55419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
555f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
5561c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
5571c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		try = blocks_at_once;
5581c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		while (currently_testing < last_block) {
559931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			if (max_bb && bb_count >= max_bb) {
560931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				if (s_flag || v_flag) {
561931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop					fputs(_("Too many bad blocks, aborting test\n"), stderr);
562931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				}
563931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				break;
564931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			}
5651c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (currently_testing + try > last_block)
5661c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = last_block - currently_testing;
5671c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			got = do_read (dev, read_buffer, try, block_size,
5681c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				       currently_testing);
5691c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (got == 0) {
5701c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				bb_count += bb_output(currently_testing++);
5711c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				continue;
5721c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			}
5731c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			for (i=0; i < got; i++) {
5741c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				if (memcmp(read_buffer + i * block_size,
5751c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					   buffer + i * block_size,
5761c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					   block_size))
5771c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					bb_count += bb_output(currently_testing+i);
5781c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			}
5791c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			currently_testing += got;
5801f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			/* recover page-aligned offset for O_DIRECT */
581acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			if ( (blocks_at_once >= sys_page_size >> 9)
5821f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			     && (currently_testing % (sys_page_size >> 9)!= 0))
5831f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				try = blocks_at_once - (sys_page_size >> 9)
5841f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					- (currently_testing
5851f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					   % (sys_page_size >> 9));
5861f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			else
5871f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				try = blocks_at_once;
58819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
58919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
5903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
5911c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
592f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
593f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
594f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
5953ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o			fputs(_(done_string), stderr);
5964d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		flush_bufs();
5973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
598849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	uncapture_terminate();
5996d40f568cdec7d654691e6eed61cf5a32e918c03Theodore Ts'o	free(buffer);
600879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
601879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
602879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
603d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'ostruct saved_blk_record {
604d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	blk_t	block;
605d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	int	num;
606d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o};
607d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
608acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic unsigned int test_nd (int dev, blk_t last_block,
609f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			     int block_size, blk_t first_block,
610acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			     unsigned int blocks_at_once)
611879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
61248e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o	unsigned char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
6131c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	unsigned char *test_base, *save_base, *read_base;
614dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int try, i;
615e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	const unsigned int patterns[] = { ~0 };
616e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	const unsigned int *pattern;
617849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	int nr_pattern, pat_idx;
618acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	int got, used2, written;
619acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	blk_t save_currently_testing;
620d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	struct saved_blk_record *test_record;
621a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	/* This is static to prevent being clobbered by the longjmp */
622a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	static int num_saved;
623879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	jmp_buf terminate_env;
624879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
625544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned long buf_used;
626544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	static unsigned int bb_count;
627879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
628544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	bb_count = 0;
629879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
630879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
631dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		com_err (program_name, errcode,
632d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
633879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
634879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
635879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
636879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
637f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	} while (next_bad && next_bad < first_block);
638879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
6391c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	blkbuf = allocate_buffer(3 * blocks_at_once * block_size);
640d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	test_record = malloc (blocks_at_once*sizeof(struct saved_blk_record));
641d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	if (!blkbuf || !test_record) {
642d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err(program_name, ENOMEM, _("while allocating buffers"));
643879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
644879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
6451c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
6461c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	save_base = blkbuf;
6471c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	test_base = blkbuf + (blocks_at_once * block_size);
6481c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	read_base = blkbuf + (2 * blocks_at_once * block_size);
6491c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
650d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	num_saved = 0;
651879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
6524d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	flush_bufs();
653879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
654544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	    fputs(_("Checking for bad blocks in non-destructive read-write mode\n"), stderr);
655acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	    fprintf (stderr, _("From block %lu to %lu\n"),
656f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		     (unsigned long) first_block,
657f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		     (unsigned long) last_block - 1);
658879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
659879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (s_flag || v_flag > 1) {
660544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks (non-destructive read-write test)\n"), stderr);
661879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
6624d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	if (setjmp(terminate_env)) {
6634d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
6644d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * Abnormal termination by a signal is handled here.
6654d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
666a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		signal (SIGALRM, SIG_IGN);
667544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("\nInterrupt caught, cleaning up\n"), stderr);
668879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
6691c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		save_ptr = save_base;
670d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		for (i=0; i < num_saved; i++) {
671d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			do_write(dev, save_ptr, test_record[i].num,
672d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				 block_size, test_record[i].block);
673d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			save_ptr += test_record[i].num * block_size;
674d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		}
675879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fflush (out);
676dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		exit(1);
677879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
6784d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
6794d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	/* set up abend handler */
6804d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	capture_terminate(terminate_env);
6814d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
682849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
683849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = t_patts;
684849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = t_flag;
685849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
686849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = patterns;
687849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
688849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
689849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
6901c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		pattern_fill(test_base, pattern[pat_idx],
6911c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			     blocks_at_once * block_size);
6924d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
693849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		buf_used = 0;
694849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		bb_count = 0;
6951c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		save_ptr = save_base;
6961c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		test_ptr = test_base;
697f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		currently_testing = first_block;
6988938ce64dca50d7d0f47f45fdc886de4f0939f0bTheodore Ts'o		num_blocks = last_block - 1;
699849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (s_flag && v_flag <= 1)
700849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			alarm_intr(SIGALRM);
7014d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
702849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		while (currently_testing < last_block) {
703931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			if (max_bb && bb_count >= max_bb) {
704931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				if (s_flag || v_flag) {
705931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop					fputs(_("Too many bad blocks, aborting test\n"), stderr);
706931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				}
707931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				break;
708931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			}
7091c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			got = try = blocks_at_once - buf_used;
710849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (next_bad) {
711849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (currently_testing == next_bad) {
712849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					/* fprintf (out, "%lu\n", nextbad); */
713849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
714849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					currently_testing++;
715849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					goto check_for_more;
716849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
717849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				else if (currently_testing + try > next_bad)
718849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					try = next_bad - currently_testing;
719d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			}
720849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (currently_testing + try > last_block)
721849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				try = last_block - currently_testing;
722849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			got = do_read (dev, save_ptr, try, block_size,
723849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				       currently_testing);
724849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (got == 0) {
725849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				/* First block must have been bad. */
726849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				bb_count += bb_output(currently_testing++);
727849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				goto check_for_more;
7284d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			}
7294d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
730849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/*
731849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * Note the fact that we've saved this much data
732849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * *before* we overwrite it with test data
733849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 */
734849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			test_record[num_saved].block = currently_testing;
735849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			test_record[num_saved].num = got;
736849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			num_saved++;
737849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
738849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/* Write the test data */
739849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			written = do_write (dev, test_ptr, got, block_size,
740849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					    currently_testing);
741849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (written != got)
742849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				com_err (program_name, errno,
743849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					 _("during test data write, block %lu"),
744acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o					 (unsigned long) currently_testing +
745acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o					 written);
746849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
747849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			buf_used += got;
7484d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			save_ptr += got * block_size;
7494d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_ptr += got * block_size;
750849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			currently_testing += got;
751849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (got != try)
752849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				bb_count += bb_output(currently_testing++);
753849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
754849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		check_for_more:
755849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/*
756849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * If there's room for more blocks to be tested this
757849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * around, and we're not done yet testing the disk, go
758849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * back and get some more blocks.
759849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 */
760849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if ((buf_used != blocks_at_once) &&
761849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			    (currently_testing < last_block))
762849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				continue;
763849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
764849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			flush_bufs();
765849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			save_currently_testing = currently_testing;
766849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
767849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/*
768849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * for each contiguous block that we read into the
769849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * buffer (and wrote test data into afterwards), read
770849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * it back (looping if necessary, to get past newly
771849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * discovered unreadable blocks, of which there should
772849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * be none, but with a hard drive which is unreliable,
773849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * it has happened), and compare with the test data
774849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * that was written; output to the bad block list if
775849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * it doesn't match.
776849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 */
777849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			used2 = 0;
7781c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			save_ptr = save_base;
7791c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			test_ptr = test_base;
7801c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			read_ptr = read_base;
781849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			try = 0;
782849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
783849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			while (1) {
784849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (try == 0) {
785849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					if (used2 >= num_saved)
786849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						break;
787849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					currently_testing = test_record[used2].block;
788849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					try = test_record[used2].num;
789849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					used2++;
790849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
791849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
792849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				got = do_read (dev, read_ptr, try,
793849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					       block_size, currently_testing);
794849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
795849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				/* test the comparison between all the
796849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				   blocks successfully read  */
797849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				for (i = 0; i < got; ++i)
798849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					if (memcmp (test_ptr+i*block_size,
799849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						    read_ptr+i*block_size, block_size))
800849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						bb_count += bb_output(currently_testing + i);
801849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (got < try) {
802849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					bb_count += bb_output(currently_testing + got);
803849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					got++;
804849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
805849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
8061c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				/* write back original data */
8071c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				do_write (dev, save_ptr, got,
8081c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					  block_size, currently_testing);
8091c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				save_ptr += got * block_size;
810849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
811849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				currently_testing += got;
812849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				test_ptr += got * block_size;
813849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				read_ptr += got * block_size;
814849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				try -= got;
815849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			}
816849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
817849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/* empty the buffer so it can be reused */
818849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			num_saved = 0;
819849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			buf_used = 0;
8201c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			save_ptr = save_base;
8211c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			test_ptr = test_base;
822849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			currently_testing = save_currently_testing;
8234d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		}
824849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		num_blocks = 0;
825849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		alarm(0);
826849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (s_flag || v_flag > 1)
8273ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o			fputs(_(done_string), stderr);
8284d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
829849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		flush_bufs();
8304d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	}
8314d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	uncapture_terminate();
832dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	fflush(stderr);
833dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	free(blkbuf);
834d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	free(test_record);
835879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
836879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
837879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
838879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
8393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
8403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
841981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void check_mount(char *device_name)
842981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o{
843981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	errcode_t	retval;
844981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	int		mount_flags;
845981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
846981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	retval = ext2fs_check_if_mounted(device_name, &mount_flags);
847981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (retval) {
848981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		com_err("ext2fs_check_if_mount", retval,
849981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			_("while determining whether %s is mounted."),
850981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			device_name);
851981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		return;
852981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
8532fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o	if (mount_flags & EXT2_MF_MOUNTED) {
8542fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		fprintf(stderr, _("%s is mounted; "), device_name);
8552fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		if (force) {
8562fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			fputs(_("badblocks forced anyway.  "
8572fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o				"Hope /etc/mtab is incorrect.\n"), stderr);
8582fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			return;
8592fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		}
8602fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o	abort_badblocks:
8612fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		fputs(_("it's not safe to run badblocks!\n"), stderr);
8622fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		exit(1);
8632fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o	}
864981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
865f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o	if ((mount_flags & EXT2_MF_BUSY) && !exclusive_ok) {
8662fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		fprintf(stderr, _("%s is apparently in use by the system; "),
8672fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			device_name);
8682fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		if (force)
8692fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			fputs(_("badblocks forced anyway.\n"), stderr);
8702fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		else
8712fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			goto abort_badblocks;
872981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
8732fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o
874981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o}
875981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
876d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o/*
877d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o * This function will convert a string to an unsigned long, printing
878d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o * an error message if it fails, and returning success or failure in err.
879d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o */
880d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'ostatic unsigned int parse_uint(const char *str, const char *descr)
881d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o{
882d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	char		*tmp;
883d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	unsigned long	ret;
884d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o
885eb594251b6d1a06d2acbb281b3816c017d7066ebIustin Pop	errno = 0;
886d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	ret = strtoul(str, &tmp, 0);
887d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	if (*tmp || errno || (ret > UINT_MAX) ||
888d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	    (ret == ULONG_MAX && errno == ERANGE)) {
889d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o		com_err (program_name, 0, _("invalid %s - %s"), descr, str);
890d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o		exit (1);
891d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	}
892d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	return ret;
893d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o}
894981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
89500e5433eb5e9f70f485968b809fdcf297d7fe7b9Theodore Ts'oint main (int argc, char ** argv)
8963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
897519149fb458b0fa69c10fecd83fae42e838cf01dTheodore Ts'o	int c;
8983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * device_name;
899879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * host_device_name = NULL;
900879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * input_file = NULL;
9013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * output_file = NULL;
902879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	FILE * in = NULL;
903dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int block_size = 1024;
904acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	unsigned int blocks_at_once = 64;
905f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	blk_t last_block, first_block;
906879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int num_passes = 0;
907879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int passes_clean = 0;
9083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int dev;
909879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
910e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	unsigned int pattern;
911acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	unsigned int (*test_func)(int, blk_t,
912acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o				  int, blk_t,
913acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o				  unsigned int);
9141c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int open_flag = 0;
9151c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	long sysval;
9163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
9173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stdout, NULL);
9183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stderr, NULL);
919d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#ifdef ENABLE_NLS
920d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	setlocale(LC_MESSAGES, "");
92114308a5398984842e808faa3ff2dd6a1c52d90bdTheodore Ts'o	setlocale(LC_CTYPE, "");
922d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
923d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	textdomain(NLS_CAT_NAME);
924d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#endif
9256d40f568cdec7d654691e6eed61cf5a32e918c03Theodore Ts'o	srandom((unsigned int)time(NULL));  /* simple randomness is enough */
9264d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	test_func = test_ro;
9274d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o
9281c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	/* Determine the system page size if possible */
9291c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_SYSCONF
9301c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
9311c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#define _SC_PAGESIZE _SC_PAGE_SIZE
9321c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif
9331c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef _SC_PAGESIZE
9341c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	sysval = sysconf(_SC_PAGESIZE);
9351c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (sysval > 0)
9361c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		sys_page_size = sysval;
9371c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* _SC_PAGESIZE */
9381c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_SYSCONF */
9391c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
9403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (argc && *argv)
9413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		program_name = *argv;
942264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	while ((c = getopt (argc, argv, "b:d:e:fi:o:svwnc:p:h:t:X")) != EOF) {
9433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		switch (c) {
9443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'b':
945d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o			block_size = parse_uint(optarg, "block size");
946d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o			if (block_size > 4096) {
9473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, 0,
948d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("bad block size - %s"), optarg);
9493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				exit (1);
9503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
9513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
952981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		case 'f':
953981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			force++;
954981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			break;
955879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'i':
956879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			input_file = optarg;
957879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
9583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'o':
9593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			output_file = optarg;
9603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
9613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 's':
9623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			s_flag = 1;
9633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
9643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'v':
96519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			v_flag++;
9663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
9673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'w':
9684d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
969d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o				exclusive_usage();
9704d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_rw;
9714d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			w_flag = 1;
972879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
973879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'n':
9744d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
975d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o				exclusive_usage();
9764d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_nd;
977879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			w_flag = 2;
978879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
979879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'c':
980d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o			blocks_at_once = parse_uint(optarg, "blocks at once");
981879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
982931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop		case 'e':
983931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			max_bb = parse_uint(optarg, "max bad block count");
984931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			break;
985264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		case 'd':
986264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			d_flag = parse_uint(optarg, "read delay factor");
987264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			break;
988879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'p':
989d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o			num_passes = parse_uint(optarg,
990d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o						"number of clean passes");
991879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
992879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'h':
993879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			host_device_name = optarg;
9943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
995849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		case 't':
996849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (t_flag + 1 > t_max) {
997e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o				unsigned int *t_patts_new;
998849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
99969d813520cf14f5700c38c82b5c147aa3756bbd9Theodore Ts'o				t_patts_new = realloc(t_patts, sizeof(int) *
100069d813520cf14f5700c38c82b5c147aa3756bbd9Theodore Ts'o						      (t_max + T_INC));
1001849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (!t_patts_new) {
1002849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					com_err(program_name, ENOMEM,
1003849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						_("can't allocate memory for "
1004849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						  "test_pattern - %s"),
1005849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						optarg);
1006849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					exit(1);
1007849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
1008849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				t_patts = t_patts_new;
1009849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				t_max += T_INC;
1010849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			}
101184c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			if (!strcmp(optarg, "r") || !strcmp(optarg,"random")) {
101284c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				t_patts[t_flag++] = ~0;
101384c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			} else {
1014d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o				pattern = parse_uint(optarg, "test pattern");
1015e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o				if (pattern == (unsigned int) ~0)
101684c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o					pattern = 0xffff;
101784c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				t_patts[t_flag++] = pattern;
1018849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			}
1019849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			break;
1020f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o		case 'X':
1021f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o			exclusive_ok++;
1022f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o			break;
10233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		default:
1024818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o			usage();
10253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
10263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1027849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (!w_flag) {
1028849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (t_flag > 1) {
1029849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			com_err(program_name, 0,
1030849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			_("Maximum of one test_pattern may be specified "
1031849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			  "in read-only mode"));
1032849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			exit(1);
1033849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
1034e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o		if (t_patts && (t_patts[0] == (unsigned int) ~0)) {
1035849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			com_err(program_name, 0,
1036849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			_("Random test_pattern is not allowed "
1037849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			  "in read-only mode"));
1038849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			exit(1);
1039849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
1040849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
10413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
1042818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
10433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	device_name = argv[optind++];
104435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind > argc - 1) {
104535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		errcode = ext2fs_get_device_size(device_name,
104635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o						 block_size,
1047cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o						 &last_block);
104835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode == EXT2_ET_UNIMPLEMENTED) {
104935964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err(program_name, 0,
105035964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("Couldn't determine device size; you "
105135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				  "must specify\nthe size manually\n"));
105235964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
105335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
105435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode) {
105535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err(program_name, errcode,
105635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("while trying to determine device size"));
105735964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
105835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
105935964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	} else {
10605267a520bb7887b146f05ffa8726664afbb6c3c2Theodore Ts'o		errno = 0;
1061f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		last_block = parse_uint(argv[optind], _("last block"));
10625267a520bb7887b146f05ffa8726664afbb6c3c2Theodore Ts'o		last_block++;
106335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		optind++;
10643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
106535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind <= argc-1) {
10665267a520bb7887b146f05ffa8726664afbb6c3c2Theodore Ts'o		errno = 0;
1067f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		first_block = parse_uint(argv[optind], _("first block"));
1068f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	} else first_block = 0;
1069f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	if (first_block >= last_block) {
1070d4e0b1c6f5aa8c6a248d9149ed5634a310952411Theodore Ts'o	    com_err (program_name, 0, _("invalid starting block (%lu): must be less than %lu"),
1071f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		     (unsigned long) first_block, (unsigned long) last_block);
1072f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    exit (1);
1073f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
1074981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (w_flag)
1075981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		check_mount(device_name);
1076981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
10771c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	open_flag = w_flag ? O_RDWR : O_RDONLY;
10781c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	dev = open (device_name, open_flag);
10795493a27dc1138d2e30193b80217a0127d247af1eTheodore Ts'o	if (dev == -1) {
1080d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("while trying to open %s"),
10813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 device_name);
10823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
10833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1084879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (host_device_name) {
10851c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		host_dev = open (host_device_name, open_flag);
10865493a27dc1138d2e30193b80217a0127d247af1eTheodore Ts'o		if (host_dev == -1) {
1087d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
1088d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
1089d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 host_device_name);
1090879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			exit (1);
1091879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
1092879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} else
1093879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = dev;
10943e69906495d5898849a6154b0311b5d4a84a27aeTheodore Ts'o	if (input_file) {
1095879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (strcmp (input_file, "-") == 0)
1096879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = stdin;
1097879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		else {
1098879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = fopen (input_file, "r");
1099879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (in == NULL)
1100879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			{
1101d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				com_err (program_name, errno,
1102d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("while trying to open %s"),
1103879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 input_file);
1104879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
1105879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
1106879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
11073e69906495d5898849a6154b0311b5d4a84a27aeTheodore Ts'o	}
11083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (output_file && strcmp (output_file, "-") != 0)
11093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
11103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = fopen (output_file, "w");
11113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (out == NULL)
11123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
1113d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
1114d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
1115879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				 output_file);
11163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			exit (1);
11173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
11183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
11193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
11203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = stdout;
1121879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1122879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_create(&bb_list,0);
1123879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
1124d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
1125bb145b01cf5fd27d9afe03c3262d0e1a326e7ec1Theodore Ts'o			 _("while creating in-memory bad blocks list"));
1126879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
1127879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
1128879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1129879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (in) {
1130879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		for(;;) {
1131a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o			switch(fscanf (in, "%u\n", &next_bad)) {
1132879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case 0:
1133879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					com_err (program_name, 0, "input file - bad format");
1134879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					exit (1);
1135879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case EOF:
1136879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					break;
1137879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				default:
1138879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
1139879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					if (errcode) {
1140bb145b01cf5fd27d9afe03c3262d0e1a326e7ec1Theodore Ts'o						com_err (program_name, errcode, _("while adding to in-memory bad block list"));
1141879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						exit (1);
1142879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					}
1143879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					continue;
1144879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
1145879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
1146879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
1147879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1148879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (in != stdin)
1149879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			fclose (in);
1150879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
1151879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1152879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
1153879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		unsigned int bb_count;
1154879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1155cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		bb_count = test_func(dev, last_block, block_size,
1156f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o				     first_block, blocks_at_once);
11574d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (bb_count)
11584d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			passes_clean = 0;
11594d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		else
11604d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			++passes_clean;
11614d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
1162879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag)
1163d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf(stderr,
1164d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				_("Pass completed, %u bad blocks found.\n"),
1165d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				bb_count);
1166879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1167879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (passes_clean < num_passes);
1168879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
11693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	close (dev);
11703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (out != stdout)
11713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fclose (out);
1172849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_patts)
1173849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		free(t_patts);
1174879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return 0;
11753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1176d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o
1177