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