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 22 #define BIGSIZE (1024 * 1024) 23 #define MEDIUMSIZE (64 * 1024) 24 25 struct lump { 26 off_t start; 27 off_t len; 28 int state; 29 TAILQ_ENTRY(lump) list; 30 }; 31 32 static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps); 33 34 35 static void 36 new_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 49 int 50 main(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, §orsize); 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