dd.c - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
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)… | |
71 fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records out\n", (intmax_t… | |
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'\… | |
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 |… | |
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 … | |
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 - opo… | |
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 } |