dd.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
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 }