Added sfdisk. Ststic-ified a bunch of stuff.
[oweals/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  * Mostly rewritten and bugs fixed for busybox by Erik Andersen <andersee@debian.org>
10  */
11
12 #include "internal.h"
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <errno.h>
16
17 static const char dd_usage[] =
18     "Copy a file, converting and formatting according to options\n\
19 \n\
20 usage: [if=name] [of=name] [bs=n] [count=n]\n\
21 \tif=FILE\tread from FILE instead of stdin\n\
22 \tof=FILE\twrite to FILE instead of stout\n\
23 \tbs=n\tread and write N BYTES at a time\n\
24 \tcount=n\tcopy only n input blocks\n\
25 \tskip=n\tskip n input blocks\n\
26 \n\
27 BYTES may be suffixed: by k for x1024, b for x512, and w for x2.\n";
28
29
30
31
32 /*
33  * Read a number with a possible multiplier.
34  * Returns -1 if the number format is illegal.
35  */
36 static long getNum (const char *cp)
37 {
38     long value;
39
40     if (!isDecimal (*cp))
41         return -1;
42
43     value = 0;
44
45     while (isDecimal (*cp))
46         value = value * 10 + *cp++ - '0';
47
48     switch (*cp++) {
49     case 'k':
50         value *= 1024;
51         break;
52
53     case 'b':
54         value *= 512;
55         break;
56
57     case 'w':
58         value *= 2;
59         break;
60
61     case '\0':
62         return value;
63
64     default:
65         return -1;
66     }
67
68     if (*cp)
69         return -1;
70
71     return value;
72 }
73
74
75 extern int dd_main (int argc, char **argv)
76 {
77     const char *inFile;
78     const char *outFile;
79     char *cp;
80     int inFd;
81     int outFd;
82     int inCc = 0;
83     int outCc;
84     int skipBlocks;
85     int blockSize;
86     long count;
87     long intotal;
88     long outTotal;
89     unsigned char *buf;
90
91     inFile = NULL;
92     outFile = NULL;
93     blockSize = 512;
94     skipBlocks = 0;
95     count = 1;
96
97
98     argc--;
99     argv++;
100
101     /* Parse any options */
102     while (argc) {
103         if (inFile == NULL && (strncmp(*argv, "if", 2) == 0))
104             inFile=((strchr(*argv, '='))+1);
105         else if (outFile == NULL && (strncmp(*argv, "of", 2) == 0))
106             outFile=((strchr(*argv, '='))+1);
107         else if (strncmp("count", *argv, 5) == 0) {
108             count = getNum ((strchr(*argv, '='))+1);
109             if (count <= 0) {
110                 fprintf (stderr, "Bad count value %ld\n", count);
111                 goto usage;
112             }
113         }
114         else if (strncmp(*argv, "bs", 2) == 0) {
115             blockSize = getNum ((strchr(*argv, '='))+1);
116             if (blockSize <= 0) {
117                 fprintf (stderr, "Bad block size value %d\n", blockSize);
118                 goto usage;
119             }
120         }
121         else if (strncmp(*argv, "skip", 4) == 0) {
122             skipBlocks = atoi( *argv); 
123             if (skipBlocks <= 0) {
124                 fprintf (stderr, "Bad skip value %d\n", skipBlocks);
125                 goto usage;
126             }
127
128         }
129         else {
130             fprintf (stderr, "Got here. argv=%s\n", *argv);
131             goto usage;
132         }
133         argc--;
134         argv++;
135     }
136     if ( inFile == NULL || outFile == NULL)
137         goto usage;
138
139     buf = malloc (blockSize);
140     if (buf == NULL) {
141         fprintf (stderr, "Cannot allocate buffer\n");
142         exit( FALSE);
143     }
144
145     intotal = 0;
146     outTotal = 0;
147
148     if (inFile == NULL)
149         inFd = STDIN;
150     else
151         inFd = open (inFile, 0);
152
153     if (inFd < 0) {
154         perror (inFile);
155         free (buf);
156         exit( FALSE);
157     }
158
159     if (outFile == NULL)
160         outFd = STDOUT;
161     else
162         outFd = creat (outFile, 0666);
163
164     if (outFd < 0) {
165         perror (outFile);
166         close (inFd);
167         free (buf);
168         exit( FALSE);
169     }
170
171     //lseek(inFd, skipBlocks*blockSize, SEEK_SET);
172     while (outTotal < count * blockSize) {
173         inCc = read (inFd, buf, blockSize);
174         if (inCc < 0) {
175             perror (inFile);
176             goto cleanup;
177         }
178         intotal += inCc;
179         cp = buf;
180
181         while (intotal > outTotal) {
182             if (outTotal + inCc > count * blockSize)
183                 inCc = count * blockSize - outTotal;
184             outCc = write (outFd, cp, inCc);
185             if (outCc < 0) {
186                 perror (outFile);
187                 goto cleanup;
188             }
189
190             inCc -= outCc;
191             cp += outCc;
192             outTotal += outCc;
193         }
194     }
195
196     if (inCc < 0)
197         perror (inFile);
198
199   cleanup:
200     close (inFd);
201     close (outFd);
202     free (buf);
203
204     printf ("%ld+%d records in\n", intotal / blockSize,
205             (intotal % blockSize) != 0);
206     printf ("%ld+%d records out\n", outTotal / blockSize,
207             (outTotal % blockSize) != 0);
208     exit( TRUE);
209   usage:
210
211     fprintf (stderr, "%s", dd_usage);
212     exit( FALSE);
213 }
214
215