Annotation of /trunk/mkinitrd-magellan/busybox/coreutils/dd.c
Parent Directory | Revision Log
Revision 816 -
(hide annotations)
(download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 8213 byte(s)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 8213 byte(s)
-updated to busybox-1.13.4
1 | niro | 532 | /* 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 tarball for details. | ||
9 | */ | ||
10 | |||
11 | #include <signal.h> /* For FEATURE_DD_SIGNAL_HANDLING */ | ||
12 | niro | 816 | #include "libbb.h" |
13 | niro | 532 | |
14 | niro | 816 | /* This is a NOEXEC applet. Be very careful! */ |
15 | |||
16 | |||
17 | enum { | ||
18 | ifd = STDIN_FILENO, | ||
19 | ofd = STDOUT_FILENO, | ||
20 | }; | ||
21 | |||
22 | niro | 532 | static const struct suffix_mult dd_suffixes[] = { |
23 | { "c", 1 }, | ||
24 | { "w", 2 }, | ||
25 | { "b", 512 }, | ||
26 | { "kD", 1000 }, | ||
27 | { "k", 1024 }, | ||
28 | niro | 816 | { "K", 1024 }, /* compat with coreutils dd */ |
29 | niro | 532 | { "MD", 1000000 }, |
30 | { "M", 1048576 }, | ||
31 | { "GD", 1000000000 }, | ||
32 | { "G", 1073741824 }, | ||
33 | niro | 816 | { } |
34 | niro | 532 | }; |
35 | |||
36 | niro | 816 | struct globals { |
37 | off_t out_full, out_part, in_full, in_part; | ||
38 | }; | ||
39 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
40 | /* We have to zero it out because of NOEXEC */ | ||
41 | #define INIT_G() memset(&G, 0, sizeof(G)) | ||
42 | niro | 532 | |
43 | niro | 816 | |
44 | static void dd_output_status(int UNUSED_PARAM cur_signal) | ||
45 | niro | 532 | { |
46 | niro | 816 | /* Deliberately using %u, not %d */ |
47 | fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n" | ||
48 | "%"OFF_FMT"u+%"OFF_FMT"u records out\n", | ||
49 | G.in_full, G.in_part, | ||
50 | G.out_full, G.out_part); | ||
51 | niro | 532 | } |
52 | |||
53 | niro | 816 | static ssize_t full_write_or_warn(const void *buf, size_t len, |
54 | const char *const filename) | ||
55 | niro | 532 | { |
56 | niro | 816 | ssize_t n = full_write(ofd, buf, len); |
57 | niro | 532 | if (n < 0) |
58 | bb_perror_msg("writing '%s'", filename); | ||
59 | return n; | ||
60 | } | ||
61 | |||
62 | niro | 816 | static bool write_and_stats(const void *buf, size_t len, size_t obs, |
63 | const char *filename) | ||
64 | { | ||
65 | ssize_t n = full_write_or_warn(buf, len, filename); | ||
66 | if (n < 0) | ||
67 | return 1; | ||
68 | if ((size_t)n == obs) | ||
69 | G.out_full++; | ||
70 | else if (n) /* > 0 */ | ||
71 | G.out_part++; | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | niro | 532 | #if ENABLE_LFS |
76 | #define XATOU_SFX xatoull_sfx | ||
77 | #else | ||
78 | #define XATOU_SFX xatoul_sfx | ||
79 | #endif | ||
80 | |||
81 | niro | 816 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
82 | int dd_main(int argc UNUSED_PARAM, char **argv) | ||
83 | niro | 532 | { |
84 | enum { | ||
85 | niro | 816 | /* Must be in the same order as OP_conv_XXX! */ |
86 | /* (see "flags |= (1 << what)" below) */ | ||
87 | FLAG_NOTRUNC = 1 << 0, | ||
88 | FLAG_SYNC = 1 << 1, | ||
89 | FLAG_NOERROR = 1 << 2, | ||
90 | FLAG_FSYNC = 1 << 3, | ||
91 | /* end of conv flags */ | ||
92 | FLAG_TWOBUFS = 1 << 4, | ||
93 | FLAG_COUNT = 1 << 5, | ||
94 | niro | 532 | }; |
95 | niro | 816 | static const char keywords[] ALIGN1 = |
96 | "bs\0""count\0""seek\0""skip\0""if\0""of\0" | ||
97 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
98 | "ibs\0""obs\0""conv\0" | ||
99 | #endif | ||
100 | ; | ||
101 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
102 | static const char conv_words[] ALIGN1 = | ||
103 | "notrunc\0""sync\0""noerror\0""fsync\0"; | ||
104 | #endif | ||
105 | enum { | ||
106 | OP_bs = 0, | ||
107 | OP_count, | ||
108 | OP_seek, | ||
109 | OP_skip, | ||
110 | OP_if, | ||
111 | OP_of, | ||
112 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
113 | OP_ibs, | ||
114 | OP_obs, | ||
115 | OP_conv, | ||
116 | /* Must be in the same order as FLAG_XXX! */ | ||
117 | OP_conv_notrunc = 0, | ||
118 | OP_conv_sync, | ||
119 | OP_conv_noerror, | ||
120 | OP_conv_fsync, | ||
121 | /* Unimplemented conv=XXX: */ | ||
122 | //nocreat do not create the output file | ||
123 | //excl fail if the output file already exists | ||
124 | //fdatasync physically write output file data before finishing | ||
125 | //swab swap every pair of input bytes | ||
126 | //lcase change upper case to lower case | ||
127 | //ucase change lower case to upper case | ||
128 | //block pad newline-terminated records with spaces to cbs-size | ||
129 | //unblock replace trailing spaces in cbs-size records with newline | ||
130 | //ascii from EBCDIC to ASCII | ||
131 | //ebcdic from ASCII to EBCDIC | ||
132 | //ibm from ASCII to alternate EBCDIC | ||
133 | #endif | ||
134 | }; | ||
135 | int exitcode = EXIT_FAILURE; | ||
136 | size_t ibs = 512, obs = 512; | ||
137 | niro | 532 | ssize_t n, w; |
138 | char *ibuf, *obuf; | ||
139 | niro | 816 | /* And these are all zeroed at once! */ |
140 | struct { | ||
141 | int flags; | ||
142 | size_t oc; | ||
143 | off_t count; | ||
144 | off_t seek, skip; | ||
145 | const char *infile, *outfile; | ||
146 | } Z; | ||
147 | #define flags (Z.flags ) | ||
148 | #define oc (Z.oc ) | ||
149 | #define count (Z.count ) | ||
150 | #define seek (Z.seek ) | ||
151 | #define skip (Z.skip ) | ||
152 | #define infile (Z.infile ) | ||
153 | #define outfile (Z.outfile) | ||
154 | niro | 532 | |
155 | niro | 816 | memset(&Z, 0, sizeof(Z)); |
156 | INIT_G(); | ||
157 | //fflush(NULL); - is this needed because of NOEXEC? | ||
158 | niro | 532 | |
159 | niro | 816 | #if ENABLE_FEATURE_DD_SIGNAL_HANDLING |
160 | signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status); | ||
161 | #endif | ||
162 | niro | 532 | |
163 | niro | 816 | for (n = 1; argv[n]; n++) { |
164 | int what; | ||
165 | char *val; | ||
166 | niro | 532 | char *arg = argv[n]; |
167 | |||
168 | niro | 816 | #if ENABLE_DESKTOP |
169 | /* "dd --". NB: coreutils 6.9 will complain if they see | ||
170 | * more than one of them. We wouldn't. */ | ||
171 | if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') | ||
172 | continue; | ||
173 | #endif | ||
174 | val = strchr(arg, '='); | ||
175 | if (val == NULL) | ||
176 | bb_show_usage(); | ||
177 | *val = '\0'; | ||
178 | what = index_in_strings(keywords, arg); | ||
179 | if (what < 0) | ||
180 | bb_show_usage(); | ||
181 | /* *val = '='; - to preserve ps listing? */ | ||
182 | val++; | ||
183 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
184 | if (what == OP_ibs) { | ||
185 | /* Must fit into positive ssize_t */ | ||
186 | ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes); | ||
187 | /*continue;*/ | ||
188 | } | ||
189 | if (what == OP_obs) { | ||
190 | obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes); | ||
191 | /*continue;*/ | ||
192 | } | ||
193 | if (what == OP_conv) { | ||
194 | niro | 532 | while (1) { |
195 | niro | 816 | /* find ',', replace them with NUL so we can use val for |
196 | * index_in_strings() without copying. | ||
197 | * We rely on val being non-null, else strchr would fault. | ||
198 | */ | ||
199 | arg = strchr(val, ','); | ||
200 | if (arg) | ||
201 | *arg = '\0'; | ||
202 | what = index_in_strings(conv_words, val); | ||
203 | if (what < 0) | ||
204 | bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv"); | ||
205 | flags |= (1 << what); | ||
206 | if (!arg) /* no ',' left, so this was the last specifier */ | ||
207 | break; | ||
208 | /* *arg = ','; - to preserve ps listing? */ | ||
209 | val = arg + 1; /* skip this keyword and ',' */ | ||
210 | niro | 532 | } |
211 | niro | 816 | continue; /* we trashed 'what', can't fall through */ |
212 | } | ||
213 | #endif | ||
214 | if (what == OP_bs) { | ||
215 | ibs = obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes); | ||
216 | /*continue;*/ | ||
217 | } | ||
218 | /* These can be large: */ | ||
219 | if (what == OP_count) { | ||
220 | flags |= FLAG_COUNT; | ||
221 | count = XATOU_SFX(val, dd_suffixes); | ||
222 | /*continue;*/ | ||
223 | } | ||
224 | if (what == OP_seek) { | ||
225 | seek = XATOU_SFX(val, dd_suffixes); | ||
226 | /*continue;*/ | ||
227 | } | ||
228 | if (what == OP_skip) { | ||
229 | skip = XATOU_SFX(val, dd_suffixes); | ||
230 | /*continue;*/ | ||
231 | } | ||
232 | if (what == OP_if) { | ||
233 | infile = val; | ||
234 | /*continue;*/ | ||
235 | } | ||
236 | if (what == OP_of) { | ||
237 | outfile = val; | ||
238 | /*continue;*/ | ||
239 | } | ||
240 | } /* end of "for (argv[n])" */ | ||
241 | niro | 532 | |
242 | niro | 816 | //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever |
243 | niro | 532 | ibuf = obuf = xmalloc(ibs); |
244 | if (ibs != obs) { | ||
245 | niro | 816 | flags |= FLAG_TWOBUFS; |
246 | niro | 532 | obuf = xmalloc(obs); |
247 | } | ||
248 | if (infile != NULL) | ||
249 | niro | 816 | xmove_fd(xopen(infile, O_RDONLY), ifd); |
250 | niro | 532 | else { |
251 | infile = bb_msg_standard_input; | ||
252 | } | ||
253 | if (outfile != NULL) { | ||
254 | niro | 816 | int oflag = O_WRONLY | O_CREAT; |
255 | niro | 532 | |
256 | niro | 816 | if (!seek && !(flags & FLAG_NOTRUNC)) |
257 | niro | 532 | oflag |= O_TRUNC; |
258 | |||
259 | niro | 816 | xmove_fd(xopen(outfile, oflag), ofd); |
260 | niro | 532 | |
261 | niro | 816 | if (seek && !(flags & FLAG_NOTRUNC)) { |
262 | niro | 532 | if (ftruncate(ofd, seek * obs) < 0) { |
263 | struct stat st; | ||
264 | |||
265 | if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) || | ||
266 | S_ISDIR(st.st_mode)) | ||
267 | goto die_outfile; | ||
268 | } | ||
269 | } | ||
270 | } else { | ||
271 | outfile = bb_msg_standard_output; | ||
272 | } | ||
273 | if (skip) { | ||
274 | if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) { | ||
275 | while (skip-- > 0) { | ||
276 | n = safe_read(ifd, ibuf, ibs); | ||
277 | if (n < 0) | ||
278 | niro | 816 | goto die_infile; |
279 | niro | 532 | if (n == 0) |
280 | break; | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | if (seek) { | ||
285 | if (lseek(ofd, seek * obs, SEEK_CUR) < 0) | ||
286 | goto die_outfile; | ||
287 | } | ||
288 | |||
289 | niro | 816 | while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { |
290 | if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */ | ||
291 | memset(ibuf, 0, ibs); | ||
292 | niro | 532 | n = safe_read(ifd, ibuf, ibs); |
293 | if (n == 0) | ||
294 | break; | ||
295 | if (n < 0) { | ||
296 | niro | 816 | if (!(flags & FLAG_NOERROR)) |
297 | goto die_infile; | ||
298 | n = ibs; | ||
299 | bb_simple_perror_msg(infile); | ||
300 | niro | 532 | } |
301 | if ((size_t)n == ibs) | ||
302 | niro | 816 | G.in_full++; |
303 | niro | 532 | else { |
304 | niro | 816 | G.in_part++; |
305 | if (flags & FLAG_SYNC) { | ||
306 | niro | 532 | memset(ibuf + n, '\0', ibs - n); |
307 | n = ibs; | ||
308 | } | ||
309 | } | ||
310 | niro | 816 | if (flags & FLAG_TWOBUFS) { |
311 | niro | 532 | char *tmp = ibuf; |
312 | while (n) { | ||
313 | size_t d = obs - oc; | ||
314 | |||
315 | niro | 816 | if (d > (size_t)n) |
316 | niro | 532 | d = n; |
317 | memcpy(obuf + oc, tmp, d); | ||
318 | n -= d; | ||
319 | tmp += d; | ||
320 | oc += d; | ||
321 | if (oc == obs) { | ||
322 | niro | 816 | if (write_and_stats(obuf, obs, obs, outfile)) |
323 | goto out_status; | ||
324 | niro | 532 | oc = 0; |
325 | } | ||
326 | } | ||
327 | niro | 816 | } else if (write_and_stats(ibuf, n, obs, outfile)) |
328 | goto out_status; | ||
329 | |||
330 | if (flags & FLAG_FSYNC) { | ||
331 | if (fsync(ofd) < 0) | ||
332 | goto die_outfile; | ||
333 | niro | 532 | } |
334 | } | ||
335 | |||
336 | if (ENABLE_FEATURE_DD_IBS_OBS && oc) { | ||
337 | niro | 816 | w = full_write_or_warn(obuf, oc, outfile); |
338 | niro | 532 | if (w < 0) goto out_status; |
339 | niro | 816 | if (w > 0) G.out_part++; |
340 | niro | 532 | } |
341 | if (close(ifd) < 0) { | ||
342 | niro | 816 | die_infile: |
343 | bb_simple_perror_msg_and_die(infile); | ||
344 | niro | 532 | } |
345 | |||
346 | if (close(ofd) < 0) { | ||
347 | die_outfile: | ||
348 | niro | 816 | bb_simple_perror_msg_and_die(outfile); |
349 | niro | 532 | } |
350 | niro | 816 | |
351 | exitcode = EXIT_SUCCESS; | ||
352 | niro | 532 | out_status: |
353 | dd_output_status(0); | ||
354 | |||
355 | niro | 816 | return exitcode; |
356 | niro | 532 | } |