aboutsummaryrefslogtreecommitdiff
path: root/coreutils/dd.c
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils/dd.c')
-rw-r--r--coreutils/dd.c143
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
135enum {
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
81static void dd_output_status(int UNUSED_PARAM cur_signal) 151static 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,
148int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 225int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
149int dd_main(int argc UNUSED_PARAM, char **argv) 226int 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