8 |
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
9 |
*/ |
*/ |
10 |
|
|
|
#include <signal.h> /* For FEATURE_DD_SIGNAL_HANDLING */ |
|
11 |
#include "libbb.h" |
#include "libbb.h" |
12 |
|
|
13 |
/* This is a NOEXEC applet. Be very careful! */ |
/* This is a NOEXEC applet. Be very careful! */ |
29 |
{ "M", 1048576 }, |
{ "M", 1048576 }, |
30 |
{ "GD", 1000000000 }, |
{ "GD", 1000000000 }, |
31 |
{ "G", 1073741824 }, |
{ "G", 1073741824 }, |
32 |
{ } |
{ "", 0 } |
33 |
}; |
}; |
34 |
|
|
35 |
struct globals { |
struct globals { |
36 |
off_t out_full, out_part, in_full, in_part; |
off_t out_full, out_part, in_full, in_part; |
37 |
|
#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE |
38 |
|
unsigned long long total_bytes; |
39 |
|
unsigned long long begin_time_us; |
40 |
|
#endif |
41 |
}; |
}; |
42 |
#define G (*(struct globals*)&bb_common_bufsiz1) |
#define G (*(struct globals*)&bb_common_bufsiz1) |
43 |
/* We have to zero it out because of NOEXEC */ |
#define INIT_G() do { \ |
44 |
#define INIT_G() memset(&G, 0, sizeof(G)) |
/* we have to zero it out because of NOEXEC */ \ |
45 |
|
memset(&G, 0, sizeof(G)); \ |
46 |
|
} while (0) |
47 |
|
|
48 |
|
|
49 |
static void dd_output_status(int UNUSED_PARAM cur_signal) |
static void dd_output_status(int UNUSED_PARAM cur_signal) |
50 |
{ |
{ |
51 |
|
#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE |
52 |
|
double seconds; |
53 |
|
unsigned long long bytes_sec; |
54 |
|
unsigned long long now_us = monotonic_us(); /* before fprintf */ |
55 |
|
#endif |
56 |
|
|
57 |
/* Deliberately using %u, not %d */ |
/* Deliberately using %u, not %d */ |
58 |
fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n" |
fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n" |
59 |
"%"OFF_FMT"u+%"OFF_FMT"u records out\n", |
"%"OFF_FMT"u+%"OFF_FMT"u records out\n", |
60 |
G.in_full, G.in_part, |
G.in_full, G.in_part, |
61 |
G.out_full, G.out_part); |
G.out_full, G.out_part); |
62 |
|
|
63 |
|
#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE |
64 |
|
fprintf(stderr, "%llu bytes (%sB) copied, ", |
65 |
|
G.total_bytes, |
66 |
|
/* show fractional digit, use suffixes */ |
67 |
|
make_human_readable_str(G.total_bytes, 1, 0) |
68 |
|
); |
69 |
|
/* Corner cases: |
70 |
|
* ./busybox dd </dev/null >/dev/null |
71 |
|
* ./busybox dd bs=1M count=2000 </dev/zero >/dev/null |
72 |
|
* (echo DONE) | ./busybox dd >/dev/null |
73 |
|
* (sleep 1; echo DONE) | ./busybox dd >/dev/null |
74 |
|
*/ |
75 |
|
seconds = (now_us - G.begin_time_us) / 1000000.0; |
76 |
|
bytes_sec = G.total_bytes / seconds; |
77 |
|
fprintf(stderr, "%f seconds, %sB/s\n", |
78 |
|
seconds, |
79 |
|
/* show fractional digit, use suffixes */ |
80 |
|
make_human_readable_str(bytes_sec, 1, 0) |
81 |
|
); |
82 |
|
#endif |
83 |
} |
} |
84 |
|
|
85 |
static ssize_t full_write_or_warn(const void *buf, size_t len, |
static ssize_t full_write_or_warn(const void *buf, size_t len, |
101 |
G.out_full++; |
G.out_full++; |
102 |
else if (n) /* > 0 */ |
else if (n) /* > 0 */ |
103 |
G.out_part++; |
G.out_part++; |
104 |
|
#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE |
105 |
|
G.total_bytes += n; |
106 |
|
#endif |
107 |
return 0; |
return 0; |
108 |
} |
} |
109 |
|
|
110 |
#if ENABLE_LFS |
#if ENABLE_LFS |
111 |
#define XATOU_SFX xatoull_sfx |
# define XATOU_SFX xatoull_sfx |
112 |
#else |
#else |
113 |
#define XATOU_SFX xatoul_sfx |
# define XATOU_SFX xatoul_sfx |
114 |
#endif |
#endif |
115 |
|
|
116 |
int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
189 |
|
|
190 |
memset(&Z, 0, sizeof(Z)); |
memset(&Z, 0, sizeof(Z)); |
191 |
INIT_G(); |
INIT_G(); |
192 |
//fflush(NULL); - is this needed because of NOEXEC? |
//fflush_all(); - is this needed because of NOEXEC? |
|
|
|
|
#if ENABLE_FEATURE_DD_SIGNAL_HANDLING |
|
|
signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status); |
|
|
#endif |
|
193 |
|
|
194 |
for (n = 1; argv[n]; n++) { |
for (n = 1; argv[n]; n++) { |
195 |
int what; |
int what; |
276 |
flags |= FLAG_TWOBUFS; |
flags |= FLAG_TWOBUFS; |
277 |
obuf = xmalloc(obs); |
obuf = xmalloc(obs); |
278 |
} |
} |
279 |
|
|
280 |
|
#if ENABLE_FEATURE_DD_SIGNAL_HANDLING |
281 |
|
signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status); |
282 |
|
#endif |
283 |
|
#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE |
284 |
|
G.begin_time_us = monotonic_us(); |
285 |
|
#endif |
286 |
|
|
287 |
if (infile != NULL) |
if (infile != NULL) |
288 |
xmove_fd(xopen(infile, O_RDONLY), ifd); |
xmove_fd(xopen(infile, O_RDONLY), ifd); |
289 |
else { |
else { |
326 |
} |
} |
327 |
|
|
328 |
while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { |
while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { |
|
if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */ |
|
|
memset(ibuf, 0, ibs); |
|
329 |
n = safe_read(ifd, ibuf, ibs); |
n = safe_read(ifd, ibuf, ibs); |
330 |
if (n == 0) |
if (n == 0) |
331 |
break; |
break; |
332 |
if (n < 0) { |
if (n < 0) { |
333 |
|
/* "Bad block" */ |
334 |
if (!(flags & FLAG_NOERROR)) |
if (!(flags & FLAG_NOERROR)) |
335 |
goto die_infile; |
goto die_infile; |
|
n = ibs; |
|
336 |
bb_simple_perror_msg(infile); |
bb_simple_perror_msg(infile); |
337 |
|
/* GNU dd with conv=noerror skips over bad blocks */ |
338 |
|
xlseek(ifd, ibs, SEEK_CUR); |
339 |
|
/* conv=noerror,sync writes NULs, |
340 |
|
* conv=noerror just ignores input bad blocks */ |
341 |
|
n = 0; |
342 |
} |
} |
343 |
if ((size_t)n == ibs) |
if ((size_t)n == ibs) |
344 |
G.in_full++; |
G.in_full++; |
345 |
else { |
else { |
346 |
G.in_part++; |
G.in_part++; |
347 |
if (flags & FLAG_SYNC) { |
if (flags & FLAG_SYNC) { |
348 |
memset(ibuf + n, '\0', ibs - n); |
memset(ibuf + n, 0, ibs - n); |
349 |
n = ibs; |
n = ibs; |
350 |
} |
} |
351 |
} |
} |