dd.c (4895B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <ctype.h> 3 #include <fcntl.h> 4 #include <inttypes.h> 5 #include <stdint.h> 6 #include <string.h> 7 #include <unistd.h> 8 9 #include "util.h" 10 11 static off_t ifull, ofull, ipart, opart; 12 13 static void 14 usage(void) 15 { 16 eprintf("usage: %s [operand...]\n", argv0); 17 } 18 19 static size_t 20 parsesize(char *expr) 21 { 22 char *s = expr; 23 size_t n = 1; 24 25 for (;;) { 26 n *= strtoumax(s, &s, 10); 27 switch (*s) { 28 case 'k': n <<= 10; s++; break; 29 case 'b': n <<= 9; s++; break; 30 } 31 if (*s != 'x' || !s[1]) 32 break; 33 s++; 34 } 35 if (*s || n == 0) 36 eprintf("invalid block size expression '%s'\n", expr); 37 38 return n; 39 } 40 41 static void 42 bswap(unsigned char *buf, size_t len) 43 { 44 int c; 45 46 for (len &= ~1; len > 0; buf += 2, len -= 2) { 47 c = buf[0]; 48 buf[0] = buf[1]; 49 buf[1] = c; 50 } 51 } 52 53 static void 54 lcase(unsigned char *buf, size_t len) 55 { 56 for (; len > 0; buf++, len--) 57 buf[0] = tolower(buf[0]); 58 } 59 60 static void 61 ucase(unsigned char *buf, size_t len) 62 { 63 for (; len > 0; buf++, len--) 64 buf[0] = toupper(buf[0]); 65 } 66 67 static void 68 summary(void) 69 { 70 fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records in\n", (intmax_t)ifull, (intmax_t)ipart); 71 fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records out\n", (intmax_t)ofull, (intmax_t)opart); 72 } 73 74 int 75 main(int argc, char *argv[]) 76 { 77 enum { 78 LCASE = 1 << 0, 79 UCASE = 1 << 1, 80 SWAB = 1 << 2, 81 NOERROR = 1 << 3, 82 NOTRUNC = 1 << 4, 83 SYNC = 1 << 5, 84 } conv = 0; 85 char *arg, *val, *end; 86 const char *iname = "-", *oname = "-"; 87 int ifd = 0, ofd = 1, eof = 0; 88 size_t len, bs = 0, ibs = 512, obs = 512, ipos = 0, opos = 0; 89 off_t skip = 0, seek = 0, count = -1; 90 ssize_t ret; 91 unsigned char *buf; 92 93 argv0 = argc ? (argc--, *argv++) : "dd"; 94 for (; argc > 0; argc--, argv++) { 95 arg = *argv; 96 val = strchr(arg, '='); 97 if (!val) 98 usage(); 99 *val++ = '\0'; 100 if (strcmp(arg, "if") == 0) { 101 iname = val; 102 } else if (strcmp(arg, "of") == 0) { 103 oname = val; 104 } else if (strcmp(arg, "ibs") == 0) { 105 ibs = parsesize(val); 106 } else if (strcmp(arg, "obs") == 0) { 107 obs = parsesize(val); 108 } else if (strcmp(arg, "bs") == 0) { 109 bs = parsesize(val); 110 } else if (strcmp(arg, "skip") == 0) { 111 skip = estrtonum(val, 0, LLONG_MAX); 112 } else if (strcmp(arg, "seek") == 0) { 113 seek = estrtonum(val, 0, LLONG_MAX); 114 } else if (strcmp(arg, "count") == 0) { 115 count = estrtonum(val, 0, LLONG_MAX); 116 } else if (strcmp(arg, "conv") == 0) { 117 do { 118 end = strchr(val, ','); 119 if (end) 120 *end++ = '\0'; 121 if (strcmp(val, "lcase") == 0) 122 conv |= LCASE; 123 else if (strcmp(val, "ucase") == 0) 124 conv |= UCASE; 125 else if (strcmp(val, "swab") == 0) 126 conv |= SWAB; 127 else if (strcmp(val, "noerror") == 0) 128 conv |= NOERROR; 129 else if (strcmp(val, "notrunc") == 0) 130 conv |= NOTRUNC; 131 else if (strcmp(val, "sync") == 0) 132 conv |= SYNC; 133 else 134 eprintf("unknown conv flag '%s'\n", val); 135 val = end; 136 } while (val); 137 } else { 138 weprintf("unknown operand '%s'\n", arg); 139 usage(); 140 } 141 } 142 143 if (bs) 144 ibs = obs = bs; 145 if (strcmp(iname, "-") != 0) { 146 ifd = open(iname, O_RDONLY); 147 if (ifd < 0) 148 eprintf("open %s:", iname); 149 } 150 if (strcmp(oname, "-") != 0) { 151 ofd = open(oname, O_WRONLY | O_CREAT | (conv & NOTRUNC || seek ? 0 : O_TRUNC), 0666); 152 if (ofd < 0) 153 eprintf("open %s:", oname); 154 } 155 156 len = MAX(ibs, obs) + ibs; 157 buf = emalloc(len); 158 if (skip && lseek(ifd, skip * ibs, SEEK_SET) < 0) { 159 while (skip--) { 160 ret = read(ifd, buf, ibs); 161 if (ret < 0) 162 eprintf("read:"); 163 if (ret == 0) { 164 eof = 1; 165 break; 166 } 167 } 168 } 169 if (seek) { 170 if (!(conv & NOTRUNC) && ftruncate(ofd, seek * ibs) != 0) 171 eprintf("ftruncate:"); 172 if (lseek(ofd, seek * ibs, SEEK_SET) < 0) 173 eprintf("lseek:"); 174 /* XXX: handle non-seekable files */ 175 } 176 while (!eof) { 177 while (ipos - opos < obs) { 178 if (ifull + ipart == count) { 179 eof = 1; 180 break; 181 } 182 ret = read(ifd, buf + ipos, ibs); 183 if (ret == 0) { 184 eof = 1; 185 break; 186 } 187 if (ret < 0) { 188 weprintf("read:"); 189 if (!(conv & NOERROR)) 190 return 1; 191 summary(); 192 if (!(conv & SYNC)) 193 continue; 194 ret = 0; 195 } 196 if (ret < ibs) { 197 ipart++; 198 if (conv & SYNC) { 199 memset(buf + ipos + ret, 0, ibs - ret); 200 ret = ibs; 201 } 202 } else { 203 ifull++; 204 } 205 if (conv & SWAB) 206 bswap(buf + ipos, ret); 207 if (conv & LCASE) 208 lcase(buf + ipos, ret); 209 if (conv & UCASE) 210 ucase(buf + ipos, ret); 211 ipos += ret; 212 if (bs && !(conv & (SWAB | LCASE | UCASE))) 213 break; 214 } 215 if (ipos == opos) 216 break; 217 do { 218 ret = write(ofd, buf + opos, MIN(obs, ipos - opos)); 219 if (ret < 0) 220 eprintf("write:"); 221 if (ret == 0) 222 eprintf("write returned 0\n"); 223 if (ret < obs) 224 opart++; 225 else 226 ofull++; 227 opos += ret; 228 } while (ipos - opos >= (eof ? 1 : obs)); 229 if (opos < ipos) 230 memmove(buf, buf + opos, ipos - opos); 231 ipos -= opos; 232 opos = 0; 233 } 234 summary(); 235 236 return 0; 237 }