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 tarball for details.
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
;
38 #define G (*(struct globals*)&bb_common_bufsiz1)
39 /* We have to zero it out because of NOEXEC */
40 #define INIT_G() memset(&G, 0, sizeof(G))
43 static void dd_output_status(int UNUSED_PARAM cur_signal
)
45 /* Deliberately using %u, not %d */
46 fprintf(stderr
, "%"OFF_FMT
"u+%"OFF_FMT
"u records in\n"
47 "%"OFF_FMT
"u+%"OFF_FMT
"u records out\n",
49 G
.out_full
, G
.out_part
);
52 static ssize_t
full_write_or_warn(const void *buf
, size_t len
,
53 const char *const filename
)
55 ssize_t n
= full_write(ofd
, buf
, len
);
57 bb_perror_msg("writing '%s'", filename
);
61 static bool write_and_stats(const void *buf
, size_t len
, size_t obs
,
64 ssize_t n
= full_write_or_warn(buf
, len
, filename
);
75 #define XATOU_SFX xatoull_sfx
77 #define XATOU_SFX xatoul_sfx
80 int dd_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
81 int dd_main(int argc UNUSED_PARAM
, char **argv
)
84 /* Must be in the same order as OP_conv_XXX! */
85 /* (see "flags |= (1 << what)" below) */
86 FLAG_NOTRUNC
= 1 << 0,
88 FLAG_NOERROR
= 1 << 2,
90 /* end of conv flags */
91 FLAG_TWOBUFS
= 1 << 4,
94 static const char keywords
[] ALIGN1
=
95 "bs\0""count\0""seek\0""skip\0""if\0""of\0"
96 #if ENABLE_FEATURE_DD_IBS_OBS
97 "ibs\0""obs\0""conv\0"
100 #if ENABLE_FEATURE_DD_IBS_OBS
101 static const char conv_words
[] ALIGN1
=
102 "notrunc\0""sync\0""noerror\0""fsync\0";
111 #if ENABLE_FEATURE_DD_IBS_OBS
115 /* Must be in the same order as FLAG_XXX! */
120 /* Unimplemented conv=XXX: */
121 //nocreat do not create the output file
122 //excl fail if the output file already exists
123 //fdatasync physically write output file data before finishing
124 //swab swap every pair of input bytes
125 //lcase change upper case to lower case
126 //ucase change lower case to upper case
127 //block pad newline-terminated records with spaces to cbs-size
128 //unblock replace trailing spaces in cbs-size records with newline
129 //ascii from EBCDIC to ASCII
130 //ebcdic from ASCII to EBCDIC
131 //ibm from ASCII to alternate EBCDIC
134 int exitcode
= EXIT_FAILURE
;
135 size_t ibs
= 512, obs
= 512;
138 /* And these are all zeroed at once! */
144 const char *infile
, *outfile
;
146 #define flags (Z.flags )
148 #define count (Z.count )
149 #define seek (Z.seek )
150 #define skip (Z.skip )
151 #define infile (Z.infile )
152 #define outfile (Z.outfile)
154 memset(&Z
, 0, sizeof(Z
));
156 //fflush(NULL); - is this needed because of NOEXEC?
158 #if ENABLE_FEATURE_DD_SIGNAL_HANDLING
159 signal_SA_RESTART_empty_mask(SIGUSR1
, dd_output_status
);
162 for (n
= 1; argv
[n
]; n
++) {
168 /* "dd --". NB: coreutils 6.9 will complain if they see
169 * more than one of them. We wouldn't. */
170 if (arg
[0] == '-' && arg
[1] == '-' && arg
[2] == '\0')
173 val
= strchr(arg
, '=');
177 what
= index_in_strings(keywords
, arg
);
180 /* *val = '='; - to preserve ps listing? */
182 #if ENABLE_FEATURE_DD_IBS_OBS
183 if (what
== OP_ibs
) {
184 /* Must fit into positive ssize_t */
185 ibs
= xatoul_range_sfx(val
, 1, ((size_t)-1L)/2, dd_suffixes
);
188 if (what
== OP_obs
) {
189 obs
= xatoul_range_sfx(val
, 1, ((size_t)-1L)/2, dd_suffixes
);
192 if (what
== OP_conv
) {
194 /* find ',', replace them with NUL so we can use val for
195 * index_in_strings() without copying.
196 * We rely on val being non-null, else strchr would fault.
198 arg
= strchr(val
, ',');
201 what
= index_in_strings(conv_words
, val
);
203 bb_error_msg_and_die(bb_msg_invalid_arg
, val
, "conv");
204 flags
|= (1 << what
);
205 if (!arg
) /* no ',' left, so this was the last specifier */
207 /* *arg = ','; - to preserve ps listing? */
208 val
= arg
+ 1; /* skip this keyword and ',' */
210 continue; /* we trashed 'what', can't fall through */
214 ibs
= obs
= xatoul_range_sfx(val
, 1, ((size_t)-1L)/2, dd_suffixes
);
217 /* These can be large: */
218 if (what
== OP_count
) {
220 count
= XATOU_SFX(val
, dd_suffixes
);
223 if (what
== OP_seek
) {
224 seek
= XATOU_SFX(val
, dd_suffixes
);
227 if (what
== OP_skip
) {
228 skip
= XATOU_SFX(val
, dd_suffixes
);
239 } /* end of "for (argv[n])" */
241 //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
242 ibuf
= obuf
= xmalloc(ibs
);
244 flags
|= FLAG_TWOBUFS
;
248 xmove_fd(xopen(infile
, O_RDONLY
), ifd
);
250 infile
= bb_msg_standard_input
;
252 if (outfile
!= NULL
) {
253 int oflag
= O_WRONLY
| O_CREAT
;
255 if (!seek
&& !(flags
& FLAG_NOTRUNC
))
258 xmove_fd(xopen(outfile
, oflag
), ofd
);
260 if (seek
&& !(flags
& FLAG_NOTRUNC
)) {
261 if (ftruncate(ofd
, seek
* obs
) < 0) {
264 if (fstat(ofd
, &st
) < 0 || S_ISREG(st
.st_mode
) ||
270 outfile
= bb_msg_standard_output
;
273 if (lseek(ifd
, skip
* ibs
, SEEK_CUR
) < 0) {
275 n
= safe_read(ifd
, ibuf
, ibs
);
284 if (lseek(ofd
, seek
* obs
, SEEK_CUR
) < 0)
288 while (!(flags
& FLAG_COUNT
) || (G
.in_full
+ G
.in_part
!= count
)) {
289 if (flags
& FLAG_NOERROR
) /* Pre-zero the buffer if conv=noerror */
290 memset(ibuf
, 0, ibs
);
291 n
= safe_read(ifd
, ibuf
, ibs
);
295 if (!(flags
& FLAG_NOERROR
))
298 bb_simple_perror_msg(infile
);
300 if ((size_t)n
== ibs
)
304 if (flags
& FLAG_SYNC
) {
305 memset(ibuf
+ n
, '\0', ibs
- n
);
309 if (flags
& FLAG_TWOBUFS
) {
316 memcpy(obuf
+ oc
, tmp
, d
);
321 if (write_and_stats(obuf
, obs
, obs
, outfile
))
326 } else if (write_and_stats(ibuf
, n
, obs
, outfile
))
329 if (flags
& FLAG_FSYNC
) {
335 if (ENABLE_FEATURE_DD_IBS_OBS
&& oc
) {
336 w
= full_write_or_warn(obuf
, oc
, outfile
);
337 if (w
< 0) goto out_status
;
338 if (w
> 0) G
.out_part
++;
340 if (close(ifd
) < 0) {
342 bb_simple_perror_msg_and_die(infile
);
345 if (close(ofd
) < 0) {
347 bb_simple_perror_msg_and_die(outfile
);
350 exitcode
= EXIT_SUCCESS
;