recoverdisk.c revision 136815
1/*
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 * ----------------------------------------------------------------------------
8 *
9 * $FreeBSD: head/sbin/recoverdisk/recoverdisk.c 136815 2004-10-23 15:58:50Z des $
10 */
11#include <stdio.h>
12#include <stdint.h>
13#include <stdlib.h>
14#include <err.h>
15#include <errno.h>
16#include <fcntl.h>
17#include <time.h>
18#include <unistd.h>
19#include <sys/queue.h>
20#include <sys/disk.h>
21
22#define BIGSIZE		(1024 * 1024)
23#define MEDIUMSIZE	(64 * 1024)
24
25struct lump {
26	off_t			start;
27	off_t			len;
28	int			state;
29	TAILQ_ENTRY(lump)	list;
30};
31
32static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
33
34
35static void
36new_lump(off_t start, off_t len, int state)
37{
38	struct lump *lp;
39
40	lp = malloc(sizeof *lp);
41	if (lp == NULL)
42		err(1, "Malloc failed");
43	lp->start = start;
44	lp->len = len;
45	lp->state = state;
46	TAILQ_INSERT_TAIL(&lumps, lp, list);
47}
48
49int
50main(int argc, const char **argv)
51{
52	int fdr, fdw;
53	struct lump *lp;
54	off_t 	t, d;
55	size_t i, j;
56	int error;
57	u_char *buf;
58	u_int sectorsize;
59	time_t t1, t2;
60
61
62	if (argc < 2)
63		errx(1, "Usage: %s source-drive [destination]", argv[0]);
64
65	buf = malloc(BIGSIZE);
66	if (buf == NULL)
67		err(1, "Cannot allocate %d bytes buffer", BIGSIZE);
68	fdr = open(argv[1], O_RDONLY);
69	if (fdr < 0)
70		err(1, "Cannot open read descriptor %s", argv[1]);
71	if (argc > 2) {
72		fdw = open(argv[2], O_WRONLY);
73		if (fdw < 0)
74			err(1, "Cannot open write descriptor %s", argv[2]);
75	} else {
76		fdw = -1;
77	}
78
79	error = ioctl(fdr, DIOCGSECTORSIZE, &sectorsize);
80	if (error < 0)
81		err(1, "DIOCGSECTORSIZE failed");
82
83	error = ioctl(fdr, DIOCGMEDIASIZE, &t);
84	if (error < 0)
85		err(1, "DIOCGMEDIASIZE failed");
86
87	new_lump(0, t, 0);
88	d = 0;
89
90	t1 = 0;
91	for (;;) {
92		lp = TAILQ_FIRST(&lumps);
93		if (lp == NULL)
94			break;
95		TAILQ_REMOVE(&lumps, lp, list);
96		while (lp->len > 0) {
97			i = BIGSIZE;
98			if (lp->len < BIGSIZE)
99				i = lp->len;
100			if (lp->state == 1)
101				i = MEDIUMSIZE;
102			if (lp->state > 1)
103				i = sectorsize;
104			time(&t2);
105			if (t1 != t2 || lp->len < BIGSIZE) {
106				printf("\r%13jd %7zu %13jd %3d %13jd %13jd %.8f",
107				    (intmax_t)lp->start,
108				    i,
109				    (intmax_t)lp->len,
110				    lp->state,
111				    (intmax_t)d,
112				    (intmax_t)(t - d),
113				    (double)d/(double)t);
114				t1 = t2;
115			}
116			if (i == 0) {
117				errx(1, "BOGUS i %10jd", (intmax_t)i);
118			}
119			fflush(stdout);
120			j = pread(fdr, buf, i, lp->start);
121			if (j == i) {
122				d += i;
123				if (fdw >= 0)
124					j = pwrite(fdw, buf, i, lp->start);
125				else
126					j = i;
127				if (j != i)
128					printf("\nWrite error at %jd/%zu\n",
129					    lp->start, i);
130				lp->start += i;
131				lp->len -= i;
132				continue;
133			}
134			printf("\n%jd %zu failed %d\n", lp->start, i, errno);
135			new_lump(lp->start, i, lp->state + 1);
136			lp->start += i;
137			lp->len -= i;
138		}
139		free(lp);
140	}
141	printf("\nCompleted\n");
142	exit (0);
143}
144
145