badblocks.c revision f63978aff759325b542de7134ab659c79dc47496
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>
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/ioctl.h>
51f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h>
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "et/com_err.h"
54d40259fd552d942903f2fd0b426c75a5c2516017Theodore Ts'o#include "ext2fs/ext2_io.h"
5554c637d4d29af3e6365779f8b12976abe95a4753Theodore Ts'o#include "ext2fs/ext2_fs.h"
56879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include "ext2fs/ext2fs.h"
57d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#include "nls-enable.h"
583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oconst char * program_name = "badblocks";
60f63978aff759325b542de7134ab659c79dc47496Theodore Ts'oconst char * done_string = N_("done                                \n");
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
624d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int v_flag = 0;			/* verbose */
634d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int w_flag = 0;			/* do r/w test: 0=no, 1=yes,
644d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o					 * 2=non-destructive */
654d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int s_flag = 0;			/* show progress of test */
66981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic int force = 0;			/* force check of mounted device */
67849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'ostatic int t_flag = 0;			/* number of test patterns */
68849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'ostatic int t_max = 0;			/* allocated test patterns */
6984c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'ostatic unsigned long *t_patts = NULL;	/* test patterns */
701c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'ostatic int current_O_DIRECT = 0;	/* Current status of O_DIRECT flag */
71f63978aff759325b542de7134ab659c79dc47496Theodore Ts'ostatic int exclusive_ok = 0;
721c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
73849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o#define T_INC 32
744d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
751c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'oint sys_page_size = 4096;
761c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
778820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void usage(void)
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
79849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	fprintf(stderr, _("Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnf]\n [-c blocks_at_once] [-p num_passes] [-t test_pattern [-t test_pattern [...]]]\n device [last_block [start_block]]\n"),
803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 program_name);
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	exit (1);
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long currently_testing = 0;
8519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long num_blocks = 0;
86879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_list bb_list = NULL;
87879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic FILE *out;
88879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic blk_t next_bad = 0;
89879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_iterate bb_iter = NULL;
9019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
911c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'ostatic void *allocate_buffer(size_t size)
921c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o{
931c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	void	*ret = 0;
941c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
951c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_POSIX_MEMALIGN
961c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (posix_memalign(&ret, sys_page_size, size) < 0)
971c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		ret = 0;
981c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#else
991c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_MEMALIGN
1001c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	ret = memalign(sys_page_size, size);
1011c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#else
1021c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_VALLOC
1031c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	ret = valloc(size);
1041c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_VALLOC */
1051c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_MEMALIGN */
1061c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_POSIX_MEMALIGN */
1071c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
1081c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (!ret)
1091c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		ret = malloc(size);
1101c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
1111c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	return ret;
1121c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o}
1131c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
114dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o/*
115dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * This routine reports a new bad block.  If the bad block has already
116dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * been seen before, then it returns 0; otherwise it returns 1.
117dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o */
118dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic int bb_output (unsigned long bad)
119879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
120879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
121879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
122dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	if (ext2fs_badblocks_list_test(bb_list, bad))
123dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		return 0;
124dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o
125cc4f98ed2deeaca33244fd77386e7d76917a3d30Theodore Ts'o	fprintf(out, "%lu\n", bad);
126cc4f98ed2deeaca33244fd77386e7d76917a3d30Theodore Ts'o	fflush(out);
127879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
128879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_add (bb_list, bad);
129879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
130879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "adding to in-memory bad block list");
131879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
132879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
133879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
134879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* kludge:
135879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   increment the iteration through the bb_list if
136879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   an element was just added before the current iteration
137879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   position.  This should not cause next_bad to change. */
138879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (bb_iter && bad < next_bad)
139879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
140dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	return 1;
141879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
142879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1438820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void print_status(void)
14419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
145c76564a8784c3c44a6a0516e0fc40f10ec6221edTheodore Ts'o	fprintf(stderr, "%15ld/%15ld", currently_testing, num_blocks);
146c76564a8784c3c44a6a0516e0fc40f10ec6221edTheodore 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);
14719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
14819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
14919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
150544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void alarm_intr(int alnum EXT2FS_ATTR((unused)))
15119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
15219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	signal (SIGALRM, alarm_intr);
15319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	alarm(1);
15419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!num_blocks)
15519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return;
156c76564a8784c3c44a6a0516e0fc40f10ec6221edTheodore Ts'o	print_status();
15719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
15819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
159879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void *terminate_addr = NULL;
160879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
161544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void terminate_intr(int signo EXT2FS_ATTR((unused)))
162879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
163879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (terminate_addr)
164879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		longjmp(terminate_addr,1);
165879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	exit(1);
166879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
167879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
168981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void capture_terminate(jmp_buf term_addr)
169879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
170879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	terminate_addr = term_addr;
171879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGHUP, terminate_intr);
172879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGINT, terminate_intr);
173879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGPIPE, terminate_intr);
174879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGTERM, terminate_intr);
175879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR1, terminate_intr);
176879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR2, terminate_intr);
177879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
178879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1798820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void uncapture_terminate(void)
1804d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o{
1814d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	terminate_addr = NULL;
1824d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGHUP, SIG_DFL);
1834d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGINT, SIG_DFL);
1844d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGPIPE, SIG_DFL);
1854d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGTERM, SIG_DFL);
1864d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR1, SIG_DFL);
1874d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR2, SIG_DFL);
1884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o}
1894d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
1901f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'ostatic void set_o_direct(int dev, unsigned char *buffer, size_t size,
1911f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			 unsigned long current_block)
1921c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o{
1931c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef O_DIRECT
1941c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int new_flag = O_DIRECT;
1951c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int flag;
1961c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
1971c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if ((((unsigned long) buffer & (sys_page_size - 1)) != 0) ||
1981f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o	    ((size & (sys_page_size - 1)) != 0) ||
1991f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o	    ((current_block & ((sys_page_size >> 9)-1)) != 0))
2001c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		new_flag = 0;
2011c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
2021c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (new_flag != current_O_DIRECT) {
203dc058719dfca9b35baec3208932702d39a502d3aTheodore Ts'o	     /* printf("%s O_DIRECT\n", new_flag ? "Setting" : "Clearing"); */
2041c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		flag = fcntl(dev, F_GETFL);
2051c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		if (flag > 0) {
2061c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			flag = (flag & ~O_DIRECT) | new_flag;
2071c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			fcntl(dev, F_SETFL, flag);
2081c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		}
2091c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		current_O_DIRECT = new_flag;
2101c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	}
2111c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif
2121c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o}
2131c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
2141c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
21584c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'ostatic void pattern_fill(unsigned char *buffer, unsigned long pattern,
21684c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			 size_t n)
217849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o{
218544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	i, nb;
21984c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o	unsigned char	bpattern[sizeof(pattern)], *ptr;
220849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
221023cbb302963a93d0247e95a02591cb304bf152cTheodore Ts'o	if (pattern == (unsigned long) ~0) {
222849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		for (ptr = buffer; ptr < buffer + n; ptr++) {
223849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			(*ptr) = random() % (1 << (8 * sizeof(char)));
224849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
225849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (s_flag | v_flag)
226544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(_("Testing with random pattern: "), stderr);
227849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
228849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		bpattern[0] = 0;
229849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		for (i = 0; i < sizeof(bpattern); i++) {
230849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (pattern == 0)
231849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				break;
232849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			bpattern[i] = pattern & 0xFF;
233849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			pattern = pattern >> 8;
234849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
235849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nb = i ? (i-1) : 0;
236849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		for (ptr = buffer, i = nb; ptr < buffer + n; ptr++) {
237544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			*ptr = bpattern[i];
238544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if (i == 0)
239849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				i = nb;
240544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			else
241544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				i--;
242849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
24384c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o		if (s_flag | v_flag) {
244544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(_("Testing with pattern 0x"), stderr);
24584c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			for (i = 0; i <= nb; i++)
24684c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				fprintf(stderr, "%02x", buffer[i]);
247544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(": ", stderr);
24884c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o		}
249849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
250849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o}
251849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
2523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
253879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a read of a sequence of blocks; return the number of blocks
254879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially read.
2553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
25648e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'ostatic long do_read (int dev, unsigned char * buffer, int try, int block_size,
2573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		     unsigned long current_block)
2583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
2603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2611f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o	set_o_direct(dev, buffer, try * block_size, current_block);
2621c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
26319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag > 1)
26419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		print_status();
26519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
2663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Seek to the correct loc. */
26719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
268f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
269d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
2703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Try the read */
2723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got = read (dev, buffer, try * block_size);
2733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (got < 0)
2743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		got = 0;
2759f10a7b31e57288093930fc9565102409eeac6e9Theodore Ts'o	if (got & 511)
276d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Weird value (%ld) in do_read\n"), got);
277879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got /= block_size;
278879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return got;
279879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
280879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
281879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o/*
282879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a write of a sequence of blocks; return the number of blocks
283879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially written.
284879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o */
28548e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'ostatic long do_write (int dev, unsigned char * buffer, int try, int block_size,
286879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long current_block)
287879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
288879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	long got;
289879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
2901f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o	set_o_direct(dev, buffer, try * block_size, current_block);
2911c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
292879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag > 1)
293879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		print_status();
294879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
295879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Seek to the correct loc. */
296879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
297879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
298d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
299879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
300879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Try the write */
301879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got = write (dev, buffer, try * block_size);
302879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got < 0)
303879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = 0;
304879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got & 511)
305544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fprintf(stderr, "Weird value (%ld) in do_write\n", got);
3063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got /= block_size;
3073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return got;
3083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
310879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic int host_dev;
311879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
3124d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'ostatic void flush_bufs(void)
313a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o{
3144d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	errcode_t	retval;
315a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
3164d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	retval = ext2fs_sync_device(host_dev, 1);
3174d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	if (retval)
3184d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		com_err(program_name, retval, _("during ext2fs_sync_device"));
319a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o}
320a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
321cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'ostatic unsigned int test_ro (int dev, unsigned long last_block,
322dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
323dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
32548e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o	unsigned char * blkbuf;
3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int try;
3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
328879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
329879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
331879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
332879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
333d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
334d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
335879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
336879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
337879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
338879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
339879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
340879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
341849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
3421c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		blkbuf = allocate_buffer((blocks_at_once + 1) * block_size);
343849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
3441c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		blkbuf = allocate_buffer(blocks_at_once * block_size);
345849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!blkbuf)
3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
348d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
3493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
351f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (v_flag) {
352849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	    fprintf (stderr, _("Checking blocks %lu to %lu\n"), from_count,
353cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		     last_block);
354f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
355849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
356544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks in read-only mode\n"), stderr);
357849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern_fill(blkbuf + blocks_at_once * block_size,
358849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			     t_patts[0], block_size);
359849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
360849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	flush_bufs();
361879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	try = blocks_at_once;
362f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	currently_testing = from_count;
363cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	num_blocks = last_block;
364849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (!t_flag && (s_flag || v_flag)) {
365544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks (read-only test): "), stderr);
36619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (v_flag <= 1)
36719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			alarm_intr(SIGALRM);
3683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
369cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	while (currently_testing < last_block)
3703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
371879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (next_bad) {
372879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (currently_testing == next_bad) {
373879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
374879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
375879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				currently_testing++;
376879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				continue;
377879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
378879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			else if (currently_testing + try > next_bad)
379879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				try = next_bad - currently_testing;
380879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
381cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		if (currently_testing + try > last_block)
382cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o			try = last_block - currently_testing;
383879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = do_read (dev, blkbuf, try, block_size, currently_testing);
384849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (t_flag) {
385849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/* test the comparison between all the
386849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			   blocks successfully read  */
387849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			int i;
388849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			for (i = 0; i < got; ++i)
389849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (memcmp (blkbuf+i*block_size,
390849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					    blkbuf+blocks_at_once*block_size,
391849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					    block_size))
392849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					bb_count += bb_output(currently_testing + i);
393849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		currently_testing += got;
3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (got == try) {
396879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			try = blocks_at_once;
3971f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			/* recover page-aligned offset for O_DIRECT */
398544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if ( blocks_at_once >= (unsigned long) (sys_page_size >> 9)
3991f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			     && (currently_testing % (sys_page_size >> 9)!= 0))
4001f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				try -= (sys_page_size >> 9)
4011f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					- (currently_testing
4021f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					   % (sys_page_size >> 9));
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			continue;
4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		else
4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = 1;
407879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (got == 0) {
408dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			bb_count += bb_output(currently_testing++);
409879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = 0;
4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	alarm(0);
413849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (s_flag || v_flag)
4143ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o		fputs(_(done_string), stderr);
415879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
416f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	fflush (stderr);
4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free (blkbuf);
418879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
419879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
420879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
421879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
424cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'ostatic unsigned int test_rw (int dev, unsigned long last_block,
425dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
426dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
4273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4281c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	unsigned char *buffer, *read_buffer;
42984c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o	const unsigned long patterns[] = {0xaa, 0x55, 0xff, 0x00};
43084c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o	const unsigned long *pattern;
4311c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int i, try, got, nr_pattern, pat_idx;
432879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
4333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4341c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	buffer = allocate_buffer(2 * blocks_at_once * block_size);
4351c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	read_buffer = buffer + blocks_at_once * block_size;
4361c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
4371c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (!buffer) {
438d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4424d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	flush_bufs();
443a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
44419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag) {
445544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks in read-write mode\n"),
446544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		      stderr);
447d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("From block %lu to %lu\n"),
448cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o			 from_count, last_block);
44919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
450849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
451849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = t_patts;
452849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = t_flag;
453849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
454849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = patterns;
455849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
456849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
457849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
4581c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		pattern_fill(buffer, pattern[pat_idx],
4591c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			     blocks_at_once * block_size);
460cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		num_blocks = last_block;
461f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
46219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
463f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
4641c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
4651c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		try = blocks_at_once;
4661c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		while (currently_testing < last_block) {
4671c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (currently_testing + try > last_block)
4681c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = last_block - currently_testing;
4691c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			got = do_write(dev, buffer, try, block_size,
4701c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					currently_testing);
47119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
47219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
4731c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
4741c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			currently_testing += got;
4751c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (got == try) {
4761c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = blocks_at_once;
4771f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				/* recover page-aligned offset for O_DIRECT */
478544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				if ( blocks_at_once >= (unsigned long) (sys_page_size >> 9)
4791f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				     && (currently_testing %
4801f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					 (sys_page_size >> 9)!= 0))
4811f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					try -= (sys_page_size >> 9)
4821f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o						- (currently_testing
4831f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o						   % (sys_page_size >> 9));
4841c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				continue;
4851c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			} else
4861c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = 1;
4871c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (got == 0) {
4881c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				bb_count += bb_output(currently_testing++);
4891c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			}
4903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
4911c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
492f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
493f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
494f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
4953ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o			fputs(_(done_string), stderr);
4964d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		flush_bufs();
497f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
498544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(_("Reading and comparing: "), stderr);
499cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		num_blocks = last_block;
500f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
50119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
502f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
5031c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
5041c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		try = blocks_at_once;
5051c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		while (currently_testing < last_block) {
5061c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (currently_testing + try > last_block)
5071c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = last_block - currently_testing;
5081c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			got = do_read (dev, read_buffer, try, block_size,
5091c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				       currently_testing);
5101c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (got == 0) {
5111c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				bb_count += bb_output(currently_testing++);
5121c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				continue;
5131c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			}
5141c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			for (i=0; i < got; i++) {
5151c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				if (memcmp(read_buffer + i * block_size,
5161c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					   buffer + i * block_size,
5171c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					   block_size))
5181c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					bb_count += bb_output(currently_testing+i);
5191c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			}
5201c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			currently_testing += got;
5211f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			/* recover page-aligned offset for O_DIRECT */
522544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if ( blocks_at_once >= (unsigned long) (sys_page_size >> 9)
5231f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			     && (currently_testing % (sys_page_size >> 9)!= 0))
5241f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				try = blocks_at_once - (sys_page_size >> 9)
5251f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					- (currently_testing
5261f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o					   % (sys_page_size >> 9));
5271f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o			else
5281f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o				try = blocks_at_once;
52919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
53019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
5321c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
533f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
534f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
535f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
5363ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o			fputs(_(done_string), stderr);
5374d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		flush_bufs();
5383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
539849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	uncapture_terminate();
5406d40f568cdec7d654691e6eed61cf5a32e918c03Theodore Ts'o	free(buffer);
541879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
542879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
543879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
544d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'ostruct saved_blk_record {
545d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	blk_t	block;
546d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	int	num;
547d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o};
548d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
549cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'ostatic unsigned int test_nd (int dev, unsigned long last_block,
550dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
551dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
552879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
55348e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o	unsigned char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
5541c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	unsigned char *test_base, *save_base, *read_base;
555dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int try, i;
55684c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o	const unsigned long patterns[] = { ~0 };
55784c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o	const unsigned long *pattern;
558849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	int nr_pattern, pat_idx;
559a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	long got, used2, written, save_currently_testing;
560d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	struct saved_blk_record *test_record;
561a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	/* This is static to prevent being clobbered by the longjmp */
562a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	static int num_saved;
563879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	jmp_buf terminate_env;
564879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
565544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned long buf_used;
566544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	static unsigned int bb_count;
567879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
568544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	bb_count = 0;
569879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
570879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
571dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		com_err (program_name, errcode,
572d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
573879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
574879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
575879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
576879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
577879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
578879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
5791c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	blkbuf = allocate_buffer(3 * blocks_at_once * block_size);
580d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	test_record = malloc (blocks_at_once*sizeof(struct saved_blk_record));
581d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	if (!blkbuf || !test_record) {
582d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err(program_name, ENOMEM, _("while allocating buffers"));
583879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
584879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
5851c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
5861c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	save_base = blkbuf;
5871c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	test_base = blkbuf + (blocks_at_once * block_size);
5881c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	read_base = blkbuf + (2 * blocks_at_once * block_size);
5891c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
590d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	num_saved = 0;
591879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
5924d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	flush_bufs();
593879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
594544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	    fputs(_("Checking for bad blocks in non-destructive read-write mode\n"), stderr);
595cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	    fprintf (stderr, _("From block %lu to %lu\n"), from_count, last_block);
596879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
597879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (s_flag || v_flag > 1) {
598544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks (non-destructive read-write test)\n"), stderr);
599879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
6004d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	if (setjmp(terminate_env)) {
6014d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
6024d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * Abnormal termination by a signal is handled here.
6034d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
604a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		signal (SIGALRM, SIG_IGN);
605544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("\nInterrupt caught, cleaning up\n"), stderr);
606879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
6071c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		save_ptr = save_base;
608d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		for (i=0; i < num_saved; i++) {
609d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			do_write(dev, save_ptr, test_record[i].num,
610d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				 block_size, test_record[i].block);
611d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			save_ptr += test_record[i].num * block_size;
612d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		}
613879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fflush (out);
614dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		exit(1);
615879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
6164d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
6174d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	/* set up abend handler */
6184d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	capture_terminate(terminate_env);
6194d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
620849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
621849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = t_patts;
622849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = t_flag;
623849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
624849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = patterns;
625849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
626849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
627849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
6281c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		pattern_fill(test_base, pattern[pat_idx],
6291c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			     blocks_at_once * block_size);
6304d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
631849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		buf_used = 0;
632849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		bb_count = 0;
6331c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		save_ptr = save_base;
6341c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		test_ptr = test_base;
635849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		currently_testing = from_count;
636849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		num_blocks = last_block;
637849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (s_flag && v_flag <= 1)
638849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			alarm_intr(SIGALRM);
6394d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
640849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		while (currently_testing < last_block) {
6411c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			got = try = blocks_at_once - buf_used;
642849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (next_bad) {
643849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (currently_testing == next_bad) {
644849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					/* fprintf (out, "%lu\n", nextbad); */
645849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
646849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					currently_testing++;
647849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					goto check_for_more;
648849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
649849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				else if (currently_testing + try > next_bad)
650849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					try = next_bad - currently_testing;
651d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			}
652849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (currently_testing + try > last_block)
653849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				try = last_block - currently_testing;
654849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			got = do_read (dev, save_ptr, try, block_size,
655849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				       currently_testing);
656849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (got == 0) {
657849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				/* First block must have been bad. */
658849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				bb_count += bb_output(currently_testing++);
659849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				goto check_for_more;
6604d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			}
6614d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
662849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/*
663849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * Note the fact that we've saved this much data
664849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * *before* we overwrite it with test data
665849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 */
666849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			test_record[num_saved].block = currently_testing;
667849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			test_record[num_saved].num = got;
668849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			num_saved++;
669849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
670849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/* Write the test data */
671849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			written = do_write (dev, test_ptr, got, block_size,
672849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					    currently_testing);
673849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (written != got)
674849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				com_err (program_name, errno,
675849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					 _("during test data write, block %lu"),
676849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					 currently_testing + written);
677849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
678849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			buf_used += got;
6794d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			save_ptr += got * block_size;
6804d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_ptr += got * block_size;
681849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			currently_testing += got;
682849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (got != try)
683849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				bb_count += bb_output(currently_testing++);
684849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
685849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		check_for_more:
686849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/*
687849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * If there's room for more blocks to be tested this
688849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * around, and we're not done yet testing the disk, go
689849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * back and get some more blocks.
690849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 */
691849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if ((buf_used != blocks_at_once) &&
692849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			    (currently_testing < last_block))
693849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				continue;
694849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
695849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			flush_bufs();
696849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			save_currently_testing = currently_testing;
697849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
698849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/*
699849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * for each contiguous block that we read into the
700849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * buffer (and wrote test data into afterwards), read
701849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * it back (looping if necessary, to get past newly
702849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * discovered unreadable blocks, of which there should
703849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * be none, but with a hard drive which is unreliable,
704849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * it has happened), and compare with the test data
705849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * that was written; output to the bad block list if
706849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * it doesn't match.
707849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 */
708849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			used2 = 0;
7091c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			save_ptr = save_base;
7101c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			test_ptr = test_base;
7111c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			read_ptr = read_base;
712849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			try = 0;
713849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
714849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			while (1) {
715849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (try == 0) {
716849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					if (used2 >= num_saved)
717849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						break;
718849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					currently_testing = test_record[used2].block;
719849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					try = test_record[used2].num;
720849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					used2++;
721849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
722849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
723849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				got = do_read (dev, read_ptr, try,
724849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					       block_size, currently_testing);
725849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
726849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				/* test the comparison between all the
727849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				   blocks successfully read  */
728849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				for (i = 0; i < got; ++i)
729849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					if (memcmp (test_ptr+i*block_size,
730849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						    read_ptr+i*block_size, block_size))
731849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						bb_count += bb_output(currently_testing + i);
732849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (got < try) {
733849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					bb_count += bb_output(currently_testing + got);
734849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					got++;
735849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
736849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
7371c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				/* write back original data */
7381c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				do_write (dev, save_ptr, got,
7391c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					  block_size, currently_testing);
7401c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				save_ptr += got * block_size;
741849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
742849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				currently_testing += got;
743849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				test_ptr += got * block_size;
744849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				read_ptr += got * block_size;
745849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				try -= got;
746849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			}
747849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
748849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/* empty the buffer so it can be reused */
749849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			num_saved = 0;
750849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			buf_used = 0;
7511c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			save_ptr = save_base;
7521c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			test_ptr = test_base;
753849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			currently_testing = save_currently_testing;
7544d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		}
755849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		num_blocks = 0;
756849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		alarm(0);
757849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (s_flag || v_flag > 1)
7583ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o			fputs(_(done_string), stderr);
7594d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
760849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		flush_bufs();
7614d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	}
7624d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	uncapture_terminate();
763dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	fflush(stderr);
764dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	free(blkbuf);
765d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	free(test_record);
766879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
767879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
768879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
769879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
7703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
7713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
772981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void check_mount(char *device_name)
773981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o{
774981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	errcode_t	retval;
775981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	int		mount_flags;
776981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
777981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	retval = ext2fs_check_if_mounted(device_name, &mount_flags);
778981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (retval) {
779981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		com_err("ext2fs_check_if_mount", retval,
780981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			_("while determining whether %s is mounted."),
781981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			device_name);
782981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		return;
783981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
7842fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o	if (mount_flags & EXT2_MF_MOUNTED) {
7852fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		fprintf(stderr, _("%s is mounted; "), device_name);
7862fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		if (force) {
7872fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			fputs(_("badblocks forced anyway.  "
7882fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o				"Hope /etc/mtab is incorrect.\n"), stderr);
7892fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			return;
7902fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		}
7912fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o	abort_badblocks:
7922fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		fputs(_("it's not safe to run badblocks!\n"), stderr);
7932fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		exit(1);
7942fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o	}
795981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
796f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o	if ((mount_flags & EXT2_MF_BUSY) && !exclusive_ok) {
7972fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		fprintf(stderr, _("%s is apparently in use by the system; "),
7982fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			device_name);
7992fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		if (force)
8002fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			fputs(_("badblocks forced anyway.\n"), stderr);
8012fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		else
8022fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			goto abort_badblocks;
803981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
8042fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o
805981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o}
806981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
807981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
80800e5433eb5e9f70f485968b809fdcf297d7fe7b9Theodore Ts'oint main (int argc, char ** argv)
8093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
810519149fb458b0fa69c10fecd83fae42e838cf01dTheodore Ts'o	int c;
8113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * tmp;
8123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * device_name;
813879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * host_device_name = NULL;
814879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * input_file = NULL;
8153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * output_file = NULL;
816879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	FILE * in = NULL;
817dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int block_size = 1024;
818167af997e3a8fb36cb9fc8db9c40fb62a7f9464bTheodore Ts'o	unsigned long blocks_at_once = 64;
819cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	blk_t last_block, from_count;
820879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int num_passes = 0;
821879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int passes_clean = 0;
8223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int dev;
823879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
82484c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o	unsigned long pattern;
8258820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o	unsigned int (*test_func)(int, unsigned long,
8268820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o				  int, unsigned long,
8278820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o				  unsigned long);
8281c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int open_flag = 0;
8291c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	long sysval;
8303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stdout, NULL);
8323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stderr, NULL);
833d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#ifdef ENABLE_NLS
834d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	setlocale(LC_MESSAGES, "");
83514308a5398984842e808faa3ff2dd6a1c52d90bdTheodore Ts'o	setlocale(LC_CTYPE, "");
836d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
837d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	textdomain(NLS_CAT_NAME);
838d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#endif
8396d40f568cdec7d654691e6eed61cf5a32e918c03Theodore Ts'o	srandom((unsigned int)time(NULL));  /* simple randomness is enough */
8404d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	test_func = test_ro;
8414d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o
8421c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	/* Determine the system page size if possible */
8431c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_SYSCONF
8441c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
8451c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#define _SC_PAGESIZE _SC_PAGE_SIZE
8461c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif
8471c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef _SC_PAGESIZE
8481c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	sysval = sysconf(_SC_PAGESIZE);
8491c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (sysval > 0)
8501c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		sys_page_size = sysval;
8511c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* _SC_PAGESIZE */
8521c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_SYSCONF */
8531c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
8543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (argc && *argv)
8553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		program_name = *argv;
856f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o	while ((c = getopt (argc, argv, "b:fi:o:svwnc:p:h:t:X")) != EOF) {
8573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		switch (c) {
8583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'b':
8593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			block_size = strtoul (optarg, &tmp, 0);
8603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (*tmp || block_size > 4096) {
8613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, 0,
862d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("bad block size - %s"), optarg);
8633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				exit (1);
8643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
8653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
866981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		case 'f':
867981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			force++;
868981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			break;
869879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'i':
870879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			input_file = optarg;
871879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
8723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'o':
8733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			output_file = optarg;
8743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
8753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 's':
8763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			s_flag = 1;
8773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
8783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'v':
87919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			v_flag++;
8803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
8813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'w':
8824d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
8834d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				usage();
8844d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_rw;
8854d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			w_flag = 1;
886879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
887879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'n':
8884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
8894d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				usage();
8904d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_nd;
891879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			w_flag = 2;
892879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
893879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'c':
894879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			blocks_at_once = strtoul (optarg, &tmp, 0);
895879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
896879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
897879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 "bad simultaneous block count - %s", optarg);
898879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
899879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
900879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
901879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'p':
902879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			num_passes = strtoul (optarg, &tmp, 0);
903879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
904879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
905879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				    "bad number of clean passes - %s", optarg);
906879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
907879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
908879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
909879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'h':
910879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			host_device_name = optarg;
9113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
912849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		case 't':
913849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (t_flag + 1 > t_max) {
91448e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o				unsigned long *t_patts_new;
915849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
916849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				t_patts_new = realloc(t_patts, t_max + T_INC);
917849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (!t_patts_new) {
918849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					com_err(program_name, ENOMEM,
919849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						_("can't allocate memory for "
920849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						  "test_pattern - %s"),
921849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						optarg);
922849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					exit(1);
923849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
924849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				t_patts = t_patts_new;
925849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				t_max += T_INC;
926849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			}
92784c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			if (!strcmp(optarg, "r") || !strcmp(optarg,"random")) {
92884c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				t_patts[t_flag++] = ~0;
92984c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			} else {
93084c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				pattern = strtoul(optarg, &tmp, 0);
93184c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				if (*tmp) {
93284c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o					com_err(program_name, 0,
933849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					_("invalid test_pattern: %s\n"),
93484c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o						optarg);
93584c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o					exit(1);
93684c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				}
937544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				if (pattern == (unsigned long) ~0)
93884c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o					pattern = 0xffff;
93984c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				t_patts[t_flag++] = pattern;
940849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			}
941849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			break;
942f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o		case 'X':
943f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o			exclusive_ok++;
944f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o			break;
9453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		default:
946818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o			usage();
9473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
9483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
949849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (!w_flag) {
950849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (t_flag > 1) {
951849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			com_err(program_name, 0,
952849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			_("Maximum of one test_pattern may be specified "
953849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			  "in read-only mode"));
954849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			exit(1);
955849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
956544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		if (t_patts && (t_patts[0] == (unsigned long) ~0)) {
957849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			com_err(program_name, 0,
958849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			_("Random test_pattern is not allowed "
959849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			  "in read-only mode"));
960849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			exit(1);
961849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
962849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
9633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
964818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
9653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	device_name = argv[optind++];
96635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind > argc - 1) {
96735964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		errcode = ext2fs_get_device_size(device_name,
96835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o						 block_size,
969cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o						 &last_block);
97035964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode == EXT2_ET_UNIMPLEMENTED) {
97135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err(program_name, 0,
97235964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("Couldn't determine device size; you "
97335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				  "must specify\nthe size manually\n"));
97435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
97535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
97635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode) {
97735964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err(program_name, errcode,
97835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("while trying to determine device size"));
97935964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
98035964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
98135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	} else {
982cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		last_block = strtoul (argv[optind], &tmp, 0);
98335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (*tmp) {
984f37ab68a26bacf4f5cc7643b8373e40292b7682aTheodore Ts'o			com_err (program_name, 0, _("invalid blocks count - %s"),
98535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				 argv[optind]);
98635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit (1);
98735964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
98835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		optind++;
9893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
99035964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind <= argc-1) {
991f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		from_count = strtoul (argv[optind], &tmp, 0);
992a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		if (*tmp) {
993f37ab68a26bacf4f5cc7643b8373e40292b7682aTheodore Ts'o			com_err (program_name, 0, _("invalid starting block - %s"),
994a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o				 argv[optind]);
995a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o			exit (1);
996a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		}
997f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	} else from_count = 0;
998cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	if (from_count >= last_block) {
999f37ab68a26bacf4f5cc7643b8373e40292b7682aTheodore Ts'o	    com_err (program_name, 0, _("invalid blocks range: %lu-%lu"),
1000544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		     (unsigned long) from_count, (unsigned long) last_block);
1001f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    exit (1);
1002f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
1003981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (w_flag)
1004981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		check_mount(device_name);
1005981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
10061c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	open_flag = w_flag ? O_RDWR : O_RDONLY;
10071c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	dev = open (device_name, open_flag);
10085493a27dc1138d2e30193b80217a0127d247af1eTheodore Ts'o	if (dev == -1) {
1009d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("while trying to open %s"),
10103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 device_name);
10113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
10123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1013879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (host_device_name) {
10141c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		host_dev = open (host_device_name, open_flag);
10155493a27dc1138d2e30193b80217a0127d247af1eTheodore Ts'o		if (host_dev == -1) {
1016d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
1017d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
1018d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 host_device_name);
1019879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			exit (1);
1020879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
1021879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} else
1022879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = dev;
10233e69906495d5898849a6154b0311b5d4a84a27aeTheodore Ts'o	if (input_file) {
1024879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (strcmp (input_file, "-") == 0)
1025879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = stdin;
1026879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		else {
1027879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = fopen (input_file, "r");
1028879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (in == NULL)
1029879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			{
1030d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				com_err (program_name, errno,
1031d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("while trying to open %s"),
1032879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 input_file);
1033879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
1034879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
1035879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
10363e69906495d5898849a6154b0311b5d4a84a27aeTheodore Ts'o	}
10373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (output_file && strcmp (output_file, "-") != 0)
10383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
10393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = fopen (output_file, "w");
10403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (out == NULL)
10413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
1042d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
1043d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
1044879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				 output_file);
10453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			exit (1);
10463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
10473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
10483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
10493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = stdout;
1050879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1051879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_create(&bb_list,0);
1052879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
1053d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
1054bb145b01cf5fd27d9afe03c3262d0e1a326e7ec1Theodore Ts'o			 _("while creating in-memory bad blocks list"));
1055879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
1056879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
1057879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1058879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (in) {
1059879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		for(;;) {
1060a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o			switch(fscanf (in, "%u\n", &next_bad)) {
1061879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case 0:
1062879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					com_err (program_name, 0, "input file - bad format");
1063879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					exit (1);
1064879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case EOF:
1065879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					break;
1066879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				default:
1067879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
1068879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					if (errcode) {
1069bb145b01cf5fd27d9afe03c3262d0e1a326e7ec1Theodore Ts'o						com_err (program_name, errcode, _("while adding to in-memory bad block list"));
1070879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						exit (1);
1071879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					}
1072879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					continue;
1073879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
1074879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
1075879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
1076879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1077879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (in != stdin)
1078879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			fclose (in);
1079879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
1080879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1081879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
1082879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		unsigned int bb_count;
1083879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1084cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		bb_count = test_func(dev, last_block, block_size,
10854d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				     from_count, blocks_at_once);
10864d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (bb_count)
10874d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			passes_clean = 0;
10884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		else
10894d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			++passes_clean;
10904d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
1091879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag)
1092d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf(stderr,
1093d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				_("Pass completed, %u bad blocks found.\n"),
1094d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				bb_count);
1095879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1096879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (passes_clean < num_passes);
1097879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
10983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	close (dev);
10993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (out != stdout)
11003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fclose (out);
1101849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_patts)
1102849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		free(t_patts);
1103879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return 0;
11043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1105d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o
1106