2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
11 #include <sys/param.h>
12 #include <sys/queue.h>
27 volatile sig_atomic_t aborting = 0;
28 static size_t bigsize = 1024 * 1024;
29 static size_t medsize = 64 * 1024;
30 static size_t minsize = 512;
36 TAILQ_ENTRY(lump) list;
39 static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
42 new_lump(off_t start, off_t len, int state)
46 lp = malloc(sizeof *lp);
48 err(1, "Malloc failed");
52 TAILQ_INSERT_TAIL(&lumps, lp, list);
55 static struct lump *lp;
56 static char *wworklist = NULL;
57 static char *rworklist = NULL;
60 #define PRINT_HEADER \
61 printf("%13s %7s %13s %5s %13s %13s %9s\n", \
62 "start", "size", "block-len", "state", "done", "remaining", "% done")
64 #define PRINT_STATUS(start, i, len, state, d, t) \
65 printf("\r%13jd %7zu %13jd %5d %13jd %13jd %9.5f", \
72 100*(double)d/(double)t)
74 /* Save the worklist if -w was given */
80 if (wworklist != NULL) {
81 (void)fprintf(stderr, "\nSaving worklist ...");
84 file = fopen(wworklist, "w");
86 err(1, "Error opening file %s", wworklist);
89 lp = TAILQ_FIRST(&lumps);
92 fprintf(file, "%jd %jd %d\n",
93 (intmax_t)lp->start, (intmax_t)lp->len, lp->state);
94 TAILQ_REMOVE(&lumps, lp, list);
96 (void)fprintf(stderr, " done.\n");
100 /* Read the worklist if -r was given */
102 read_worklist(off_t t)
108 (void)fprintf(stderr, "Reading worklist ...");
110 file = fopen(rworklist, "r");
112 err(1, "Error opening file %s", rworklist);
118 if (3 != fscanf(file, "%jd %jd %d\n", &s, &l, &state)) {
120 err(1, "Error parsing file %s at line %d",
125 new_lump(s, l, state);
128 (void)fprintf(stderr, " done.\n");
130 * Return the number of bytes already read
131 * (at least not in worklist).
139 (void)fprintf(stderr,
140 "usage: recoverdisk [-r worklist] [-w worklist] source-drive [destination]\n");
145 sighandler(__unused int sig)
152 main(int argc, char * const argv[])
156 off_t t, d, start, len;
158 int error, flags, state;
164 while ((ch = getopt(argc, argv, "r:w:")) != -1) {
167 rworklist = strdup(optarg);
168 if (rworklist == NULL)
169 err(1, "Cannot allocate enough memory");
172 wworklist = strdup(optarg);
173 if (wworklist == NULL)
174 err(1, "Cannot allocate enough memory");
184 if (argc < 1 || argc > 2)
187 fdr = open(argv[0], O_RDONLY);
189 err(1, "Cannot open read descriptor %s", argv[0]);
191 error = fstat(fdr, &sb);
193 err(1, "fstat failed");
195 if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
196 error = ioctl(fdr, DIOCGSECTORSIZE, §orsize);
198 err(1, "DIOCGSECTORSIZE failed");
201 * Make medsize roughly 64kB, depending on native sector
202 * size. bigsize has to be a multiple of medsize.
203 * For media with 2352 sectors, this will
204 * result in 2352, 63504, and 1016064 bytes.
206 minsize = sectorsize;
207 medsize = (medsize / sectorsize) * sectorsize;
208 bigsize = medsize * 16;
210 error = ioctl(fdr, DIOCGMEDIASIZE, &t);
212 err(1, "DIOCGMEDIASIZE failed");
215 flags |= O_CREAT | O_TRUNC;
218 buf = malloc(bigsize);
220 err(1, "Cannot allocate %jd bytes buffer", (intmax_t)bigsize);
223 fdw = open(argv[1], flags, DEFFILEMODE);
225 err(1, "Cannot open write descriptor %s", argv[1]);
229 if (rworklist != NULL) {
230 d = read_worklist(t);
235 if (wworklist != NULL)
236 signal(SIGINT, sighandler);
239 start = len = i = state = 0;
242 lp = TAILQ_FIRST(&lumps);
245 while (lp->len > 0 && !aborting) {
246 /* These are only copied for printing stats */
251 i = MIN(lp->len, (off_t)bigsize);
253 i = MIN(lp->len, (off_t)medsize);
255 i = MIN(lp->len, (off_t)minsize);
257 if (t1 != t2 || lp->len < (off_t)bigsize) {
258 PRINT_STATUS(start, i, len, state, d, t);
262 errx(1, "BOGUS i %10jd", (intmax_t)i);
265 j = pread(fdr, buf, i, lp->start);
269 j = pwrite(fdw, buf, i, lp->start);
273 printf("\nWrite error at %jd/%zu\n",
279 printf("\n%jd %zu failed %d\n", lp->start, i, errno);
280 new_lump(lp->start, i, lp->state + 1);
288 TAILQ_REMOVE(&lumps, lp, list);
291 PRINT_STATUS(start, i, len, state, d, t);
292 printf("\nCompleted\n");