xref: /haiku/src/bin/badblocks.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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 
12 int blockSize = 1024;
13 int group = 64;
14 int progress = 1;
15 int verbose = 0;
16 FILE *outputFile = NULL;
17 
18 int 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);
88 err1:
89 	free(buffer);
90 	return 1;
91 }
92 
93 int 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 
100 int 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