recoverdisk.c revision 149605
1135911Sphk/* 2135911Sphk * ---------------------------------------------------------------------------- 3135911Sphk * "THE BEER-WARE LICENSE" (Revision 42): 4135911Sphk * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5135911Sphk * can do whatever you want with this stuff. If we meet some day, and you think 6135911Sphk * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7135911Sphk * ---------------------------------------------------------------------------- 8135911Sphk * 9135911Sphk * $FreeBSD: head/sbin/recoverdisk/recoverdisk.c 149605 2005-08-29 23:08:01Z sobomax $ 10135911Sphk */ 11135911Sphk#include <stdio.h> 12135911Sphk#include <stdint.h> 13135911Sphk#include <stdlib.h> 14136257Sphk#include <err.h> 15135911Sphk#include <errno.h> 16135911Sphk#include <fcntl.h> 17136257Sphk#include <time.h> 18135911Sphk#include <unistd.h> 19135911Sphk#include <sys/queue.h> 20135911Sphk#include <sys/disk.h> 21149605Ssobomax#include <sys/stat.h> 22135911Sphk 23135911Sphk#define BIGSIZE (1024 * 1024) 24135911Sphk#define MEDIUMSIZE (64 * 1024) 25149605Ssobomax#define MINSIZE (512) 26135911Sphk 27135911Sphkstruct lump { 28135911Sphk off_t start; 29135911Sphk off_t len; 30135911Sphk int state; 31135911Sphk TAILQ_ENTRY(lump) list; 32135911Sphk}; 33135911Sphk 34135911Sphkstatic TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps); 35135911Sphk 36135911Sphk 37135911Sphkstatic void 38135911Sphknew_lump(off_t start, off_t len, int state) 39135911Sphk{ 40135911Sphk struct lump *lp; 41135911Sphk 42135911Sphk lp = malloc(sizeof *lp); 43135911Sphk if (lp == NULL) 44135911Sphk err(1, "Malloc failed"); 45135911Sphk lp->start = start; 46135911Sphk lp->len = len; 47135911Sphk lp->state = state; 48135911Sphk TAILQ_INSERT_TAIL(&lumps, lp, list); 49135911Sphk} 50135911Sphk 51135911Sphkint 52135911Sphkmain(int argc, const char **argv) 53135911Sphk{ 54135911Sphk int fdr, fdw; 55135911Sphk struct lump *lp; 56135911Sphk off_t t, d; 57135911Sphk size_t i, j; 58149605Ssobomax int error, flags; 59135911Sphk u_char *buf; 60149605Ssobomax u_int sectorsize, minsize; 61136257Sphk time_t t1, t2; 62149605Ssobomax struct stat sb; 63135911Sphk 64135911Sphk 65135911Sphk if (argc < 2) 66135911Sphk errx(1, "Usage: %s source-drive [destination]", argv[0]); 67135911Sphk 68135911Sphk buf = malloc(BIGSIZE); 69135911Sphk if (buf == NULL) 70135911Sphk err(1, "Cannot allocate %d bytes buffer", BIGSIZE); 71135911Sphk fdr = open(argv[1], O_RDONLY); 72135911Sphk if (fdr < 0) 73135911Sphk err(1, "Cannot open read descriptor %s", argv[1]); 74149605Ssobomax 75149605Ssobomax error = fstat(fdr, &sb); 76149605Ssobomax if (error < 0) 77149605Ssobomax err(1, "fstat failed"); 78149605Ssobomax flags = O_WRONLY; 79149605Ssobomax if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { 80149605Ssobomax error = ioctl(fdr, DIOCGSECTORSIZE, §orsize); 81149605Ssobomax if (error < 0) 82149605Ssobomax err(1, "DIOCGSECTORSIZE failed"); 83149605Ssobomax minsize = sectorsize; 84149605Ssobomax 85149605Ssobomax error = ioctl(fdr, DIOCGMEDIASIZE, &t); 86149605Ssobomax if (error < 0) 87149605Ssobomax err(1, "DIOCGMEDIASIZE failed"); 88149605Ssobomax } else { 89149605Ssobomax sectorsize = 1; 90149605Ssobomax t = sb.st_size; 91149605Ssobomax minsize = MINSIZE; 92149605Ssobomax flags |= O_CREAT | O_TRUNC; 93149605Ssobomax } 94149605Ssobomax 95135911Sphk if (argc > 2) { 96149605Ssobomax fdw = open(argv[2], flags, DEFFILEMODE); 97135911Sphk if (fdw < 0) 98135911Sphk err(1, "Cannot open write descriptor %s", argv[2]); 99135911Sphk } else { 100135911Sphk fdw = -1; 101135911Sphk } 102135911Sphk 103135911Sphk new_lump(0, t, 0); 104135911Sphk d = 0; 105135911Sphk 106136257Sphk t1 = 0; 107135911Sphk for (;;) { 108135911Sphk lp = TAILQ_FIRST(&lumps); 109135911Sphk if (lp == NULL) 110135911Sphk break; 111135911Sphk TAILQ_REMOVE(&lumps, lp, list); 112135911Sphk while (lp->len > 0) { 113135911Sphk i = BIGSIZE; 114135911Sphk if (lp->len < BIGSIZE) 115135911Sphk i = lp->len; 116135911Sphk if (lp->state == 1) 117135911Sphk i = MEDIUMSIZE; 118135911Sphk if (lp->state > 1) 119149605Ssobomax i = minsize; 120136257Sphk time(&t2); 121136257Sphk if (t1 != t2 || lp->len < BIGSIZE) { 122136815Sdes printf("\r%13jd %7zu %13jd %3d %13jd %13jd %.8f", 123136257Sphk (intmax_t)lp->start, 124136815Sdes i, 125136257Sphk (intmax_t)lp->len, 126136257Sphk lp->state, 127136257Sphk (intmax_t)d, 128136257Sphk (intmax_t)(t - d), 129136257Sphk (double)d/(double)t); 130136257Sphk t1 = t2; 131136257Sphk } 132135911Sphk if (i == 0) { 133135911Sphk errx(1, "BOGUS i %10jd", (intmax_t)i); 134135911Sphk } 135135911Sphk fflush(stdout); 136135911Sphk j = pread(fdr, buf, i, lp->start); 137135911Sphk if (j == i) { 138135911Sphk d += i; 139135911Sphk if (fdw >= 0) 140135911Sphk j = pwrite(fdw, buf, i, lp->start); 141135911Sphk else 142135911Sphk j = i; 143135911Sphk if (j != i) 144136815Sdes printf("\nWrite error at %jd/%zu\n", 145136815Sdes lp->start, i); 146135911Sphk lp->start += i; 147135911Sphk lp->len -= i; 148135911Sphk continue; 149135911Sphk } 150136815Sdes printf("\n%jd %zu failed %d\n", lp->start, i, errno); 151135911Sphk new_lump(lp->start, i, lp->state + 1); 152135911Sphk lp->start += i; 153135911Sphk lp->len -= i; 154135911Sphk } 155135911Sphk free(lp); 156135911Sphk } 157135911Sphk printf("\nCompleted\n"); 158135911Sphk exit (0); 159135911Sphk} 160135911Sphk 161