blob: 33e789311071c53ebb921605c409ccc9642cc65e [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002/*
Eric Andersenc4996011999-10-20 22:08:37 +00003 * Mini dd implementation for busybox
4 *
Eric Andersenc4996011999-10-20 22:08:37 +00005 *
Matt Kraai3eeab3b2001-12-07 16:27:37 +00006 * Copyright (C) 2000,2001 Matt Kraai
Eric Andersenc4996011999-10-20 22:08:37 +00007 *
Bernhard Reutner-Fischerc2cb0f32006-04-13 12:45:04 +00008 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersencc8ed391999-10-05 16:24:54 +00009 */
10
Matt Kraai24ac0172000-12-18 21:38:57 +000011#include <sys/types.h>
Matt Kraaieb834782002-02-05 15:28:54 +000012#include <sys/stat.h>
Eric Andersened3ef502001-01-27 08:24:39 +000013#include <stdlib.h>
14#include <stdio.h>
15#include <unistd.h>
16#include <string.h>
Eric Andersen3cf52d11999-10-12 22:26:06 +000017#include <fcntl.h>
Rob Landleyc5598172006-05-02 22:44:04 +000018#include <signal.h> // For FEATURE_DD_SIGNAL_HANDLING
Eric Andersencbe31da2001-02-20 06:14:08 +000019#include "busybox.h"
20
Matt Kraaia164c642001-02-05 17:50:03 +000021static const struct suffix_mult dd_suffixes[] = {
Matt Kraai24ac0172000-12-18 21:38:57 +000022 { "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
Rob Landleyc5598172006-05-02 22:44:04 +000034static size_t out_full;
35static size_t out_part;
36static size_t in_full;
37static size_t in_part;
38
39static 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
Matt Kraai24ac0172000-12-18 21:38:57 +000046int dd_main(int argc, char **argv)
Eric Andersen3cf52d11999-10-12 22:26:06 +000047{
Rob Landley2686d3b2006-05-16 16:52:12 +000048 size_t count = -1, oc = 0, ibs = 512, obs = 512;
Matt Kraai24ac0172000-12-18 21:38:57 +000049 ssize_t n;
Rob Landley2686d3b2006-05-16 16:52:12 +000050 off_t seek = 0, skip = 0;
51 int sync_flag = FALSE, noerror = FALSE, trunc_flag = TRUE, twobufs_flag = 0,
52 oflag, ifd, ofd, i;
53 const char *infile = NULL, *outfile = NULL;
54 char *ibuf, *obuf;
Eric Andersenddea3682000-11-29 22:33:02 +000055
Rob Landleyc5598172006-05-02 22:44:04 +000056 if (ENABLE_FEATURE_DD_SIGNAL_HANDLING)
57 {
58 struct sigaction sa;
59
60 memset(&sa, 0, sizeof(sa));
61 sa.sa_handler = dd_output_status;
62 sa.sa_flags = SA_RESTART;
63 sigemptyset(&sa.sa_mask);
64 sigaction(SIGUSR1, &sa, 0);
65 }
66
Matt Kraai24ac0172000-12-18 21:38:57 +000067 for (i = 1; i < argc; i++) {
Rob Landley2686d3b2006-05-16 16:52:12 +000068 if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("ibs=", argv[i], 4)) {
69 ibs = bb_xparse_number(argv[i]+4, dd_suffixes);
70 twobufs_flag++;
71 } else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("obs=", argv[i], 4)) {
72 obs = bb_xparse_number(argv[i]+4, dd_suffixes);
73 twobufs_flag++;
74 } else if (!strncmp("bs=", argv[i], 3)) {
75 ibs = obs = bb_xparse_number(argv[i]+3, dd_suffixes);
76 } else if (!strncmp("count=", argv[i], 6))
Manuel Novoa III cad53642003-03-19 09:13:01 +000077 count = bb_xparse_number(argv[i]+6, dd_suffixes);
Rob Landley2686d3b2006-05-16 16:52:12 +000078 else if (!strncmp("seek=", argv[i], 5))
Manuel Novoa III cad53642003-03-19 09:13:01 +000079 seek = bb_xparse_number(argv[i]+5, dd_suffixes);
Rob Landley2686d3b2006-05-16 16:52:12 +000080 else if (!strncmp("skip=", argv[i], 5))
Manuel Novoa III cad53642003-03-19 09:13:01 +000081 skip = bb_xparse_number(argv[i]+5, dd_suffixes);
Rob Landley2686d3b2006-05-16 16:52:12 +000082 else if (!strncmp("if=", argv[i], 3))
Matt Kraai24ac0172000-12-18 21:38:57 +000083 infile = argv[i]+3;
Rob Landley2686d3b2006-05-16 16:52:12 +000084 else if (!strncmp("of=", argv[i], 3))
Matt Kraai24ac0172000-12-18 21:38:57 +000085 outfile = argv[i]+3;
Rob Landley2686d3b2006-05-16 16:52:12 +000086 else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("conv=", argv[i], 5)) {
87 ibuf = argv[i]+5;
Matt Kraai24ac0172000-12-18 21:38:57 +000088 while (1) {
Rob Landley2686d3b2006-05-16 16:52:12 +000089 if (!strncmp("notrunc", ibuf, 7)) {
Eric Andersenab26cc32004-01-30 22:24:32 +000090 trunc_flag = FALSE;
Rob Landley2686d3b2006-05-16 16:52:12 +000091 ibuf += 7;
92 } else if (!strncmp("sync", ibuf, 4)) {
Eric Andersen1ca20a72001-03-21 07:34:27 +000093 sync_flag = TRUE;
Rob Landley2686d3b2006-05-16 16:52:12 +000094 ibuf += 4;
95 } else if (!strncmp("noerror", ibuf, 7)) {
Eric Andersenef38b392002-04-27 01:31:43 +000096 noerror = TRUE;
Rob Landley2686d3b2006-05-16 16:52:12 +000097 ibuf += 7;
Matt Kraai24ac0172000-12-18 21:38:57 +000098 } else {
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +000099 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i]+5, "conv");
Matt Kraai24ac0172000-12-18 21:38:57 +0000100 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000101 if (ibuf[0] == '\0') break;
102 if (ibuf[0] == ',') ibuf++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000103 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000104 } else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000105 bb_show_usage();
Eric Andersen3cf52d11999-10-12 22:26:06 +0000106 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000107 ibuf = xmalloc(ibs);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000108
Rob Landley2686d3b2006-05-16 16:52:12 +0000109 if (twobufs_flag) obuf = xmalloc(obs);
110 else obuf = ibuf;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000111
Matt Kraai24ac0172000-12-18 21:38:57 +0000112 if (infile != NULL) {
Eric Andersen8876fb22003-06-20 09:01:58 +0000113 ifd = bb_xopen(infile, O_RDONLY);
Matt Kraai24ac0172000-12-18 21:38:57 +0000114 } else {
115 ifd = STDIN_FILENO;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000116 infile = bb_msg_standard_input;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000117 }
118
Matt Kraai24ac0172000-12-18 21:38:57 +0000119 if (outfile != NULL) {
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000120 oflag = O_WRONLY | O_CREAT;
121
Eric Andersenab26cc32004-01-30 22:24:32 +0000122 if (!seek && trunc_flag) {
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000123 oflag |= O_TRUNC;
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000124 }
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000125
Bernhard Reutner-Fischerc2cb0f32006-04-13 12:45:04 +0000126 ofd = bb_xopen3(outfile, oflag, 0666);
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000127
Eric Andersenab26cc32004-01-30 22:24:32 +0000128 if (seek && trunc_flag) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000129 if (ftruncate(ofd, seek * obs) < 0) {
Matt Kraaieb834782002-02-05 15:28:54 +0000130 struct stat st;
131
132 if (fstat (ofd, &st) < 0 || S_ISREG (st.st_mode) ||
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000133 S_ISDIR (st.st_mode)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000134 bb_perror_msg_and_die("%s", outfile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000135 }
Matt Kraaieb834782002-02-05 15:28:54 +0000136 }
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000137 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000138 } else {
139 ofd = STDOUT_FILENO;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000140 outfile = bb_msg_standard_output;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000141 }
142
Matt Kraai24ac0172000-12-18 21:38:57 +0000143 if (skip) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000144 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
145 while (skip-- > 0) {
146 n = safe_read(ifd, ibuf, ibs);
147 if (n < 0)
148 bb_perror_msg_and_die("%s", infile);
149 if (n == 0)
150 break;
151 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000152 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000153 }
Eric Andersenddea3682000-11-29 22:33:02 +0000154
Matt Kraai24ac0172000-12-18 21:38:57 +0000155 if (seek) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000156 if (lseek(ofd, seek * obs, SEEK_CUR) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000157 bb_perror_msg_and_die("%s", outfile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000158 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000159 }
Eric Andersenddea3682000-11-29 22:33:02 +0000160
Matt Kraai24ac0172000-12-18 21:38:57 +0000161 while (in_full + in_part != count) {
Eric Andersenef38b392002-04-27 01:31:43 +0000162 if (noerror) {
163 /* Pre-zero the buffer when doing the noerror thing */
Rob Landley2686d3b2006-05-16 16:52:12 +0000164 memset(ibuf, '\0', ibs);
Eric Andersenef38b392002-04-27 01:31:43 +0000165 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000166
167 n = safe_read(ifd, ibuf, ibs);
168 if (n == 0) {
169 break;
170 }
Eric Andersenef38b392002-04-27 01:31:43 +0000171 if (n < 0) {
172 if (noerror) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000173 n = ibs;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000174 bb_perror_msg("%s", infile);
Eric Andersenef38b392002-04-27 01:31:43 +0000175 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000176 bb_perror_msg_and_die("%s", infile);
Eric Andersenef38b392002-04-27 01:31:43 +0000177 }
178 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000179 if ((size_t)n == ibs) {
Matt Kraai24ac0172000-12-18 21:38:57 +0000180 in_full++;
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000181 } else {
Matt Kraai24ac0172000-12-18 21:38:57 +0000182 in_part++;
Rob Landley2686d3b2006-05-16 16:52:12 +0000183 if (sync_flag) {
184 memset(ibuf + n, '\0', ibs - n);
185 n = ibs;
186 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000187 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000188 if (twobufs_flag) {
189 char *tmp = ibuf;
190 while (n) {
191 size_t d = obs - oc;
192
193 if (d > n) d = n;
194 memcpy(obuf + oc, tmp, d);
195 n -= d;
196 tmp += d;
197 oc += d;
198 if (oc == obs) {
199 if (bb_full_write(ofd, obuf, obs) < 0) {
200 bb_perror_msg_and_die("%s", outfile);
201 }
202 out_full++;
203 oc = 0;
204 }
205 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000206 } else {
Rob Landley2686d3b2006-05-16 16:52:12 +0000207 if ((n = bb_full_write(ofd, ibuf, n)) < 0) {
208 bb_perror_msg_and_die("%s", outfile);
209 }
210 if (n == ibs) out_full++;
211 else out_part++;
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000212 }
Glenn L McGrathf0b073f2000-09-11 00:32:13 +0000213 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000214
215 if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
216 if (bb_full_write(ofd, obuf, oc) < 0) {
217 bb_perror_msg_and_die("%s", outfile);
218 }
219 out_part++;
220 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000221 if (close (ifd) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000222 bb_perror_msg_and_die("%s", infile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000223 }
Matt Kraai3eeab3b2001-12-07 16:27:37 +0000224
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000225 if (close (ofd) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000226 bb_perror_msg_and_die("%s", outfile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000227 }
Matt Kraai3eeab3b2001-12-07 16:27:37 +0000228
Rob Landleyc5598172006-05-02 22:44:04 +0000229 dd_output_status(0);
Matt Kraai24ac0172000-12-18 21:38:57 +0000230
Matt Kraai3e856ce2000-12-01 02:55:13 +0000231 return EXIT_SUCCESS;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000232}