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