recoverdisk(8): treat output file consistently and abort on EINVAL

This improves usability a little as we no longer require using touch.
Also reword the manpage wrt. parameters and fix usage() [1]

With no media in a cd(4) drive, the reads will loop producing EINVAL,
abort in that case [2].

Document the shortcoming of sectorsize and MAXPHYS (a quick solution
to this might be having MAXPHYS as the "bigsize", in short testing it
didn't make a difference on throughput).

Submitted by:	arundel [1]
PR:		bin/154528 [2]
This commit is contained in:
Ulrich Spörlein 2011-05-01 20:14:10 +00:00
parent aeea395e35
commit 5df69e92de
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=221304
2 changed files with 42 additions and 26 deletions

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 6, 2006
.Dd May 1, 2011
.Dt RECOVERDISK 1
.Os
.Sh NAME
@ -33,17 +33,20 @@
.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
.Op Fl r Ar readlist
.Op Fl s Ar interval
.Op Fl w Ar writelist
.Ar source
.Op Ar destination
.Sh DESCRIPTION
The
.Nm
utility reads data from the
.Ar special
.Ar source
file until all blocks could be successfully read.
If
.Ar destination
was specified all data is being written to that file.
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.
@ -59,13 +62,13 @@ The options are as follows:
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
.It Fl r Ar readlist
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
.It Fl s Ar interval
How often we should update the writelist file while things go OK.
The default is 60 and the unit is "progress messages" so if things
go well, this is the same as once per minute.
.It Fl w Ar wlist
.It Fl w Ar writelist
Write the list of remaining blocks to read to the specified file if
.Nm
is aborted via
@ -102,20 +105,19 @@ Percent complete.
.Sh EXAMPLES
.Bd -literal
# recover data from failing hard drive ad3
touch /data/lots_of_space
recoverdisk /dev/ad3 /data/lots_of_space
recoverdisk /dev/ad3 /data/disk.img
# clone a hard disk
recoverdisk /dev/ad3 /dev/ad4
# read an ISO image from a CD-ROM
touch /data/cd.iso; recoverdisk /dev/acd0 /data/cd.iso
recoverdisk /dev/cd0 /data/cd.iso
# continue reading from a broken CD and update the existing worklist
recoverdisk -r worklist -w worklist /dev/acd0 /data/cd.iso
recoverdisk -r worklist -w worklist /dev/cd0 /data/cd.iso
# recover a single file from the unreadable media
touch file.avi; recoverdisk /cdrom/file.avi file.avi
recoverdisk /cdrom/file.avi file.avi
# If the disk hangs the system on read-errors try:
recoverdisk -b 0 /dev/ad3 /somewhere
@ -133,7 +135,7 @@ utility first appeared in
The original implementation was done by
.An Poul-Henning Kamp Aq phk@FreeBSD.org
with minor improvements from
.An Ulrich Sp\(:orlein Aq uspoerlein@gmail.com .
.An Ulrich Sp\(:orlein Aq uqs@FreeBSD.org .
.Pp
This manual page was written by
.An Ulrich Sp\(:orlein .
@ -144,4 +146,13 @@ This is due to the DMA reads being split up into blocks of at most 128kB.
These reads then fail if the sectorsize is not a divisor of 128kB.
When reading a full raw audio CD, this leads to roughly 700 error messages
flying by.
This is harmless.
This is harmless and can be avoided by setting
.Fl b
to no more than 128kB.
.\".Pp
.\"When reading from optical media, a bug in the GEOM framework will
.\"prevent it from seeing that the media has been removed.
.\"The device can still be opened, but all reads will fail.
.\"This is usually harmless, but will send
.\".Nm
.\"into an infinite loop.

View File

@ -86,7 +86,7 @@ save_worklist(void)
if (file == NULL)
err(1, "Error opening file %s", wworklist);
TAILQ_FOREACH(llp, &lumps, list)
TAILQ_FOREACH(llp, &lumps, list)
fprintf(file, "%jd %jd %d\n",
(intmax_t)llp->start, (intmax_t)llp->len,
llp->state);
@ -134,8 +134,8 @@ read_worklist(off_t t)
static void
usage(void)
{
(void)fprintf(stderr,
"usage: recoverdisk [-r worklist] [-w worklist] source-drive [destination]\n");
(void)fprintf(stderr, "usage: recoverdisk [-b bigsize] [-r readlist] "
"[-s interval] [-w writelist] source [destination]\n");
exit(1);
}
@ -153,7 +153,7 @@ main(int argc, char * const argv[])
int fdr, fdw;
off_t t, d, start, len;
size_t i, j;
int error, flags, state;
int error, state;
u_char *buf;
u_int sectorsize;
time_t t1, t2;
@ -196,7 +196,6 @@ main(int argc, char * const argv[])
error = fstat(fdr, &sb);
if (error < 0)
err(1, "fstat failed");
flags = O_WRONLY;
if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
error = ioctl(fdr, DIOCGSECTORSIZE, &sectorsize);
if (error < 0)
@ -210,7 +209,6 @@ main(int argc, char * const argv[])
err(1, "DIOCGMEDIASIZE failed");
} else {
t = sb.st_size;
flags |= O_CREAT | O_TRUNC;
}
if (bigsize < minsize)
@ -229,9 +227,12 @@ main(int argc, char * const argv[])
err(1, "Cannot allocate %zu bytes buffer", bigsize);
if (argc > 1) {
fdw = open(argv[1], flags, DEFFILEMODE);
fdw = open(argv[1], O_WRONLY | O_CREAT, DEFFILEMODE);
if (fdw < 0)
err(1, "Cannot open write descriptor %s", argv[1]);
if (ftruncate(fdw, t) < 0)
err(1, "Cannot truncate output %s to %jd bytes",
argv[1], (intmax_t)t);
} else
fdw = -1;
@ -292,6 +293,10 @@ main(int argc, char * const argv[])
}
printf("\n%jd %zu failed (%s)\n",
lp->start, i, strerror(errno));
if (errno == EINVAL) {
printf("read() size too big? Try with -b 131072");
aborting = 1;
}
if (errno == ENXIO)
aborting = 1;
new_lump(lp->start, i, lp->state + 1);