bin/96677: Improvements for src/tools/tools/recoverdisk
Ulrich Spoerlein
uspoerlein at gmail.com
Thu May 4 22:50:18 UTC 2006
The following reply was made to PR bin/96677; it has been noted by GNATS.
From: Ulrich Spoerlein <uspoerlein at gmail.com>
To: Maxim Konovalov <maxim at macomnet.ru>
Cc: bug-followup at freebsd.org
Subject: Re: bin/96677: Improvements for src/tools/tools/recoverdisk
Date: Thu, 4 May 2006 15:56:17 +0200
Here's a simple alternative, that only sets a flag in the signal
handler.
Ulrich Spoerlein
--- recoverdisk.c.orig Thu Dec 15 19:41:42 2005
+++ recoverdisk.c Thu May 4 15:51:08 2006
@@ -1,4 +1,4 @@
-/*
+/*-
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk at FreeBSD.ORG> wrote this file. As long as you retain this notice you
@@ -8,21 +8,29 @@
*
* $FreeBSD: src/tools/tools/recoverdisk/recoverdisk.c,v 1.4.4.1 2005/12/15 03:50:03 sobomax Exp $
*/
+#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#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 (1024 * 1024)
-#define MEDIUMSIZE (64 * 1024)
-#define MINSIZE (512)
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+static bool aborting = false;
+
+static size_t bigsize = 1024 * 1024;
+static size_t medsize = 64 * 1024;
+static size_t minsize = 512;
struct lump {
off_t start;
@@ -33,7 +41,6 @@
static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
-
static void
new_lump(off_t start, off_t len, int state)
{
@@ -48,29 +55,128 @@
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(void)
+{
+ FILE *file;
+
+ if (wworklist != NULL) {
+ (void)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);
+ }
+ (void)fprintf(stderr, " done.\n");
+ }
+ exit(0);
+}
+
+/* Read the worklist if -r was given */
+static off_t
+read_worklist(off_t t)
+{
+ off_t s, l, d;
+ int state, lines;
+ FILE *file;
+
+ (void)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;
+ }
+ (void)fprintf(stderr, " done.\n");
+
+ /*
+ * Return the number of bytes already read
+ * (at least not in worklist).
+ */
+ return (d);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: recoverdisk [-r worklist] [-w worklist] source-drive [destination]\n");
+ exit(EX_USAGE);
+}
+
+static void
+sighandler(__unused int sig)
+{
+ aborting = true;
+ signal(SIGINT, SIG_DFL);
+}
+
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;
+ 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 || argc > 2)
+ 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 +186,66 @@
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;
+ }
+
+ if (wworklist != NULL) {
+ signal(SIGINT, sighandler);
+ /* Has this any effect on pread/pwrite at all? */
+ siginterrupt(SIGINT, 1);
+ }
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;
+ while (lp->len > 0 && !aborting) {
+ 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 +278,13 @@
lp->start += i;
lp->len -= i;
}
+
+ if (aborting)
+ save_worklist();
+
+ TAILQ_REMOVE(&lumps, lp, list);
free(lp);
}
printf("\nCompleted\n");
- exit (0);
+ return (0);
}
-
More information about the freebsd-bugs
mailing list