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
97
98
99
100
101
102
103
104#include "libbb.h"
105#include "common_bufsiz.h"
106
107
108
109
110enum {
111 ifd = STDIN_FILENO,
112 ofd = STDOUT_FILENO,
113};
114
115struct globals {
116 off_t out_full, out_part, in_full, in_part;
117#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
118 unsigned long long total_bytes;
119 unsigned long long begin_time_us;
120#endif
121 int flags;
122} FIX_ALIASING;
123#define G (*(struct globals*)bb_common_bufsiz1)
124#define INIT_G() do { \
125 setup_common_bufsiz(); \
126 \
127 memset(&G, 0, sizeof(G)); \
128} while (0)
129
130enum {
131
132
133 FLAG_NOTRUNC = (1 << 0) * ENABLE_FEATURE_DD_IBS_OBS,
134 FLAG_SYNC = (1 << 1) * ENABLE_FEATURE_DD_IBS_OBS,
135 FLAG_NOERROR = (1 << 2) * ENABLE_FEATURE_DD_IBS_OBS,
136 FLAG_FSYNC = (1 << 3) * ENABLE_FEATURE_DD_IBS_OBS,
137 FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS,
138
139
140 FLAG_IFLAG_SHIFT = 5,
141 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
142 FLAG_COUNT_BYTES = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
143 FLAG_FULLBLOCK = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
144 FLAG_IDIRECT = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS,
145
146
147 FLAG_OFLAG_SHIFT = 9,
148 FLAG_SEEK_BYTES = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS,
149 FLAG_APPEND = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS,
150 FLAG_ODIRECT = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS,
151
152 FLAG_TWOBUFS = (1 << 12) * ENABLE_FEATURE_DD_IBS_OBS,
153 FLAG_COUNT = 1 << 13,
154 FLAG_STATUS_NONE = 1 << 14,
155 FLAG_STATUS_NOXFER = 1 << 15,
156};
157
158static void dd_output_status(int UNUSED_PARAM cur_signal)
159{
160#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
161 double seconds;
162 unsigned long long bytes_sec;
163 unsigned long long now_us = monotonic_us();
164#endif
165
166
167 fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n"
168 "%"OFF_FMT"u+%"OFF_FMT"u records out\n",
169 G.in_full, G.in_part,
170 G.out_full, G.out_part);
171
172#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
173# if ENABLE_FEATURE_DD_STATUS
174 if (G.flags & FLAG_STATUS_NOXFER)
175 return;
176
177
178
179# endif
180 fprintf(stderr,
181 "%llu bytes (%sB) copied, "
182 , G.total_bytes,
183
184 make_human_readable_str(G.total_bytes, 1, 0)
185 );
186
187
188
189
190
191
192 seconds = (now_us - G.begin_time_us) / 1000000.0;
193 bytes_sec = G.total_bytes / seconds;
194 fprintf(stderr, "%f seconds, %sB/s\n",
195 seconds,
196
197 make_human_readable_str(bytes_sec, 1, 0)
198 );
199#endif
200}
201
202#if ENABLE_FEATURE_DD_IBS_OBS
203static int clear_O_DIRECT(int fd)
204{
205 if (errno == EINVAL) {
206 int fl = fcntl(fd, F_GETFL);
207 if (fl & O_DIRECT) {
208 fcntl(fd, F_SETFL, fl & ~O_DIRECT);
209 return 1;
210 }
211 }
212 return 0;
213}
214#endif
215
216static ssize_t dd_read(void *ibuf, size_t ibs)
217{
218 ssize_t n;
219
220#if ENABLE_FEATURE_DD_IBS_OBS
221 read_again:
222 if (G.flags & FLAG_FULLBLOCK)
223 n = full_read(ifd, ibuf, ibs);
224 else
225#endif
226 n = safe_read(ifd, ibuf, ibs);
227#if ENABLE_FEATURE_DD_IBS_OBS
228 if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd))
229 goto read_again;
230#endif
231 return n;
232}
233
234static bool write_and_stats(const void *buf, size_t len, size_t obs,
235 const char *filename)
236{
237 ssize_t n;
238
239 IF_FEATURE_DD_IBS_OBS(write_again:)
240 n = full_write(ofd, buf, len);
241#if ENABLE_FEATURE_DD_IBS_OBS
242 if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd))
243 goto write_again;
244#endif
245
246#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
247 if (n > 0)
248 G.total_bytes += n;
249#endif
250 if ((size_t)n == obs) {
251 G.out_full++;
252 return 0;
253 }
254 if ((size_t)n == len) {
255 G.out_part++;
256 return 0;
257 }
258
259
260
261
262
263
264
265 bb_perror_msg("error writing '%s'", filename);
266 return 1;
267}
268
269#if ENABLE_LFS
270# define XATOU_SFX xatoull_sfx
271#else
272# define XATOU_SFX xatoul_sfx
273#endif
274
275#if ENABLE_FEATURE_DD_IBS_OBS
276static int parse_comma_flags(char *val, const char *words, const char *error_in)
277{
278 int flags = 0;
279 while (1) {
280 int n;
281 char *arg;
282
283
284
285
286 arg = strchr(val, ',');
287 if (arg)
288 *arg = '\0';
289 n = index_in_strings(words, val);
290 if (n < 0)
291 bb_error_msg_and_die(bb_msg_invalid_arg_to, val, error_in);
292 flags |= (1 << n);
293 if (!arg)
294 break;
295 *arg = ',';
296 val = arg + 1;
297 }
298 return flags;
299}
300#endif
301
302static void *alloc_buf(size_t size)
303{
304
305 if (size >= bb_getpagesize())
306 return xmmap_anon(size);
307 return xmalloc(size);
308}
309
310int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
311int dd_main(int argc UNUSED_PARAM, char **argv)
312{
313 static const char keywords[] ALIGN1 =
314 "bs\0""count\0""seek\0""skip\0""if\0""of\0"IF_FEATURE_DD_STATUS("status\0")
315#if ENABLE_FEATURE_DD_IBS_OBS
316 "ibs\0""obs\0""conv\0""iflag\0""oflag\0"
317#endif
318 ;
319#if ENABLE_FEATURE_DD_IBS_OBS
320 static const char conv_words[] ALIGN1 =
321 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
322 static const char iflag_words[] ALIGN1 =
323 "skip_bytes\0""count_bytes\0""fullblock\0""direct\0";
324 static const char oflag_words[] ALIGN1 =
325 "seek_bytes\0append\0""direct\0";
326#endif
327#if ENABLE_FEATURE_DD_STATUS
328 static const char status_words[] ALIGN1 =
329 "none\0""noxfer\0";
330#endif
331 enum {
332 OP_bs = 0,
333 OP_count,
334 OP_seek,
335 OP_skip,
336 OP_if,
337 OP_of,
338 IF_FEATURE_DD_STATUS(OP_status,)
339#if ENABLE_FEATURE_DD_IBS_OBS
340 OP_ibs,
341 OP_obs,
342 OP_conv,
343 OP_iflag,
344 OP_oflag,
345
346 OP_conv_notrunc = 0,
347 OP_conv_sync,
348 OP_conv_noerror,
349 OP_conv_fsync,
350 OP_conv_swab,
351
352
353
354
355
356
357
358
359
360
361
362
363
364 OP_iflag_skip_bytes,
365 OP_iflag_count_bytes,
366 OP_iflag_fullblock,
367 OP_iflag_direct,
368 OP_oflag_seek_bytes,
369 OP_oflag_direct,
370#endif
371 };
372 smallint exitcode = EXIT_FAILURE;
373 int i;
374 size_t ibs = 512;
375 char *ibuf;
376#if ENABLE_FEATURE_DD_IBS_OBS
377 size_t obs = 512;
378 char *obuf;
379#else
380# define obs ibs
381# define obuf ibuf
382#endif
383
384 struct {
385 IF_FEATURE_DD_IBS_OBS(size_t ocount;)
386 ssize_t prev_read_size;
387 off_t count;
388 off_t seek, skip;
389 const char *infile, *outfile;
390 } Z;
391#define ocount (Z.ocount )
392#define prev_read_size (Z.prev_read_size)
393#define count (Z.count )
394#define seek (Z.seek )
395#define skip (Z.skip )
396#define infile (Z.infile )
397#define outfile (Z.outfile)
398
399 memset(&Z, 0, sizeof(Z));
400 INIT_G();
401
402
403 for (i = 1; argv[i]; i++) {
404 int what;
405 char *val;
406 char *arg = argv[i];
407
408#if ENABLE_DESKTOP
409
410
411 if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0')
412 continue;
413#endif
414 val = strchr(arg, '=');
415 if (val == NULL)
416 bb_show_usage();
417 *val = '\0';
418 what = index_in_strings(keywords, arg);
419 if (what < 0)
420 bb_show_usage();
421
422 val++;
423#if ENABLE_FEATURE_DD_IBS_OBS
424 if (what == OP_ibs) {
425
426 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
427
428 }
429 if (what == OP_obs) {
430 obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
431
432 }
433 if (what == OP_conv) {
434 G.flags |= parse_comma_flags(val, conv_words, "conv");
435
436 }
437 if (what == OP_iflag) {
438 G.flags |= parse_comma_flags(val, iflag_words, "iflag") << FLAG_IFLAG_SHIFT;
439
440 }
441 if (what == OP_oflag) {
442 G.flags |= parse_comma_flags(val, oflag_words, "oflag") << FLAG_OFLAG_SHIFT;
443
444 }
445#endif
446 if (what == OP_bs) {
447 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
448 obs = ibs;
449
450 }
451
452 if (what == OP_count) {
453 G.flags |= FLAG_COUNT;
454 count = XATOU_SFX(val, cwbkMG_suffixes);
455
456 }
457 if (what == OP_seek) {
458 seek = XATOU_SFX(val, cwbkMG_suffixes);
459
460 }
461 if (what == OP_skip) {
462 skip = XATOU_SFX(val, cwbkMG_suffixes);
463
464 }
465 if (what == OP_if) {
466 infile = val;
467
468 }
469 if (what == OP_of) {
470 outfile = val;
471
472 }
473#if ENABLE_FEATURE_DD_STATUS
474 if (what == OP_status) {
475 int n;
476 n = index_in_strings(status_words, val);
477 if (n < 0)
478 bb_error_msg_and_die(bb_msg_invalid_arg_to, val, "status");
479 G.flags |= FLAG_STATUS_NONE << n;
480
481 }
482#endif
483 }
484
485 ibuf = alloc_buf(ibs);
486 obuf = ibuf;
487#if ENABLE_FEATURE_DD_IBS_OBS
488 if (ibs != obs) {
489 G.flags |= FLAG_TWOBUFS;
490 obuf = alloc_buf(obs);
491 }
492#endif
493
494#if ENABLE_FEATURE_DD_SIGNAL_HANDLING
495 signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status);
496#endif
497#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
498 G.begin_time_us = monotonic_us();
499#endif
500
501 if (infile) {
502 int iflag = O_RDONLY;
503#if ENABLE_FEATURE_DD_IBS_OBS
504 if (G.flags & FLAG_IDIRECT)
505 iflag |= O_DIRECT;
506#endif
507 xmove_fd(xopen(infile, iflag), ifd);
508 } else {
509 infile = bb_msg_standard_input;
510 }
511 if (outfile) {
512 int oflag = O_WRONLY | O_CREAT;
513
514 if (!seek && !(G.flags & FLAG_NOTRUNC))
515 oflag |= O_TRUNC;
516 if (G.flags & FLAG_APPEND)
517 oflag |= O_APPEND;
518#if ENABLE_FEATURE_DD_IBS_OBS
519 if (G.flags & FLAG_ODIRECT)
520 oflag |= O_DIRECT;
521#endif
522 xmove_fd(xopen(outfile, oflag), ofd);
523
524 if (seek && !(G.flags & FLAG_NOTRUNC)) {
525 size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs;
526 if (ftruncate(ofd, seek * blocksz) < 0) {
527 struct stat st;
528
529 if (fstat(ofd, &st) < 0
530 || S_ISREG(st.st_mode)
531 || S_ISDIR(st.st_mode)
532 ) {
533 goto die_outfile;
534 }
535 }
536 }
537 } else {
538 outfile = bb_msg_standard_output;
539 }
540 if (skip) {
541 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs;
542 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) {
543 do {
544 ssize_t n = dd_read(ibuf, blocksz);
545 if (n < 0)
546 goto die_infile;
547 if (n == 0)
548 break;
549 } while (--skip != 0);
550 }
551 }
552 if (seek) {
553 size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs;
554 if (lseek(ofd, seek * blocksz, SEEK_CUR) < 0)
555 goto die_outfile;
556 }
557
558 while (1) {
559 ssize_t n = ibs;
560
561 if (G.flags & FLAG_COUNT) {
562 if (count == 0)
563 break;
564 if ((G.flags & FLAG_COUNT_BYTES) && count < ibs)
565 n = count;
566 }
567
568 n = dd_read(ibuf, n);
569 if (n == 0)
570 break;
571 if (n < 0) {
572
573 if (!(G.flags & FLAG_NOERROR))
574 goto die_infile;
575 bb_simple_perror_msg(infile);
576
577 xlseek(ifd, ibs, SEEK_CUR);
578
579
580 n = 0;
581 }
582 if (G.flags & FLAG_SWAB) {
583 uint16_t *p16;
584 ssize_t n2;
585
586
587 if (prev_read_size & 1)
588 bb_error_msg_and_die("can't swab %lu byte buffer",
589 (unsigned long)prev_read_size);
590 prev_read_size = n;
591
592
593
594
595
596 p16 = (void*) ibuf;
597 n2 = (n >> 1);
598 while (--n2 >= 0) {
599 *p16 = bswap_16(*p16);
600 p16++;
601 }
602 }
603 count -= (G.flags & FLAG_COUNT_BYTES) ? n : 1;
604 if ((size_t)n == ibs)
605 G.in_full++;
606 else {
607 G.in_part++;
608 if (G.flags & FLAG_SYNC) {
609 memset(ibuf + n, 0, ibs - n);
610 n = ibs;
611 }
612 }
613#if ENABLE_FEATURE_DD_IBS_OBS
614 if (G.flags & FLAG_TWOBUFS) {
615 char *tmp = ibuf;
616 while (n) {
617 size_t d = obs - ocount;
618 if (d > (size_t)n)
619 d = n;
620 memcpy(obuf + ocount, tmp, d);
621 n -= d;
622 tmp += d;
623 ocount += d;
624 if (ocount == obs) {
625 if (write_and_stats(obuf, obs, obs, outfile))
626 goto out_status;
627 ocount = 0;
628 }
629 }
630 } else
631#endif
632 {
633 if (write_and_stats(ibuf, n, obs, outfile))
634 goto out_status;
635 }
636 }
637
638 if (G.flags & FLAG_FSYNC) {
639 if (fsync(ofd) < 0)
640 goto die_outfile;
641 }
642
643#if ENABLE_FEATURE_DD_IBS_OBS
644 if (ocount != 0) {
645 if (write_and_stats(obuf, ocount, obs, outfile))
646 goto out_status;
647 }
648#endif
649 if (close(ifd) < 0) {
650 die_infile:
651 bb_simple_perror_msg_and_die(infile);
652 }
653
654 if (close(ofd) < 0) {
655 die_outfile:
656 bb_simple_perror_msg_and_die(outfile);
657 }
658
659 exitcode = EXIT_SUCCESS;
660 out_status:
661 if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE))
662 dd_output_status(0);
663
664#if 0
665 if (ENABLE_FEATURE_CLEAN_UP) {
666 free(obuf);
667 if (G.flags & FLAG_TWOBUFS)
668 free(ibuf);
669 }
670#endif
671
672 return exitcode;
673}
674