diff --git a/sbin/recoverdisk/recoverdisk.1 b/sbin/recoverdisk/recoverdisk.1 index c5526b36f62b..d4afac259da6 100644 --- a/sbin/recoverdisk/recoverdisk.1 +++ b/sbin/recoverdisk/recoverdisk.1 @@ -32,7 +32,9 @@ .Nd recover data from hard disk or optical media .Sh SYNOPSIS .Nm +.Op Fl b Ar bigsize .Op Fl r Ar rlist +.Op Fl s Ar snapshot .Op Fl w Ar wlist .Ar special .Op Ar file @@ -46,15 +48,24 @@ It starts reading in multiples of the sector size. Whenever a block fails, it is put to the end of the working queue and will be read again, possibly with a smaller read size. .Pp -It uses block sizes of roughly 1 MB, 64kB, and the native sector size (usually -512 bytes). +By default it uses block sizes of roughly 1 MB, 32kB, and the native +sector size (usually 512 bytes). These figures are adjusted slightly, for devices whose sectorsize is not a power of 2, e.g., audio CDs with a sector size of 2352 bytes. .Pp +.Pp The options are as follows: .Bl -tag -width indent +.It Fl b Ar bigsize +The size of reads attempted first. +The middle pass is roughly the logarithmic average of the bigsize and +the sectorsize. .It Fl r Ar rlist Read the list of blocks and block sizes to read from the specified file. +.It Fl s Ar snapshot +How often we should update the worklist file while things go OK. +The default is 60 and the units is "progress messages" so if things +go well, this is the same as once per minute. .It Fl w Ar wlist Write the list of remaining blocks to read to the specified file if .Nm @@ -106,6 +117,10 @@ recoverdisk -r worklist -w worklist /dev/acd0 /data/cd.iso # recover a single file from the unreadable media touch file.avi; recoverdisk /cdrom/file.avi file.avi + +# If the disk hangs the system on read-errors try: +recoverdisk -b 0 /dev/ad3 /somewhere + .Ed .Sh SEE ALSO .Xr dd 1 diff --git a/sbin/recoverdisk/recoverdisk.c b/sbin/recoverdisk/recoverdisk.c index 63536354dfe9..4c25181bdc74 100644 --- a/sbin/recoverdisk/recoverdisk.c +++ b/sbin/recoverdisk/recoverdisk.c @@ -26,7 +26,7 @@ volatile sig_atomic_t aborting = 0; static size_t bigsize = 1024 * 1024; -static size_t medsize = 64 * 1024; +static size_t medsize; static size_t minsize = 512; struct lump { @@ -76,6 +76,7 @@ static void save_worklist(void) { FILE *file; + struct lump *llp; if (wworklist != NULL) { (void)fprintf(stderr, "\nSaving worklist ..."); @@ -85,14 +86,11 @@ save_worklist(void) if (file == NULL) err(1, "Error opening file %s", wworklist); - for (;;) { - lp = TAILQ_FIRST(&lumps); - if (lp == NULL) - break; + TAILQ_FOREACH(llp, &lumps, list) fprintf(file, "%jd %jd %d\n", - (intmax_t)lp->start, (intmax_t)lp->len, lp->state); - TAILQ_REMOVE(&lumps, lp, list); - } + (intmax_t)llp->start, (intmax_t)llp->len, + llp->state); + fclose(file); (void)fprintf(stderr, " done.\n"); } } @@ -160,14 +158,21 @@ main(int argc, char * const argv[]) u_int sectorsize; time_t t1, t2; struct stat sb; + u_int n, snapshot = 60; - while ((ch = getopt(argc, argv, "r:w:")) != -1) { + while ((ch = getopt(argc, argv, "b:r:w:s:")) != -1) { switch (ch) { + case 'b': + bigsize = strtoul(optarg, NULL, 0); + break; case 'r': rworklist = strdup(optarg); if (rworklist == NULL) err(1, "Cannot allocate enough memory"); break; + case 's': + snapshot = strtoul(optarg, NULL, 0); + break; case 'w': wworklist = strdup(optarg); if (wworklist == NULL) @@ -197,15 +202,8 @@ main(int argc, char * const argv[]) if (error < 0) err(1, "DIOCGSECTORSIZE failed"); - /* - * Make medsize roughly 64kB, depending on native sector - * size. bigsize has to be a multiple of medsize. - * For media with 2352 sectors, this will - * result in 2352, 63504, and 1016064 bytes. - */ minsize = sectorsize; - medsize = (medsize / sectorsize) * sectorsize; - bigsize = medsize * 16; + bigsize = (bigsize / sectorsize) * sectorsize; error = ioctl(fdr, DIOCGMEDIASIZE, &t); if (error < 0) @@ -215,6 +213,17 @@ main(int argc, char * const argv[]) flags |= O_CREAT | O_TRUNC; } + if (bigsize < minsize) + bigsize = minsize; + + for (ch = 0; (bigsize >> ch) > minsize; ch++) + continue; + medsize = bigsize >> (ch / 2); + medsize = (medsize / minsize) * minsize; + + fprintf(stderr, "Bigsize = %u, medsize = %u, minsize = %u\n", + bigsize, medsize, minsize); + buf = malloc(bigsize); if (buf == NULL) err(1, "Cannot allocate %jd bytes buffer", (intmax_t)bigsize); @@ -238,6 +247,7 @@ main(int argc, char * const argv[]) t1 = 0; start = len = i = state = 0; PRINT_HEADER; + n = 0; for (;;) { lp = TAILQ_FIRST(&lumps); if (lp == NULL) @@ -257,6 +267,10 @@ main(int argc, char * const argv[]) if (t1 != t2 || lp->len < (off_t)bigsize) { PRINT_STATUS(start, i, len, state, d, t); t1 = t2; + if (++n == snapshot) { + save_worklist(); + n = 0; + } } if (i == 0) { errx(1, "BOGUS i %10jd", (intmax_t)i);