blob: 4a094e81a3174c398fd92f2f055631c93547c6c3 [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
Eric Andersencbe31da2001-02-20 06:14:08 +000011#include "busybox.h"
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000012#include <signal.h> /* For FEATURE_DD_SIGNAL_HANDLING */
Eric Andersencbe31da2001-02-20 06:14:08 +000013
Matt Kraaia164c642001-02-05 17:50:03 +000014static const struct suffix_mult dd_suffixes[] = {
Matt Kraai24ac0172000-12-18 21:38:57 +000015 { "c", 1 },
16 { "w", 2 },
17 { "b", 512 },
18 { "kD", 1000 },
19 { "k", 1024 },
Denis Vlasenko56254152006-10-07 16:24:46 +000020 { "K", 1024 }, // compat with coreutils dd
Matt Kraai24ac0172000-12-18 21:38:57 +000021 { "MD", 1000000 },
22 { "M", 1048576 },
23 { "GD", 1000000000 },
24 { "G", 1073741824 },
25 { NULL, 0 }
26};
27
Denis Vlasenko7039a662006-10-08 17:54:47 +000028static off_t out_full, out_part, in_full, in_part;
Rob Landleyc5598172006-05-02 22:44:04 +000029
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000030static void dd_output_status(int ATTRIBUTE_UNUSED cur_signal)
Rob Landleyc5598172006-05-02 22:44:04 +000031{
Denis Vlasenkocf30cc82006-11-24 14:53:18 +000032 fprintf(stderr, "%"OFF_FMT"d+%"OFF_FMT"d records in\n"
33 "%"OFF_FMT"d+%"OFF_FMT"d records out\n",
Denis Vlasenko56254152006-10-07 16:24:46 +000034 in_full, in_part,
35 out_full, out_part);
Rob Landleyc5598172006-05-02 22:44:04 +000036}
37
Denis Vlasenko3b8ff682006-10-31 15:55:56 +000038static ssize_t full_write_or_warn(int fd, const void *buf, size_t len,
39 const char* filename)
40{
41 ssize_t n = full_write(fd, buf, len);
42 if (n < 0)
43 bb_perror_msg("writing '%s'", filename);
44 return n;
45}
46
Denis Vlasenko5dd27b12006-11-25 14:46:21 +000047#if ENABLE_LFS
48#define XATOU_SFX xatoull_sfx
49#else
50#define XATOU_SFX xatoul_sfx
51#endif
52
Denis Vlasenko06af2162007-02-03 17:28:39 +000053int dd_main(int argc, char **argv);
Matt Kraai24ac0172000-12-18 21:38:57 +000054int dd_main(int argc, char **argv)
Eric Andersen3cf52d11999-10-12 22:26:06 +000055{
Denis Vlasenko3b8ff682006-10-31 15:55:56 +000056 enum {
57 sync_flag = 1 << 0,
58 noerror = 1 << 1,
59 trunc_flag = 1 << 2,
60 twobufs_flag = 1 << 3,
61 };
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000062 int flags = trunc_flag;
Denis Vlasenko56254152006-10-07 16:24:46 +000063 size_t oc = 0, ibs = 512, obs = 512;
Denis Vlasenko3b8ff682006-10-31 15:55:56 +000064 ssize_t n, w;
Denis Vlasenko7039a662006-10-08 17:54:47 +000065 off_t seek = 0, skip = 0, count = OFF_T_MAX;
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000066 int oflag, ifd, ofd;
Rob Landley2686d3b2006-05-16 16:52:12 +000067 const char *infile = NULL, *outfile = NULL;
68 char *ibuf, *obuf;
Eric Andersenddea3682000-11-29 22:33:02 +000069
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000070 if (ENABLE_FEATURE_DD_SIGNAL_HANDLING) {
Rob Landleyc5598172006-05-02 22:44:04 +000071 struct sigaction sa;
72
73 memset(&sa, 0, sizeof(sa));
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000074 sa.sa_handler = dd_output_status;
Rob Landleyc5598172006-05-02 22:44:04 +000075 sa.sa_flags = SA_RESTART;
76 sigemptyset(&sa.sa_mask);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000077 sigaction(SIGUSR1, &sa, 0);
Rob Landleyc5598172006-05-02 22:44:04 +000078 }
79
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000080 for (n = 1; n < argc; n++) {
Denis Vlasenko3b8ff682006-10-31 15:55:56 +000081 char *arg = argv[n];
82 /* Must fit into positive ssize_t */
83 if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("ibs=", arg, 4))
84 ibs = xatoul_range_sfx(arg+4, 0, ((size_t)-1L)/2, dd_suffixes);
85 else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("obs=", arg, 4))
86 obs = xatoul_range_sfx(arg+4, 0, ((size_t)-1L)/2, dd_suffixes);
87 else if (!strncmp("bs=", arg, 3))
88 ibs = obs = xatoul_range_sfx(arg+3, 0, ((size_t)-1L)/2, dd_suffixes);
Denis Vlasenko5dd27b12006-11-25 14:46:21 +000089 /* These can be large: */
Denis Vlasenko3b8ff682006-10-31 15:55:56 +000090 else if (!strncmp("count=", arg, 6))
Denis Vlasenko5dd27b12006-11-25 14:46:21 +000091 count = XATOU_SFX(arg+6, dd_suffixes);
Denis Vlasenko3b8ff682006-10-31 15:55:56 +000092 else if (!strncmp("seek=", arg, 5))
Denis Vlasenko5dd27b12006-11-25 14:46:21 +000093 seek = XATOU_SFX(arg+5, dd_suffixes);
Denis Vlasenko3b8ff682006-10-31 15:55:56 +000094 else if (!strncmp("skip=", arg, 5))
Denis Vlasenko5dd27b12006-11-25 14:46:21 +000095 skip = XATOU_SFX(arg+5, dd_suffixes);
Denis Vlasenko3b8ff682006-10-31 15:55:56 +000096
97 else if (!strncmp("if=", arg, 3))
98 infile = arg+3;
99 else if (!strncmp("of=", arg, 3))
100 outfile = arg+3;
101 else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("conv=", arg, 5)) {
102 arg += 5;
Matt Kraai24ac0172000-12-18 21:38:57 +0000103 while (1) {
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000104 if (!strncmp("notrunc", arg, 7)) {
Denis Vlasenko56254152006-10-07 16:24:46 +0000105 flags &= ~trunc_flag;
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000106 arg += 7;
107 } else if (!strncmp("sync", arg, 4)) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000108 flags |= sync_flag;
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000109 arg += 4;
110 } else if (!strncmp("noerror", arg, 7)) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000111 flags |= noerror;
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000112 arg += 7;
Matt Kraai24ac0172000-12-18 21:38:57 +0000113 } else {
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000114 bb_error_msg_and_die(bb_msg_invalid_arg, arg, "conv");
Matt Kraai24ac0172000-12-18 21:38:57 +0000115 }
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000116 if (arg[0] == '\0') break;
117 if (*arg++ != ',') bb_show_usage();
Erik Andersene49d5ec2000-02-08 19:58:47 +0000118 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000119 } else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000120 bb_show_usage();
Eric Andersen3cf52d11999-10-12 22:26:06 +0000121 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000122
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000123 ibuf = obuf = xmalloc(ibs);
124 if (ibs != obs) {
125 flags |= twobufs_flag;
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000126 obuf = xmalloc(obs);
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000127 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000128
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000129 if (infile != NULL)
Denis Vlasenko7039a662006-10-08 17:54:47 +0000130 ifd = xopen(infile, O_RDONLY);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000131 else {
Matt Kraai24ac0172000-12-18 21:38:57 +0000132 ifd = STDIN_FILENO;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000133 infile = bb_msg_standard_input;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000134 }
135
Matt Kraai24ac0172000-12-18 21:38:57 +0000136 if (outfile != NULL) {
Denis Vlasenko7039a662006-10-08 17:54:47 +0000137 oflag = O_WRONLY | O_CREAT;
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000138
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000139 if (!seek && (flags & trunc_flag))
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000140 oflag |= O_TRUNC;
141
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000142 ofd = xopen(outfile, oflag);
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000143
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000144 if (seek && (flags & trunc_flag)) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000145 if (ftruncate(ofd, seek * obs) < 0) {
Matt Kraaieb834782002-02-05 15:28:54 +0000146 struct stat st;
147
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000148 if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) ||
149 S_ISDIR(st.st_mode))
150 goto die_outfile;
Matt Kraaieb834782002-02-05 15:28:54 +0000151 }
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000152 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000153 } else {
154 ofd = STDOUT_FILENO;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000155 outfile = bb_msg_standard_output;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000156 }
157
Matt Kraai24ac0172000-12-18 21:38:57 +0000158 if (skip) {
Denis Vlasenko7039a662006-10-08 17:54:47 +0000159 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000160 while (skip-- > 0) {
161 n = safe_read(ifd, ibuf, ibs);
162 if (n < 0)
163 bb_perror_msg_and_die("%s", infile);
164 if (n == 0)
165 break;
166 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000167 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000168 }
Eric Andersenddea3682000-11-29 22:33:02 +0000169
Matt Kraai24ac0172000-12-18 21:38:57 +0000170 if (seek) {
Denis Vlasenko7039a662006-10-08 17:54:47 +0000171 if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000172 goto die_outfile;
Matt Kraai24ac0172000-12-18 21:38:57 +0000173 }
Eric Andersenddea3682000-11-29 22:33:02 +0000174
Matt Kraai24ac0172000-12-18 21:38:57 +0000175 while (in_full + in_part != count) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000176 if (flags & noerror) {
Eric Andersenef38b392002-04-27 01:31:43 +0000177 /* Pre-zero the buffer when doing the noerror thing */
Rob Landley2686d3b2006-05-16 16:52:12 +0000178 memset(ibuf, '\0', ibs);
Eric Andersenef38b392002-04-27 01:31:43 +0000179 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000180
181 n = safe_read(ifd, ibuf, ibs);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000182 if (n == 0)
Rob Landley2686d3b2006-05-16 16:52:12 +0000183 break;
Eric Andersenef38b392002-04-27 01:31:43 +0000184 if (n < 0) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000185 if (flags & noerror) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000186 n = ibs;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000187 bb_perror_msg("%s", infile);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000188 } else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000189 bb_perror_msg_and_die("%s", infile);
Eric Andersenef38b392002-04-27 01:31:43 +0000190 }
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000191 if ((size_t)n == ibs)
Matt Kraai24ac0172000-12-18 21:38:57 +0000192 in_full++;
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000193 else {
Matt Kraai24ac0172000-12-18 21:38:57 +0000194 in_part++;
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000195 if (flags & sync_flag) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000196 memset(ibuf + n, '\0', ibs - n);
197 n = ibs;
198 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000199 }
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000200 if (flags & twobufs_flag) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000201 char *tmp = ibuf;
202 while (n) {
203 size_t d = obs - oc;
204
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000205 if (d > n)
206 d = n;
Rob Landley2686d3b2006-05-16 16:52:12 +0000207 memcpy(obuf + oc, tmp, d);
208 n -= d;
209 tmp += d;
210 oc += d;
211 if (oc == obs) {
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000212 w = full_write_or_warn(ofd, obuf, obs, outfile);
213 if (w < 0) goto out_status;
214 if (w == obs)
215 out_full++;
216 else if (w > 0)
217 out_part++;
Rob Landley2686d3b2006-05-16 16:52:12 +0000218 oc = 0;
219 }
220 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000221 } else {
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000222 w = full_write_or_warn(ofd, ibuf, n, outfile);
223 if (w < 0) goto out_status;
224 if (w == obs)
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000225 out_full++;
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000226 else if (w > 0)
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000227 out_part++;
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000228 }
Glenn L McGrathf0b073f2000-09-11 00:32:13 +0000229 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000230
Rob Landley2686d3b2006-05-16 16:52:12 +0000231 if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000232 w = full_write_or_warn(ofd, obuf, oc, outfile);
233 if (w < 0) goto out_status;
234 if (w > 0)
235 out_part++;
Rob Landley2686d3b2006-05-16 16:52:12 +0000236 }
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000237 if (close(ifd) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000238 bb_perror_msg_and_die("%s", infile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000239 }
Matt Kraai3eeab3b2001-12-07 16:27:37 +0000240
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000241 if (close(ofd) < 0) {
242 die_outfile:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000243 bb_perror_msg_and_die("%s", outfile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000244 }
Denis Vlasenko3b8ff682006-10-31 15:55:56 +0000245 out_status:
Rob Landleyc5598172006-05-02 22:44:04 +0000246 dd_output_status(0);
Matt Kraai24ac0172000-12-18 21:38:57 +0000247
Matt Kraai3e856ce2000-12-01 02:55:13 +0000248 return EXIT_SUCCESS;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000249}