summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2009-03-11 10:37:02 +0000
committerphk <phk@FreeBSD.org>2009-03-11 10:37:02 +0000
commit5af10de8b83989429fcd51aa56f22ad38dda5ae6 (patch)
treed54183724094c83db854a783fe8880695ed89ac1 /sbin
parentf1ee91324d2c186fc1dcca507bea55635cae4dc3 (diff)
downloadFreeBSD-src-5af10de8b83989429fcd51aa56f22ad38dda5ae6.zip
FreeBSD-src-5af10de8b83989429fcd51aa56f22ad38dda5ae6.tar.gz
Some improvements to recoverdisk
Diffstat (limited to 'sbin')
-rw-r--r--sbin/recoverdisk/recoverdisk.119
-rw-r--r--sbin/recoverdisk/recoverdisk.c48
2 files changed, 48 insertions, 19 deletions
diff --git a/sbin/recoverdisk/recoverdisk.1 b/sbin/recoverdisk/recoverdisk.1
index c5526b3..d4afac2 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 6353635..4c25181 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);
OpenPOWER on IntegriCloud