Contents of /tags/mkinitrd-6_1_8/busybox/coreutils/dd.c
Parent Directory | Revision Log
Revision 916 -
(show annotations)
(download)
Wed Oct 28 00:17:50 2009 UTC (14 years, 11 months ago) by niro
File MIME type: text/plain
File size: 8213 byte(s)
Wed Oct 28 00:17:50 2009 UTC (14 years, 11 months ago) by niro
File MIME type: text/plain
File size: 8213 byte(s)
tagged 'mkinitrd-6_1_8'
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 tarball for details. |
9 | */ |
10 | |
11 | #include <signal.h> /* For FEATURE_DD_SIGNAL_HANDLING */ |
12 | #include "libbb.h" |
13 | |
14 | /* This is a NOEXEC applet. Be very careful! */ |
15 | |
16 | |
17 | enum { |
18 | ifd = STDIN_FILENO, |
19 | ofd = STDOUT_FILENO, |
20 | }; |
21 | |
22 | static const struct suffix_mult dd_suffixes[] = { |
23 | { "c", 1 }, |
24 | { "w", 2 }, |
25 | { "b", 512 }, |
26 | { "kD", 1000 }, |
27 | { "k", 1024 }, |
28 | { "K", 1024 }, /* compat with coreutils dd */ |
29 | { "MD", 1000000 }, |
30 | { "M", 1048576 }, |
31 | { "GD", 1000000000 }, |
32 | { "G", 1073741824 }, |
33 | { } |
34 | }; |
35 | |
36 | 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 | |
43 | |
44 | static void dd_output_status(int UNUSED_PARAM cur_signal) |
45 | { |
46 | /* 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 | } |
52 | |
53 | static ssize_t full_write_or_warn(const void *buf, size_t len, |
54 | const char *const filename) |
55 | { |
56 | ssize_t n = full_write(ofd, buf, len); |
57 | if (n < 0) |
58 | bb_perror_msg("writing '%s'", filename); |
59 | return n; |
60 | } |
61 | |
62 | 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 | #if ENABLE_LFS |
76 | #define XATOU_SFX xatoull_sfx |
77 | #else |
78 | #define XATOU_SFX xatoul_sfx |
79 | #endif |
80 | |
81 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
82 | int dd_main(int argc UNUSED_PARAM, char **argv) |
83 | { |
84 | enum { |
85 | /* 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 | }; |
95 | 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 | ssize_t n, w; |
138 | char *ibuf, *obuf; |
139 | /* 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 | |
155 | memset(&Z, 0, sizeof(Z)); |
156 | INIT_G(); |
157 | //fflush(NULL); - is this needed because of NOEXEC? |
158 | |
159 | #if ENABLE_FEATURE_DD_SIGNAL_HANDLING |
160 | signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status); |
161 | #endif |
162 | |
163 | for (n = 1; argv[n]; n++) { |
164 | int what; |
165 | char *val; |
166 | char *arg = argv[n]; |
167 | |
168 | #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 | while (1) { |
195 | /* 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 | } |
211 | 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 | |
242 | //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever |
243 | ibuf = obuf = xmalloc(ibs); |
244 | if (ibs != obs) { |
245 | flags |= FLAG_TWOBUFS; |
246 | obuf = xmalloc(obs); |
247 | } |
248 | if (infile != NULL) |
249 | xmove_fd(xopen(infile, O_RDONLY), ifd); |
250 | else { |
251 | infile = bb_msg_standard_input; |
252 | } |
253 | if (outfile != NULL) { |
254 | int oflag = O_WRONLY | O_CREAT; |
255 | |
256 | if (!seek && !(flags & FLAG_NOTRUNC)) |
257 | oflag |= O_TRUNC; |
258 | |
259 | xmove_fd(xopen(outfile, oflag), ofd); |
260 | |
261 | if (seek && !(flags & FLAG_NOTRUNC)) { |
262 | 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 | goto die_infile; |
279 | 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 | 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 | n = safe_read(ifd, ibuf, ibs); |
293 | if (n == 0) |
294 | break; |
295 | if (n < 0) { |
296 | if (!(flags & FLAG_NOERROR)) |
297 | goto die_infile; |
298 | n = ibs; |
299 | bb_simple_perror_msg(infile); |
300 | } |
301 | if ((size_t)n == ibs) |
302 | G.in_full++; |
303 | else { |
304 | G.in_part++; |
305 | if (flags & FLAG_SYNC) { |
306 | memset(ibuf + n, '\0', ibs - n); |
307 | n = ibs; |
308 | } |
309 | } |
310 | if (flags & FLAG_TWOBUFS) { |
311 | char *tmp = ibuf; |
312 | while (n) { |
313 | size_t d = obs - oc; |
314 | |
315 | if (d > (size_t)n) |
316 | d = n; |
317 | memcpy(obuf + oc, tmp, d); |
318 | n -= d; |
319 | tmp += d; |
320 | oc += d; |
321 | if (oc == obs) { |
322 | if (write_and_stats(obuf, obs, obs, outfile)) |
323 | goto out_status; |
324 | oc = 0; |
325 | } |
326 | } |
327 | } 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 | } |
334 | } |
335 | |
336 | if (ENABLE_FEATURE_DD_IBS_OBS && oc) { |
337 | w = full_write_or_warn(obuf, oc, outfile); |
338 | if (w < 0) goto out_status; |
339 | if (w > 0) G.out_part++; |
340 | } |
341 | if (close(ifd) < 0) { |
342 | die_infile: |
343 | bb_simple_perror_msg_and_die(infile); |
344 | } |
345 | |
346 | if (close(ofd) < 0) { |
347 | die_outfile: |
348 | bb_simple_perror_msg_and_die(outfile); |
349 | } |
350 | |
351 | exitcode = EXIT_SUCCESS; |
352 | out_status: |
353 | dd_output_status(0); |
354 | |
355 | return exitcode; |
356 | } |