diff options
Diffstat (limited to 'coreutils/dd.c')
-rw-r--r-- | coreutils/dd.c | 143 |
1 files changed, 111 insertions, 32 deletions
diff --git a/coreutils/dd.c b/coreutils/dd.c index db61f665e..e2d95931c 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c | |||
@@ -8,6 +8,51 @@ | |||
8 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | 8 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | //config:config DD | ||
12 | //config: bool "dd" | ||
13 | //config: default y | ||
14 | //config: help | ||
15 | //config: dd copies a file (from standard input to standard output, | ||
16 | //config: by default) using specific input and output blocksizes, | ||
17 | //config: while optionally performing conversions on it. | ||
18 | //config: | ||
19 | //config:config FEATURE_DD_SIGNAL_HANDLING | ||
20 | //config: bool "Enable signal handling for status reporting" | ||
21 | //config: default y | ||
22 | //config: depends on DD | ||
23 | //config: help | ||
24 | //config: Sending a SIGUSR1 signal to a running `dd' process makes it | ||
25 | //config: print to standard error the number of records read and written | ||
26 | //config: so far, then to resume copying. | ||
27 | //config: | ||
28 | //config: $ dd if=/dev/zero of=/dev/null & | ||
29 | //config: $ pid=$!; kill -USR1 $pid; sleep 1; kill $pid | ||
30 | //config: 10899206+0 records in | ||
31 | //config: 10899206+0 records out | ||
32 | //config: | ||
33 | //config:config FEATURE_DD_THIRD_STATUS_LINE | ||
34 | //config: bool "Enable the third status line upon signal" | ||
35 | //config: default y | ||
36 | //config: depends on DD && FEATURE_DD_SIGNAL_HANDLING | ||
37 | //config: help | ||
38 | //config: Displays a coreutils-like third status line with transferred bytes, | ||
39 | //config: elapsed time and speed. | ||
40 | //config: | ||
41 | //config:config FEATURE_DD_IBS_OBS | ||
42 | //config: bool "Enable ibs, obs and conv options" | ||
43 | //config: default y | ||
44 | //config: depends on DD | ||
45 | //config: help | ||
46 | //config: Enables support for writing a certain number of bytes in and out, | ||
47 | //config: at a time, and performing conversions on the data stream. | ||
48 | //config: | ||
49 | //config:config FEATURE_DD_STATUS | ||
50 | //config: bool "Enable status display options" | ||
51 | //config: default y | ||
52 | //config: depends on DD | ||
53 | //config: help | ||
54 | //config: Enables support for status=noxfer/none option. | ||
55 | |||
11 | //usage:#define dd_trivial_usage | 56 | //usage:#define dd_trivial_usage |
12 | //usage: "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" | 57 | //usage: "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" |
13 | //usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]") | 58 | //usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]") |
@@ -32,8 +77,12 @@ | |||
32 | //usage: "\n conv=fsync Physically write data out before finishing" | 77 | //usage: "\n conv=fsync Physically write data out before finishing" |
33 | //usage: "\n conv=swab Swap every pair of bytes" | 78 | //usage: "\n conv=swab Swap every pair of bytes" |
34 | //usage: ) | 79 | //usage: ) |
80 | //usage: IF_FEATURE_DD_STATUS( | ||
81 | //usage: "\n status=noxfer Suppress rate output" | ||
82 | //usage: "\n status=none Suppress all output" | ||
83 | //usage: ) | ||
35 | //usage: "\n" | 84 | //usage: "\n" |
36 | //usage: "\nN may be suffixed by c (1), w (2), b (512), kD (1000), k (1024), MD, M, GD, G" | 85 | //usage: "\nN may be suffixed by c (1), w (2), b (512), kB (1000), k (1024), MB, M, GB, G" |
37 | //usage: | 86 | //usage: |
38 | //usage:#define dd_example_usage | 87 | //usage:#define dd_example_usage |
39 | //usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" | 88 | //usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" |
@@ -54,13 +103,18 @@ static const struct suffix_mult dd_suffixes[] = { | |||
54 | { "c", 1 }, | 103 | { "c", 1 }, |
55 | { "w", 2 }, | 104 | { "w", 2 }, |
56 | { "b", 512 }, | 105 | { "b", 512 }, |
106 | { "kB", 1000 }, | ||
57 | { "kD", 1000 }, | 107 | { "kD", 1000 }, |
58 | { "k", 1024 }, | 108 | { "k", 1024 }, |
59 | { "K", 1024 }, /* compat with coreutils dd */ | 109 | { "K", 1024 }, /* compat with coreutils dd (it also accepts KB and KD, TODO?) */ |
110 | { "MB", 1000000 }, | ||
60 | { "MD", 1000000 }, | 111 | { "MD", 1000000 }, |
61 | { "M", 1048576 }, | 112 | { "M", 1024*1024 }, |
113 | { "GB", 1000000000 }, | ||
62 | { "GD", 1000000000 }, | 114 | { "GD", 1000000000 }, |
63 | { "G", 1073741824 }, | 115 | { "G", 1024*1024*1024 }, |
116 | /* "D" suffix for decimal is not in coreutils manpage, looks like it's deprecated */ | ||
117 | /* coreutils also understands TPEZY suffixes for tera- and so on, with B suffix for decimal */ | ||
64 | { "", 0 } | 118 | { "", 0 } |
65 | }; | 119 | }; |
66 | 120 | ||
@@ -70,6 +124,7 @@ struct globals { | |||
70 | unsigned long long total_bytes; | 124 | unsigned long long total_bytes; |
71 | unsigned long long begin_time_us; | 125 | unsigned long long begin_time_us; |
72 | #endif | 126 | #endif |
127 | int flags; | ||
73 | } FIX_ALIASING; | 128 | } FIX_ALIASING; |
74 | #define G (*(struct globals*)&bb_common_bufsiz1) | 129 | #define G (*(struct globals*)&bb_common_bufsiz1) |
75 | #define INIT_G() do { \ | 130 | #define INIT_G() do { \ |
@@ -77,6 +132,21 @@ struct globals { | |||
77 | memset(&G, 0, sizeof(G)); \ | 132 | memset(&G, 0, sizeof(G)); \ |
78 | } while (0) | 133 | } while (0) |
79 | 134 | ||
135 | enum { | ||
136 | /* Must be in the same order as OP_conv_XXX! */ | ||
137 | /* (see "flags |= (1 << what)" below) */ | ||
138 | FLAG_NOTRUNC = (1 << 0) * ENABLE_FEATURE_DD_IBS_OBS, | ||
139 | FLAG_SYNC = (1 << 1) * ENABLE_FEATURE_DD_IBS_OBS, | ||
140 | FLAG_NOERROR = (1 << 2) * ENABLE_FEATURE_DD_IBS_OBS, | ||
141 | FLAG_FSYNC = (1 << 3) * ENABLE_FEATURE_DD_IBS_OBS, | ||
142 | FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS, | ||
143 | /* end of conv flags */ | ||
144 | FLAG_TWOBUFS = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, | ||
145 | FLAG_COUNT = 1 << 6, | ||
146 | FLAG_STATUS = 1 << 7, | ||
147 | FLAG_STATUS_NONE = 1 << 7, | ||
148 | FLAG_STATUS_NOXFER = 1 << 8, | ||
149 | }; | ||
80 | 150 | ||
81 | static void dd_output_status(int UNUSED_PARAM cur_signal) | 151 | static void dd_output_status(int UNUSED_PARAM cur_signal) |
82 | { | 152 | { |
@@ -93,6 +163,13 @@ static void dd_output_status(int UNUSED_PARAM cur_signal) | |||
93 | G.out_full, G.out_part); | 163 | G.out_full, G.out_part); |
94 | 164 | ||
95 | #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE | 165 | #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE |
166 | # if ENABLE_FEATURE_DD_STATUS | ||
167 | if (G.flags & FLAG_STATUS_NOXFER) /* status=noxfer active? */ | ||
168 | return; | ||
169 | //TODO: should status=none make dd stop reacting to USR1 entirely? | ||
170 | //So far we react to it (we print the stats), | ||
171 | //status=none only suppresses final, non-USR1 generated status message. | ||
172 | # endif | ||
96 | fprintf(stderr, "%llu bytes (%sB) copied, ", | 173 | fprintf(stderr, "%llu bytes (%sB) copied, ", |
97 | G.total_bytes, | 174 | G.total_bytes, |
98 | /* show fractional digit, use suffixes */ | 175 | /* show fractional digit, use suffixes */ |
@@ -148,20 +225,8 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs, | |||
148 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 225 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
149 | int dd_main(int argc UNUSED_PARAM, char **argv) | 226 | int dd_main(int argc UNUSED_PARAM, char **argv) |
150 | { | 227 | { |
151 | enum { | ||
152 | /* Must be in the same order as OP_conv_XXX! */ | ||
153 | /* (see "flags |= (1 << what)" below) */ | ||
154 | FLAG_NOTRUNC = (1 << 0) * ENABLE_FEATURE_DD_IBS_OBS, | ||
155 | FLAG_SYNC = (1 << 1) * ENABLE_FEATURE_DD_IBS_OBS, | ||
156 | FLAG_NOERROR = (1 << 2) * ENABLE_FEATURE_DD_IBS_OBS, | ||
157 | FLAG_FSYNC = (1 << 3) * ENABLE_FEATURE_DD_IBS_OBS, | ||
158 | FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS, | ||
159 | /* end of conv flags */ | ||
160 | FLAG_TWOBUFS = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, | ||
161 | FLAG_COUNT = 1 << 6, | ||
162 | }; | ||
163 | static const char keywords[] ALIGN1 = | 228 | static const char keywords[] ALIGN1 = |
164 | "bs\0""count\0""seek\0""skip\0""if\0""of\0" | 229 | "bs\0""count\0""seek\0""skip\0""if\0""of\0"IF_FEATURE_DD_STATUS("status\0") |
165 | #if ENABLE_FEATURE_DD_IBS_OBS | 230 | #if ENABLE_FEATURE_DD_IBS_OBS |
166 | "ibs\0""obs\0""conv\0" | 231 | "ibs\0""obs\0""conv\0" |
167 | #endif | 232 | #endif |
@@ -170,6 +235,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
170 | static const char conv_words[] ALIGN1 = | 235 | static const char conv_words[] ALIGN1 = |
171 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; | 236 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; |
172 | #endif | 237 | #endif |
238 | #if ENABLE_FEATURE_DD_STATUS | ||
239 | static const char status_words[] ALIGN1 = | ||
240 | "none\0""noxfer\0"; | ||
241 | #endif | ||
173 | enum { | 242 | enum { |
174 | OP_bs = 0, | 243 | OP_bs = 0, |
175 | OP_count, | 244 | OP_count, |
@@ -177,6 +246,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
177 | OP_skip, | 246 | OP_skip, |
178 | OP_if, | 247 | OP_if, |
179 | OP_of, | 248 | OP_of, |
249 | IF_FEATURE_DD_STATUS(OP_status,) | ||
180 | #if ENABLE_FEATURE_DD_IBS_OBS | 250 | #if ENABLE_FEATURE_DD_IBS_OBS |
181 | OP_ibs, | 251 | OP_ibs, |
182 | OP_obs, | 252 | OP_obs, |
@@ -216,14 +286,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
216 | #endif | 286 | #endif |
217 | /* These are all zeroed at once! */ | 287 | /* These are all zeroed at once! */ |
218 | struct { | 288 | struct { |
219 | int flags; | ||
220 | size_t oc; | 289 | size_t oc; |
221 | ssize_t prev_read_size; /* for detecting swab failure */ | 290 | ssize_t prev_read_size; /* for detecting swab failure */ |
222 | off_t count; | 291 | off_t count; |
223 | off_t seek, skip; | 292 | off_t seek, skip; |
224 | const char *infile, *outfile; | 293 | const char *infile, *outfile; |
225 | } Z; | 294 | } Z; |
226 | #define flags (Z.flags ) | ||
227 | #define oc (Z.oc ) | 295 | #define oc (Z.oc ) |
228 | #define prev_read_size (Z.prev_read_size) | 296 | #define prev_read_size (Z.prev_read_size) |
229 | #define count (Z.count ) | 297 | #define count (Z.count ) |
@@ -279,7 +347,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
279 | n = index_in_strings(conv_words, val); | 347 | n = index_in_strings(conv_words, val); |
280 | if (n < 0) | 348 | if (n < 0) |
281 | bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv"); | 349 | bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv"); |
282 | flags |= (1 << n); | 350 | G.flags |= (1 << n); |
283 | if (!arg) /* no ',' left, so this was the last specifier */ | 351 | if (!arg) /* no ',' left, so this was the last specifier */ |
284 | break; | 352 | break; |
285 | /* *arg = ','; - to preserve ps listing? */ | 353 | /* *arg = ','; - to preserve ps listing? */ |
@@ -295,7 +363,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
295 | } | 363 | } |
296 | /* These can be large: */ | 364 | /* These can be large: */ |
297 | if (what == OP_count) { | 365 | if (what == OP_count) { |
298 | flags |= FLAG_COUNT; | 366 | G.flags |= FLAG_COUNT; |
299 | count = XATOU_SFX(val, dd_suffixes); | 367 | count = XATOU_SFX(val, dd_suffixes); |
300 | /*continue;*/ | 368 | /*continue;*/ |
301 | } | 369 | } |
@@ -315,6 +383,16 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
315 | outfile = val; | 383 | outfile = val; |
316 | /*continue;*/ | 384 | /*continue;*/ |
317 | } | 385 | } |
386 | #if ENABLE_FEATURE_DD_STATUS | ||
387 | if (what == OP_status) { | ||
388 | int n; | ||
389 | n = index_in_strings(status_words, val); | ||
390 | if (n < 0) | ||
391 | bb_error_msg_and_die(bb_msg_invalid_arg, val, "status"); | ||
392 | G.flags |= FLAG_STATUS << n; | ||
393 | /*continue;*/ | ||
394 | } | ||
395 | #endif | ||
318 | } /* end of "for (argv[i])" */ | 396 | } /* end of "for (argv[i])" */ |
319 | 397 | ||
320 | //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever | 398 | //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever |
@@ -322,7 +400,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
322 | obuf = ibuf; | 400 | obuf = ibuf; |
323 | #if ENABLE_FEATURE_DD_IBS_OBS | 401 | #if ENABLE_FEATURE_DD_IBS_OBS |
324 | if (ibs != obs) { | 402 | if (ibs != obs) { |
325 | flags |= FLAG_TWOBUFS; | 403 | G.flags |= FLAG_TWOBUFS; |
326 | obuf = xmalloc(obs); | 404 | obuf = xmalloc(obs); |
327 | } | 405 | } |
328 | #endif | 406 | #endif |
@@ -347,12 +425,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
347 | if (outfile) { | 425 | if (outfile) { |
348 | int oflag = O_WRONLY | O_CREAT; | 426 | int oflag = O_WRONLY | O_CREAT; |
349 | 427 | ||
350 | if (!seek && !(flags & FLAG_NOTRUNC)) | 428 | if (!seek && !(G.flags & FLAG_NOTRUNC)) |
351 | oflag |= O_TRUNC; | 429 | oflag |= O_TRUNC; |
352 | 430 | ||
353 | xmove_fd(xopen(outfile, oflag), ofd); | 431 | xmove_fd(xopen(outfile, oflag), ofd); |
354 | 432 | ||
355 | if (seek && !(flags & FLAG_NOTRUNC)) { | 433 | if (seek && !(G.flags & FLAG_NOTRUNC)) { |
356 | if (ftruncate(ofd, seek * obs) < 0) { | 434 | if (ftruncate(ofd, seek * obs) < 0) { |
357 | struct stat st; | 435 | struct stat st; |
358 | 436 | ||
@@ -383,7 +461,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
383 | goto die_outfile; | 461 | goto die_outfile; |
384 | } | 462 | } |
385 | 463 | ||
386 | while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { | 464 | while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { |
387 | ssize_t n; | 465 | ssize_t n; |
388 | 466 | ||
389 | if (devzero) { | 467 | if (devzero) { |
@@ -396,7 +474,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
396 | break; | 474 | break; |
397 | if (n < 0) { | 475 | if (n < 0) { |
398 | /* "Bad block" */ | 476 | /* "Bad block" */ |
399 | if (!(flags & FLAG_NOERROR)) | 477 | if (!(G.flags & FLAG_NOERROR)) |
400 | goto die_infile; | 478 | goto die_infile; |
401 | bb_simple_perror_msg(infile); | 479 | bb_simple_perror_msg(infile); |
402 | /* GNU dd with conv=noerror skips over bad blocks */ | 480 | /* GNU dd with conv=noerror skips over bad blocks */ |
@@ -405,7 +483,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
405 | * conv=noerror just ignores input bad blocks */ | 483 | * conv=noerror just ignores input bad blocks */ |
406 | n = 0; | 484 | n = 0; |
407 | } | 485 | } |
408 | if (flags & FLAG_SWAB) { | 486 | if (G.flags & FLAG_SWAB) { |
409 | uint16_t *p16; | 487 | uint16_t *p16; |
410 | ssize_t n2; | 488 | ssize_t n2; |
411 | 489 | ||
@@ -430,12 +508,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
430 | G.in_full++; | 508 | G.in_full++; |
431 | else { | 509 | else { |
432 | G.in_part++; | 510 | G.in_part++; |
433 | if (flags & FLAG_SYNC) { | 511 | if (G.flags & FLAG_SYNC) { |
434 | memset(ibuf + n, 0, ibs - n); | 512 | memset(ibuf + n, 0, ibs - n); |
435 | n = ibs; | 513 | n = ibs; |
436 | } | 514 | } |
437 | } | 515 | } |
438 | if (flags & FLAG_TWOBUFS) { | 516 | if (G.flags & FLAG_TWOBUFS) { |
439 | char *tmp = ibuf; | 517 | char *tmp = ibuf; |
440 | while (n) { | 518 | while (n) { |
441 | size_t d = obs - oc; | 519 | size_t d = obs - oc; |
@@ -457,7 +535,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
457 | goto out_status; | 535 | goto out_status; |
458 | } | 536 | } |
459 | 537 | ||
460 | if (flags & FLAG_FSYNC) { | 538 | if (G.flags & FLAG_FSYNC) { |
461 | if (fsync(ofd) < 0) | 539 | if (fsync(ofd) < 0) |
462 | goto die_outfile; | 540 | goto die_outfile; |
463 | } | 541 | } |
@@ -480,11 +558,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
480 | 558 | ||
481 | exitcode = EXIT_SUCCESS; | 559 | exitcode = EXIT_SUCCESS; |
482 | out_status: | 560 | out_status: |
483 | dd_output_status(0); | 561 | if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE)) |
562 | dd_output_status(0); | ||
484 | 563 | ||
485 | if (ENABLE_FEATURE_CLEAN_UP) { | 564 | if (ENABLE_FEATURE_CLEAN_UP) { |
486 | free(obuf); | 565 | free(obuf); |
487 | if (flags & FLAG_TWOBUFS) | 566 | if (G.flags & FLAG_TWOBUFS) |
488 | free(ibuf); | 567 | free(ibuf); |
489 | } | 568 | } |
490 | 569 | ||