1 /* vi: set sw=4 ts=4: */
3 * Mini dd implementation for busybox
6 * Copyright (C) 2000,2001 Matt Kraai
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
11 //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"
13 //usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]")
14 //usage:#define dd_full_usage "\n\n"
15 //usage: "Copy a file with converting and formatting\n"
16 //usage: "\n if=FILE Read from FILE instead of stdin"
17 //usage: "\n of=FILE Write to FILE instead of stdout"
18 //usage: "\n bs=N Read and write N bytes at a time"
19 //usage: IF_FEATURE_DD_IBS_OBS(
20 //usage: "\n ibs=N Read N bytes at a time"
22 //usage: IF_FEATURE_DD_IBS_OBS(
23 //usage: "\n obs=N Write N bytes at a time"
25 //usage: "\n count=N Copy only N input blocks"
26 //usage: "\n skip=N Skip N input blocks"
27 //usage: "\n seek=N Skip N output blocks"
28 //usage: IF_FEATURE_DD_IBS_OBS(
29 //usage: "\n conv=notrunc Don't truncate output file"
30 //usage: "\n conv=noerror Continue after read errors"
31 //usage: "\n conv=sync Pad blocks with zeros"
32 //usage: "\n conv=fsync Physically write data out before finishing"
35 //usage: "\nNumbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),"
36 //usage: "\nMD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)"
38 //usage:#define dd_example_usage
39 //usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n"
40 //usage: "4+0 records in\n"
41 //usage: "4+0 records out\n"
45 /* This is a NOEXEC applet. Be very careful! */
53 static const struct suffix_mult dd_suffixes
[] = {
59 { "K", 1024 }, /* compat with coreutils dd */
68 off_t out_full
, out_part
, in_full
, in_part
;
69 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
70 unsigned long long total_bytes
;
71 unsigned long long begin_time_us
;
74 #define G (*(struct globals*)&bb_common_bufsiz1)
75 #define INIT_G() do { \
76 /* we have to zero it out because of NOEXEC */ \
77 memset(&G, 0, sizeof(G)); \
81 static void dd_output_status(int UNUSED_PARAM cur_signal
)
83 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
85 unsigned long long bytes_sec
;
86 unsigned long long now_us
= monotonic_us(); /* before fprintf */
89 /* Deliberately using %u, not %d */
90 fprintf(stderr
, "%"OFF_FMT
"u+%"OFF_FMT
"u records in\n"
91 "%"OFF_FMT
"u+%"OFF_FMT
"u records out\n",
93 G
.out_full
, G
.out_part
);
95 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
96 fprintf(stderr
, "%llu bytes (%sB) copied, ",
98 /* show fractional digit, use suffixes */
99 make_human_readable_str(G
.total_bytes
, 1, 0)
102 * ./busybox dd </dev/null >/dev/null
103 * ./busybox dd bs=1M count=2000 </dev/zero >/dev/null
104 * (echo DONE) | ./busybox dd >/dev/null
105 * (sleep 1; echo DONE) | ./busybox dd >/dev/null
107 seconds
= (now_us
- G
.begin_time_us
) / 1000000.0;
108 bytes_sec
= G
.total_bytes
/ seconds
;
109 fprintf(stderr
, "%f seconds, %sB/s\n",
111 /* show fractional digit, use suffixes */
112 make_human_readable_str(bytes_sec
, 1, 0)
117 static ssize_t
full_write_or_warn(const void *buf
, size_t len
,
118 const char *const filename
)
120 ssize_t n
= full_write(ofd
, buf
, len
);
122 bb_perror_msg("writing '%s'", filename
);
126 static bool write_and_stats(const void *buf
, size_t len
, size_t obs
,
127 const char *filename
)
129 ssize_t n
= full_write_or_warn(buf
, len
, filename
);
132 if ((size_t)n
== obs
)
134 else if (n
) /* > 0 */
136 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
143 # define XATOU_SFX xatoull_sfx
145 # define XATOU_SFX xatoul_sfx
148 int dd_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
149 int dd_main(int argc UNUSED_PARAM
, char **argv
)
152 /* Must be in the same order as OP_conv_XXX! */
153 /* (see "flags |= (1 << what)" below) */
154 FLAG_NOTRUNC
= 1 << 0,
156 FLAG_NOERROR
= 1 << 2,
158 /* end of conv flags */
159 FLAG_TWOBUFS
= 1 << 4,
162 static const char keywords
[] ALIGN1
=
163 "bs\0""count\0""seek\0""skip\0""if\0""of\0"
164 #if ENABLE_FEATURE_DD_IBS_OBS
165 "ibs\0""obs\0""conv\0"
168 #if ENABLE_FEATURE_DD_IBS_OBS
169 static const char conv_words
[] ALIGN1
=
170 "notrunc\0""sync\0""noerror\0""fsync\0";
179 #if ENABLE_FEATURE_DD_IBS_OBS
183 /* Must be in the same order as FLAG_XXX! */
188 /* Unimplemented conv=XXX: */
189 //nocreat do not create the output file
190 //excl fail if the output file already exists
191 //fdatasync physically write output file data before finishing
192 //swab swap every pair of input bytes
193 //lcase change upper case to lower case
194 //ucase change lower case to upper case
195 //block pad newline-terminated records with spaces to cbs-size
196 //unblock replace trailing spaces in cbs-size records with newline
197 //ascii from EBCDIC to ASCII
198 //ebcdic from ASCII to EBCDIC
199 //ibm from ASCII to alternate EBCDIC
202 int exitcode
= EXIT_FAILURE
;
203 size_t ibs
= 512, obs
= 512;
206 /* And these are all zeroed at once! */
212 const char *infile
, *outfile
;
214 #define flags (Z.flags )
216 #define count (Z.count )
217 #define seek (Z.seek )
218 #define skip (Z.skip )
219 #define infile (Z.infile )
220 #define outfile (Z.outfile)
222 memset(&Z
, 0, sizeof(Z
));
224 //fflush_all(); - is this needed because of NOEXEC?
226 for (n
= 1; argv
[n
]; n
++) {
232 /* "dd --". NB: coreutils 6.9 will complain if they see
233 * more than one of them. We wouldn't. */
234 if (arg
[0] == '-' && arg
[1] == '-' && arg
[2] == '\0')
237 val
= strchr(arg
, '=');
241 what
= index_in_strings(keywords
, arg
);
244 /* *val = '='; - to preserve ps listing? */
246 #if ENABLE_FEATURE_DD_IBS_OBS
247 if (what
== OP_ibs
) {
248 /* Must fit into positive ssize_t */
249 ibs
= xatoul_range_sfx(val
, 1, ((size_t)-1L)/2, dd_suffixes
);
252 if (what
== OP_obs
) {
253 obs
= xatoul_range_sfx(val
, 1, ((size_t)-1L)/2, dd_suffixes
);
256 if (what
== OP_conv
) {
258 /* find ',', replace them with NUL so we can use val for
259 * index_in_strings() without copying.
260 * We rely on val being non-null, else strchr would fault.
262 arg
= strchr(val
, ',');
265 what
= index_in_strings(conv_words
, val
);
267 bb_error_msg_and_die(bb_msg_invalid_arg
, val
, "conv");
268 flags
|= (1 << what
);
269 if (!arg
) /* no ',' left, so this was the last specifier */
271 /* *arg = ','; - to preserve ps listing? */
272 val
= arg
+ 1; /* skip this keyword and ',' */
274 continue; /* we trashed 'what', can't fall through */
278 ibs
= obs
= xatoul_range_sfx(val
, 1, ((size_t)-1L)/2, dd_suffixes
);
281 /* These can be large: */
282 if (what
== OP_count
) {
284 count
= XATOU_SFX(val
, dd_suffixes
);
287 if (what
== OP_seek
) {
288 seek
= XATOU_SFX(val
, dd_suffixes
);
291 if (what
== OP_skip
) {
292 skip
= XATOU_SFX(val
, dd_suffixes
);
303 } /* end of "for (argv[n])" */
305 //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
306 ibuf
= obuf
= xmalloc(ibs
);
308 flags
|= FLAG_TWOBUFS
;
312 #if ENABLE_FEATURE_DD_SIGNAL_HANDLING
313 signal_SA_RESTART_empty_mask(SIGUSR1
, dd_output_status
);
315 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
316 G
.begin_time_us
= monotonic_us();
320 xmove_fd(xopen(infile
, O_RDONLY
), ifd
);
322 infile
= bb_msg_standard_input
;
324 if (outfile
!= NULL
) {
325 int oflag
= O_WRONLY
| O_CREAT
;
327 if (!seek
&& !(flags
& FLAG_NOTRUNC
))
330 xmove_fd(xopen(outfile
, oflag
), ofd
);
332 if (seek
&& !(flags
& FLAG_NOTRUNC
)) {
333 if (ftruncate(ofd
, seek
* obs
) < 0) {
336 if (fstat(ofd
, &st
) < 0
337 || S_ISREG(st
.st_mode
)
338 || S_ISDIR(st
.st_mode
)
345 outfile
= bb_msg_standard_output
;
348 if (lseek(ifd
, skip
* ibs
, SEEK_CUR
) < 0) {
350 n
= safe_read(ifd
, ibuf
, ibs
);
359 if (lseek(ofd
, seek
* obs
, SEEK_CUR
) < 0)
363 while (!(flags
& FLAG_COUNT
) || (G
.in_full
+ G
.in_part
!= count
)) {
364 n
= safe_read(ifd
, ibuf
, ibs
);
369 if (!(flags
& FLAG_NOERROR
))
371 bb_simple_perror_msg(infile
);
372 /* GNU dd with conv=noerror skips over bad blocks */
373 xlseek(ifd
, ibs
, SEEK_CUR
);
374 /* conv=noerror,sync writes NULs,
375 * conv=noerror just ignores input bad blocks */
378 if ((size_t)n
== ibs
)
382 if (flags
& FLAG_SYNC
) {
383 memset(ibuf
+ n
, 0, ibs
- n
);
387 if (flags
& FLAG_TWOBUFS
) {
394 memcpy(obuf
+ oc
, tmp
, d
);
399 if (write_and_stats(obuf
, obs
, obs
, outfile
))
404 } else if (write_and_stats(ibuf
, n
, obs
, outfile
))
407 if (flags
& FLAG_FSYNC
) {
413 if (ENABLE_FEATURE_DD_IBS_OBS
&& oc
) {
414 w
= full_write_or_warn(obuf
, oc
, outfile
);
415 if (w
< 0) goto out_status
;
416 if (w
> 0) G
.out_part
++;
418 if (close(ifd
) < 0) {
420 bb_simple_perror_msg_and_die(infile
);
423 if (close(ofd
) < 0) {
425 bb_simple_perror_msg_and_die(outfile
);
428 exitcode
= EXIT_SUCCESS
;
432 if (ENABLE_FEATURE_CLEAN_UP
) {
434 if (flags
& FLAG_TWOBUFS
)