source: MondoRescue/branches/3.3/mindi-busybox/coreutils/dd.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 14.7 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini dd implementation for busybox
4 *
5 *
6 * Copyright (C) 2000,2001 Matt Kraai
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */
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
56//usage:#define dd_trivial_usage
57//usage: "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n"
58//usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync] [iflag=skip_bytes]")
59//usage:#define dd_full_usage "\n\n"
60//usage: "Copy a file with converting and formatting\n"
61//usage: "\n if=FILE Read from FILE instead of stdin"
62//usage: "\n of=FILE Write to FILE instead of stdout"
63//usage: "\n bs=N Read and write N bytes at a time"
64//usage: IF_FEATURE_DD_IBS_OBS(
65//usage: "\n ibs=N Read N bytes at a time"
66//usage: )
67//usage: IF_FEATURE_DD_IBS_OBS(
68//usage: "\n obs=N Write N bytes at a time"
69//usage: )
70//usage: "\n count=N Copy only N input blocks"
71//usage: "\n skip=N Skip N input blocks"
72//usage: "\n seek=N Skip N output blocks"
73//usage: IF_FEATURE_DD_IBS_OBS(
74//usage: "\n conv=notrunc Don't truncate output file"
75//usage: "\n conv=noerror Continue after read errors"
76//usage: "\n conv=sync Pad blocks with zeros"
77//usage: "\n conv=fsync Physically write data out before finishing"
78//usage: "\n conv=swab Swap every pair of bytes"
79//usage: "\n iflag=skip_bytes skip=N is in bytes"
80//usage: )
81//usage: IF_FEATURE_DD_STATUS(
82//usage: "\n status=noxfer Suppress rate output"
83//usage: "\n status=none Suppress all output"
84//usage: )
85//usage: "\n"
86//usage: "\nN may be suffixed by c (1), w (2), b (512), kB (1000), k (1024), MB, M, GB, G"
87//usage:
88//usage:#define dd_example_usage
89//usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n"
90//usage: "4+0 records in\n"
91//usage: "4+0 records out\n"
92
93#include "libbb.h"
94#include "common_bufsiz.h"
95
96/* This is a NOEXEC applet. Be very careful! */
97
98
99enum {
100 ifd = STDIN_FILENO,
101 ofd = STDOUT_FILENO,
102};
103
104struct globals {
105 off_t out_full, out_part, in_full, in_part;
106#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
107 unsigned long long total_bytes;
108 unsigned long long begin_time_us;
109#endif
110 int flags;
111} FIX_ALIASING;
112#define G (*(struct globals*)bb_common_bufsiz1)
113#define INIT_G() do { \
114 setup_common_bufsiz(); \
115 /* we have to zero it out because of NOEXEC */ \
116 memset(&G, 0, sizeof(G)); \
117} while (0)
118
119enum {
120 /* Must be in the same order as OP_conv_XXX! */
121 /* (see "flags |= (1 << what)" below) */
122 FLAG_NOTRUNC = (1 << 0) * ENABLE_FEATURE_DD_IBS_OBS,
123 FLAG_SYNC = (1 << 1) * ENABLE_FEATURE_DD_IBS_OBS,
124 FLAG_NOERROR = (1 << 2) * ENABLE_FEATURE_DD_IBS_OBS,
125 FLAG_FSYNC = (1 << 3) * ENABLE_FEATURE_DD_IBS_OBS,
126 FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS,
127 /* end of conv flags */
128 /* start of input flags */
129 FLAG_IFLAG_SHIFT = 5,
130 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
131 /* end of input flags */
132 FLAG_TWOBUFS = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
133 FLAG_COUNT = 1 << 7,
134 FLAG_STATUS = 1 << 8,
135 FLAG_STATUS_NONE = 1 << 9,
136 FLAG_STATUS_NOXFER = 1 << 10,
137};
138
139static void dd_output_status(int UNUSED_PARAM cur_signal)
140{
141#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
142 double seconds;
143 unsigned long long bytes_sec;
144 unsigned long long now_us = monotonic_us(); /* before fprintf */
145#endif
146
147 /* Deliberately using %u, not %d */
148 fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n"
149 "%"OFF_FMT"u+%"OFF_FMT"u records out\n",
150 G.in_full, G.in_part,
151 G.out_full, G.out_part);
152
153#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
154# if ENABLE_FEATURE_DD_STATUS
155 if (G.flags & FLAG_STATUS_NOXFER) /* status=noxfer active? */
156 return;
157 //TODO: should status=none make dd stop reacting to USR1 entirely?
158 //So far we react to it (we print the stats),
159 //status=none only suppresses final, non-USR1 generated status message.
160# endif
161 fprintf(stderr, "%llu bytes (%sB) copied, ",
162 G.total_bytes,
163 /* show fractional digit, use suffixes */
164 make_human_readable_str(G.total_bytes, 1, 0)
165 );
166 /* Corner cases:
167 * ./busybox dd </dev/null >/dev/null
168 * ./busybox dd bs=1M count=2000 </dev/zero >/dev/null
169 * (echo DONE) | ./busybox dd >/dev/null
170 * (sleep 1; echo DONE) | ./busybox dd >/dev/null
171 */
172 seconds = (now_us - G.begin_time_us) / 1000000.0;
173 bytes_sec = G.total_bytes / seconds;
174 fprintf(stderr, "%f seconds, %sB/s\n",
175 seconds,
176 /* show fractional digit, use suffixes */
177 make_human_readable_str(bytes_sec, 1, 0)
178 );
179#endif
180}
181
182static ssize_t full_write_or_warn(const void *buf, size_t len,
183 const char *const filename)
184{
185 ssize_t n = full_write(ofd, buf, len);
186 if (n < 0)
187 bb_perror_msg("writing '%s'", filename);
188 return n;
189}
190
191static bool write_and_stats(const void *buf, size_t len, size_t obs,
192 const char *filename)
193{
194 ssize_t n = full_write_or_warn(buf, len, filename);
195 if (n < 0)
196 return 1;
197 if ((size_t)n == obs)
198 G.out_full++;
199 else if (n) /* > 0 */
200 G.out_part++;
201#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
202 G.total_bytes += n;
203#endif
204 return 0;
205}
206
207#if ENABLE_LFS
208# define XATOU_SFX xatoull_sfx
209#else
210# define XATOU_SFX xatoul_sfx
211#endif
212
213#if ENABLE_FEATURE_DD_IBS_OBS
214static int parse_comma_flags(char *val, const char *words, const char *error_in)
215{
216 int flags = 0;
217 while (1) {
218 int n;
219 char *arg;
220 /* find ',', replace them with NUL so we can use val for
221 * index_in_strings() without copying.
222 * We rely on val being non-null, else strchr would fault.
223 */
224 arg = strchr(val, ',');
225 if (arg)
226 *arg = '\0';
227 n = index_in_strings(words, val);
228 if (n < 0)
229 bb_error_msg_and_die(bb_msg_invalid_arg_to, val, error_in);
230 flags |= (1 << n);
231 if (!arg) /* no ',' left, so this was the last specifier */
232 break;
233 *arg = ','; /* to preserve ps listing */
234 val = arg + 1; /* skip this keyword and ',' */
235 }
236 return flags;
237}
238#endif
239
240int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
241int dd_main(int argc UNUSED_PARAM, char **argv)
242{
243 static const char keywords[] ALIGN1 =
244 "bs\0""count\0""seek\0""skip\0""if\0""of\0"IF_FEATURE_DD_STATUS("status\0")
245#if ENABLE_FEATURE_DD_IBS_OBS
246 "ibs\0""obs\0""conv\0""iflag\0"
247#endif
248 ;
249#if ENABLE_FEATURE_DD_IBS_OBS
250 static const char conv_words[] ALIGN1 =
251 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
252 static const char iflag_words[] ALIGN1 =
253 "skip_bytes\0";
254#endif
255#if ENABLE_FEATURE_DD_STATUS
256 static const char status_words[] ALIGN1 =
257 "none\0""noxfer\0";
258#endif
259 enum {
260 OP_bs = 0,
261 OP_count,
262 OP_seek,
263 OP_skip,
264 OP_if,
265 OP_of,
266 IF_FEATURE_DD_STATUS(OP_status,)
267#if ENABLE_FEATURE_DD_IBS_OBS
268 OP_ibs,
269 OP_obs,
270 OP_conv,
271 OP_iflag,
272 /* Must be in the same order as FLAG_XXX! */
273 OP_conv_notrunc = 0,
274 OP_conv_sync,
275 OP_conv_noerror,
276 OP_conv_fsync,
277 OP_conv_swab,
278 /* Unimplemented conv=XXX: */
279 //nocreat do not create the output file
280 //excl fail if the output file already exists
281 //fdatasync physically write output file data before finishing
282 //lcase change upper case to lower case
283 //ucase change lower case to upper case
284 //block pad newline-terminated records with spaces to cbs-size
285 //unblock replace trailing spaces in cbs-size records with newline
286 //ascii from EBCDIC to ASCII
287 //ebcdic from ASCII to EBCDIC
288 //ibm from ASCII to alternate EBCDIC
289 /* Partially implemented: */
290 //swab swap every pair of input bytes: will abort on non-even reads
291 OP_iflag_skip_bytes,
292#endif
293 };
294 smallint exitcode = EXIT_FAILURE;
295 int i;
296 size_t ibs = 512;
297 char *ibuf;
298#if ENABLE_FEATURE_DD_IBS_OBS
299 size_t obs = 512;
300 char *obuf;
301#else
302# define obs ibs
303# define obuf ibuf
304#endif
305 /* These are all zeroed at once! */
306 struct {
307 size_t oc;
308 ssize_t prev_read_size; /* for detecting swab failure */
309 off_t count;
310 off_t seek, skip;
311 const char *infile, *outfile;
312 } Z;
313#define oc (Z.oc )
314#define prev_read_size (Z.prev_read_size)
315#define count (Z.count )
316#define seek (Z.seek )
317#define skip (Z.skip )
318#define infile (Z.infile )
319#define outfile (Z.outfile)
320
321 memset(&Z, 0, sizeof(Z));
322 INIT_G();
323 //fflush_all(); - is this needed because of NOEXEC?
324
325 for (i = 1; argv[i]; i++) {
326 int what;
327 char *val;
328 char *arg = argv[i];
329
330#if ENABLE_DESKTOP
331 /* "dd --". NB: coreutils 6.9 will complain if they see
332 * more than one of them. We wouldn't. */
333 if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0')
334 continue;
335#endif
336 val = strchr(arg, '=');
337 if (val == NULL)
338 bb_show_usage();
339 *val = '\0';
340 what = index_in_strings(keywords, arg);
341 if (what < 0)
342 bb_show_usage();
343 /* *val = '='; - to preserve ps listing? */
344 val++;
345#if ENABLE_FEATURE_DD_IBS_OBS
346 if (what == OP_ibs) {
347 /* Must fit into positive ssize_t */
348 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
349 /*continue;*/
350 }
351 if (what == OP_obs) {
352 obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
353 /*continue;*/
354 }
355 if (what == OP_conv) {
356 G.flags |= parse_comma_flags(val, conv_words, "conv");
357 /*continue;*/
358 }
359 if (what == OP_iflag) {
360 G.flags |= parse_comma_flags(val, iflag_words, "iflag") << FLAG_IFLAG_SHIFT;
361 /*continue;*/
362 }
363#endif
364 if (what == OP_bs) {
365 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
366 obs = ibs;
367 /*continue;*/
368 }
369 /* These can be large: */
370 if (what == OP_count) {
371 G.flags |= FLAG_COUNT;
372 count = XATOU_SFX(val, cwbkMG_suffixes);
373 /*continue;*/
374 }
375 if (what == OP_seek) {
376 seek = XATOU_SFX(val, cwbkMG_suffixes);
377 /*continue;*/
378 }
379 if (what == OP_skip) {
380 skip = XATOU_SFX(val, cwbkMG_suffixes);
381 /*continue;*/
382 }
383 if (what == OP_if) {
384 infile = val;
385 /*continue;*/
386 }
387 if (what == OP_of) {
388 outfile = val;
389 /*continue;*/
390 }
391#if ENABLE_FEATURE_DD_STATUS
392 if (what == OP_status) {
393 int n;
394 n = index_in_strings(status_words, val);
395 if (n < 0)
396 bb_error_msg_and_die(bb_msg_invalid_arg_to, val, "status");
397 G.flags |= FLAG_STATUS << n;
398 /*continue;*/
399 }
400#endif
401 } /* end of "for (argv[i])" */
402
403//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
404 ibuf = xmalloc(ibs);
405 obuf = ibuf;
406#if ENABLE_FEATURE_DD_IBS_OBS
407 if (ibs != obs) {
408 G.flags |= FLAG_TWOBUFS;
409 obuf = xmalloc(obs);
410 }
411#endif
412
413#if ENABLE_FEATURE_DD_SIGNAL_HANDLING
414 signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status);
415#endif
416#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
417 G.begin_time_us = monotonic_us();
418#endif
419
420 if (infile) {
421 xmove_fd(xopen(infile, O_RDONLY), ifd);
422 } else {
423 infile = bb_msg_standard_input;
424 }
425 if (outfile) {
426 int oflag = O_WRONLY | O_CREAT;
427
428 if (!seek && !(G.flags & FLAG_NOTRUNC))
429 oflag |= O_TRUNC;
430
431 xmove_fd(xopen(outfile, oflag), ofd);
432
433 if (seek && !(G.flags & FLAG_NOTRUNC)) {
434 if (ftruncate(ofd, seek * obs) < 0) {
435 struct stat st;
436
437 if (fstat(ofd, &st) < 0
438 || S_ISREG(st.st_mode)
439 || S_ISDIR(st.st_mode)
440 ) {
441 goto die_outfile;
442 }
443 }
444 }
445 } else {
446 outfile = bb_msg_standard_output;
447 }
448 if (skip) {
449 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs;
450 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) {
451 do {
452 ssize_t n = safe_read(ifd, ibuf, blocksz);
453 if (n < 0)
454 goto die_infile;
455 if (n == 0)
456 break;
457 } while (--skip != 0);
458 }
459 }
460 if (seek) {
461 if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
462 goto die_outfile;
463 }
464
465 while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
466 ssize_t n;
467
468 n = safe_read(ifd, ibuf, ibs);
469 if (n == 0)
470 break;
471 if (n < 0) {
472 /* "Bad block" */
473 if (!(G.flags & FLAG_NOERROR))
474 goto die_infile;
475 bb_simple_perror_msg(infile);
476 /* GNU dd with conv=noerror skips over bad blocks */
477 xlseek(ifd, ibs, SEEK_CUR);
478 /* conv=noerror,sync writes NULs,
479 * conv=noerror just ignores input bad blocks */
480 n = 0;
481 }
482 if (G.flags & FLAG_SWAB) {
483 uint16_t *p16;
484 ssize_t n2;
485
486 /* Our code allows only last read to be odd-sized */
487 if (prev_read_size & 1)
488 bb_error_msg_and_die("can't swab %lu byte buffer",
489 (unsigned long)prev_read_size);
490 prev_read_size = n;
491
492 /* If n is odd, last byte is not swapped:
493 * echo -n "qwe" | dd conv=swab
494 * prints "wqe".
495 */
496 p16 = (void*) ibuf;
497 n2 = (n >> 1);
498 while (--n2 >= 0) {
499 *p16 = bswap_16(*p16);
500 p16++;
501 }
502 }
503 if ((size_t)n == ibs)
504 G.in_full++;
505 else {
506 G.in_part++;
507 if (G.flags & FLAG_SYNC) {
508 memset(ibuf + n, 0, ibs - n);
509 n = ibs;
510 }
511 }
512 if (G.flags & FLAG_TWOBUFS) {
513 char *tmp = ibuf;
514 while (n) {
515 size_t d = obs - oc;
516
517 if (d > (size_t)n)
518 d = n;
519 memcpy(obuf + oc, tmp, d);
520 n -= d;
521 tmp += d;
522 oc += d;
523 if (oc == obs) {
524 if (write_and_stats(obuf, obs, obs, outfile))
525 goto out_status;
526 oc = 0;
527 }
528 }
529 } else {
530 if (write_and_stats(ibuf, n, obs, outfile))
531 goto out_status;
532 }
533
534 if (G.flags & FLAG_FSYNC) {
535 if (fsync(ofd) < 0)
536 goto die_outfile;
537 }
538 }
539
540 if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
541 if (write_and_stats(obuf, oc, obs, outfile))
542 goto out_status;
543 }
544 if (close(ifd) < 0) {
545 die_infile:
546 bb_simple_perror_msg_and_die(infile);
547 }
548
549 if (close(ofd) < 0) {
550 die_outfile:
551 bb_simple_perror_msg_and_die(outfile);
552 }
553
554 exitcode = EXIT_SUCCESS;
555 out_status:
556 if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE))
557 dd_output_status(0);
558
559 if (ENABLE_FEATURE_CLEAN_UP) {
560 free(obuf);
561 if (G.flags & FLAG_TWOBUFS)
562 free(ibuf);
563 }
564
565 return exitcode;
566}
Note: See TracBrowser for help on using the repository browser.