Another whack at scripts/individual. Now builds 212 applets.
[oweals/busybox.git] / coreutils / dd.c
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 "busybox.h"
12
13 static const struct suffix_mult dd_suffixes[] = {
14         { "c", 1 },
15         { "w", 2 },
16         { "b", 512 },
17         { "kD", 1000 },
18         { "k", 1024 },
19         { "MD", 1000000 },
20         { "M", 1048576 },
21         { "GD", 1000000000 },
22         { "G", 1073741824 },
23         { NULL, 0 }
24 };
25
26 static size_t out_full;
27 static size_t out_part;
28 static size_t in_full;
29 static size_t in_part;
30
31 static void dd_output_status(int cur_signal)
32 {
33         fprintf(stderr, "%ld+%ld records in\n%ld+%ld records out\n",
34                         (long)in_full, (long)in_part,
35                         (long)out_full, (long)out_part);
36 }
37
38 int dd_main(int argc, char **argv)
39 {
40         size_t count = -1, oc = 0, ibs = 512, obs = 512;
41         ssize_t n;
42         off_t seek = 0, skip = 0;
43         int sync_flag = FALSE, noerror = FALSE, trunc_flag = TRUE, twobufs_flag = 0,
44                 oflag, ifd, ofd, i;
45         const char *infile = NULL, *outfile = NULL;
46         char *ibuf, *obuf;
47
48         if (ENABLE_FEATURE_DD_SIGNAL_HANDLING)
49         {
50                 struct sigaction sa;
51
52                 memset(&sa, 0, sizeof(sa));
53                 sa.sa_handler = dd_output_status; 
54                 sa.sa_flags = SA_RESTART;
55                 sigemptyset(&sa.sa_mask);
56                 sigaction(SIGUSR1, &sa, 0); 
57         }
58
59         for (i = 1; i < argc; i++) {
60                 if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("ibs=", argv[i], 4)) {
61                         ibs = bb_xparse_number(argv[i]+4, dd_suffixes);
62                         twobufs_flag++;
63                 } else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("obs=", argv[i], 4)) {
64                         obs = bb_xparse_number(argv[i]+4, dd_suffixes);
65                         twobufs_flag++;
66                 } else if (!strncmp("bs=", argv[i], 3)) {
67                         ibs = obs = bb_xparse_number(argv[i]+3, dd_suffixes);
68                 } else if (!strncmp("count=", argv[i], 6))
69                         count = bb_xparse_number(argv[i]+6, dd_suffixes);
70                 else if (!strncmp("seek=", argv[i], 5))
71                         seek = bb_xparse_number(argv[i]+5, dd_suffixes);
72                 else if (!strncmp("skip=", argv[i], 5))
73                         skip = bb_xparse_number(argv[i]+5, dd_suffixes);
74                 else if (!strncmp("if=", argv[i], 3))
75                         infile = argv[i]+3;
76                 else if (!strncmp("of=", argv[i], 3))
77                         outfile = argv[i]+3;
78                 else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("conv=", argv[i], 5)) {
79                         ibuf = argv[i]+5;
80                         while (1) {
81                                 if (!strncmp("notrunc", ibuf, 7)) {
82                                         trunc_flag = FALSE;
83                                         ibuf += 7;
84                                 } else if (!strncmp("sync", ibuf, 4)) {
85                                         sync_flag = TRUE;
86                                         ibuf += 4;
87                                 } else if (!strncmp("noerror", ibuf, 7)) {
88                                         noerror = TRUE;
89                                         ibuf += 7;
90                                 } else {
91                                         bb_error_msg_and_die(bb_msg_invalid_arg, argv[i]+5, "conv");
92                                 }
93                                 if (ibuf[0] == '\0') break;
94                                 if (ibuf[0] == ',') ibuf++;
95                         }
96                 } else
97                         bb_show_usage();
98         }
99         ibuf = xmalloc(ibs);
100
101         if (twobufs_flag) obuf = xmalloc(obs);
102         else obuf = ibuf;
103
104         if (infile != NULL) {
105                 ifd = xopen(infile, O_RDONLY);
106         } else {
107                 ifd = STDIN_FILENO;
108                 infile = bb_msg_standard_input;
109         }
110
111         if (outfile != NULL) {
112                 oflag = O_WRONLY | O_CREAT;
113
114                 if (!seek && trunc_flag) {
115                         oflag |= O_TRUNC;
116                 }
117
118                 ofd = xopen3(outfile, oflag, 0666);
119
120                 if (seek && trunc_flag) {
121                         if (ftruncate(ofd, seek * obs) < 0) {
122                                 struct stat st;
123
124                                 if (fstat (ofd, &st) < 0 || S_ISREG (st.st_mode) ||
125                                                 S_ISDIR (st.st_mode)) {
126                                         bb_perror_msg_and_die("%s", outfile);
127                                 }
128                         }
129                 }
130         } else {
131                 ofd = STDOUT_FILENO;
132                 outfile = bb_msg_standard_output;
133         }
134
135         if (skip) {
136                 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
137                         while (skip-- > 0) {
138                                 n = safe_read(ifd, ibuf, ibs);
139                                 if (n < 0)
140                                         bb_perror_msg_and_die("%s", infile);
141                                 if (n == 0)
142                                         break;
143                         }
144                 }
145         }
146
147         if (seek) {
148                 if (lseek(ofd, seek * obs, SEEK_CUR) < 0) {
149                         bb_perror_msg_and_die("%s", outfile);
150                 }
151         }
152
153         while (in_full + in_part != count) {
154                 if (noerror) {
155                         /* Pre-zero the buffer when doing the noerror thing */
156                         memset(ibuf, '\0', ibs);
157                 }
158
159                 n = safe_read(ifd, ibuf, ibs);
160                 if (n == 0) {
161                         break;
162                 }
163                 if (n < 0) {
164                         if (noerror) {
165                                 n = ibs;
166                                 bb_perror_msg("%s", infile);
167                         } else {
168                                 bb_perror_msg_and_die("%s", infile);
169                         }
170                 }
171                 if ((size_t)n == ibs) {
172                         in_full++;
173                 } else {
174                         in_part++;
175                         if (sync_flag) {
176                                 memset(ibuf + n, '\0', ibs - n);
177                                 n = ibs;
178                         }
179                 }
180                 if (twobufs_flag) {
181                         char *tmp = ibuf;
182                         while (n) {
183                                 size_t d = obs - oc;
184
185                                 if (d > n) d = n;
186                                 memcpy(obuf + oc, tmp, d);
187                                 n -= d;
188                                 tmp += d;
189                                 oc += d;
190                                 if (oc == obs) {
191                                         xwrite(ofd, obuf, obs);
192                                         out_full++;
193                                         oc = 0;
194                                 }
195                         }
196                 } else {
197                         xwrite(ofd, ibuf, n);
198                         if (n == ibs) out_full++;
199                         else out_part++;
200                 }
201         }
202         
203         if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
204                 xwrite(ofd, obuf, oc);
205                 out_part++;
206         }
207         if (close (ifd) < 0) {
208                 bb_perror_msg_and_die("%s", infile);
209         }
210
211         if (close (ofd) < 0) {
212                 bb_perror_msg_and_die("%s", outfile);
213         }
214
215         dd_output_status(0);
216
217         return EXIT_SUCCESS;
218 }