#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int blockSize = 1024;
int group = 64;
int progress = 1;
int verbose = 0;
FILE *outputFile = NULL;
int scan_device(const char *dev, off_t startBlock, off_t endBlock)
{
char *buffer = NULL;
size_t len = group * blockSize;
off_t block = startBlock;
off_t at = block * blockSize;
int i;
int fd;
buffer = (char *)malloc(len);
if (buffer == NULL)
return 1;
fd = open(dev, O_RDONLY);
if (fd < 0) {
perror("open");
goto err1;
}
if (verbose)
fprintf(stderr, "Scanning '%s', %d * %d bytes at once\n",
dev, group, blockSize);
if (progress)
fprintf(stderr, "\n");
for (; block <= endBlock; block += group, at += len) {
int got;
if (progress)
fprintf(stderr, "checking block %lld\x1b[1A\n", block);
got = pread(fd, buffer, len, at);
if (got == len)
continue;
if (got >= 0) {
if (verbose)
fprintf(stderr, "block %lld (offset %lld): got %d < %zd\n",
block, at, got, len);
break;
}
if (got < 0) {
fprintf(stderr, "block %lld: error: %s\n", block, strerror(errno));
if (errno != EIO && errno != ENXIO) {
perror("pread");
goto err2;
}
*/
}
for (i = 0; i < group; i++) {
got = pread(fd, buffer, blockSize, at + blockSize * i);
if (got == blockSize)
continue;
if (got < blockSize) {
if (got < 0)
fprintf(stderr, "block %lld: error: %s\n", block + i, strerror(errno));
else
fprintf(stderr, "block %lld: read %d bytes\n", block + i, got);
fprintf(outputFile, "%lld\n", block + i);
fflush(stdout);
}
}
}
close(fd);
free(buffer);
return 0;
close(fd);
err1:
free(buffer);
return 1;
}
int usage(int ret)
{
fprintf(stderr, "badblocks [-sv] [-b block-size] [-c block-at-once] "
"/dev/disk/... [end-block [start-block]]\n");
return ret;
}
int main(int argc, char **argv)
{
int ch;
off_t startBlock = 0LL;
off_t endBlock = INT64_MAX;
outputFile = stdout;
if (argc < 2)
return usage(1);
while ((ch = getopt(argc, argv, "b:c:hsv?")) != -1) {
switch (ch) {
case 'b':
blockSize = atoi(optarg);
break;
case 'c':
group = atoi(optarg);
break;
case 's':
progress = 1;
break;
case 'v':
verbose = 1;
break;
case 'h':
case '?':
return usage(0);
default:
return usage(1);
}
}
argc -= optind;
argv += optind;
if (argc > 2)
startBlock = atoll(argv[2]);
if (argc > 1)
endBlock = atoll(argv[1]);
return scan_device(argv[0], startBlock, endBlock);
}