Improvements to src/tools/tools/recoverdisk
Maxim Sobolev
sobomax at FreeBSD.org
Tue Apr 25 19:48:53 UTC 2006
Sounds cool, perhaps it's time to move recoverdisk into the base system
to give it better exposure?
-Maxim
Ulrich Spoerlein wrote:
> Dear Poul-Henning, current@,
>
> I made two, what I call, improvements to recoverdisk. It only tries to
> read in multiples of 512 bytes OR the sectorsize. This sucks for CD/DVD
> with 2352 bytes sectorsize. My patch takes the native sectorsize into
> account, when dimensioning BIG and MEDIUMSIZE.
>
> Second feature is the saving and loading of the worklist. Again, not
> very helpful for reading hard disks, but very useful for CDs. This way,
> you can first try a scratched CD in drive A, then drive B and drive C.
> You don't have to start all over again, but instead can profit from the
> different error recovery mechanisms.
>
> Previously, I did this with dd(1) and paper and pencil. Not funny.
>
> Please try the attached patch, thanks!
>
> Ulrich Spoerlein
>
>
> ------------------------------------------------------------------------
>
> --- recoverdisk.orig.c Mon Apr 24 19:34:57 2006
> +++ recoverdisk.c Tue Apr 25 14:11:44 2006
> @@ -14,15 +14,20 @@
> #include <err.h>
> #include <errno.h>
> #include <fcntl.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <sysexits.h>
> #include <time.h>
> #include <unistd.h>
> #include <sys/queue.h>
> #include <sys/disk.h>
> #include <sys/stat.h>
>
> -#define BIGSIZE (1046640)
> -#define MEDIUMSIZE (63504)
> -#define MINSIZE (512)
> +#define MIN(a,b) (((a)<(b))?(a):(b))
> +
> +static off_t bigsize = 1024 * 1024;
> +static off_t medsize = 64 * 1024;
> +static off_t minsize = 512;
>
> struct lump {
> off_t start;
> @@ -48,29 +53,119 @@
> TAILQ_INSERT_TAIL(&lumps, lp, list);
> }
>
> +static struct lump *lp;
> +static char *wworklist = NULL;
> +static char *rworklist = NULL;
> +
> +/* Save the worklist, if -w was given */
> +static void
> +save_worklist(__unused int sig)
> +{
> + FILE *file;
> +
> + if (wworklist != NULL) {
> + fprintf(stderr, "\nSaving worklist ...");
> + fflush(stderr);
> +
> + file = fopen(wworklist, "w");
> + if (file == NULL)
> + err(1, "Error opening file %s", wworklist);
> +
> + for (;;) {
> + lp = TAILQ_FIRST(&lumps);
> + if (lp == NULL)
> + break;
> + fprintf(file, "%jd %jd %d\n",
> + (intmax_t)lp->start, (intmax_t)lp->len, lp->state);
> + TAILQ_REMOVE(&lumps, lp, list);
> + }
> + fprintf(stderr, " done.\n");
> + }
> + exit(0);
> +}
> +
> +static off_t
> +read_worklist(off_t t)
> +{
> + off_t s, l, d;
> + int state, lines;
> + FILE *file;
> +
> + fprintf(stderr, "Reading worklist ...");
> + fflush(stderr);
> + file = fopen(rworklist, "r");
> + if (file == NULL)
> + err(1, "Error opening file %s", rworklist);
> +
> + lines = 0;
> + d = t;
> + for (;;) {
> + ++lines;
> + if (3 != fscanf(file, "%jd %jd %d\n", &s, &l, &state)) {
> + if (!feof(file))
> + err(1, "Error parsing file %s at line %d",
> + rworklist, lines);
> + else
> + break;
> + }
> +
> + new_lump(s, l, state);
> + d -= l;
> + }
> + fprintf(stderr, " done.\n");
> +
> + /*
> + * Return the number of bytes already read (at least not in
> + * worklist).
> + */
> + return (d);
> +}
> +
> +static void
> +usage(void)
> +{
> + fprintf(stderr, "Usage: %s [-r worklist] [-w worklist] source-drive [destination]", "recoverdisk");
> + exit(EX_USAGE);
> +}
> +
> int
> -main(int argc, const char **argv)
> +main(int argc, char * const argv[])
> {
> + int ch;
> int fdr, fdw;
> - struct lump *lp;
> off_t t, d;
> size_t i, j;
> int error, flags;
> u_char *buf;
> - u_int sectorsize, minsize;
> + u_int sectorsize;
> time_t t1, t2;
> struct stat sb;
>
> + while ((ch = getopt(argc, argv, "r:w:")) != -1) {
> + switch (ch) {
> + case 'w':
> + wworklist = strdup(optarg);
> + if (wworklist == NULL)
> + err(1, "Cannot allocate enough memory");
> + break;
> + case 'r':
> + rworklist = strdup(optarg);
> + if (rworklist == NULL)
> + err(1, "Cannot allocate enough memory");
> + break;
> + default:
> + usage();
> + }
> + }
> + argc -= optind;
> + argv += optind;
>
> - if (argc < 2)
> - errx(1, "Usage: %s source-drive [destination]", argv[0]);
> + if (argc < 1)
> + usage();
>
> - buf = malloc(BIGSIZE);
> - if (buf == NULL)
> - err(1, "Cannot allocate %d bytes buffer", BIGSIZE);
> - fdr = open(argv[1], O_RDONLY);
> + fdr = open(argv[0], O_RDONLY);
> if (fdr < 0)
> - err(1, "Cannot open read descriptor %s", argv[1]);
> + err(1, "Cannot open read descriptor %s", argv[0]);
>
> error = fstat(fdr, &sb);
> if (error < 0)
> @@ -80,46 +175,62 @@
> error = ioctl(fdr, DIOCGSECTORSIZE, §orsize);
> 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;
>
> error = ioctl(fdr, DIOCGMEDIASIZE, &t);
> if (error < 0)
> err(1, "DIOCGMEDIASIZE failed");
> } else {
> - sectorsize = 1;
> t = sb.st_size;
> - minsize = MINSIZE;
> flags |= O_CREAT | O_TRUNC;
> }
>
> - if (argc > 2) {
> - fdw = open(argv[2], flags, DEFFILEMODE);
> + buf = malloc(bigsize);
> + if (buf == NULL)
> + err(1, "Cannot allocate %jd bytes buffer", (intmax_t)bigsize);
> +
> + if (argc > 1) {
> + fdw = open(argv[1], flags, DEFFILEMODE);
> if (fdw < 0)
> - err(1, "Cannot open write descriptor %s", argv[2]);
> + err(1, "Cannot open write descriptor %s", argv[1]);
> } else {
> fdw = -1;
> }
>
> - new_lump(0, t, 0);
> - d = 0;
> + if (rworklist != NULL) {
> + d = read_worklist(t);
> + } else {
> + new_lump(0, t, 0);
> + d = 0;
> + }
> +
> + signal(SIGINT, save_worklist);
>
> t1 = 0;
> + printf("%13s %7s %13s %5s %13s %13s %9s\n",
> + "start", "size", "len", "state", "done", "remaining", "% done");
> 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;
> + i = MIN(lp->len, bigsize);
> if (lp->state == 1)
> - i = MEDIUMSIZE;
> + i = MIN(lp->len, medsize);
> if (lp->state > 1)
> - i = minsize;
> + i = MIN(lp->len, minsize);
> time(&t2);
> - if (t1 != t2 || lp->len < BIGSIZE) {
> - printf("\r%13jd %7zu %13jd %3d %13jd %13jd %.8f",
> + if (t1 != t2 || lp->len < bigsize) {
> + printf("\r%13jd %7zu %13jd %5d %13jd %13jd %.7f",
> (intmax_t)lp->start,
> i,
> (intmax_t)lp->len,
> @@ -152,9 +263,10 @@
> lp->start += i;
> lp->len -= i;
> }
> + TAILQ_REMOVE(&lumps, lp, list);
> free(lp);
> }
> printf("\nCompleted\n");
> - exit (0);
> + return (0);
> }
>
More information about the freebsd-current
mailing list