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>
13efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore 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
27efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore 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
32e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifndef _GNU_SOURCE
331c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#define _GNU_SOURCE /* for O_DIRECT */
34cf5301d7f2c3bbed3d26600335102414cbf0c4baAndreas Dilger#endif
351c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <errno.h>
373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
38a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef HAVE_GETOPT_H
393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <getopt.h>
40373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'o#else
41373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'oextern char *optarg;
42373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'oextern int optind;
43a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <signal.h>
453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdlib.h>
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
49879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include <setjmp.h>
506d40f568cdec7d654691e6eed61cf5a32e918c03Theodore Ts'o#include <time.h>
515267a520bb7887b146f05ffa8726664afbb6c3c2Theodore Ts'o#include <limits.h>
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
53edf261f6f859ed0ff3c16803ab61a78373089ad8Iustin Pop#include <sys/time.h>
543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/ioctl.h>
55f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h>
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "et/com_err.h"
58d40259fd552d942903f2fd0b426c75a5c2516017Theodore Ts'o#include "ext2fs/ext2_io.h"
5954c637d4d29af3e6365779f8b12976abe95a4753Theodore Ts'o#include "ext2fs/ext2_fs.h"
60879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include "ext2fs/ext2fs.h"
61d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#include "nls-enable.h"
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
63e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifndef O_LARGEFILE
64e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#define O_LARGEFILE 0
65e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
66e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
67e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic const char * program_name = "badblocks";
68e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic const char * done_string = N_("done                                                 \n");
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
70e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int v_flag;			/* verbose */
71e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int w_flag;			/* do r/w test: 0=no, 1=yes,
724d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o					 * 2=non-destructive */
73e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int s_flag;			/* show progress of test */
74e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int force;			/* force check of mounted device */
75e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int t_flag;			/* number of test patterns */
76e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int t_max;			/* allocated test patterns */
77e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic unsigned int *t_patts;		/* test patterns */
78e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int use_buffered_io;
79e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int exclusive_ok;
80e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic unsigned int max_bb;		/* Abort test if more than this number of bad blocks has been encountered */
81e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic unsigned int d_flag;		/* delay factor between reads */
82504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyarstatic struct timeval time_start;
831c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
84849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o#define T_INC 32
854d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
86e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic unsigned int sys_page_size = 4096;
871c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
888820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void usage(void)
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
90ad39bcd9e3b0fe98c33825db6dfdf343463e388cBenno Schulenberg	fprintf(stderr, _(
91ad39bcd9e3b0fe98c33825db6dfdf343463e388cBenno Schulenberg"Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnf]\n"
92ad39bcd9e3b0fe98c33825db6dfdf343463e388cBenno Schulenberg"       [-c blocks_at_once] [-d delay_factor_between_reads] [-e max_bad_blocks]\n"
93ad39bcd9e3b0fe98c33825db6dfdf343463e388cBenno Schulenberg"       [-p num_passes] [-t test_pattern [-t test_pattern [...]]]\n"
94ad39bcd9e3b0fe98c33825db6dfdf343463e388cBenno Schulenberg"       device [last_block [first_block]]\n"),
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 program_name);
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	exit (1);
973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
99d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'ostatic void exclusive_usage(void)
100d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o{
101efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	fprintf(stderr,
102efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		_("%s: The -n and -w options are mutually exclusive.\n\n"),
103017a76ee39356ecb13911d666a152f2a4856cbbbTheodore Ts'o		program_name);
104017a76ee39356ecb13911d666a152f2a4856cbbbTheodore Ts'o	exit(1);
105d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o}
106d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o
107acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic blk_t currently_testing = 0;
108acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic blk_t num_blocks = 0;
109e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic blk_t num_read_errors = 0;
110e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic blk_t num_write_errors = 0;
111e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic blk_t num_corruption_errors = 0;
112879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_list bb_list = NULL;
113879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic FILE *out;
114879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic blk_t next_bad = 0;
115879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_iterate bb_iter = NULL;
11619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
117e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallenum error_types { READ_ERROR, WRITE_ERROR, CORRUPTION_ERROR };
118e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
1191c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'ostatic void *allocate_buffer(size_t size)
1201c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o{
1211c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	void	*ret = 0;
122efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1231c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_POSIX_MEMALIGN
1241c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (posix_memalign(&ret, sys_page_size, size) < 0)
1251c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		ret = 0;
1261c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#else
1271c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_MEMALIGN
1281c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	ret = memalign(sys_page_size, size);
1291c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#else
1301c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_VALLOC
1311c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	ret = valloc(size);
1321c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_VALLOC */
133efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o#endif /* HAVE_MEMALIGN */
1341c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_POSIX_MEMALIGN */
1351c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
1361c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (!ret)
1371c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		ret = malloc(size);
1381c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
1391c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	return ret;
1401c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o}
1411c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
142dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o/*
143dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * This routine reports a new bad block.  If the bad block has already
144dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * been seen before, then it returns 0; otherwise it returns 1.
145dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o */
146e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int bb_output (blk_t bad, enum error_types error_type)
147879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
148879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
149879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
150dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	if (ext2fs_badblocks_list_test(bb_list, bad))
151dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		return 0;
152dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o
153acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	fprintf(out, "%lu\n", (unsigned long) bad);
154cc4f98ed2deeaca33244fd77386e7d76917a3d30Theodore Ts'o	fflush(out);
155879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
156879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_add (bb_list, bad);
157879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
158879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "adding to in-memory bad block list");
159879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
160879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
161879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
162879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* kludge:
163efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	   increment the iteration through the bb_list if
164879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   an element was just added before the current iteration
165879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   position.  This should not cause next_bad to change. */
166879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (bb_iter && bad < next_bad)
167879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
168e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
169e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (error_type == READ_ERROR) {
170e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	  num_read_errors++;
171e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	} else if (error_type == WRITE_ERROR) {
172e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	  num_write_errors++;
173e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	} else if (error_type == CORRUPTION_ERROR) {
174e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	  num_corruption_errors++;
175e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
176dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	return 1;
177879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
178879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
179504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyarstatic char *time_diff_format(struct timeval *tv1,
180504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar			      struct timeval *tv2, char *buf)
181504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar{
182504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar        time_t	diff = (tv1->tv_sec - tv2->tv_sec);
183504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	int	hr,min,sec;
184504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar
185504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	sec = diff % 60;
186504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	diff /= 60;
187504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	min = diff % 60;
188504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	hr = diff / 60;
189504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar
190504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	if (hr)
191504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar		sprintf(buf, "%d:%02d:%02d", hr, min, sec);
192504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	else
193504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar		sprintf(buf, "%d:%02d", min, sec);
194504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	return buf;
195504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar}
196504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar
197504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyarstatic float calc_percent(unsigned long current, unsigned long total) {
198504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	float percent = 0.0;
199504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	if (total <= 0)
200504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar		return percent;
201504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	if (current >= total) {
202504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar		percent = 100.0;
203504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	} else {
204504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar		percent=(100.0*(float)current/(float)total);
205504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	}
206504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	return percent;
207504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar}
208504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar
2098820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void print_status(void)
21019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
211504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	struct timeval time_end;
212504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	char diff_buf[32], line_buf[128];
213504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	int len;
214504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar
215504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	gettimeofday(&time_end, 0);
216504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	len = snprintf(line_buf, sizeof(line_buf),
217e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		       _("%6.2f%% done, %s elapsed. "
218e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		         "(%d/%d/%d errors)"),
219504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar		       calc_percent((unsigned long) currently_testing,
220504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar				    (unsigned long) num_blocks),
221e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		       time_diff_format(&time_end, &time_start, diff_buf),
222e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		       num_read_errors,
223e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		       num_write_errors,
224e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		       num_corruption_errors);
22561ef2474c24c80a5bf0e24ba85a7506fd7651a5cTheodore Ts'o#ifdef HAVE_MBSTOWCS
22661ef2474c24c80a5bf0e24ba85a7506fd7651a5cTheodore Ts'o	len = mbstowcs(NULL, line_buf, sizeof(line_buf));
22761ef2474c24c80a5bf0e24ba85a7506fd7651a5cTheodore Ts'o#endif
228504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	fputs(line_buf, stderr);
229504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	memset(line_buf, '\b', len);
230504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	line_buf[len] = 0;
231504f7a2981306032fff7084c0d90beaa45872ee0Manish Katiyar	fputs(line_buf, stderr);
23219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
23319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
23419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
235544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void alarm_intr(int alnum EXT2FS_ATTR((unused)))
23619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
23719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	signal (SIGALRM, alarm_intr);
23819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	alarm(1);
23919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!num_blocks)
24019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return;
241c76564a8784c3c44a6a0516e0fc40f10ec6221edTheodore Ts'o	print_status();
24219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
24319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
244879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void *terminate_addr = NULL;
245879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
246544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void terminate_intr(int signo EXT2FS_ATTR((unused)))
247879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
248c510d6f2684f2e2fa05c0de7bdaee954743546f8Theodore Ts'o	fflush(out);
24983bfa27d3272631ef26f569471845c3755428134Theodore Ts'o	fprintf(stderr, "\n\nInterrupted at block %llu\n",
25083bfa27d3272631ef26f569471845c3755428134Theodore Ts'o		(unsigned long long) currently_testing);
25183bfa27d3272631ef26f569471845c3755428134Theodore Ts'o	fflush(stderr);
252879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (terminate_addr)
253879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		longjmp(terminate_addr,1);
254879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	exit(1);
255879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
256879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
257981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void capture_terminate(jmp_buf term_addr)
258879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
259879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	terminate_addr = term_addr;
260879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGHUP, terminate_intr);
261879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGINT, terminate_intr);
262879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGPIPE, terminate_intr);
263879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGTERM, terminate_intr);
264879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR1, terminate_intr);
265879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR2, terminate_intr);
266879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
267879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
2688820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void uncapture_terminate(void)
2694d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o{
2704d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	terminate_addr = NULL;
2714d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGHUP, SIG_DFL);
2724d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGINT, SIG_DFL);
2734d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGPIPE, SIG_DFL);
2744d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGTERM, SIG_DFL);
2754d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR1, SIG_DFL);
2764d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR2, SIG_DFL);
2774d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o}
2784d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
279e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/* Linux requires that O_DIRECT I/Os be 512-byte sector aligned */
280e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
281e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#define O_DIRECT_SIZE 512
282e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
2831f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'ostatic void set_o_direct(int dev, unsigned char *buffer, size_t size,
284e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			 ext2_loff_t offset)
2851c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o{
2861c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef O_DIRECT
287e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	static int current_O_DIRECT;	/* Current status of O_DIRECT flag */
2881c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int new_flag = O_DIRECT;
2891c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int flag;
290efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
291e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if ((use_buffered_io != 0) ||
292e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    (((unsigned long) buffer & (sys_page_size - 1)) != 0) ||
2931f9a60c251261f8c10d29da4e6202fe530b4684dTheodore Ts'o	    ((size & (sys_page_size - 1)) != 0) ||
294e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    ((offset & (O_DIRECT_SIZE - 1)) != 0))
2951c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		new_flag = 0;
2961c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
2971c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (new_flag != current_O_DIRECT) {
298dc058719dfca9b35baec3208932702d39a502d3aTheodore Ts'o	     /* printf("%s O_DIRECT\n", new_flag ? "Setting" : "Clearing"); */
2991c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		flag = fcntl(dev, F_GETFL);
3001c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		if (flag > 0) {
3011c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			flag = (flag & ~O_DIRECT) | new_flag;
3021c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			fcntl(dev, F_SETFL, flag);
3031c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		}
3041c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		current_O_DIRECT = new_flag;
3051c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	}
3061c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif
3071c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o}
3081c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
3091c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
310e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'ostatic void pattern_fill(unsigned char *buffer, unsigned int pattern,
31184c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			 size_t n)
312849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o{
313544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	i, nb;
31484c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o	unsigned char	bpattern[sizeof(pattern)], *ptr;
315efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
316e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	if (pattern == (unsigned int) ~0) {
317849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		for (ptr = buffer; ptr < buffer + n; ptr++) {
318849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			(*ptr) = random() % (1 << (8 * sizeof(char)));
319849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
320849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (s_flag | v_flag)
321544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(_("Testing with random pattern: "), stderr);
322849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
323849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		bpattern[0] = 0;
324849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		for (i = 0; i < sizeof(bpattern); i++) {
325849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (pattern == 0)
326849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				break;
327849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			bpattern[i] = pattern & 0xFF;
328849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			pattern = pattern >> 8;
329849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
330849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nb = i ? (i-1) : 0;
331849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		for (ptr = buffer, i = nb; ptr < buffer + n; ptr++) {
332544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			*ptr = bpattern[i];
333544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if (i == 0)
334849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				i = nb;
335544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			else
336544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				i--;
337849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
33884c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o		if (s_flag | v_flag) {
339544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(_("Testing with pattern 0x"), stderr);
34084c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			for (i = 0; i <= nb; i++)
34184c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				fprintf(stderr, "%02x", buffer[i]);
342544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(": ", stderr);
34384c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o		}
344849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
345849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o}
346849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
348879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a read of a sequence of blocks; return the number of blocks
349879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially read.
3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
351acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic int do_read (int dev, unsigned char * buffer, int try, int block_size,
352acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o		    blk_t current_block)
3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
355264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	struct timeval tv1, tv2;
356264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop#define NANOSEC (1000000000L)
357264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop#define MILISEC (1000L)
3583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
359e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if 0
360e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	printf("do_read: block %d, try %d\n", current_block, try);
361e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
362e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	set_o_direct(dev, buffer, try * block_size,
363e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		     ((ext2_loff_t) current_block) * block_size);
3641c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
36519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag > 1)
36619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		print_status();
36719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
3683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Seek to the correct loc. */
36919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
370f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
371e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err (program_name, errno, "%s", _("during seek"));
3723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Try the read */
374264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	if (d_flag)
375edf261f6f859ed0ff3c16803ab61a78373089ad8Iustin Pop		gettimeofday(&tv1, NULL);
3763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got = read (dev, buffer, try * block_size);
377264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	if (d_flag)
378edf261f6f859ed0ff3c16803ab61a78373089ad8Iustin Pop		gettimeofday(&tv2, NULL);
3793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (got < 0)
380efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		got = 0;
3819f10a7b31e57288093930fc9565102409eeac6e9Theodore Ts'o	if (got & 511)
382d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Weird value (%ld) in do_read\n"), got);
383879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got /= block_size;
384264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	if (d_flag && got == try) {
385c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o#ifdef HAVE_NANOSLEEP
386264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		struct timespec ts;
387264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		ts.tv_sec = tv2.tv_sec - tv1.tv_sec;
388264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		ts.tv_nsec = (tv2.tv_usec - tv1.tv_usec) * MILISEC;
389264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		if (ts.tv_nsec < 0) {
390264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			ts.tv_nsec += NANOSEC;
391264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			ts.tv_sec -= 1;
392264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		}
393264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		/* increase/decrease the sleep time based on d_flag value */
394264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		ts.tv_sec = ts.tv_sec * d_flag / 100;
395264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		ts.tv_nsec = ts.tv_nsec * d_flag / 100;
396264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		if (ts.tv_nsec > NANOSEC) {
397264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			ts.tv_sec += ts.tv_nsec / NANOSEC;
398264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			ts.tv_nsec %= NANOSEC;
399264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		}
400264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		if (ts.tv_sec || ts.tv_nsec)
401264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			nanosleep(&ts, NULL);
402c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o#else
403c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o#ifdef HAVE_USLEEP
404c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o		struct timeval tv;
405c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o		tv.tv_sec = tv2.tv_sec - tv1.tv_sec;
406c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o		tv.tv_usec = tv2.tv_usec - tv1.tv_usec;
407c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o		tv.tv_sec = tv.tv_sec * d_flag / 100;
408c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o		tv.tv_usec = tv.tv_usec * d_flag / 100;
409c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o		if (tv.tv_usec > 1000000) {
410c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o			tv.tv_sec += tv.tv_usec / 1000000;
411c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o			tv.tv_usec %= 1000000;
412c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o		}
413c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o		if (tv.tv_sec)
414c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o			sleep(tv.tv_sec);
415c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o		if (tv.tv_usec)
416c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o			usleep(tv.tv_usec);
417c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o#endif
418c13ab4fa7aa2ddd3daa66c353ad41422265de9c3Theodore Ts'o#endif
419264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop	}
420879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return got;
421879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
422879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
423879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o/*
424879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a write of a sequence of blocks; return the number of blocks
425879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially written.
426879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o */
427acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic int do_write(int dev, unsigned char * buffer, int try, int block_size,
428acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o		    unsigned long current_block)
429879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
430879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	long got;
431879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
432e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if 0
433e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	printf("do_write: block %lu, try %d\n", current_block, try);
434e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
435e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	set_o_direct(dev, buffer, try * block_size,
436e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		     ((ext2_loff_t) current_block) * block_size);
4371c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
438879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag > 1)
439879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		print_status();
440879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
441879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Seek to the correct loc. */
442879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
443879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
444e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err (program_name, errno, "%s", _("during seek"));
445879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
446879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Try the write */
447879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got = write (dev, buffer, try * block_size);
448879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got < 0)
449efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		got = 0;
450879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got & 511)
451544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fprintf(stderr, "Weird value (%ld) in do_write\n", got);
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got /= block_size;
4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return got;
4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
456879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic int host_dev;
457879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
4584d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'ostatic void flush_bufs(void)
459a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o{
4604d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	errcode_t	retval;
461a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
462e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifdef O_DIRECT
463e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!use_buffered_io)
464e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return;
465e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
4664d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	retval = ext2fs_sync_device(host_dev, 1);
4674d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	if (retval)
468e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err(program_name, retval, "%s",
469e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			_("during ext2fs_sync_device"));
470a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o}
471a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
472acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic unsigned int test_ro (int dev, blk_t last_block,
473f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			     int block_size, blk_t first_block,
474acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			     unsigned int blocks_at_once)
4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
47648e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o	unsigned char * blkbuf;
4773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int try;
478acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	int got;
479879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
480879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
481e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk_t recover_block = ~0;
4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
48383bfa27d3272631ef26f569471845c3755428134Theodore Ts'o	/* set up abend handler */
48483bfa27d3272631ef26f569471845c3755428134Theodore Ts'o	capture_terminate(NULL);
48583bfa27d3272631ef26f569471845c3755428134Theodore Ts'o
486879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
487879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
488e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err(program_name, errcode, "%s",
489e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			_("while beginning bad block list iteration"));
490879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
491879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
492879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
493879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
494f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	} while (next_bad && next_bad < first_block);
495879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
496849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
4971c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		blkbuf = allocate_buffer((blocks_at_once + 1) * block_size);
498849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
4991c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		blkbuf = allocate_buffer(blocks_at_once * block_size);
500849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!blkbuf)
5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
503e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err(program_name, ENOMEM, "%s",
504e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			_("while allocating buffers"));
5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
507f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (v_flag) {
508e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fprintf(stderr, _("Checking blocks %lu to %lu\n"),
509e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			(unsigned long)first_block,
510e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			(unsigned long)last_block - 1);
511f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
512849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
513544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks in read-only mode\n"), stderr);
514849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern_fill(blkbuf + blocks_at_once * block_size,
515849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			     t_patts[0], block_size);
516849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
517849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	flush_bufs();
518879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	try = blocks_at_once;
519f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	currently_testing = first_block;
5208938ce64dca50d7d0f47f45fdc886de4f0939f0bTheodore Ts'o	num_blocks = last_block - 1;
521e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!t_flag && (s_flag || v_flag))
522544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks (read-only test): "), stderr);
523e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (s_flag && v_flag <= 1)
524e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		alarm_intr(SIGALRM);
525cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o	while (currently_testing < last_block)
5263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
527931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop		if (max_bb && bb_count >= max_bb) {
528931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			if (s_flag || v_flag) {
529931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				fputs(_("Too many bad blocks, aborting test\n"), stderr);
530931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			}
531931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			break;
532931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop		}
533879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (next_bad) {
534879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (currently_testing == next_bad) {
535879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
536879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
537879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				currently_testing++;
538879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				continue;
539879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
540879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			else if (currently_testing + try > next_bad)
541879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				try = next_bad - currently_testing;
542879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
543cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		if (currently_testing + try > last_block)
544cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o			try = last_block - currently_testing;
545879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = do_read (dev, blkbuf, try, block_size, currently_testing);
546849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (t_flag) {
547849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/* test the comparison between all the
548849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			   blocks successfully read  */
549849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			int i;
550849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			for (i = 0; i < got; ++i)
551849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (memcmp (blkbuf+i*block_size,
552849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					    blkbuf+blocks_at_once*block_size,
553849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					    block_size))
554e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
555849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
556e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (got == 0 && try == 1)
557e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			bb_count += bb_output(currently_testing++, READ_ERROR);
5583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		currently_testing += got;
559e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (got != try) {
56065f0aab98b20b5994a726ab90d355248bcddfffdJP Abgrall			try = 1;
561e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (recover_block == ~0U)
562e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				recover_block = currently_testing - got +
563e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					blocks_at_once;
564e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			continue;
565e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		} else if (currently_testing == recover_block) {
566e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			try = blocks_at_once;
567e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			recover_block = ~0;
568879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
5693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = 0;
5713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	alarm(0);
572849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (s_flag || v_flag)
5733ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o		fputs(_(done_string), stderr);
574879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
575f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	fflush (stderr);
5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free (blkbuf);
577879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
578879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
579879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
58083bfa27d3272631ef26f569471845c3755428134Theodore Ts'o	uncapture_terminate();
58183bfa27d3272631ef26f569471845c3755428134Theodore Ts'o
582879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
5833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
585acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic unsigned int test_rw (int dev, blk_t last_block,
586f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			     int block_size, blk_t first_block,
587acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			     unsigned int blocks_at_once)
5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5891c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	unsigned char *buffer, *read_buffer;
590e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	const unsigned int patterns[] = {0xaa, 0x55, 0xff, 0x00};
591e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	const unsigned int *pattern;
5921c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	int i, try, got, nr_pattern, pat_idx;
593879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
594e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk_t recover_block = ~0;
5953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
59683bfa27d3272631ef26f569471845c3755428134Theodore Ts'o	/* set up abend handler */
59783bfa27d3272631ef26f569471845c3755428134Theodore Ts'o	capture_terminate(NULL);
59883bfa27d3272631ef26f569471845c3755428134Theodore Ts'o
5991c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	buffer = allocate_buffer(2 * blocks_at_once * block_size);
6001c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	read_buffer = buffer + blocks_at_once * block_size;
601efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
6021c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (!buffer) {
603e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err(program_name, ENOMEM, "%s",
604e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			_("while allocating buffers"));
6053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
6063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6084d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	flush_bufs();
609a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
61019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag) {
611efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		fputs(_("Checking for bad blocks in read-write mode\n"),
612544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		      stderr);
613d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("From block %lu to %lu\n"),
614efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			(unsigned long) first_block,
615f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			(unsigned long) last_block - 1);
61619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
617849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
618849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = t_patts;
619849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = t_flag;
620849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
621849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = patterns;
622849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
623849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
624849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
6251c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		pattern_fill(buffer, pattern[pat_idx],
6261c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			     blocks_at_once * block_size);
6278938ce64dca50d7d0f47f45fdc886de4f0939f0bTheodore Ts'o		num_blocks = last_block - 1;
628f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		currently_testing = first_block;
62919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
630f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
6311c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
6321c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		try = blocks_at_once;
6331c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		while (currently_testing < last_block) {
634931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			if (max_bb && bb_count >= max_bb) {
635931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				if (s_flag || v_flag) {
636931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop					fputs(_("Too many bad blocks, aborting test\n"), stderr);
637931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				}
638931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				break;
639931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			}
6401c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (currently_testing + try > last_block)
6411c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = last_block - currently_testing;
6421c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			got = do_write(dev, buffer, try, block_size,
6431c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					currently_testing);
64419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
64519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
6461c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
647e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (got == 0 && try == 1)
648e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				bb_count += bb_output(currently_testing++, WRITE_ERROR);
6491c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			currently_testing += got;
650e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (got != try) {
65165f0aab98b20b5994a726ab90d355248bcddfffdJP Abgrall				try = 1;
652e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				if (recover_block == ~0U)
653e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					recover_block = currently_testing -
654e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						got + blocks_at_once;
655e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				continue;
656e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			} else if (currently_testing == recover_block) {
657e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				try = blocks_at_once;
658e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				recover_block = ~0;
6591c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			}
6603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
661efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
662f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
663f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
664f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
6653ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o			fputs(_(done_string), stderr);
6664d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		flush_bufs();
667f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
668544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			fputs(_("Reading and comparing: "), stderr);
669cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		num_blocks = last_block;
670f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		currently_testing = first_block;
67119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
672f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
6731c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
6741c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		try = blocks_at_once;
6751c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		while (currently_testing < last_block) {
676931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			if (max_bb && bb_count >= max_bb) {
677931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				if (s_flag || v_flag) {
678931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop					fputs(_("Too many bad blocks, aborting test\n"), stderr);
679931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				}
680931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				break;
681931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			}
6821c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			if (currently_testing + try > last_block)
6831c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				try = last_block - currently_testing;
6841c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			got = do_read (dev, read_buffer, try, block_size,
6851c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				       currently_testing);
686e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (got == 0 && try == 1)
687e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				bb_count += bb_output(currently_testing++, READ_ERROR);
688e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			currently_testing += got;
689e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (got != try) {
690e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				try = 1;
691e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				if (recover_block == ~0U)
692e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					recover_block = currently_testing -
693e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						got + blocks_at_once;
6941c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				continue;
695e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			} else if (currently_testing == recover_block) {
696e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				try = blocks_at_once;
697e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				recover_block = ~0U;
6981c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			}
6991c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			for (i=0; i < got; i++) {
7001c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				if (memcmp(read_buffer + i * block_size,
7011c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					   buffer + i * block_size,
7021c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					   block_size))
703e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					bb_count += bb_output(currently_testing+i, CORRUPTION_ERROR);
704468d82f430dfdf270b738e14345b879560c2cd9eTheodore Ts'o			}
70519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
70619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
7073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
708efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
709f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
710f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
711f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
7123ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o			fputs(_(done_string), stderr);
7134d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o		flush_bufs();
7143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
715849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	uncapture_terminate();
7166d40f568cdec7d654691e6eed61cf5a32e918c03Theodore Ts'o	free(buffer);
717879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
718879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
719879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
720d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'ostruct saved_blk_record {
721d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	blk_t	block;
722d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	int	num;
723d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o};
724d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
725acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'ostatic unsigned int test_nd (int dev, blk_t last_block,
726f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o			     int block_size, blk_t first_block,
727acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o			     unsigned int blocks_at_once)
728879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
72948e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o	unsigned char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
7301c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	unsigned char *test_base, *save_base, *read_base;
731dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int try, i;
732e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	const unsigned int patterns[] = { ~0 };
733e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	const unsigned int *pattern;
734849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	int nr_pattern, pat_idx;
735acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	int got, used2, written;
736acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	blk_t save_currently_testing;
737d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	struct saved_blk_record *test_record;
738a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	/* This is static to prevent being clobbered by the longjmp */
739a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	static int num_saved;
740879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	jmp_buf terminate_env;
741879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
742544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned long buf_used;
743544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	static unsigned int bb_count;
744e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned int granularity = blocks_at_once;
745e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk_t recover_block = ~0U;
746879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
747544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	bb_count = 0;
748879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
749879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
750e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err(program_name, errcode, "%s",
751e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			_("while beginning bad block list iteration"));
752879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
753879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
754879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
755879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
756f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	} while (next_bad && next_bad < first_block);
757879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
7581c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	blkbuf = allocate_buffer(3 * blocks_at_once * block_size);
759e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	test_record = malloc(blocks_at_once * sizeof(struct saved_blk_record));
760d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	if (!blkbuf || !test_record) {
761e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err(program_name, ENOMEM, "%s",
762e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			_("while allocating buffers"));
763879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
764879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
7651c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o
7661c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	save_base = blkbuf;
7671c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	test_base = blkbuf + (blocks_at_once * block_size);
7681c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	read_base = blkbuf + (2 * blocks_at_once * block_size);
769efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
770d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	num_saved = 0;
771879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
7724d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o	flush_bufs();
773879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
774544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	    fputs(_("Checking for bad blocks in non-destructive read-write mode\n"), stderr);
775efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	    fprintf (stderr, _("From block %lu to %lu\n"),
776f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		     (unsigned long) first_block,
777f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		     (unsigned long) last_block - 1);
778879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
779879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (s_flag || v_flag > 1) {
780544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("Checking for bad blocks (non-destructive read-write test)\n"), stderr);
781879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
7824d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	if (setjmp(terminate_env)) {
7834d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
7844d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * Abnormal termination by a signal is handled here.
7854d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
786a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		signal (SIGALRM, SIG_IGN);
787544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		fputs(_("\nInterrupt caught, cleaning up\n"), stderr);
788879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
7891c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		save_ptr = save_base;
790d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		for (i=0; i < num_saved; i++) {
791d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			do_write(dev, save_ptr, test_record[i].num,
792d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				 block_size, test_record[i].block);
793d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			save_ptr += test_record[i].num * block_size;
794d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		}
795879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fflush (out);
796dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		exit(1);
797879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
798efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
7994d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	/* set up abend handler */
8004d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	capture_terminate(terminate_env);
8014d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
802849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (t_flag) {
803849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = t_patts;
804849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = t_flag;
805849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	} else {
806849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		pattern = patterns;
807849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
808849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
809849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
8101c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		pattern_fill(test_base, pattern[pat_idx],
8111c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			     blocks_at_once * block_size);
8124d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
813849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		buf_used = 0;
814849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		bb_count = 0;
8151c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		save_ptr = save_base;
8161c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		test_ptr = test_base;
817f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		currently_testing = first_block;
8188938ce64dca50d7d0f47f45fdc886de4f0939f0bTheodore Ts'o		num_blocks = last_block - 1;
819849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (s_flag && v_flag <= 1)
820849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			alarm_intr(SIGALRM);
8214d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
822849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		while (currently_testing < last_block) {
823931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			if (max_bb && bb_count >= max_bb) {
824931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				if (s_flag || v_flag) {
825931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop					fputs(_("Too many bad blocks, aborting test\n"), stderr);
826931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				}
827931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop				break;
828931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			}
829e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			got = try = granularity - buf_used;
830849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (next_bad) {
831849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (currently_testing == next_bad) {
832849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					/* fprintf (out, "%lu\n", nextbad); */
833849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
834849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					currently_testing++;
835849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					goto check_for_more;
836849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
837849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				else if (currently_testing + try > next_bad)
838849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					try = next_bad - currently_testing;
839d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			}
840849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (currently_testing + try > last_block)
841849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				try = last_block - currently_testing;
842849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			got = do_read (dev, save_ptr, try, block_size,
843849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				       currently_testing);
844849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (got == 0) {
845e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				if (recover_block == ~0U)
846e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					recover_block = currently_testing +
847e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						blocks_at_once;
848e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				if (granularity != 1) {
849e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					granularity = 1;
850e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					continue;
851e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				}
852849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				/* First block must have been bad. */
853e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				bb_count += bb_output(currently_testing++, READ_ERROR);
854849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				goto check_for_more;
8554d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			}
8564d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
857849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/*
858849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * Note the fact that we've saved this much data
859849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * *before* we overwrite it with test data
860849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 */
861849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			test_record[num_saved].block = currently_testing;
862849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			test_record[num_saved].num = got;
863849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			num_saved++;
864849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
865849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/* Write the test data */
866849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			written = do_write (dev, test_ptr, got, block_size,
867849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					    currently_testing);
868849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (written != got)
869849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				com_err (program_name, errno,
870849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					 _("during test data write, block %lu"),
871efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o					 (unsigned long) currently_testing +
872acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o					 written);
873849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
874849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			buf_used += got;
8754d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			save_ptr += got * block_size;
8764d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_ptr += got * block_size;
877849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			currently_testing += got;
878e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (got != try) {
879e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				try = 1;
880e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				if (recover_block == ~0U)
881e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					recover_block = currently_testing -
882e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						got + blocks_at_once;
883e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				continue;
884e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			}
885849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
886849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		check_for_more:
887849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/*
888849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * If there's room for more blocks to be tested this
889849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * around, and we're not done yet testing the disk, go
890849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * back and get some more blocks.
891849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 */
892e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if ((buf_used != granularity) &&
893849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			    (currently_testing < last_block))
894849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				continue;
895849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
896e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (currently_testing >= recover_block) {
897e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				granularity = blocks_at_once;
898e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				recover_block = ~0;
899e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			}
900e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
901849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			flush_bufs();
902849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			save_currently_testing = currently_testing;
903849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
904849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/*
905849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * for each contiguous block that we read into the
906849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * buffer (and wrote test data into afterwards), read
907849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * it back (looping if necessary, to get past newly
908849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * discovered unreadable blocks, of which there should
909849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * be none, but with a hard drive which is unreliable,
910849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * it has happened), and compare with the test data
911849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * that was written; output to the bad block list if
912849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 * it doesn't match.
913849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			 */
914849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			used2 = 0;
9151c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			save_ptr = save_base;
9161c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			test_ptr = test_base;
9171c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			read_ptr = read_base;
918849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			try = 0;
919849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
920849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			while (1) {
921849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (try == 0) {
922849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					if (used2 >= num_saved)
923849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						break;
924849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					currently_testing = test_record[used2].block;
925849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					try = test_record[used2].num;
926849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					used2++;
927849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
928efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
929849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				got = do_read (dev, read_ptr, try,
930849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					       block_size, currently_testing);
931849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
932849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				/* test the comparison between all the
933849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				   blocks successfully read  */
934849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				for (i = 0; i < got; ++i)
935849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					if (memcmp (test_ptr+i*block_size,
936849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						    read_ptr+i*block_size, block_size))
937e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
938849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (got < try) {
939e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					bb_count += bb_output(currently_testing + got, READ_ERROR);
940849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					got++;
941849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
942efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
9431c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				/* write back original data */
9441c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				do_write (dev, save_ptr, got,
9451c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o					  block_size, currently_testing);
9461c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o				save_ptr += got * block_size;
947849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
948849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				currently_testing += got;
949849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				test_ptr += got * block_size;
950849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				read_ptr += got * block_size;
951849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				try -= got;
952849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			}
953849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
954849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			/* empty the buffer so it can be reused */
955849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			num_saved = 0;
956849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			buf_used = 0;
9571c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			save_ptr = save_base;
9581c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o			test_ptr = test_base;
959849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			currently_testing = save_currently_testing;
9604d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		}
961849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		num_blocks = 0;
962849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		alarm(0);
963849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (s_flag || v_flag > 1)
9643ef681c5dbaccd2d905026b964c580f2ce3466caTheodore Ts'o			fputs(_(done_string), stderr);
9654d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
966849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		flush_bufs();
9674d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	}
9684d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	uncapture_terminate();
969dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	fflush(stderr);
970dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	free(blkbuf);
971d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	free(test_record);
972879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
973879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
974879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
975879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
9763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
9773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
978981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void check_mount(char *device_name)
979981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o{
980981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	errcode_t	retval;
981981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	int		mount_flags;
982981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
983981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	retval = ext2fs_check_if_mounted(device_name, &mount_flags);
984981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (retval) {
985981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		com_err("ext2fs_check_if_mount", retval,
986981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			_("while determining whether %s is mounted."),
987981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			device_name);
988981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		return;
989981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
9902fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o	if (mount_flags & EXT2_MF_MOUNTED) {
9912fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		fprintf(stderr, _("%s is mounted; "), device_name);
9922fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		if (force) {
9932fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			fputs(_("badblocks forced anyway.  "
9942fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o				"Hope /etc/mtab is incorrect.\n"), stderr);
9952fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			return;
9962fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		}
9972fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o	abort_badblocks:
9982fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		fputs(_("it's not safe to run badblocks!\n"), stderr);
9992fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		exit(1);
10002fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o	}
1001981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
1002f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o	if ((mount_flags & EXT2_MF_BUSY) && !exclusive_ok) {
10032fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		fprintf(stderr, _("%s is apparently in use by the system; "),
10042fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			device_name);
10052fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		if (force)
10062fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			fputs(_("badblocks forced anyway.\n"), stderr);
10072fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o		else
10082fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o			goto abort_badblocks;
1009981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
10102fa8f37ffff4687228d9f204062f2d27b0e5b919Theodore Ts'o
1011981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o}
1012981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
1013d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o/*
1014d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o * This function will convert a string to an unsigned long, printing
1015d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o * an error message if it fails, and returning success or failure in err.
1016d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o */
1017d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'ostatic unsigned int parse_uint(const char *str, const char *descr)
1018d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o{
1019d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	char		*tmp;
1020d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	unsigned long	ret;
1021efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1022eb594251b6d1a06d2acbb281b3816c017d7066ebIustin Pop	errno = 0;
1023d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	ret = strtoul(str, &tmp, 0);
1024d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	if (*tmp || errno || (ret > UINT_MAX) ||
1025d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	    (ret == ULONG_MAX && errno == ERANGE)) {
1026d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o		com_err (program_name, 0, _("invalid %s - %s"), descr, str);
1027d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o		exit (1);
1028d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	}
1029d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o	return ret;
1030d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o}
1031981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
103200e5433eb5e9f70f485968b809fdcf297d7fe7b9Theodore Ts'oint main (int argc, char ** argv)
10333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1034519149fb458b0fa69c10fecd83fae42e838cf01dTheodore Ts'o	int c;
10353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * device_name;
1036879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * host_device_name = NULL;
1037879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * input_file = NULL;
10383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * output_file = NULL;
1039879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	FILE * in = NULL;
1040dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int block_size = 1024;
1041acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	unsigned int blocks_at_once = 64;
1042e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t last_block, first_block;
1043879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int num_passes = 0;
1044879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int passes_clean = 0;
10453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int dev;
1046879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
1047e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o	unsigned int pattern;
1048acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o	unsigned int (*test_func)(int, blk_t,
1049acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o				  int, blk_t,
1050acd77415a9c0d6279f4effee2a5e59ededc7b2d2Theodore Ts'o				  unsigned int);
105122301afb01f3059a2b1baf68abff26aaf6db7c9eTheodore Ts'o	int open_flag;
10521c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	long sysval;
1053e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t inblk;
10543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
10553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stdout, NULL);
10563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stderr, NULL);
1057d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#ifdef ENABLE_NLS
1058d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	setlocale(LC_MESSAGES, "");
105914308a5398984842e808faa3ff2dd6a1c52d90bdTheodore Ts'o	setlocale(LC_CTYPE, "");
1060d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1061d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	textdomain(NLS_CAT_NAME);
1062e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	set_com_err_gettext(gettext);
1063d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#endif
10646d40f568cdec7d654691e6eed61cf5a32e918c03Theodore Ts'o	srandom((unsigned int)time(NULL));  /* simple randomness is enough */
10654d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	test_func = test_ro;
10664d4045475f80ad2901c468815976d2beffd0cb59Theodore Ts'o
10671c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	/* Determine the system page size if possible */
10681c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef HAVE_SYSCONF
10691c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
10701c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#define _SC_PAGESIZE _SC_PAGE_SIZE
10711c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif
10721c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#ifdef _SC_PAGESIZE
10731c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	sysval = sysconf(_SC_PAGESIZE);
10741c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	if (sysval > 0)
10751c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		sys_page_size = sysval;
10761c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* _SC_PAGESIZE */
10771c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o#endif /* HAVE_SYSCONF */
1078efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
10793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (argc && *argv)
10803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		program_name = *argv;
1081e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	while ((c = getopt (argc, argv, "b:d:e:fi:o:svwnc:p:h:t:BX")) != EOF) {
10823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		switch (c) {
10833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'b':
1084d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o			block_size = parse_uint(optarg, "block size");
10853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
1086981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		case 'f':
1087981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			force++;
1088981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			break;
1089879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'i':
1090879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			input_file = optarg;
1091879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
10923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'o':
10933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			output_file = optarg;
10943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
10953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 's':
10963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			s_flag = 1;
10973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
10983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'v':
109919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			v_flag++;
11003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
11013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'w':
11024d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
1103d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o				exclusive_usage();
11044d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_rw;
11054d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			w_flag = 1;
1106879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
1107879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'n':
11084d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
1109d8b5f777438445407f7cd408bd5fe301e4687271Theodore Ts'o				exclusive_usage();
11104d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_nd;
1111879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			w_flag = 2;
1112879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
1113879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'c':
1114d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o			blocks_at_once = parse_uint(optarg, "blocks at once");
1115879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
1116931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop		case 'e':
1117931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			max_bb = parse_uint(optarg, "max bad block count");
1118931b0289eee5d83bff7e80c7420bda0a5bb078daIustin Pop			break;
1119264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop		case 'd':
1120264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			d_flag = parse_uint(optarg, "read delay factor");
1121264f64a5a8bb7225ab8513de6f1c6ac9e7448790Iustin Pop			break;
1122879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'p':
1123efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			num_passes = parse_uint(optarg,
1124d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o						"number of clean passes");
1125879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
1126879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'h':
1127879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			host_device_name = optarg;
11283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
1129849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		case 't':
1130849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			if (t_flag + 1 > t_max) {
1131e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o				unsigned int *t_patts_new;
1132849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o
1133efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o				t_patts_new = realloc(t_patts, sizeof(int) *
113469d813520cf14f5700c38c82b5c147aa3756bbd9Theodore Ts'o						      (t_max + T_INC));
1135849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				if (!t_patts_new) {
1136849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					com_err(program_name, ENOMEM,
1137849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						_("can't allocate memory for "
1138849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						  "test_pattern - %s"),
1139849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o						optarg);
1140849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o					exit(1);
1141849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				}
1142849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				t_patts = t_patts_new;
1143849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o				t_max += T_INC;
1144849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			}
114584c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			if (!strcmp(optarg, "r") || !strcmp(optarg,"random")) {
114684c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				t_patts[t_flag++] = ~0;
114784c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o			} else {
1148d4be9fad6eb65752a623521f9b66b5c30831a3a1Theodore Ts'o				pattern = parse_uint(optarg, "test pattern");
1149e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o				if (pattern == (unsigned int) ~0)
115084c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o					pattern = 0xffff;
115184c054577fcc08cee6683fb1c8905711c5b985f3Theodore Ts'o				t_patts[t_flag++] = pattern;
1152849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			}
1153849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			break;
1154e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		case 'B':
1155e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			use_buffered_io = 1;
1156e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			break;
1157f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o		case 'X':
1158f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o			exclusive_ok++;
1159f63978aff759325b542de7134ab659c79dc47496Theodore Ts'o			break;
11603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		default:
1161818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o			usage();
11623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
11633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1164849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	if (!w_flag) {
1165849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		if (t_flag > 1) {
1166e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			com_err(program_name, 0, "%s",
1167e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				_("Maximum of one test_pattern may be "
1168e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				  "specified in read-only mode"));
1169849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			exit(1);
1170849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
1171e9860ae966c71bca8af8013c7d3148b171c8491fTheodore Ts'o		if (t_patts && (t_patts[0] == (unsigned int) ~0)) {
1172e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			com_err(program_name, 0, "%s",
1173e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				_("Random test_pattern is not allowed "
1174e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				  "in read-only mode"));
1175849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o			exit(1);
1176849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o		}
1177849b6bc8ec0d4959913ea6f412ac5b6e9939e9ffTheodore Ts'o	}
11783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
1179818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
11803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	device_name = argv[optind++];
118135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind > argc - 1) {
1182e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		errcode = ext2fs_get_device_size2(device_name,
118335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o						 block_size,
1184cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o						 &last_block);
118535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode == EXT2_ET_UNIMPLEMENTED) {
1186e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			com_err(program_name, 0, "%s",
118735964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("Couldn't determine device size; you "
118835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				  "must specify\nthe size manually\n"));
118935964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
119035964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
119135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode) {
1192e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			com_err(program_name, errcode, "%s",
119335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("while trying to determine device size"));
119435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
119535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
119635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	} else {
11975267a520bb7887b146f05ffa8726664afbb6c3c2Theodore Ts'o		errno = 0;
1198f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		last_block = parse_uint(argv[optind], _("last block"));
11995267a520bb7887b146f05ffa8726664afbb6c3c2Theodore Ts'o		last_block++;
120035964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		optind++;
12013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
120235964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind <= argc-1) {
12035267a520bb7887b146f05ffa8726664afbb6c3c2Theodore Ts'o		errno = 0;
1204f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o		first_block = parse_uint(argv[optind], _("first block"));
1205f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	} else first_block = 0;
1206f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o	if (first_block >= last_block) {
1207e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    com_err (program_name, 0, _("invalid starting block (%llu): must be less than %llu"),
1208e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		     first_block, last_block);
1209f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    exit (1);
1210f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
1211e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/* ext2 badblocks file can't handle large values */
1212e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (last_block >> 32) {
1213e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err(program_name, EOVERFLOW,
1214e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			_("invalid end block (%llu): must be 32-bit value"),
1215e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			last_block);
1216e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		exit(1);
1217e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
1218981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (w_flag)
1219981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		check_mount(device_name);
1220efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
122142e572b5b6aa71a567219265686c90eabff3fc31Theodore Ts'o	gettimeofday(&time_start, 0);
122222301afb01f3059a2b1baf68abff26aaf6db7c9eTheodore Ts'o	open_flag = O_LARGEFILE | (w_flag ? O_RDWR : O_RDONLY);
12231c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o	dev = open (device_name, open_flag);
12245493a27dc1138d2e30193b80217a0127d247af1eTheodore Ts'o	if (dev == -1) {
1225d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("while trying to open %s"),
12263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 device_name);
12273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
12283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1229879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (host_device_name) {
12301c29b0979a7100a4fd254c006997a08b3bdd72dfTheodore Ts'o		host_dev = open (host_device_name, open_flag);
12315493a27dc1138d2e30193b80217a0127d247af1eTheodore Ts'o		if (host_dev == -1) {
1232d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
1233d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
1234d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 host_device_name);
1235879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			exit (1);
1236879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
1237879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} else
1238879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = dev;
12393e69906495d5898849a6154b0311b5d4a84a27aeTheodore Ts'o	if (input_file) {
1240879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (strcmp (input_file, "-") == 0)
1241879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = stdin;
1242879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		else {
1243879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = fopen (input_file, "r");
1244879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (in == NULL)
1245879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			{
1246d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				com_err (program_name, errno,
1247d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("while trying to open %s"),
1248879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 input_file);
1249879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
1250879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
1251879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
12523e69906495d5898849a6154b0311b5d4a84a27aeTheodore Ts'o	}
12533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (output_file && strcmp (output_file, "-") != 0)
12543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
12553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = fopen (output_file, "w");
12563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (out == NULL)
12573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
1258d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
1259d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
1260879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				 output_file);
12613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			exit (1);
12623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
12633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
12643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
12653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = stdout;
1266879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1267879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_create(&bb_list,0);
1268879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
1269e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err(program_name, errcode, "%s",
1270e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			_("while creating in-memory bad blocks list"));
1271879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
1272879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
1273879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1274879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (in) {
1275879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		for(;;) {
1276e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			switch (fscanf(in, "%llu\n", &inblk)) {
1277879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case 0:
1278e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					com_err(program_name, 0, "%s",
1279e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						_("input file - bad format"));
1280879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					exit (1);
1281879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case EOF:
1282879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					break;
1283879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				default:
1284e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					if (inblk >> 32) {
1285e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						com_err(program_name,
1286e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall							EOVERFLOW, "%s",
1287e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						_("while adding to in-memory "
1288e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						  "bad block list"));
1289e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						exit(1);
1290e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					}
1291e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					next_bad = inblk;
1292879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
1293879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					if (errcode) {
1294e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						com_err(program_name, errcode,
1295e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall							"%s",
1296e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						_("while adding to in-memory "
1297e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						  "bad block list"));
1298879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						exit (1);
1299879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					}
1300879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					continue;
1301879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
1302879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
1303879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
1304879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1305879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (in != stdin)
1306879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			fclose (in);
1307879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
1308879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1309879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
1310879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		unsigned int bb_count;
1311879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1312cd130a0887b5e5e9436533bbcda4c17ec5202788Theodore Ts'o		bb_count = test_func(dev, last_block, block_size,
1313f56f32b0a505e34712c8b8fb908dffb616743726Theodore Ts'o				     first_block, blocks_at_once);
13144d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (bb_count)
13154d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			passes_clean = 0;
13164d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		else
13174d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			++passes_clean;
1318efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1319879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag)
1320d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf(stderr,
1321e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				_("Pass completed, %u bad blocks found. (%d/%d/%d errors)\n"),
1322e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				bb_count, num_read_errors, num_write_errors, num_corruption_errors);
1323879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1324879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (passes_clean < num_passes);
1325879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
13263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	close (dev);
13273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (out != stdout)
13283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fclose (out);
132945e338f5332a54295893dba2e32cc093d1316f60Jim Meyering	free(t_patts);
1330879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return 0;
13313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1332