recoverdisk.c revision 136815
1135911Sphk/*
2135911Sphk * ----------------------------------------------------------------------------
3135911Sphk * "THE BEER-WARE LICENSE" (Revision 42):
4135911Sphk * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5135911Sphk * can do whatever you want with this stuff. If we meet some day, and you think
6135911Sphk * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7135911Sphk * ----------------------------------------------------------------------------
8135911Sphk *
9135911Sphk * $FreeBSD: head/sbin/recoverdisk/recoverdisk.c 136815 2004-10-23 15:58:50Z des $
10135911Sphk */
11135911Sphk#include <stdio.h>
12135911Sphk#include <stdint.h>
13135911Sphk#include <stdlib.h>
14136257Sphk#include <err.h>
15135911Sphk#include <errno.h>
16135911Sphk#include <fcntl.h>
17136257Sphk#include <time.h>
18135911Sphk#include <unistd.h>
19135911Sphk#include <sys/queue.h>
20135911Sphk#include <sys/disk.h>
21135911Sphk
22135911Sphk#define BIGSIZE		(1024 * 1024)
23135911Sphk#define MEDIUMSIZE	(64 * 1024)
24135911Sphk
25135911Sphkstruct lump {
26135911Sphk	off_t			start;
27135911Sphk	off_t			len;
28135911Sphk	int			state;
29135911Sphk	TAILQ_ENTRY(lump)	list;
30135911Sphk};
31135911Sphk
32135911Sphkstatic TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
33135911Sphk
34135911Sphk
35135911Sphkstatic void
36135911Sphknew_lump(off_t start, off_t len, int state)
37135911Sphk{
38135911Sphk	struct lump *lp;
39135911Sphk
40135911Sphk	lp = malloc(sizeof *lp);
41135911Sphk	if (lp == NULL)
42135911Sphk		err(1, "Malloc failed");
43135911Sphk	lp->start = start;
44135911Sphk	lp->len = len;
45135911Sphk	lp->state = state;
46135911Sphk	TAILQ_INSERT_TAIL(&lumps, lp, list);
47135911Sphk}
48135911Sphk
49135911Sphkint
50135911Sphkmain(int argc, const char **argv)
51135911Sphk{
52135911Sphk	int fdr, fdw;
53135911Sphk	struct lump *lp;
54135911Sphk	off_t 	t, d;
55135911Sphk	size_t i, j;
56135911Sphk	int error;
57135911Sphk	u_char *buf;
58135911Sphk	u_int sectorsize;
59136257Sphk	time_t t1, t2;
60135911Sphk
61135911Sphk
62135911Sphk	if (argc < 2)
63135911Sphk		errx(1, "Usage: %s source-drive [destination]", argv[0]);
64135911Sphk
65135911Sphk	buf = malloc(BIGSIZE);
66135911Sphk	if (buf == NULL)
67135911Sphk		err(1, "Cannot allocate %d bytes buffer", BIGSIZE);
68135911Sphk	fdr = open(argv[1], O_RDONLY);
69135911Sphk	if (fdr < 0)
70135911Sphk		err(1, "Cannot open read descriptor %s", argv[1]);
71135911Sphk	if (argc > 2) {
72135911Sphk		fdw = open(argv[2], O_WRONLY);
73135911Sphk		if (fdw < 0)
74135911Sphk			err(1, "Cannot open write descriptor %s", argv[2]);
75135911Sphk	} else {
76135911Sphk		fdw = -1;
77135911Sphk	}
78135911Sphk
79135911Sphk	error = ioctl(fdr, DIOCGSECTORSIZE, &sectorsize);
80135911Sphk	if (error < 0)
81135911Sphk		err(1, "DIOCGSECTORSIZE failed");
82135911Sphk
83135911Sphk	error = ioctl(fdr, DIOCGMEDIASIZE, &t);
84135911Sphk	if (error < 0)
85135911Sphk		err(1, "DIOCGMEDIASIZE failed");
86135911Sphk
87135911Sphk	new_lump(0, t, 0);
88135911Sphk	d = 0;
89135911Sphk
90136257Sphk	t1 = 0;
91135911Sphk	for (;;) {
92135911Sphk		lp = TAILQ_FIRST(&lumps);
93135911Sphk		if (lp == NULL)
94135911Sphk			break;
95135911Sphk		TAILQ_REMOVE(&lumps, lp, list);
96135911Sphk		while (lp->len > 0) {
97135911Sphk			i = BIGSIZE;
98135911Sphk			if (lp->len < BIGSIZE)
99135911Sphk				i = lp->len;
100135911Sphk			if (lp->state == 1)
101135911Sphk				i = MEDIUMSIZE;
102135911Sphk			if (lp->state > 1)
103135911Sphk				i = sectorsize;
104136257Sphk			time(&t2);
105136257Sphk			if (t1 != t2 || lp->len < BIGSIZE) {
106136815Sdes				printf("\r%13jd %7zu %13jd %3d %13jd %13jd %.8f",
107136257Sphk				    (intmax_t)lp->start,
108136815Sdes				    i,
109136257Sphk				    (intmax_t)lp->len,
110136257Sphk				    lp->state,
111136257Sphk				    (intmax_t)d,
112136257Sphk				    (intmax_t)(t - d),
113136257Sphk				    (double)d/(double)t);
114136257Sphk				t1 = t2;
115136257Sphk			}
116135911Sphk			if (i == 0) {
117135911Sphk				errx(1, "BOGUS i %10jd", (intmax_t)i);
118135911Sphk			}
119135911Sphk			fflush(stdout);
120135911Sphk			j = pread(fdr, buf, i, lp->start);
121135911Sphk			if (j == i) {
122135911Sphk				d += i;
123135911Sphk				if (fdw >= 0)
124135911Sphk					j = pwrite(fdw, buf, i, lp->start);
125135911Sphk				else
126135911Sphk					j = i;
127135911Sphk				if (j != i)
128136815Sdes					printf("\nWrite error at %jd/%zu\n",
129136815Sdes					    lp->start, i);
130135911Sphk				lp->start += i;
131135911Sphk				lp->len -= i;
132135911Sphk				continue;
133135911Sphk			}
134136815Sdes			printf("\n%jd %zu failed %d\n", lp->start, i, errno);
135135911Sphk			new_lump(lp->start, i, lp->state + 1);
136135911Sphk			lp->start += i;
137135911Sphk			lp->len -= i;
138135911Sphk		}
139135911Sphk		free(lp);
140135911Sphk	}
141135911Sphk	printf("\nCompleted\n");
142135911Sphk	exit (0);
143135911Sphk}
144135911Sphk
145