1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96#include "libbb.h"
97#include "common_bufsiz.h"
98
99
100
101
102enum {
103 ifd = STDIN_FILENO,
104 ofd = STDOUT_FILENO,
105};
106
107struct globals {
108 off_t out_full, out_part, in_full, in_part;
109#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
110 unsigned long long total_bytes;
111 unsigned long long begin_time_us;
112#endif
113 int flags;
114} FIX_ALIASING;
115#define G (*(struct globals*)bb_common_bufsiz1)
116#define INIT_G() do { \
117 setup_common_bufsiz(); \
118 \
119 memset(&G, 0, sizeof(G)); \
120} while (0)
121
122enum {
123
124
125 FLAG_NOTRUNC = (1 << 0) * ENABLE_FEATURE_DD_IBS_OBS,
126 FLAG_SYNC = (1 << 1) * ENABLE_FEATURE_DD_IBS_OBS,
127 FLAG_NOERROR = (1 << 2) * ENABLE_FEATURE_DD_IBS_OBS,
128 FLAG_FSYNC = (1 << 3) * ENABLE_FEATURE_DD_IBS_OBS,
129 FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS,
130
131
132 FLAG_IFLAG_SHIFT = 5,
133 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
134 FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
135
136 FLAG_TWOBUFS = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
137 FLAG_COUNT = 1 << 8,
138 FLAG_STATUS_NONE = 1 << 9,
139 FLAG_STATUS_NOXFER = 1 << 10,
140};
141
142static void dd_output_status(int UNUSED_PARAM cur_signal)
143{
144#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
145 double seconds;
146 unsigned long long bytes_sec;
147 unsigned long long now_us = monotonic_us();
148#endif
149
150
151 fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n"
152 "%"OFF_FMT"u+%"OFF_FMT"u records out\n",
153 G.in_full, G.in_part,
154 G.out_full, G.out_part);
155
156#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
157# if ENABLE_FEATURE_DD_STATUS
158 if (G.flags & FLAG_STATUS_NOXFER)
159 return;
160
161
162
163# endif
164 fprintf(stderr, "%llu bytes (%sB) copied, ",
165 G.total_bytes,
166
167 make_human_readable_str(G.total_bytes, 1, 0)
168 );
169
170
171
172
173
174
175 seconds = (now_us - G.begin_time_us) / 1000000.0;
176 bytes_sec = G.total_bytes / seconds;
177 fprintf(stderr, "%f seconds, %sB/s\n",
178 seconds,
179
180 make_human_readable_str(bytes_sec, 1, 0)
181 );
182#endif
183}
184
185static ssize_t full_write_or_warn(const void *buf, size_t len,
186 const char *const filename)
187{
188 ssize_t n = full_write(ofd, buf, len);
189 if (n < 0)
190 bb_perror_msg("writing '%s'", filename);
191 return n;
192}
193
194static bool write_and_stats(const void *buf, size_t len, size_t obs,
195 const char *filename)
196{
197 ssize_t n = full_write_or_warn(buf, len, filename);
198 if (n < 0)
199 return 1;
200#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
201 G.total_bytes += n;
202#endif
203 if ((size_t)n == obs) {
204 G.out_full++;
205 return 0;
206 }
207 if ((size_t)n == len) {
208 G.out_part++;
209 return 0;
210 }
211 return 1;
212}
213
214#if ENABLE_LFS
215# define XATOU_SFX xatoull_sfx
216#else
217# define XATOU_SFX xatoul_sfx
218#endif
219
220#if ENABLE_FEATURE_DD_IBS_OBS
221static int parse_comma_flags(char *val, const char *words, const char *error_in)
222{
223 int flags = 0;
224 while (1) {
225 int n;
226 char *arg;
227
228
229
230
231 arg = strchr(val, ',');
232 if (arg)
233 *arg = '\0';
234 n = index_in_strings(words, val);
235 if (n < 0)
236 bb_error_msg_and_die(bb_msg_invalid_arg_to, val, error_in);
237 flags |= (1 << n);
238 if (!arg)
239 break;
240 *arg = ',';
241 val = arg + 1;
242 }
243 return flags;
244}
245#endif
246
247int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
248int dd_main(int argc UNUSED_PARAM, char **argv)
249{
250 static const char keywords[] ALIGN1 =
251 "bs\0""count\0""seek\0""skip\0""if\0""of\0"IF_FEATURE_DD_STATUS("status\0")
252#if ENABLE_FEATURE_DD_IBS_OBS
253 "ibs\0""obs\0""conv\0""iflag\0"
254#endif
255 ;
256#if ENABLE_FEATURE_DD_IBS_OBS
257 static const char conv_words[] ALIGN1 =
258 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
259 static const char iflag_words[] ALIGN1 =
260 "skip_bytes\0""fullblock\0";
261#endif
262#if ENABLE_FEATURE_DD_STATUS
263 static const char status_words[] ALIGN1 =
264 "none\0""noxfer\0";
265#endif
266 enum {
267 OP_bs = 0,
268 OP_count,
269 OP_seek,
270 OP_skip,
271 OP_if,
272 OP_of,
273 IF_FEATURE_DD_STATUS(OP_status,)
274#if ENABLE_FEATURE_DD_IBS_OBS
275 OP_ibs,
276 OP_obs,
277 OP_conv,
278 OP_iflag,
279
280 OP_conv_notrunc = 0,
281 OP_conv_sync,
282 OP_conv_noerror,
283 OP_conv_fsync,
284 OP_conv_swab,
285
286
287
288
289
290
291
292
293
294
295
296
297
298 OP_iflag_skip_bytes,
299 OP_iflag_fullblock,
300#endif
301 };
302 smallint exitcode = EXIT_FAILURE;
303 int i;
304 size_t ibs = 512;
305 char *ibuf;
306#if ENABLE_FEATURE_DD_IBS_OBS
307 size_t obs = 512;
308 char *obuf;
309#else
310# define obs ibs
311# define obuf ibuf
312#endif
313
314 struct {
315 size_t oc;
316 ssize_t prev_read_size;
317 off_t count;
318 off_t seek, skip;
319 const char *infile, *outfile;
320 } Z;
321#define oc (Z.oc )
322#define prev_read_size (Z.prev_read_size)
323#define count (Z.count )
324#define seek (Z.seek )
325#define skip (Z.skip )
326#define infile (Z.infile )
327#define outfile (Z.outfile)
328
329 memset(&Z, 0, sizeof(Z));
330 INIT_G();
331
332
333 for (i = 1; argv[i]; i++) {
334 int what;
335 char *val;
336 char *arg = argv[i];
337
338#if ENABLE_DESKTOP
339
340
341 if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0')
342 continue;
343#endif
344 val = strchr(arg, '=');
345 if (val == NULL)
346 bb_show_usage();
347 *val = '\0';
348 what = index_in_strings(keywords, arg);
349 if (what < 0)
350 bb_show_usage();
351
352 val++;
353#if ENABLE_FEATURE_DD_IBS_OBS
354 if (what == OP_ibs) {
355
356 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
357
358 }
359 if (what == OP_obs) {
360 obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
361
362 }
363 if (what == OP_conv) {
364 G.flags |= parse_comma_flags(val, conv_words, "conv");
365
366 }
367 if (what == OP_iflag) {
368 G.flags |= parse_comma_flags(val, iflag_words, "iflag") << FLAG_IFLAG_SHIFT;
369
370 }
371#endif
372 if (what == OP_bs) {
373 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
374 obs = ibs;
375
376 }
377
378 if (what == OP_count) {
379 G.flags |= FLAG_COUNT;
380 count = XATOU_SFX(val, cwbkMG_suffixes);
381
382 }
383 if (what == OP_seek) {
384 seek = XATOU_SFX(val, cwbkMG_suffixes);
385
386 }
387 if (what == OP_skip) {
388 skip = XATOU_SFX(val, cwbkMG_suffixes);
389
390 }
391 if (what == OP_if) {
392 infile = val;
393
394 }
395 if (what == OP_of) {
396 outfile = val;
397
398 }
399#if ENABLE_FEATURE_DD_STATUS
400 if (what == OP_status) {
401 int n;
402 n = index_in_strings(status_words, val);
403 if (n < 0)
404 bb_error_msg_and_die(bb_msg_invalid_arg_to, val, "status");
405 G.flags |= FLAG_STATUS_NONE << n;
406
407 }
408#endif
409 }
410
411
412 ibuf = xmalloc(ibs);
413 obuf = ibuf;
414#if ENABLE_FEATURE_DD_IBS_OBS
415 if (ibs != obs) {
416 G.flags |= FLAG_TWOBUFS;
417 obuf = xmalloc(obs);
418 }
419#endif
420
421#if ENABLE_FEATURE_DD_SIGNAL_HANDLING
422 signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status);
423#endif
424#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
425 G.begin_time_us = monotonic_us();
426#endif
427
428 if (infile) {
429 xmove_fd(xopen(infile, O_RDONLY), ifd);
430 } else {
431 infile = bb_msg_standard_input;
432 }
433 if (outfile) {
434 int oflag = O_WRONLY | O_CREAT;
435
436 if (!seek && !(G.flags & FLAG_NOTRUNC))
437 oflag |= O_TRUNC;
438
439 xmove_fd(xopen(outfile, oflag), ofd);
440
441 if (seek && !(G.flags & FLAG_NOTRUNC)) {
442 if (ftruncate(ofd, seek * obs) < 0) {
443 struct stat st;
444
445 if (fstat(ofd, &st) < 0
446 || S_ISREG(st.st_mode)
447 || S_ISDIR(st.st_mode)
448 ) {
449 goto die_outfile;
450 }
451 }
452 }
453 } else {
454 outfile = bb_msg_standard_output;
455 }
456 if (skip) {
457 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs;
458 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) {
459 do {
460 ssize_t n;
461#if ENABLE_FEATURE_DD_IBS_OBS
462 if (G.flags & FLAG_FULLBLOCK)
463 n = full_read(ifd, ibuf, blocksz);
464 else
465#endif
466 n = safe_read(ifd, ibuf, blocksz);
467 if (n < 0)
468 goto die_infile;
469 if (n == 0)
470 break;
471 } while (--skip != 0);
472 }
473 }
474 if (seek) {
475 if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
476 goto die_outfile;
477 }
478
479 while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
480 ssize_t n;
481#if ENABLE_FEATURE_DD_IBS_OBS
482 if (G.flags & FLAG_FULLBLOCK)
483 n = full_read(ifd, ibuf, ibs);
484 else
485#endif
486 n = safe_read(ifd, ibuf, ibs);
487 if (n == 0)
488 break;
489 if (n < 0) {
490
491 if (!(G.flags & FLAG_NOERROR))
492 goto die_infile;
493 bb_simple_perror_msg(infile);
494
495 xlseek(ifd, ibs, SEEK_CUR);
496
497
498 n = 0;
499 }
500 if (G.flags & FLAG_SWAB) {
501 uint16_t *p16;
502 ssize_t n2;
503
504
505 if (prev_read_size & 1)
506 bb_error_msg_and_die("can't swab %lu byte buffer",
507 (unsigned long)prev_read_size);
508 prev_read_size = n;
509
510
511
512
513
514 p16 = (void*) ibuf;
515 n2 = (n >> 1);
516 while (--n2 >= 0) {
517 *p16 = bswap_16(*p16);
518 p16++;
519 }
520 }
521 if ((size_t)n == ibs)
522 G.in_full++;
523 else {
524 G.in_part++;
525 if (G.flags & FLAG_SYNC) {
526 memset(ibuf + n, 0, ibs - n);
527 n = ibs;
528 }
529 }
530 if (G.flags & FLAG_TWOBUFS) {
531 char *tmp = ibuf;
532 while (n) {
533 size_t d = obs - oc;
534
535 if (d > (size_t)n)
536 d = n;
537 memcpy(obuf + oc, tmp, d);
538 n -= d;
539 tmp += d;
540 oc += d;
541 if (oc == obs) {
542 if (write_and_stats(obuf, obs, obs, outfile))
543 goto out_status;
544 oc = 0;
545 }
546 }
547 } else {
548 if (write_and_stats(ibuf, n, obs, outfile))
549 goto out_status;
550 }
551 }
552
553 if (G.flags & FLAG_FSYNC) {
554 if (fsync(ofd) < 0)
555 goto die_outfile;
556 }
557
558 if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
559 if (write_and_stats(obuf, oc, obs, outfile))
560 goto out_status;
561 }
562 if (close(ifd) < 0) {
563 die_infile:
564 bb_simple_perror_msg_and_die(infile);
565 }
566
567 if (close(ofd) < 0) {
568 die_outfile:
569 bb_simple_perror_msg_and_die(outfile);
570 }
571
572 exitcode = EXIT_SUCCESS;
573 out_status:
574 if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE))
575 dd_output_status(0);
576
577 if (ENABLE_FEATURE_CLEAN_UP) {
578 free(obuf);
579 if (G.flags & FLAG_TWOBUFS)
580 free(ibuf);
581 }
582
583 return exitcode;
584}
585