1#include <stdio.h>
2#include <errno.h>
3#include <fcntl.h>
4#include <stdint.h>
5#include <stdlib.h>
6#include <string.h>
7#include <unistd.h>
8
9// for R5:
10//#define pread(fd, buf, count, pos) read_pos(fd, pos, buf, count)
11
12int blockSize = 1024;
13int group = 64;
14int progress = 1;
15int verbose = 0;
16FILE *outputFile = NULL;
17
18int scan_device(const char *dev, off_t startBlock, off_t endBlock)
19{
20	char *buffer = NULL;
21	size_t len = group * blockSize;
22	off_t block = startBlock;
23	off_t at = block * blockSize;
24	int i;
25	int fd;
26
27	buffer = (char *)malloc(len);
28	if (buffer == NULL)
29		return 1;
30
31
32	fd = open(dev, O_RDONLY);
33	if (fd < 0) {
34		perror("open");
35		goto err1;
36	}
37	// Check size
38
39	if (verbose)
40		fprintf(stderr, "Scanning '%s', %d * %d bytes at once\n",
41			dev, group, blockSize);
42
43	if (progress)
44		fprintf(stderr, "\n");
45
46	for (; block <= endBlock; block += group, at += len) {
47		int got;
48		if (progress)
49			fprintf(stderr, "checking block %lld\x1b[1A\n", block);
50		got = pread(fd, buffer, len, at);
51		if (got == len)
52			continue;
53		if (got >= 0) {
54			if (verbose)
55				fprintf(stderr, "block %lld (offset %lld): got %d < %zd\n",
56					block, at, got, len);
57			break;
58		}
59		if (got < 0) {
60			fprintf(stderr, "block %lld: error: %s\n", block, strerror(errno));
61			/*
62			if (errno != EIO && errno != ENXIO) {
63				perror("pread");
64				goto err2;
65			}
66			*/
67		}
68		// try each block separately
69		for (i = 0; i < group; i++) {
70			got = pread(fd, buffer, blockSize, at + blockSize * i);
71			if (got == blockSize)
72				continue;
73			if (got < blockSize) {
74				if (got < 0)
75					fprintf(stderr, "block %lld: error: %s\n", block + i, strerror(errno));
76				else
77					fprintf(stderr, "block %lld: read %d bytes\n", block + i, got);
78				fprintf(outputFile, "%lld\n", block + i);
79				fflush(stdout);
80			}
81		}
82	}
83	close(fd);
84	free(buffer);
85	return 0;
86
87	close(fd);
88err1:
89	free(buffer);
90	return 1;
91}
92
93int usage(int ret)
94{
95	fprintf(stderr, "badblocks [-sv] [-b block-size] [-c block-at-once] "
96		"/dev/disk/... [end-block [start-block]]\n");
97	return ret;
98}
99
100int main(int argc, char **argv)
101{
102	int ch;
103	off_t startBlock = 0LL;
104	off_t endBlock = INT64_MAX;
105	outputFile = stdout;
106	if (argc < 2)
107		return usage(1);
108
109	while ((ch = getopt(argc, argv, "b:c:hsv?")) != -1) {
110		switch (ch) {
111		case 'b':
112			blockSize = atoi(optarg);
113			//fprintf(stderr, "bs %d\n", blockSize);
114			break;
115		case 'c':
116			group = atoi(optarg);
117			//fprintf(stderr, "g %d\n", group);
118			break;
119		case 's':
120			progress = 1;
121			break;
122		case 'v':
123			verbose = 1;
124			break;
125		case 'h':
126		case '?':
127			return usage(0);
128		default:
129			return usage(1);
130		}
131	}
132	argc -= optind;
133	argv += optind;
134
135	if (argc > 2)
136		startBlock = atoll(argv[2]);
137	if (argc > 1)
138		endBlock = atoll(argv[1]);
139
140	return scan_device(argv[0], startBlock, endBlock);
141}
142