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.
13 /* This is a NOEXEC applet. Be very careful! */
21 static const struct suffix_mult dd_suffixes
[] = {
27 { "K", 1024 }, /* compat with coreutils dd */
36 off_t out_full
, out_part
, in_full
, in_part
;
37 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
38 unsigned long long total_bytes
;
39 unsigned long long begin_time_us
;
42 #define G (*(struct globals*)&bb_common_bufsiz1)
43 #define INIT_G() do { \
44 /* we have to zero it out because of NOEXEC */ \
45 memset(&G, 0, sizeof(G)); \
49 static void dd_output_status(int UNUSED_PARAM cur_signal
)
51 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
53 unsigned long long bytes_sec
;
54 unsigned long long now_us
= monotonic_us(); /* before fprintf */
57 /* Deliberately using %u, not %d */
58 fprintf(stderr
, "%"OFF_FMT
"u+%"OFF_FMT
"u records in\n"
59 "%"OFF_FMT
"u+%"OFF_FMT
"u records out\n",
61 G
.out_full
, G
.out_part
);
63 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
64 fprintf(stderr
, "%llu bytes (%sB) copied, ",
66 /* show fractional digit, use suffixes */
67 make_human_readable_str(G
.total_bytes
, 1, 0)
70 * ./busybox dd </dev/null >/dev/null
71 * ./busybox dd bs=1M count=2000 </dev/zero >/dev/null
72 * (echo DONE) | ./busybox dd >/dev/null
73 * (sleep 1; echo DONE) | ./busybox dd >/dev/null
75 seconds
= (now_us
- G
.begin_time_us
) / 1000000.0;
76 bytes_sec
= G
.total_bytes
/ seconds
;
77 fprintf(stderr
, "%f seconds, %sB/s\n",
79 /* show fractional digit, use suffixes */
80 make_human_readable_str(bytes_sec
, 1, 0)
85 static ssize_t
full_write_or_warn(const void *buf
, size_t len
,
86 const char *const filename
)
88 ssize_t n
= full_write(ofd
, buf
, len
);
90 bb_perror_msg("writing '%s'", filename
);
94 static bool write_and_stats(const void *buf
, size_t len
, size_t obs
,
97 ssize_t n
= full_write_or_warn(buf
, len
, filename
);
100 if ((size_t)n
== obs
)
102 else if (n
) /* > 0 */
104 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
111 # define XATOU_SFX xatoull_sfx
113 # define XATOU_SFX xatoul_sfx
116 int dd_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
117 int dd_main(int argc UNUSED_PARAM
, char **argv
)
120 /* Must be in the same order as OP_conv_XXX! */
121 /* (see "flags |= (1 << what)" below) */
122 FLAG_NOTRUNC
= 1 << 0,
124 FLAG_NOERROR
= 1 << 2,
126 /* end of conv flags */
127 FLAG_TWOBUFS
= 1 << 4,
130 static const char keywords
[] ALIGN1
=
131 "bs\0""count\0""seek\0""skip\0""if\0""of\0"
132 #if ENABLE_FEATURE_DD_IBS_OBS
133 "ibs\0""obs\0""conv\0"
136 #if ENABLE_FEATURE_DD_IBS_OBS
137 static const char conv_words
[] ALIGN1
=
138 "notrunc\0""sync\0""noerror\0""fsync\0";
147 #if ENABLE_FEATURE_DD_IBS_OBS
151 /* Must be in the same order as FLAG_XXX! */
156 /* Unimplemented conv=XXX: */
157 //nocreat do not create the output file
158 //excl fail if the output file already exists
159 //fdatasync physically write output file data before finishing
160 //swab swap every pair of input bytes
161 //lcase change upper case to lower case
162 //ucase change lower case to upper case
163 //block pad newline-terminated records with spaces to cbs-size
164 //unblock replace trailing spaces in cbs-size records with newline
165 //ascii from EBCDIC to ASCII
166 //ebcdic from ASCII to EBCDIC
167 //ibm from ASCII to alternate EBCDIC
170 int exitcode
= EXIT_FAILURE
;
171 size_t ibs
= 512, obs
= 512;
174 /* And these are all zeroed at once! */
180 const char *infile
, *outfile
;
182 #define flags (Z.flags )
184 #define count (Z.count )
185 #define seek (Z.seek )
186 #define skip (Z.skip )
187 #define infile (Z.infile )
188 #define outfile (Z.outfile)
190 memset(&Z
, 0, sizeof(Z
));
192 //fflush_all(); - is this needed because of NOEXEC?
194 for (n
= 1; argv
[n
]; n
++) {
200 /* "dd --". NB: coreutils 6.9 will complain if they see
201 * more than one of them. We wouldn't. */
202 if (arg
[0] == '-' && arg
[1] == '-' && arg
[2] == '\0')
205 val
= strchr(arg
, '=');
209 what
= index_in_strings(keywords
, arg
);
212 /* *val = '='; - to preserve ps listing? */
214 #if ENABLE_FEATURE_DD_IBS_OBS
215 if (what
== OP_ibs
) {
216 /* Must fit into positive ssize_t */
217 ibs
= xatoul_range_sfx(val
, 1, ((size_t)-1L)/2, dd_suffixes
);
220 if (what
== OP_obs
) {
221 obs
= xatoul_range_sfx(val
, 1, ((size_t)-1L)/2, dd_suffixes
);
224 if (what
== OP_conv
) {
226 /* find ',', replace them with NUL so we can use val for
227 * index_in_strings() without copying.
228 * We rely on val being non-null, else strchr would fault.
230 arg
= strchr(val
, ',');
233 what
= index_in_strings(conv_words
, val
);
235 bb_error_msg_and_die(bb_msg_invalid_arg
, val
, "conv");
236 flags
|= (1 << what
);
237 if (!arg
) /* no ',' left, so this was the last specifier */
239 /* *arg = ','; - to preserve ps listing? */
240 val
= arg
+ 1; /* skip this keyword and ',' */
242 continue; /* we trashed 'what', can't fall through */
246 ibs
= obs
= xatoul_range_sfx(val
, 1, ((size_t)-1L)/2, dd_suffixes
);
249 /* These can be large: */
250 if (what
== OP_count
) {
252 count
= XATOU_SFX(val
, dd_suffixes
);
255 if (what
== OP_seek
) {
256 seek
= XATOU_SFX(val
, dd_suffixes
);
259 if (what
== OP_skip
) {
260 skip
= XATOU_SFX(val
, dd_suffixes
);
271 } /* end of "for (argv[n])" */
273 //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
274 ibuf
= obuf
= xmalloc(ibs
);
276 flags
|= FLAG_TWOBUFS
;
280 #if ENABLE_FEATURE_DD_SIGNAL_HANDLING
281 signal_SA_RESTART_empty_mask(SIGUSR1
, dd_output_status
);
283 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
284 G
.begin_time_us
= monotonic_us();
288 xmove_fd(xopen(infile
, O_RDONLY
), ifd
);
290 infile
= bb_msg_standard_input
;
292 if (outfile
!= NULL
) {
293 int oflag
= O_WRONLY
| O_CREAT
;
295 if (!seek
&& !(flags
& FLAG_NOTRUNC
))
298 xmove_fd(xopen(outfile
, oflag
), ofd
);
300 if (seek
&& !(flags
& FLAG_NOTRUNC
)) {
301 if (ftruncate(ofd
, seek
* obs
) < 0) {
304 if (fstat(ofd
, &st
) < 0
305 || S_ISREG(st
.st_mode
)
306 || S_ISDIR(st
.st_mode
)
313 outfile
= bb_msg_standard_output
;
316 if (lseek(ifd
, skip
* ibs
, SEEK_CUR
) < 0) {
318 n
= safe_read(ifd
, ibuf
, ibs
);
327 if (lseek(ofd
, seek
* obs
, SEEK_CUR
) < 0)
331 while (!(flags
& FLAG_COUNT
) || (G
.in_full
+ G
.in_part
!= count
)) {
332 n
= safe_read(ifd
, ibuf
, ibs
);
337 if (!(flags
& FLAG_NOERROR
))
339 bb_simple_perror_msg(infile
);
340 /* GNU dd with conv=noerror skips over bad blocks */
341 xlseek(ifd
, ibs
, SEEK_CUR
);
342 /* conv=noerror,sync writes NULs,
343 * conv=noerror just ignores input bad blocks */
346 if ((size_t)n
== ibs
)
350 if (flags
& FLAG_SYNC
) {
351 memset(ibuf
+ n
, 0, ibs
- n
);
355 if (flags
& FLAG_TWOBUFS
) {
362 memcpy(obuf
+ oc
, tmp
, d
);
367 if (write_and_stats(obuf
, obs
, obs
, outfile
))
372 } else if (write_and_stats(ibuf
, n
, obs
, outfile
))
375 if (flags
& FLAG_FSYNC
) {
381 if (ENABLE_FEATURE_DD_IBS_OBS
&& oc
) {
382 w
= full_write_or_warn(obuf
, oc
, outfile
);
383 if (w
< 0) goto out_status
;
384 if (w
> 0) G
.out_part
++;
386 if (close(ifd
) < 0) {
388 bb_simple_perror_msg_and_die(infile
);
391 if (close(ofd
) < 0) {
393 bb_simple_perror_msg_and_die(outfile
);
396 exitcode
= EXIT_SUCCESS
;