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;
59 /* Save the worklist if -w was given */
65 if (wworklist != NULL) {
66 (void)fprintf(stderr, "\nSaving worklist ...");
69 file = fopen(wworklist, "w");
71 err(1, "Error opening file %s", wworklist);
74 lp = TAILQ_FIRST(&lumps);
77 fprintf(file, "%jd %jd %d\n",
78 (intmax_t)lp->start, (intmax_t)lp->len, lp->state);
79 TAILQ_REMOVE(&lumps, lp, list);
81 (void)fprintf(stderr, " done.\n");
85 /* Read the worklist if -r was given */
87 read_worklist(off_t t)
93 (void)fprintf(stderr, "Reading worklist ...");
95 file = fopen(rworklist, "r");
97 err(1, "Error opening file %s", rworklist);
103 if (3 != fscanf(file, "%jd %jd %d\n", &s, &l, &state)) {
105 err(1, "Error parsing file %s at line %d",
110 new_lump(s, l, state);
113 (void)fprintf(stderr, " done.\n");
115 * Return the number of bytes already read
116 * (at least not in worklist).
124 (void)fprintf(stderr,
125 "usage: recoverdisk [-r worklist] [-w worklist] source-drive [destination]\n");
130 sighandler(__unused int sig)
137 main(int argc, char * const argv[])
149 while ((ch = getopt(argc, argv, "r:w:")) != -1) {
152 rworklist = strdup(optarg);
153 if (rworklist == NULL)
154 err(1, "Cannot allocate enough memory");
157 wworklist = strdup(optarg);
158 if (wworklist == NULL)
159 err(1, "Cannot allocate enough memory");
169 if (argc < 1 || argc > 2)
172 fdr = open(argv[0], O_RDONLY);
174 err(1, "Cannot open read descriptor %s", argv[0]);
176 error = fstat(fdr, &sb);
178 err(1, "fstat failed");
180 if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
181 error = ioctl(fdr, DIOCGSECTORSIZE, §orsize);
183 err(1, "DIOCGSECTORSIZE failed");
186 * Make medsize roughly 64kB, depending on native sector
187 * size. bigsize has to be a multiple of medsize.
188 * For media with 2352 sectors, this will
189 * result in 2352, 63504, and 1016064 bytes.
191 minsize = sectorsize;
192 medsize = (medsize / sectorsize) * sectorsize;
193 bigsize = medsize * 16;
195 error = ioctl(fdr, DIOCGMEDIASIZE, &t);
197 err(1, "DIOCGMEDIASIZE failed");
200 flags |= O_CREAT | O_TRUNC;
203 buf = malloc(bigsize);
205 err(1, "Cannot allocate %jd bytes buffer", (intmax_t)bigsize);
208 fdw = open(argv[1], flags, DEFFILEMODE);
210 err(1, "Cannot open write descriptor %s", argv[1]);
214 if (rworklist != NULL) {
215 d = read_worklist(t);
220 if (wworklist != NULL)
221 signal(SIGINT, sighandler);
224 printf("%13s %7s %13s %5s %13s %13s %9s\n",
225 "start", "size", "len", "state", "done", "remaining", "% done");
227 lp = TAILQ_FIRST(&lumps);
230 while (lp->len > 0 && !aborting) {
231 i = MIN(lp->len, (off_t)bigsize);
233 i = MIN(lp->len, (off_t)medsize);
235 i = MIN(lp->len, (off_t)minsize);
237 if (t1 != t2 || lp->len < (off_t)bigsize) {
238 printf("\r%13jd %7zu %13jd %5d %13jd %13jd %.7f",
245 (double)d/(double)t);
249 errx(1, "BOGUS i %10jd", (intmax_t)i);
252 j = pread(fdr, buf, i, lp->start);
256 j = pwrite(fdw, buf, i, lp->start);
260 printf("\nWrite error at %jd/%zu\n",
266 printf("\n%jd %zu failed %d\n", lp->start, i, errno);
267 new_lump(lp->start, i, lp->state + 1);
275 TAILQ_REMOVE(&lumps, lp, list);
278 printf("\nCompleted\n");