recoverdisk.c revision 135911
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 135911 2004-09-28 22:00:01Z phk $
10135911Sphk */
11135911Sphk#include <stdio.h>
12135911Sphk#include <stdint.h>
13135911Sphk#include <stdlib.h>
14135911Sphk#include <errno.h>
15135911Sphk#include <fcntl.h>
16135911Sphk#include <err.h>
17135911Sphk#include <unistd.h>
18135911Sphk#include <sys/queue.h>
19135911Sphk#include <sys/disk.h>
20135911Sphk
21135911Sphk#define BIGSIZE		(1024 * 1024)
22135911Sphk#define MEDIUMSIZE	(64 * 1024)
23135911Sphk
24135911Sphkstruct lump {
25135911Sphk	off_t			start;
26135911Sphk	off_t			len;
27135911Sphk	int			state;
28135911Sphk	TAILQ_ENTRY(lump)	list;
29135911Sphk};
30135911Sphk
31135911Sphkstatic TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
32135911Sphk
33135911Sphk
34135911Sphkstatic void
35135911Sphknew_lump(off_t start, off_t len, int state)
36135911Sphk{
37135911Sphk	struct lump *lp;
38135911Sphk
39135911Sphk	lp = malloc(sizeof *lp);
40135911Sphk	if (lp == NULL)
41135911Sphk		err(1, "Malloc failed");
42135911Sphk	lp->start = start;
43135911Sphk	lp->len = len;
44135911Sphk	lp->state = state;
45135911Sphk	TAILQ_INSERT_TAIL(&lumps, lp, list);
46135911Sphk}
47135911Sphk
48135911Sphkint
49135911Sphkmain(int argc, const char **argv)
50135911Sphk{
51135911Sphk	int fdr, fdw;
52135911Sphk	struct lump *lp;
53135911Sphk	off_t 	t, d;
54135911Sphk	size_t i, j;
55135911Sphk	int error;
56135911Sphk	u_char *buf;
57135911Sphk	u_int sectorsize;
58135911Sphk
59135911Sphk
60135911Sphk	if (argc < 2)
61135911Sphk		errx(1, "Usage: %s source-drive [destination]", argv[0]);
62135911Sphk
63135911Sphk	buf = malloc(BIGSIZE);
64135911Sphk	if (buf == NULL)
65135911Sphk		err(1, "Cannot allocate %d bytes buffer", BIGSIZE);
66135911Sphk	fdr = open(argv[1], O_RDONLY);
67135911Sphk	if (fdr < 0)
68135911Sphk		err(1, "Cannot open read descriptor %s", argv[1]);
69135911Sphk	if (argc > 2) {
70135911Sphk		fdw = open(argv[2], O_WRONLY);
71135911Sphk		if (fdw < 0)
72135911Sphk			err(1, "Cannot open write descriptor %s", argv[2]);
73135911Sphk	} else {
74135911Sphk		fdw = -1;
75135911Sphk	}
76135911Sphk
77135911Sphk	error = ioctl(fdr, DIOCGSECTORSIZE, &sectorsize);
78135911Sphk	if (error < 0)
79135911Sphk		err(1, "DIOCGSECTORSIZE failed");
80135911Sphk
81135911Sphk	error = ioctl(fdr, DIOCGMEDIASIZE, &t);
82135911Sphk	if (error < 0)
83135911Sphk		err(1, "DIOCGMEDIASIZE failed");
84135911Sphk
85135911Sphk	new_lump(0, t, 0);
86135911Sphk	d = 0;
87135911Sphk
88135911Sphk	for (;;) {
89135911Sphk		lp = TAILQ_FIRST(&lumps);
90135911Sphk		if (lp == NULL)
91135911Sphk			break;
92135911Sphk		TAILQ_REMOVE(&lumps, lp, list);
93135911Sphk		while (lp->len > 0) {
94135911Sphk			i = BIGSIZE;
95135911Sphk			if (lp->len < BIGSIZE)
96135911Sphk				i = lp->len;
97135911Sphk			if (lp->state == 1)
98135911Sphk				i = MEDIUMSIZE;
99135911Sphk			if (lp->state > 1)
100135911Sphk				i = sectorsize;
101135911Sphk			printf("\r%13jd %7jd %13jd %3d %13jd %13jd %.8f",
102135911Sphk			    (intmax_t)lp->start,
103135911Sphk			    (intmax_t)i,
104135911Sphk			    (intmax_t)lp->len,
105135911Sphk			    lp->state,
106135911Sphk			    (intmax_t)d,
107135911Sphk			    (intmax_t)(t - d),
108135911Sphk			    (double)d/(double)t);
109135911Sphk			if (i == 0) {
110135911Sphk				errx(1, "BOGUS i %10jd", (intmax_t)i);
111135911Sphk			}
112135911Sphk			fflush(stdout);
113135911Sphk			j = pread(fdr, buf, i, lp->start);
114135911Sphk			if (j == i) {
115135911Sphk				d += i;
116135911Sphk				if (fdw >= 0)
117135911Sphk					j = pwrite(fdw, buf, i, lp->start);
118135911Sphk				else
119135911Sphk					j = i;
120135911Sphk				if (j != i)
121135911Sphk					printf("\nWrite error at %jd/%d\n",
122135911Sphk					    lp->start, i);
123135911Sphk				lp->start += i;
124135911Sphk				lp->len -= i;
125135911Sphk				continue;
126135911Sphk			}
127135911Sphk			printf("\n%jd %d failed %d\n", lp->start, i, errno);
128135911Sphk			new_lump(lp->start, i, lp->state + 1);
129135911Sphk			lp->start += i;
130135911Sphk			lp->len -= i;
131135911Sphk		}
132135911Sphk		free(lp);
133135911Sphk	}
134135911Sphk	printf("\nCompleted\n");
135135911Sphk	exit (0);
136135911Sphk}
137135911Sphk
138