dd.c 4.8 KB

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