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