2 * SPDX-License-Identifier: Beerware
4 * ----------------------------------------------------------------------------
5 * "THE BEER-WARE LICENSE" (Revision 42):
6 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
7 * can do whatever you want with this stuff. If we meet some day, and you think
8 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
9 * ----------------------------------------------------------------------------
13 #include <sys/param.h>
14 #include <sys/queue.h>
29 static volatile sig_atomic_t aborting = 0;
30 static size_t bigsize = 1024 * 1024;
31 static size_t medsize;
32 static size_t minsize = 512;
38 TAILQ_ENTRY(lump) list;
41 static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
44 new_lump(off_t start, off_t len, int state)
48 lp = malloc(sizeof *lp);
50 err(1, "Malloc failed");
54 TAILQ_INSERT_TAIL(&lumps, lp, list);
57 static struct lump *lp;
58 static char *wworklist = NULL;
59 static char *rworklist = NULL;
62 #define PRINT_HEADER \
63 printf("%13s %7s %13s %5s %13s %13s %9s\n", \
64 "start", "size", "block-len", "state", "done", "remaining", "% done")
66 #define PRINT_STATUS(start, i, len, state, d, t) \
67 printf("\r%13jd %7zu %13jd %5d %13jd %13jd %9.5f", \
74 100*(double)d/(double)t)
76 /* Save the worklist if -w was given */
83 if (wworklist != NULL) {
84 (void)fprintf(stderr, "\nSaving worklist ...");
87 file = fopen(wworklist, "w");
89 err(1, "Error opening file %s", wworklist);
91 TAILQ_FOREACH(llp, &lumps, list)
92 fprintf(file, "%jd %jd %d\n",
93 (intmax_t)llp->start, (intmax_t)llp->len,
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, "usage: recoverdisk [-b bigsize] [-r readlist] "
140 "[-s interval] [-w writelist] source [destination]\n");
145 sighandler(__unused int sig)
152 main(int argc, char * const argv[])
156 off_t t, d, start, len;
164 u_int n, snapshot = 60;
166 while ((ch = getopt(argc, argv, "b:r:w:s:")) != -1) {
169 bigsize = strtoul(optarg, NULL, 0);
172 rworklist = strdup(optarg);
173 if (rworklist == NULL)
174 err(1, "Cannot allocate enough memory");
177 snapshot = strtoul(optarg, NULL, 0);
180 wworklist = strdup(optarg);
181 if (wworklist == NULL)
182 err(1, "Cannot allocate enough memory");
192 if (argc < 1 || argc > 2)
195 fdr = open(argv[0], O_RDONLY);
197 err(1, "Cannot open read descriptor %s", argv[0]);
199 error = fstat(fdr, &sb);
201 err(1, "fstat failed");
202 if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
203 error = ioctl(fdr, DIOCGSECTORSIZE, §orsize);
205 err(1, "DIOCGSECTORSIZE failed");
207 error = ioctl(fdr, DIOCGSTRIPESIZE, &stripesize);
208 if (error == 0 && stripesize > sectorsize)
209 sectorsize = stripesize;
211 minsize = sectorsize;
212 bigsize = rounddown(bigsize, sectorsize);
214 error = ioctl(fdr, DIOCGMEDIASIZE, &t);
216 err(1, "DIOCGMEDIASIZE failed");
221 if (bigsize < minsize)
224 for (ch = 0; (bigsize >> ch) > minsize; ch++)
226 medsize = bigsize >> (ch / 2);
227 medsize = rounddown(medsize, minsize);
229 fprintf(stderr, "Bigsize = %zu, medsize = %zu, minsize = %zu\n",
230 bigsize, medsize, minsize);
232 buf = malloc(bigsize);
234 err(1, "Cannot allocate %zu bytes buffer", bigsize);
237 fdw = open(argv[1], O_WRONLY | O_CREAT, DEFFILEMODE);
239 err(1, "Cannot open write descriptor %s", argv[1]);
240 if (ftruncate(fdw, t) < 0)
241 err(1, "Cannot truncate output %s to %jd bytes",
242 argv[1], (intmax_t)t);
246 if (rworklist != NULL) {
247 d = read_worklist(t);
252 if (wworklist != NULL)
253 signal(SIGINT, sighandler);
256 start = len = i = state = 0;
260 lp = TAILQ_FIRST(&lumps);
263 while (lp->len > 0 && !aborting) {
264 /* These are only copied for printing stats */
269 i = MIN(lp->len, (off_t)bigsize);
271 i = MIN(lp->len, (off_t)medsize);
273 i = MIN(lp->len, (off_t)minsize);
275 if (t1 != t2 || lp->len < (off_t)bigsize) {
276 PRINT_STATUS(start, i, len, state, d, t);
278 if (++n == snapshot) {
284 errx(1, "BOGUS i %10jd", (intmax_t)i);
287 j = pread(fdr, buf, i, lp->start);
291 j = pwrite(fdw, buf, i, lp->start);
295 printf("\nWrite error at %jd/%zu\n",
301 printf("\n%jd %zu failed (%s)\n",
302 lp->start, i, strerror(errno));
303 if (errno == EINVAL) {
304 printf("read() size too big? Try with -b 131072");
309 new_lump(lp->start, i, lp->state + 1);
317 TAILQ_REMOVE(&lumps, lp, list);
320 PRINT_STATUS(start, i, len, state, d, t);
322 printf("\nCompleted\n");