Initial revision
[platform/upstream/busybox.git] / dd.c
1 /*
2  * Copyright (c) 1999 by David I. Bell
3  * Permission is granted to use, distribute, or modify this source,
4  * provided that this copyright notice remains intact.
5  *
6  * The "dd" command, originally taken from sash.
7  *
8  * Permission to distribute this code under the GPL has been granted.
9  * Majorly modified, and bugs fixed for busybox by Erik Andersen <andersee@debian.org> <andersen@lineo.com>
10  */
11
12 #include "internal.h"
13 #ifdef BB_DD
14
15 const char dd_usage[] = 
16 "Copy a file, converting and formatting according to options\n\
17 \n\
18 usage: [if=name] [of=name] [bs=n] [count=n]\n\
19 \tif=FILE\tread from FILE instead of stdin\n\
20 \tof=FILE\twrite to FILE instead of stout\n\
21 \tbs=n\tread and write N bytes at a time\n\
22 \tcount=n\tcopy only n input blocks\n\
23 \n\
24 BYTES may be suffixed: by k for x1024, b for x512, and w for x2.\n";
25
26
27 #include <stdio.h>
28 #include <dirent.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <signal.h>
32 #include <time.h>
33
34
35 #define PAR_NONE        0
36 #define PAR_IF          1
37 #define PAR_OF          2
38 #define PAR_BS          3
39 #define PAR_COUNT       4
40
41
42 typedef struct
43 {
44         const char *    name;
45         int             value;
46 } PARAM;
47
48
49 static const PARAM      params[] =
50 {
51         {"if",          PAR_IF},
52         {"of",          PAR_OF},
53         {"bs",          PAR_BS},
54         {"count",       PAR_COUNT},
55         {NULL,          PAR_NONE}
56 };
57
58
59 static  long    getNum(const char * cp);
60
61 extern int
62 dd_main (struct FileInfo *unused, int argc, char **argv)
63 {
64         const char *    str;
65         const PARAM *   par;
66         const char *    inFile;
67         const char *    outFile;
68         char *          cp;
69         int             inFd;
70         int             outFd;
71         int             inCc=0;
72         int             outCc;
73         int             blockSize;
74         long            count;
75         long            intotal;
76         long            outTotal;
77         unsigned char*  buf;
78         unsigned char   localBuf[BUF_SIZE];
79
80         inFile = NULL;
81         outFile = NULL;
82         blockSize = 512;
83         count = 1;
84
85
86         while (--argc > 0)
87         {
88                 str = *++argv;
89                 cp = strchr(str, '=');
90
91                 if (cp == NULL)
92                 {
93                         fprintf(stderr, "Bad dd argument\n");
94                         goto usage;
95                 }
96
97                 *cp++ = '\0';
98
99                 for (par = params; par->name; par++)
100                 {
101                         if (strcmp(str, par->name) == 0)
102                                 break;
103                 }
104
105                 switch (par->value)
106                 {
107                         case PAR_IF:
108                                 if (inFile)
109                                 {
110                                         fprintf(stderr, "Multiple input files illegal\n");
111                                         goto usage;
112                                 }
113         
114                                 //fprintf(stderr, "if=%s\n", cp);
115                                 inFile = cp;
116                                 break;
117
118                         case PAR_OF:
119                                 if (outFile)
120                                 {
121                                         fprintf(stderr, "Multiple output files illegal\n");
122                                         goto usage;
123                                 }
124
125                                 //fprintf(stderr, "of=%s\n", cp);
126                                 outFile = cp;
127                                 break;
128
129                         case PAR_BS:
130                                 blockSize = getNum(cp);
131                                 //fprintf(stderr, "bs=%d\n", blockSize);
132
133                                 if (blockSize <= 0)
134                                 {
135                                         fprintf(stderr, "Bad block size value\n");
136                                         goto usage;
137                                 }
138
139                                 break;
140
141                         case PAR_COUNT:
142                                 count = getNum(cp);
143                                 //fprintf(stderr, "count=%ld\n", count);
144
145                                 if (count < 0)
146                                 {
147                                         fprintf(stderr, "Bad count value\n");
148                                         goto usage;
149                                 }
150
151                                 break;
152
153                         default:
154                                 goto usage;
155                 }
156         }
157
158         buf = localBuf;
159
160         if (blockSize > sizeof(localBuf))
161         {
162                 buf = malloc(blockSize);
163
164                 if (buf == NULL)
165                 {
166                         fprintf(stderr, "Cannot allocate buffer\n");
167                         return 1;
168                 }
169         }
170
171         intotal = 0;
172         outTotal = 0;
173
174         if (inFile == NULL)
175             inFd = STDIN;
176         else
177             inFd = open(inFile, 0);
178
179         if (inFd < 0)
180         {
181                 perror(inFile);
182
183                 if (buf != localBuf)
184                         free(buf);
185
186                 return 1;
187         }
188
189         if (outFile == NULL)
190             outFd = STDOUT;
191         else
192             outFd = creat(outFile, 0666);
193
194         if (outFd < 0)
195         {
196                 perror(outFile);
197                 close(inFd);
198
199                 if (buf != localBuf)
200                         free(buf);
201
202                 return 1;
203         }
204
205         while ( outTotal < count*blockSize )
206         {
207                 inCc = read(inFd, buf, blockSize);
208                 if (inCc < 0) {
209                     perror(inFile);
210                     goto cleanup;
211                 }
212                 //fprintf(stderr, "read in =%d\n", inCc);
213                 intotal += inCc;
214                 cp = buf;
215
216
217                 while ( intotal > outTotal )
218                 {
219                         if (outTotal+inCc > count*blockSize)
220                             inCc=count*blockSize-outTotal;
221                         outCc = write(outFd, cp, inCc);
222                         if (outCc < 0)
223                         {
224                                 perror(outFile);
225                                 goto cleanup;
226                         }
227                         //fprintf(stderr, "wrote out =%d\n", outCc);
228
229                         inCc -= outCc;
230                         cp += outCc;
231                         outTotal += outCc;
232                         //fprintf(stderr, "outTotal=%ld\n", outTotal);
233                 }
234         }
235
236         if (inCc < 0)
237                 perror(inFile);
238
239 cleanup:
240         close(inFd);
241
242         if (close(outFd) < 0)
243                 perror(outFile);
244
245         if (buf != localBuf)
246                 free(buf);
247
248         printf("%ld+%d records in\n", intotal / blockSize,
249                 (intotal % blockSize) != 0);
250
251         printf("%ld+%d records out\n", outTotal / blockSize,
252                 (outTotal % blockSize) != 0);
253         return 0;
254 usage:
255         
256         fprintf(stderr, "%s", dd_usage);
257         return 1;
258 }
259
260
261 /*
262  * Read a number with a possible multiplier.
263  * Returns -1 if the number format is illegal.
264  */
265 static long
266 getNum(const char * cp)
267 {
268         long    value;
269
270         if (!isDecimal(*cp))
271                 return -1;
272
273         value = 0;
274
275         while (isDecimal(*cp))
276                 value = value * 10 + *cp++ - '0';
277
278         switch (*cp++)
279         {
280                 case 'k':
281                         value *= 1024;
282                         break;
283
284                 case 'b':
285                         value *= 512;
286                         break;
287
288                 case 'w':
289                         value *= 2;
290                         break;
291
292                 case '\0':
293                         return value;
294
295                 default:
296                         return -1;
297         }
298
299         if (*cp)
300                 return -1;
301
302         return value;
303 }
304
305 #endif
306 /* END CODE */
307