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 2838f6341..302497074 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,
@@ -215,14 +285,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
215#endif 285#endif
216 /* These are all zeroed at once! */ 286 /* These are all zeroed at once! */
217 struct { 287 struct {
218 int flags;
219 size_t oc; 288 size_t oc;
220 ssize_t prev_read_size; /* for detecting swab failure */ 289 ssize_t prev_read_size; /* for detecting swab failure */
221 off_t count; 290 off_t count;
222 off_t seek, skip; 291 off_t seek, skip;
223 const char *infile, *outfile; 292 const char *infile, *outfile;
224 } Z; 293 } Z;
225#define flags (Z.flags )
226#define oc (Z.oc ) 294#define oc (Z.oc )
227#define prev_read_size (Z.prev_read_size) 295#define prev_read_size (Z.prev_read_size)
228#define count (Z.count ) 296#define count (Z.count )
@@ -278,7 +346,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
278 n = index_in_strings(conv_words, val); 346 n = index_in_strings(conv_words, val);
279 if (n < 0) 347 if (n < 0)
280 bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv"); 348 bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv");
281 flags |= (1 << n); 349 G.flags |= (1 << n);
282 if (!arg) /* no ',' left, so this was the last specifier */ 350 if (!arg) /* no ',' left, so this was the last specifier */
283 break; 351 break;
284 /* *arg = ','; - to preserve ps listing? */ 352 /* *arg = ','; - to preserve ps listing? */
@@ -294,7 +362,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
294 } 362 }
295 /* These can be large: */ 363 /* These can be large: */
296 if (what == OP_count) { 364 if (what == OP_count) {
297 flags |= FLAG_COUNT; 365 G.flags |= FLAG_COUNT;
298 count = XATOU_SFX(val, dd_suffixes); 366 count = XATOU_SFX(val, dd_suffixes);
299 /*continue;*/ 367 /*continue;*/
300 } 368 }
@@ -314,6 +382,16 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
314 outfile = val; 382 outfile = val;
315 /*continue;*/ 383 /*continue;*/
316 } 384 }
385#if ENABLE_FEATURE_DD_STATUS
386 if (what == OP_status) {
387 int n;
388 n = index_in_strings(status_words, val);
389 if (n < 0)
390 bb_error_msg_and_die(bb_msg_invalid_arg, val, "status");
391 G.flags |= FLAG_STATUS << n;
392 /*continue;*/
393 }
394#endif
317 } /* end of "for (argv[i])" */ 395 } /* end of "for (argv[i])" */
318 396
319//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever 397//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
@@ -321,7 +399,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
321 obuf = ibuf; 399 obuf = ibuf;
322#if ENABLE_FEATURE_DD_IBS_OBS 400#if ENABLE_FEATURE_DD_IBS_OBS
323 if (ibs != obs) { 401 if (ibs != obs) {
324 flags |= FLAG_TWOBUFS; 402 G.flags |= FLAG_TWOBUFS;
325 obuf = xmalloc(obs); 403 obuf = xmalloc(obs);
326 } 404 }
327#endif 405#endif
@@ -341,12 +419,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
341 if (outfile) { 419 if (outfile) {
342 int oflag = O_WRONLY | O_CREAT; 420 int oflag = O_WRONLY | O_CREAT;
343 421
344 if (!seek && !(flags & FLAG_NOTRUNC)) 422 if (!seek && !(G.flags & FLAG_NOTRUNC))
345 oflag |= O_TRUNC; 423 oflag |= O_TRUNC;
346 424
347 xmove_fd(xopen(outfile, oflag), ofd); 425 xmove_fd(xopen(outfile, oflag), ofd);
348 426
349 if (seek && !(flags & FLAG_NOTRUNC)) { 427 if (seek && !(G.flags & FLAG_NOTRUNC)) {
350 if (ftruncate(ofd, seek * obs) < 0) { 428 if (ftruncate(ofd, seek * obs) < 0) {
351 struct stat st; 429 struct stat st;
352 430
@@ -377,7 +455,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
377 goto die_outfile; 455 goto die_outfile;
378 } 456 }
379 457
380 while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { 458 while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
381 ssize_t n; 459 ssize_t n;
382 460
383 n = safe_read(ifd, ibuf, ibs); 461 n = safe_read(ifd, ibuf, ibs);
@@ -385,7 +463,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
385 break; 463 break;
386 if (n < 0) { 464 if (n < 0) {
387 /* "Bad block" */ 465 /* "Bad block" */
388 if (!(flags & FLAG_NOERROR)) 466 if (!(G.flags & FLAG_NOERROR))
389 goto die_infile; 467 goto die_infile;
390 bb_simple_perror_msg(infile); 468 bb_simple_perror_msg(infile);
391 /* GNU dd with conv=noerror skips over bad blocks */ 469 /* GNU dd with conv=noerror skips over bad blocks */
@@ -394,7 +472,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
394 * conv=noerror just ignores input bad blocks */ 472 * conv=noerror just ignores input bad blocks */
395 n = 0; 473 n = 0;
396 } 474 }
397 if (flags & FLAG_SWAB) { 475 if (G.flags & FLAG_SWAB) {
398 uint16_t *p16; 476 uint16_t *p16;
399 ssize_t n2; 477 ssize_t n2;
400 478
@@ -419,12 +497,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
419 G.in_full++; 497 G.in_full++;
420 else { 498 else {
421 G.in_part++; 499 G.in_part++;
422 if (flags & FLAG_SYNC) { 500 if (G.flags & FLAG_SYNC) {
423 memset(ibuf + n, 0, ibs - n); 501 memset(ibuf + n, 0, ibs - n);
424 n = ibs; 502 n = ibs;
425 } 503 }
426 } 504 }
427 if (flags & FLAG_TWOBUFS) { 505 if (G.flags & FLAG_TWOBUFS) {
428 char *tmp = ibuf; 506 char *tmp = ibuf;
429 while (n) { 507 while (n) {
430 size_t d = obs - oc; 508 size_t d = obs - oc;
@@ -446,7 +524,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
446 goto out_status; 524 goto out_status;
447 } 525 }
448 526
449 if (flags & FLAG_FSYNC) { 527 if (G.flags & FLAG_FSYNC) {
450 if (fsync(ofd) < 0) 528 if (fsync(ofd) < 0)
451 goto die_outfile; 529 goto die_outfile;
452 } 530 }
@@ -468,11 +546,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
468 546
469 exitcode = EXIT_SUCCESS; 547 exitcode = EXIT_SUCCESS;
470 out_status: 548 out_status:
471 dd_output_status(0); 549 if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE))
550 dd_output_status(0);
472 551
473 if (ENABLE_FEATURE_CLEAN_UP) { 552 if (ENABLE_FEATURE_CLEAN_UP) {
474 free(obuf); 553 free(obuf);
475 if (flags & FLAG_TWOBUFS) 554 if (G.flags & FLAG_TWOBUFS)
476 free(ibuf); 555 free(ibuf);
477 } 556 }
478 557