badblocks.c revision 818180cdfcff84b9048ecdc5dc86323f0fefba24
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 *
819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * Copyright 1995, 1996, 1997 by Theodore Ts'o
919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This file is based on the minix file system programs fsck and mkfs
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi>
1219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
1319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
1419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
1519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License.
1619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * History:
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 93/05/26	- Creation from e2fsck
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 94/02/27	- Made a separate bad blocks checker
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <errno.h>
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
27a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef HAVE_GETOPT_H
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <getopt.h>
29a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <signal.h>
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdlib.h>
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/ioctl.h>
37f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h>
383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
39a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#if HAVE_LINUX_FS_H
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <linux/fd.h>
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <linux/fs.h>
42a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "et/com_err.h"
45d40259fd552d942903f2fd0b426c75a5c2516017Theodore Ts'o#include "ext2fs/ext2_io.h"
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oconst char * program_name = "badblocks";
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oint v_flag = 0;			/* verbose */
503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oint w_flag = 0;			/* do r/w test */
513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oint s_flag = 0;			/* show progress of test */
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
53818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'ostatic void usage(void)
543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
55f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	fprintf (stderr, "Usage: %s [-b block_size] [-o output_file] [-svw] device blocks_count\n [start_count]\n",
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 program_name);
573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	exit (1);
583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long currently_testing = 0;
6119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long num_blocks = 0;
6219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
6319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic void print_status(void)
6419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
6519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
6619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
6719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
6819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
6919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
7019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic void alarm_intr (int alnum)
7119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
7219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	signal (SIGALRM, alarm_intr);
7319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	alarm(1);
7419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!num_blocks)
7519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return;
7619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
7719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
7819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
7919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
8019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Perform a test of a block; return the number of blocks readable/writeable.
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic long do_test (int dev, char * buffer, int try, unsigned long block_size,
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		     unsigned long current_block)
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag > 1)
9019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		print_status();
9119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Seek to the correct loc. */
9319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
94f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
95f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		com_err (program_name, errno, "during seek");
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Try the read */
983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got = read (dev, buffer, try * block_size);
993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (got < 0)
1003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		got = 0;
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (got & (block_size - 1))
102f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		fprintf (stderr,
103f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 "Weird value (%ld) in do_test: probably bugs\n",
104f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 got);
1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got /= block_size;
1063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return got;
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
109a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'ostatic void flush_bufs (int dev, int sync)
110a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o{
111a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o  if (v_flag
112a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#if !defined (BLKFLSBUF) && !defined (FDFLUSH)
113a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o      && sync
114a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
115a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o      )
116a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o    fprintf (stderr, "Flushing buffers\n");
117a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
118a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o  if (sync && fsync (dev) == -1)
119a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o    com_err (program_name, errno, "during fsync");
120a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
121a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef BLKLSBUF
122a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o  ioctl (dev, BLKFLSBUF, 0);	/* In case this is a HD */
123a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
124a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef FDFLUSH
125a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o  ioctl (dev, FDFLUSH, 0);	/* In case this is floppy */
126a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
127a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o}
128a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
1293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic void test_ro (int dev, unsigned long blocks_count,
130f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     unsigned long block_size, FILE * out,
131f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     unsigned long from_count)
1323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#define TEST_BUFFER_BLOCKS 16
1343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * blkbuf;
1353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int try;
1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blkbuf = malloc (TEST_BUFFER_BLOCKS * block_size);
1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!blkbuf)
1403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
1413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err (program_name, ENOMEM, "while allocating buffers");
1423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
1433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
144a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o	flush_bufs (dev, 0);
145f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (v_flag) {
146f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    fprintf (stderr,
147f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     "Checking for bad blocks in read-only mode\n");
148f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    fprintf (stderr, "From block %lu to %lu\n", from_count, blocks_count);
149f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
1503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	try = TEST_BUFFER_BLOCKS;
151f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	currently_testing = from_count;
1523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = blocks_count;
15319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1) {
1543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fprintf(stderr, "Checking for bad blocks (read-only test): ");
15519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (v_flag <= 1)
15619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			alarm_intr(SIGALRM);
1573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	while (currently_testing < blocks_count)
1593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
1603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (currently_testing + try > blocks_count)
1613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = blocks_count - currently_testing;
1623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		got = do_test (dev, blkbuf, try, block_size, currently_testing);
1633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		currently_testing += got;
1643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (got == try) {
1653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = TEST_BUFFER_BLOCKS;
1663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			continue;
1673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
1683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		else
1693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = 1;
1703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (got == 0)
1713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			fprintf (out, "%lu\n", currently_testing++);
1723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = 0;
1743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	alarm(0);
17519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1)
176f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		fprintf(stderr, "done               \n");
177f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	fflush (stderr);
1783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free (blkbuf);
1793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic void test_rw (int dev, unsigned long blocks_count,
182f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     unsigned long block_size, FILE * out,
183f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     unsigned long from_count)
1843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int i;
1863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * buffer;
1873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
1883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	buffer = malloc (2 * block_size);
1903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!buffer)
1913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
1923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err (program_name, ENOMEM, "while allocating buffers");
1933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
1943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
196a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o	flush_bufs (dev, 0);
197a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
19819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag) {
19919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		fprintf(stderr,
20019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			"Checking for bad blocks in read-write mode\n");
20119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		fprintf(stderr, "From block %lu to %lu\n",
20219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 from_count, blocks_count);
20319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
20419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	for (i = 0; i < sizeof (pattern); i++) {
2053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset (buffer, pattern[i], block_size);
206f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
207f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			fprintf (stderr, "Writing pattern 0x%08x: ",
2083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				 *((int *) buffer));
209f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = blocks_count;
210f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
21119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
212f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
213f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
214f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing < blocks_count;
215f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
2163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
21719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
218f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
219f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
2203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
221f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 "during seek on block %d",
222f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
22319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
22419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
2253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			write (dev, buffer, block_size);
2263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
227f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
228f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
229f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
230f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			fprintf(stderr, "done               \n");
231a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o		flush_bufs (dev, 1);
232f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
233f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			fprintf (stderr, "Reading and comparing: ");
234f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = blocks_count;
235f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
23619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
237f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
238f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
239f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing < blocks_count;
240f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
2413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
24219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
243f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
244f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
2453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
246f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 "during seek on block %d",
247f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
24819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
24919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
2503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (read (dev, buffer + block_size, block_size) < block_size)
251f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o				fprintf (out, "%ld\n", currently_testing);
2523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			else if (memcmp (buffer, buffer + block_size, block_size))
253f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o				fprintf (out, "%ld\n", currently_testing);
2543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
255f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
256f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
257f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
258f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			fprintf(stderr, "done           \n");
259a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o		flush_bufs (dev, 0);
2603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
26300e5433eb5e9f70f485968b809fdcf297d7fe7b9Theodore Ts'oint main (int argc, char ** argv)
2643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
265519149fb458b0fa69c10fecd83fae42e838cf01dTheodore Ts'o	int c;
2663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * tmp;
2673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * device_name;
2683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * output_file = NULL;
2693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	FILE * out;
2703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unsigned long block_size = 1024;
271f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	unsigned long blocks_count, from_count;
2723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int dev;
2733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stdout, NULL);
2753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stderr, NULL);
2763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (argc && *argv)
2773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		program_name = *argv;
2783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	while ((c = getopt (argc, argv, "b:o:svw")) != EOF) {
2793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		switch (c) {
2803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'b':
2813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			block_size = strtoul (optarg, &tmp, 0);
2823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (*tmp || block_size > 4096) {
2833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, 0,
2843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					 "bad block size - %s", optarg);
2853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				exit (1);
2863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
2873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'o':
2893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			output_file = optarg;
2903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 's':
2923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			s_flag = 1;
2933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'v':
29519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			v_flag++;
2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'w':
2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			w_flag = 1;
2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
3003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		default:
301818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o			usage();
3023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
3033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
305818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
3063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	device_name = argv[optind++];
3073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
308818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
3093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blocks_count = strtoul (argv[optind], &tmp, 0);
3103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*tmp)
3113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
3123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err (program_name, 0, "bad blocks count - %s", argv[optind]);
3133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
3143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
315f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (++optind <= argc-1) {
316f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		from_count = strtoul (argv[optind], &tmp, 0);
317f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	} else from_count = 0;
318f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (from_count >= blocks_count) {
319f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    com_err (program_name, 0, "bad blocks range: %lu-%lu",
320f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     from_count, blocks_count);
321f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    exit (1);
322f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
3233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dev == -1)
3253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err (program_name, errno,"while trying to open %s",
3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 device_name);
3283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
3293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (output_file && strcmp (output_file, "-") != 0)
3313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
3323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = fopen (output_file, "w");
3333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (out == NULL)
3343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
3353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			com_err (program_name, errno,"while trying to open %s",
3363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				 device_name);
3373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			exit (1);
3383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
3393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
3413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = stdout;
3423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (w_flag)
343f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		test_rw (dev, blocks_count, block_size, out, from_count);
3443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
345f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		test_ro (dev, blocks_count, block_size, out, from_count);
3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	close (dev);
3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (out != stdout)
3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fclose (out);
34900e5433eb5e9f70f485968b809fdcf297d7fe7b9Theodore Ts'o	exit(0);
3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
351