This is a small tool which will read an entire disk(partition) using
1M blocks and optionally write the read data to a file or disk. If a read error happens, the 1M block gets put on the end of the worklist and will be retried with 64k blocksize. If a read error happens again, the 64k block gets put at the end of the worklist and will be retried with single sector reads. The program keeps trying until you stop it. You can refresh a disk: recoverdisk /dev/ad1 /dev/ad1 or salvage a floppy: recoverdisk /dev/fd0 myfloppy.flp
This commit is contained in:
parent
2f4ac8072d
commit
d0514db4ed
12
sbin/recoverdisk/Makefile
Normal file
12
sbin/recoverdisk/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= recoverdisk
|
||||
|
||||
NOMAN=1
|
||||
|
||||
WARNS?= 5
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
test: ${PROG}
|
||||
./${PROG} /dev/ad0
|
137
sbin/recoverdisk/recoverdisk.c
Normal file
137
sbin/recoverdisk/recoverdisk.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/disk.h>
|
||||
|
||||
#define BIGSIZE (1024 * 1024)
|
||||
#define MEDIUMSIZE (64 * 1024)
|
||||
|
||||
struct lump {
|
||||
off_t start;
|
||||
off_t len;
|
||||
int state;
|
||||
TAILQ_ENTRY(lump) list;
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
|
||||
|
||||
|
||||
static void
|
||||
new_lump(off_t start, off_t len, int state)
|
||||
{
|
||||
struct lump *lp;
|
||||
|
||||
lp = malloc(sizeof *lp);
|
||||
if (lp == NULL)
|
||||
err(1, "Malloc failed");
|
||||
lp->start = start;
|
||||
lp->len = len;
|
||||
lp->state = state;
|
||||
TAILQ_INSERT_TAIL(&lumps, lp, list);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
int fdr, fdw;
|
||||
struct lump *lp;
|
||||
off_t t, d;
|
||||
size_t i, j;
|
||||
int error;
|
||||
u_char *buf;
|
||||
u_int sectorsize;
|
||||
|
||||
|
||||
if (argc < 2)
|
||||
errx(1, "Usage: %s source-drive [destination]", argv[0]);
|
||||
|
||||
buf = malloc(BIGSIZE);
|
||||
if (buf == NULL)
|
||||
err(1, "Cannot allocate %d bytes buffer", BIGSIZE);
|
||||
fdr = open(argv[1], O_RDONLY);
|
||||
if (fdr < 0)
|
||||
err(1, "Cannot open read descriptor %s", argv[1]);
|
||||
if (argc > 2) {
|
||||
fdw = open(argv[2], O_WRONLY);
|
||||
if (fdw < 0)
|
||||
err(1, "Cannot open write descriptor %s", argv[2]);
|
||||
} else {
|
||||
fdw = -1;
|
||||
}
|
||||
|
||||
error = ioctl(fdr, DIOCGSECTORSIZE, §orsize);
|
||||
if (error < 0)
|
||||
err(1, "DIOCGSECTORSIZE failed");
|
||||
|
||||
error = ioctl(fdr, DIOCGMEDIASIZE, &t);
|
||||
if (error < 0)
|
||||
err(1, "DIOCGMEDIASIZE failed");
|
||||
|
||||
new_lump(0, t, 0);
|
||||
d = 0;
|
||||
|
||||
for (;;) {
|
||||
lp = TAILQ_FIRST(&lumps);
|
||||
if (lp == NULL)
|
||||
break;
|
||||
TAILQ_REMOVE(&lumps, lp, list);
|
||||
while (lp->len > 0) {
|
||||
i = BIGSIZE;
|
||||
if (lp->len < BIGSIZE)
|
||||
i = lp->len;
|
||||
if (lp->state == 1)
|
||||
i = MEDIUMSIZE;
|
||||
if (lp->state > 1)
|
||||
i = sectorsize;
|
||||
printf("\r%13jd %7jd %13jd %3d %13jd %13jd %.8f",
|
||||
(intmax_t)lp->start,
|
||||
(intmax_t)i,
|
||||
(intmax_t)lp->len,
|
||||
lp->state,
|
||||
(intmax_t)d,
|
||||
(intmax_t)(t - d),
|
||||
(double)d/(double)t);
|
||||
if (i == 0) {
|
||||
errx(1, "BOGUS i %10jd", (intmax_t)i);
|
||||
}
|
||||
fflush(stdout);
|
||||
j = pread(fdr, buf, i, lp->start);
|
||||
if (j == i) {
|
||||
d += i;
|
||||
if (fdw >= 0)
|
||||
j = pwrite(fdw, buf, i, lp->start);
|
||||
else
|
||||
j = i;
|
||||
if (j != i)
|
||||
printf("\nWrite error at %jd/%d\n",
|
||||
lp->start, i);
|
||||
lp->start += i;
|
||||
lp->len -= i;
|
||||
continue;
|
||||
}
|
||||
printf("\n%jd %d failed %d\n", lp->start, i, errno);
|
||||
new_lump(lp->start, i, lp->state + 1);
|
||||
lp->start += i;
|
||||
lp->len -= i;
|
||||
}
|
||||
free(lp);
|
||||
}
|
||||
printf("\nCompleted\n");
|
||||
exit (0);
|
||||
}
|
||||
|
12
tools/tools/recoverdisk/Makefile
Normal file
12
tools/tools/recoverdisk/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= recoverdisk
|
||||
|
||||
NOMAN=1
|
||||
|
||||
WARNS?= 5
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
test: ${PROG}
|
||||
./${PROG} /dev/ad0
|
21
tools/tools/recoverdisk/README
Normal file
21
tools/tools/recoverdisk/README
Normal file
@ -0,0 +1,21 @@
|
||||
$FreeBSD$
|
||||
|
||||
This is a small tool which will read an entire disk(partition) using
|
||||
1M blocks and optionally write the read data to a file or disk.
|
||||
|
||||
If a read error happens, the 1M block gets put on the end of the worklist
|
||||
and will be retried with 64k blocksize.
|
||||
|
||||
If a read error happens again, the 64k block gets put at the end of the
|
||||
worklist and will be retried with single sector reads.
|
||||
|
||||
The program keeps trying until you stop it.
|
||||
|
||||
You can refresh a disk:
|
||||
|
||||
recoverdisk /dev/ad1 /dev/ad1
|
||||
|
||||
or salvage a floppy:
|
||||
|
||||
recoverdisk /dev/fd0 myfloppy.flp
|
||||
|
137
tools/tools/recoverdisk/recoverdisk.c
Normal file
137
tools/tools/recoverdisk/recoverdisk.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/disk.h>
|
||||
|
||||
#define BIGSIZE (1024 * 1024)
|
||||
#define MEDIUMSIZE (64 * 1024)
|
||||
|
||||
struct lump {
|
||||
off_t start;
|
||||
off_t len;
|
||||
int state;
|
||||
TAILQ_ENTRY(lump) list;
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
|
||||
|
||||
|
||||
static void
|
||||
new_lump(off_t start, off_t len, int state)
|
||||
{
|
||||
struct lump *lp;
|
||||
|
||||
lp = malloc(sizeof *lp);
|
||||
if (lp == NULL)
|
||||
err(1, "Malloc failed");
|
||||
lp->start = start;
|
||||
lp->len = len;
|
||||
lp->state = state;
|
||||
TAILQ_INSERT_TAIL(&lumps, lp, list);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
int fdr, fdw;
|
||||
struct lump *lp;
|
||||
off_t t, d;
|
||||
size_t i, j;
|
||||
int error;
|
||||
u_char *buf;
|
||||
u_int sectorsize;
|
||||
|
||||
|
||||
if (argc < 2)
|
||||
errx(1, "Usage: %s source-drive [destination]", argv[0]);
|
||||
|
||||
buf = malloc(BIGSIZE);
|
||||
if (buf == NULL)
|
||||
err(1, "Cannot allocate %d bytes buffer", BIGSIZE);
|
||||
fdr = open(argv[1], O_RDONLY);
|
||||
if (fdr < 0)
|
||||
err(1, "Cannot open read descriptor %s", argv[1]);
|
||||
if (argc > 2) {
|
||||
fdw = open(argv[2], O_WRONLY);
|
||||
if (fdw < 0)
|
||||
err(1, "Cannot open write descriptor %s", argv[2]);
|
||||
} else {
|
||||
fdw = -1;
|
||||
}
|
||||
|
||||
error = ioctl(fdr, DIOCGSECTORSIZE, §orsize);
|
||||
if (error < 0)
|
||||
err(1, "DIOCGSECTORSIZE failed");
|
||||
|
||||
error = ioctl(fdr, DIOCGMEDIASIZE, &t);
|
||||
if (error < 0)
|
||||
err(1, "DIOCGMEDIASIZE failed");
|
||||
|
||||
new_lump(0, t, 0);
|
||||
d = 0;
|
||||
|
||||
for (;;) {
|
||||
lp = TAILQ_FIRST(&lumps);
|
||||
if (lp == NULL)
|
||||
break;
|
||||
TAILQ_REMOVE(&lumps, lp, list);
|
||||
while (lp->len > 0) {
|
||||
i = BIGSIZE;
|
||||
if (lp->len < BIGSIZE)
|
||||
i = lp->len;
|
||||
if (lp->state == 1)
|
||||
i = MEDIUMSIZE;
|
||||
if (lp->state > 1)
|
||||
i = sectorsize;
|
||||
printf("\r%13jd %7jd %13jd %3d %13jd %13jd %.8f",
|
||||
(intmax_t)lp->start,
|
||||
(intmax_t)i,
|
||||
(intmax_t)lp->len,
|
||||
lp->state,
|
||||
(intmax_t)d,
|
||||
(intmax_t)(t - d),
|
||||
(double)d/(double)t);
|
||||
if (i == 0) {
|
||||
errx(1, "BOGUS i %10jd", (intmax_t)i);
|
||||
}
|
||||
fflush(stdout);
|
||||
j = pread(fdr, buf, i, lp->start);
|
||||
if (j == i) {
|
||||
d += i;
|
||||
if (fdw >= 0)
|
||||
j = pwrite(fdw, buf, i, lp->start);
|
||||
else
|
||||
j = i;
|
||||
if (j != i)
|
||||
printf("\nWrite error at %jd/%d\n",
|
||||
lp->start, i);
|
||||
lp->start += i;
|
||||
lp->len -= i;
|
||||
continue;
|
||||
}
|
||||
printf("\n%jd %d failed %d\n", lp->start, i, errno);
|
||||
new_lump(lp->start, i, lp->state + 1);
|
||||
lp->start += i;
|
||||
lp->len -= i;
|
||||
}
|
||||
free(lp);
|
||||
}
|
||||
printf("\nCompleted\n");
|
||||
exit (0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user