#include #include #include #include #include #include #include #include #include #include #include #include #if DEV_BSIZE != 512 #error "unexpected DEV_BSIZE" #endif #define FMT_BASE "o %12"PRId64" %12"PRId64" l %6"PRId64" %6"PRId64" p %10"PRId64" %10"PRId64 #define FMT_SEEK FMT_BASE " s %10"PRId64"\n" #define FMT_END FMT_BASE "\n" int main(int argc, char *argv[]) { int fd; int debug; int error; daddr_t nblks; struct statvfs stfs; struct stat st; daddr_t lbn, pbn, off; daddr_t runlbn, runpbn, runoff; daddr_t prev; if (argc < 2) errx(EXIT_FAILURE, "usage: %s diskdev DEBUG", getprogname()); debug = argc > 2; fd = open(argv[1], O_RDONLY, 0); if (fd == -1) err(EXIT_FAILURE, "open %s", argv[1]); error = fstatvfs(fd, &stfs); if (error == -1) err(EXIT_FAILURE, "fstatfs"); error = fstat(fd, &st); if (error == -1) err(EXIT_FAILURE, "fstatfs"); nblks = howmany(st.st_size, st.st_blksize); setbuf(stdout, NULL); if (debug) { fprintf(stderr, "st.st_size: %"PRIu64"\n", (uint64_t)st.st_size); fprintf(stderr, "st.st_blocks: %"PRId64"\n", st.st_blocks); fprintf(stderr, "st.st_blksize: %d\n", st.st_blksize); fprintf(stderr, "stfs.f_bsize: %ld\n", stfs.f_bsize); fprintf(stderr, "nlks: %"PRId64" * %d = %"PRId64"\n", nblks, st.st_blksize, nblks * st.st_blksize); } for (off = 0, lbn = 0; lbn < nblks; off += st.st_blksize, lbn++) { daddr_t addr; addr = lbn; error = ioctl(fd, FIOGETBMAP, &addr); if (error == -1) err(EXIT_FAILURE, "ioctl FIOGETBMAP"); pbn = addr; if (lbn == 0) { runlbn = lbn; runoff = off; runpbn = pbn; } else if ((pbn != prev + howmany(st.st_blksize, DEV_BSIZE)) && !(pbn == -1 && prev == -1)) { printf(FMT_SEEK, runoff, MIN(off, st.st_size) - runoff, runlbn, lbn - runlbn, runpbn, prev < 0 ? howmany(MIN(off, st.st_size) - runoff, DEV_BSIZE) : (prev + MIN(howmany(st.st_blksize, DEV_BSIZE), howmany((st.st_blocks*512), DEV_BSIZE)) - runpbn), pbn - (prev + howmany(st.st_blksize, DEV_BSIZE))); runoff = off; runlbn = lbn; runpbn = pbn; } if (debug) { fprintf(stderr, "FIOGETBMAP: o: %16"PRId64" l: %16"PRId64" p: %16"PRId64"\n", off, lbn, pbn); } prev = pbn; } printf(FMT_END, runoff, MIN(off, st.st_size) - runoff, runlbn, lbn - runlbn, runpbn, prev < 0 ? 0 : prev + MIN(howmany(st.st_blksize, DEV_BSIZE), howmany((st.st_blocks*512), DEV_BSIZE)) - runpbn); error = close(fd); if (error == -1) err(EXIT_FAILURE, "close"); return EXIT_SUCCESS; }