]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/recoverdisk/recoverdisk.c
This commit was generated by cvs2svn to compensate for changes in r150765,
[FreeBSD/FreeBSD.git] / tools / tools / recoverdisk / recoverdisk.c
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$
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 #include <sys/stat.h>
22
23 #define BIGSIZE         (1024 * 1024)
24 #define MEDIUMSIZE      (64 * 1024)
25 #define MINSIZE         (512)
26
27 struct lump {
28         off_t                   start;
29         off_t                   len;
30         int                     state;
31         TAILQ_ENTRY(lump)       list;
32 };
33
34 static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
35
36
37 static void
38 new_lump(off_t start, off_t len, int state)
39 {
40         struct lump *lp;
41
42         lp = malloc(sizeof *lp);
43         if (lp == NULL)
44                 err(1, "Malloc failed");
45         lp->start = start;
46         lp->len = len;
47         lp->state = state;
48         TAILQ_INSERT_TAIL(&lumps, lp, list);
49 }
50
51 int
52 main(int argc, const char **argv)
53 {
54         int fdr, fdw;
55         struct lump *lp;
56         off_t   t, d;
57         size_t i, j;
58         int error, flags;
59         u_char *buf;
60         u_int sectorsize, minsize;
61         time_t t1, t2;
62         struct stat sb;
63
64
65         if (argc < 2)
66                 errx(1, "Usage: %s source-drive [destination]", argv[0]);
67
68         buf = malloc(BIGSIZE);
69         if (buf == NULL)
70                 err(1, "Cannot allocate %d bytes buffer", BIGSIZE);
71         fdr = open(argv[1], O_RDONLY);
72         if (fdr < 0)
73                 err(1, "Cannot open read descriptor %s", argv[1]);
74
75         error = fstat(fdr, &sb);
76         if (error < 0)
77                 err(1, "fstat failed");
78         flags = O_WRONLY;
79         if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
80                 error = ioctl(fdr, DIOCGSECTORSIZE, &sectorsize);
81                 if (error < 0)
82                         err(1, "DIOCGSECTORSIZE failed");
83                 minsize = sectorsize;
84
85                 error = ioctl(fdr, DIOCGMEDIASIZE, &t);
86                 if (error < 0)
87                         err(1, "DIOCGMEDIASIZE failed");
88         } else {
89                 sectorsize = 1;
90                 t = sb.st_size;
91                 minsize = MINSIZE;
92                 flags |= O_CREAT | O_TRUNC;
93         }
94
95         if (argc > 2) {
96                 fdw = open(argv[2], flags, DEFFILEMODE);
97                 if (fdw < 0)
98                         err(1, "Cannot open write descriptor %s", argv[2]);
99         } else {
100                 fdw = -1;
101         }
102
103         new_lump(0, t, 0);
104         d = 0;
105
106         t1 = 0;
107         for (;;) {
108                 lp = TAILQ_FIRST(&lumps);
109                 if (lp == NULL)
110                         break;
111                 TAILQ_REMOVE(&lumps, lp, list);
112                 while (lp->len > 0) {
113                         i = BIGSIZE;
114                         if (lp->len < BIGSIZE)
115                                 i = lp->len;
116                         if (lp->state == 1)
117                                 i = MEDIUMSIZE;
118                         if (lp->state > 1)
119                                 i = minsize;
120                         time(&t2);
121                         if (t1 != t2 || lp->len < BIGSIZE) {
122                                 printf("\r%13jd %7zu %13jd %3d %13jd %13jd %.8f",
123                                     (intmax_t)lp->start,
124                                     i, 
125                                     (intmax_t)lp->len,
126                                     lp->state,
127                                     (intmax_t)d,
128                                     (intmax_t)(t - d),
129                                     (double)d/(double)t);
130                                 t1 = t2;
131                         }
132                         if (i == 0) {
133                                 errx(1, "BOGUS i %10jd", (intmax_t)i);
134                         }
135                         fflush(stdout);
136                         j = pread(fdr, buf, i, lp->start);
137                         if (j == i) {
138                                 d += i;
139                                 if (fdw >= 0)
140                                         j = pwrite(fdw, buf, i, lp->start);
141                                 else
142                                         j = i;
143                                 if (j != i)
144                                         printf("\nWrite error at %jd/%zu\n",
145                                             lp->start, i);
146                                 lp->start += i;
147                                 lp->len -= i;
148                                 continue;
149                         }
150                         printf("\n%jd %zu failed %d\n", lp->start, i, errno);
151                         new_lump(lp->start, i, lp->state + 1);
152                         lp->start += i;
153                         lp->len -= i;
154                 }
155                 free(lp);
156         }
157         printf("\nCompleted\n");
158         exit (0);
159 }
160