blob: d60192e7ce1e30b45af3a22d4453b7bce5baf4c9 [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 Vlasenko7039a662006-10-08 17:54:47 +000032 bb_fprintf(stderr, OFF_FMT"+"OFF_FMT" records in\n"
33 OFF_FMT"+"OFF_FMT" 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
Matt Kraai24ac0172000-12-18 21:38:57 +000038int dd_main(int argc, char **argv)
Eric Andersen3cf52d11999-10-12 22:26:06 +000039{
Denis Vlasenko56254152006-10-07 16:24:46 +000040#define sync_flag (1<<0)
41#define noerror (1<<1)
42#define trunc_flag (1<<2)
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000043#define twobufs_flag (1<<3)
44 int flags = trunc_flag;
Denis Vlasenko56254152006-10-07 16:24:46 +000045 size_t oc = 0, ibs = 512, obs = 512;
Matt Kraai24ac0172000-12-18 21:38:57 +000046 ssize_t n;
Denis Vlasenko7039a662006-10-08 17:54:47 +000047 off_t seek = 0, skip = 0, count = OFF_T_MAX;
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000048 int oflag, ifd, ofd;
Rob Landley2686d3b2006-05-16 16:52:12 +000049 const char *infile = NULL, *outfile = NULL;
50 char *ibuf, *obuf;
Eric Andersenddea3682000-11-29 22:33:02 +000051
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000052 if (ENABLE_FEATURE_DD_SIGNAL_HANDLING) {
Rob Landleyc5598172006-05-02 22:44:04 +000053 struct sigaction sa;
54
55 memset(&sa, 0, sizeof(sa));
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000056 sa.sa_handler = dd_output_status;
Rob Landleyc5598172006-05-02 22:44:04 +000057 sa.sa_flags = SA_RESTART;
58 sigemptyset(&sa.sa_mask);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000059 sigaction(SIGUSR1, &sa, 0);
Rob Landleyc5598172006-05-02 22:44:04 +000060 }
61
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000062 for (n = 1; n < argc; n++) {
Denis Vlasenko56254152006-10-07 16:24:46 +000063 // FIXME: make them capable of eating LARGE numbers
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000064 if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("ibs=", argv[n], 4)) {
Denis Vlasenko13858992006-10-08 12:49:22 +000065 ibs = xatoul_sfx(argv[n]+4, dd_suffixes);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000066 flags |= twobufs_flag;
67 } else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("obs=", argv[n], 4)) {
Denis Vlasenko13858992006-10-08 12:49:22 +000068 obs = xatoul_sfx(argv[n]+4, dd_suffixes);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000069 flags |= twobufs_flag;
70 } else if (!strncmp("bs=", argv[n], 3))
Denis Vlasenko13858992006-10-08 12:49:22 +000071 ibs = obs = xatoul_sfx(argv[n]+3, dd_suffixes);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000072 else if (!strncmp("count=", argv[n], 6))
Denis Vlasenko13858992006-10-08 12:49:22 +000073 count = xatoul_sfx(argv[n]+6, dd_suffixes);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000074 else if (!strncmp("seek=", argv[n], 5))
Denis Vlasenko13858992006-10-08 12:49:22 +000075 seek = xatoul_sfx(argv[n]+5, dd_suffixes);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000076 else if (!strncmp("skip=", argv[n], 5))
Denis Vlasenko13858992006-10-08 12:49:22 +000077 skip = xatoul_sfx(argv[n]+5, dd_suffixes);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000078 else if (!strncmp("if=", argv[n], 3))
79 infile = argv[n]+3;
80 else if (!strncmp("of=", argv[n], 3))
81 outfile = argv[n]+3;
82 else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("conv=", argv[n], 5)) {
83 ibuf = argv[n]+5;
Matt Kraai24ac0172000-12-18 21:38:57 +000084 while (1) {
Rob Landley2686d3b2006-05-16 16:52:12 +000085 if (!strncmp("notrunc", ibuf, 7)) {
Denis Vlasenko56254152006-10-07 16:24:46 +000086 flags &= ~trunc_flag;
Rob Landley2686d3b2006-05-16 16:52:12 +000087 ibuf += 7;
88 } else if (!strncmp("sync", ibuf, 4)) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000089 flags |= sync_flag;
Rob Landley2686d3b2006-05-16 16:52:12 +000090 ibuf += 4;
91 } else if (!strncmp("noerror", ibuf, 7)) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000092 flags |= noerror;
Rob Landley2686d3b2006-05-16 16:52:12 +000093 ibuf += 7;
Matt Kraai24ac0172000-12-18 21:38:57 +000094 } else {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000095 bb_error_msg_and_die(bb_msg_invalid_arg, argv[n]+5, "conv");
Matt Kraai24ac0172000-12-18 21:38:57 +000096 }
Rob Landley2686d3b2006-05-16 16:52:12 +000097 if (ibuf[0] == '\0') break;
98 if (ibuf[0] == ',') ibuf++;
Erik Andersene49d5ec2000-02-08 19:58:47 +000099 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000100 } else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000101 bb_show_usage();
Eric Andersen3cf52d11999-10-12 22:26:06 +0000102 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000103 ibuf = xmalloc(ibs);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000104
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000105 if (flags & twobufs_flag)
106 obuf = xmalloc(obs);
107 else
108 obuf = ibuf;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000109
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000110 if (infile != NULL)
Denis Vlasenko7039a662006-10-08 17:54:47 +0000111 ifd = xopen(infile, O_RDONLY);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000112 else {
Matt Kraai24ac0172000-12-18 21:38:57 +0000113 ifd = STDIN_FILENO;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000114 infile = bb_msg_standard_input;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000115 }
116
Matt Kraai24ac0172000-12-18 21:38:57 +0000117 if (outfile != NULL) {
Denis Vlasenko7039a662006-10-08 17:54:47 +0000118 oflag = O_WRONLY | O_CREAT;
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000119
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000120 if (!seek && (flags & trunc_flag))
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000121 oflag |= O_TRUNC;
122
Rob Landleyd921b2e2006-08-03 15:41:12 +0000123 ofd = xopen3(outfile, oflag, 0666);
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000124
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000125 if (seek && (flags & trunc_flag)) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000126 if (ftruncate(ofd, seek * obs) < 0) {
Matt Kraaieb834782002-02-05 15:28:54 +0000127 struct stat st;
128
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000129 if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) ||
130 S_ISDIR(st.st_mode))
131 goto die_outfile;
Matt Kraaieb834782002-02-05 15:28:54 +0000132 }
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000133 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000134 } else {
135 ofd = STDOUT_FILENO;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000136 outfile = bb_msg_standard_output;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000137 }
138
Matt Kraai24ac0172000-12-18 21:38:57 +0000139 if (skip) {
Denis Vlasenko7039a662006-10-08 17:54:47 +0000140 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000141 while (skip-- > 0) {
142 n = safe_read(ifd, ibuf, ibs);
143 if (n < 0)
144 bb_perror_msg_and_die("%s", infile);
145 if (n == 0)
146 break;
147 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000148 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000149 }
Eric Andersenddea3682000-11-29 22:33:02 +0000150
Matt Kraai24ac0172000-12-18 21:38:57 +0000151 if (seek) {
Denis Vlasenko7039a662006-10-08 17:54:47 +0000152 if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000153 goto die_outfile;
Matt Kraai24ac0172000-12-18 21:38:57 +0000154 }
Eric Andersenddea3682000-11-29 22:33:02 +0000155
Matt Kraai24ac0172000-12-18 21:38:57 +0000156 while (in_full + in_part != count) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000157 if (flags & noerror) {
Eric Andersenef38b392002-04-27 01:31:43 +0000158 /* Pre-zero the buffer when doing the noerror thing */
Rob Landley2686d3b2006-05-16 16:52:12 +0000159 memset(ibuf, '\0', ibs);
Eric Andersenef38b392002-04-27 01:31:43 +0000160 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000161
162 n = safe_read(ifd, ibuf, ibs);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000163 if (n == 0)
Rob Landley2686d3b2006-05-16 16:52:12 +0000164 break;
Eric Andersenef38b392002-04-27 01:31:43 +0000165 if (n < 0) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000166 if (flags & noerror) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000167 n = ibs;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000168 bb_perror_msg("%s", infile);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000169 } else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000170 bb_perror_msg_and_die("%s", infile);
Eric Andersenef38b392002-04-27 01:31:43 +0000171 }
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000172 if ((size_t)n == ibs)
Matt Kraai24ac0172000-12-18 21:38:57 +0000173 in_full++;
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000174 else {
Matt Kraai24ac0172000-12-18 21:38:57 +0000175 in_part++;
Rob Landley2686d3b2006-05-16 16:52:12 +0000176 if (sync_flag) {
177 memset(ibuf + n, '\0', ibs - n);
178 n = ibs;
179 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000180 }
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000181 if (flags & twobufs_flag) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000182 char *tmp = ibuf;
183 while (n) {
184 size_t d = obs - oc;
185
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000186 if (d > n)
187 d = n;
Rob Landley2686d3b2006-05-16 16:52:12 +0000188 memcpy(obuf + oc, tmp, d);
189 n -= d;
190 tmp += d;
191 oc += d;
192 if (oc == obs) {
Rob Landley53437472006-07-16 08:14:35 +0000193 xwrite(ofd, obuf, obs);
Rob Landley2686d3b2006-05-16 16:52:12 +0000194 out_full++;
195 oc = 0;
196 }
197 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000198 } else {
Rob Landley53437472006-07-16 08:14:35 +0000199 xwrite(ofd, ibuf, n);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000200 if (n == ibs)
201 out_full++;
202 else
203 out_part++;
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000204 }
Glenn L McGrathf0b073f2000-09-11 00:32:13 +0000205 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000206
Rob Landley2686d3b2006-05-16 16:52:12 +0000207 if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
Rob Landley53437472006-07-16 08:14:35 +0000208 xwrite(ofd, obuf, oc);
Rob Landley2686d3b2006-05-16 16:52:12 +0000209 out_part++;
210 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000211 if (close (ifd) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000212 bb_perror_msg_and_die("%s", infile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000213 }
Matt Kraai3eeab3b2001-12-07 16:27:37 +0000214
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000215 if (close (ofd) < 0) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000216die_outfile:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000217 bb_perror_msg_and_die("%s", outfile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000218 }
Matt Kraai3eeab3b2001-12-07 16:27:37 +0000219
Rob Landleyc5598172006-05-02 22:44:04 +0000220 dd_output_status(0);
Matt Kraai24ac0172000-12-18 21:38:57 +0000221
Matt Kraai3e856ce2000-12-01 02:55:13 +0000222 return EXIT_SUCCESS;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000223}