blob: a9536a584c0d43eb0e463ac2f2c6bb4865d4114a [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 },
20 { "MD", 1000000 },
21 { "M", 1048576 },
22 { "GD", 1000000000 },
23 { "G", 1073741824 },
24 { NULL, 0 }
25};
26
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000027static size_t out_full, out_part, in_full, in_part;
Rob Landleyc5598172006-05-02 22:44:04 +000028
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000029static void dd_output_status(int ATTRIBUTE_UNUSED cur_signal)
Rob Landleyc5598172006-05-02 22:44:04 +000030{
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000031 bb_fprintf(stderr, "%ld+%ld records in\n%ld+%ld records out\n",
Rob Landleyc5598172006-05-02 22:44:04 +000032 (long)in_full, (long)in_part,
33 (long)out_full, (long)out_part);
34}
35
Matt Kraai24ac0172000-12-18 21:38:57 +000036int dd_main(int argc, char **argv)
Eric Andersen3cf52d11999-10-12 22:26:06 +000037{
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000038#define sync_flag (1<<0)
39#define noerror (1<<1)
40#define trunc_flag (1<<2)
41#define twobufs_flag (1<<3)
42 int flags = trunc_flag;
Rob Landley2686d3b2006-05-16 16:52:12 +000043 size_t count = -1, oc = 0, ibs = 512, obs = 512;
Matt Kraai24ac0172000-12-18 21:38:57 +000044 ssize_t n;
Rob Landley2686d3b2006-05-16 16:52:12 +000045 off_t seek = 0, skip = 0;
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000046 int oflag, ifd, ofd;
Rob Landley2686d3b2006-05-16 16:52:12 +000047 const char *infile = NULL, *outfile = NULL;
48 char *ibuf, *obuf;
Eric Andersenddea3682000-11-29 22:33:02 +000049
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000050 if (ENABLE_FEATURE_DD_SIGNAL_HANDLING) {
Rob Landleyc5598172006-05-02 22:44:04 +000051 struct sigaction sa;
52
53 memset(&sa, 0, sizeof(sa));
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000054 sa.sa_handler = dd_output_status;
Rob Landleyc5598172006-05-02 22:44:04 +000055 sa.sa_flags = SA_RESTART;
56 sigemptyset(&sa.sa_mask);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000057 sigaction(SIGUSR1, &sa, 0);
Rob Landleyc5598172006-05-02 22:44:04 +000058 }
59
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000060 for (n = 1; n < argc; n++) {
61 if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("ibs=", argv[n], 4)) {
62 ibs = bb_xparse_number(argv[n]+4, dd_suffixes);
63 flags |= twobufs_flag;
64 } else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("obs=", argv[n], 4)) {
65 obs = bb_xparse_number(argv[n]+4, dd_suffixes);
66 flags |= twobufs_flag;
67 } else if (!strncmp("bs=", argv[n], 3))
68 ibs = obs = bb_xparse_number(argv[n]+3, dd_suffixes);
69 else if (!strncmp("count=", argv[n], 6))
70 count = bb_xparse_number(argv[n]+6, dd_suffixes);
71 else if (!strncmp("seek=", argv[n], 5))
72 seek = bb_xparse_number(argv[n]+5, dd_suffixes);
73 else if (!strncmp("skip=", argv[n], 5))
74 skip = bb_xparse_number(argv[n]+5, dd_suffixes);
75 else if (!strncmp("if=", argv[n], 3))
76 infile = argv[n]+3;
77 else if (!strncmp("of=", argv[n], 3))
78 outfile = argv[n]+3;
79 else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("conv=", argv[n], 5)) {
80 ibuf = argv[n]+5;
Matt Kraai24ac0172000-12-18 21:38:57 +000081 while (1) {
Rob Landley2686d3b2006-05-16 16:52:12 +000082 if (!strncmp("notrunc", ibuf, 7)) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000083 flags ^= trunc_flag;
Rob Landley2686d3b2006-05-16 16:52:12 +000084 ibuf += 7;
85 } else if (!strncmp("sync", ibuf, 4)) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000086 flags |= sync_flag;
Rob Landley2686d3b2006-05-16 16:52:12 +000087 ibuf += 4;
88 } else if (!strncmp("noerror", ibuf, 7)) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000089 flags |= noerror;
Rob Landley2686d3b2006-05-16 16:52:12 +000090 ibuf += 7;
Matt Kraai24ac0172000-12-18 21:38:57 +000091 } else {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +000092 bb_error_msg_and_die(bb_msg_invalid_arg, argv[n]+5, "conv");
Matt Kraai24ac0172000-12-18 21:38:57 +000093 }
Rob Landley2686d3b2006-05-16 16:52:12 +000094 if (ibuf[0] == '\0') break;
95 if (ibuf[0] == ',') ibuf++;
Erik Andersene49d5ec2000-02-08 19:58:47 +000096 }
Matt Kraai24ac0172000-12-18 21:38:57 +000097 } else
Manuel Novoa III cad53642003-03-19 09:13:01 +000098 bb_show_usage();
Eric Andersen3cf52d11999-10-12 22:26:06 +000099 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000100 ibuf = xmalloc(ibs);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000101
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000102 if (flags & twobufs_flag)
103 obuf = xmalloc(obs);
104 else
105 obuf = ibuf;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000106
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000107 if (infile != NULL)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000108 ifd = xopen(infile, O_RDONLY);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000109 else {
Matt Kraai24ac0172000-12-18 21:38:57 +0000110 ifd = STDIN_FILENO;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000111 infile = bb_msg_standard_input;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000112 }
113
Matt Kraai24ac0172000-12-18 21:38:57 +0000114 if (outfile != NULL) {
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000115 oflag = O_WRONLY | O_CREAT;
116
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000117 if (!seek && (flags & trunc_flag))
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000118 oflag |= O_TRUNC;
119
Rob Landleyd921b2e2006-08-03 15:41:12 +0000120 ofd = xopen3(outfile, oflag, 0666);
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000121
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000122 if (seek && (flags & trunc_flag)) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000123 if (ftruncate(ofd, seek * obs) < 0) {
Matt Kraaieb834782002-02-05 15:28:54 +0000124 struct stat st;
125
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000126 if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) ||
127 S_ISDIR(st.st_mode))
128 goto die_outfile;
Matt Kraaieb834782002-02-05 15:28:54 +0000129 }
Matt Kraaic9acf8c2001-01-17 00:21:05 +0000130 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000131 } else {
132 ofd = STDOUT_FILENO;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000133 outfile = bb_msg_standard_output;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000134 }
135
Matt Kraai24ac0172000-12-18 21:38:57 +0000136 if (skip) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000137 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
138 while (skip-- > 0) {
139 n = safe_read(ifd, ibuf, ibs);
140 if (n < 0)
141 bb_perror_msg_and_die("%s", infile);
142 if (n == 0)
143 break;
144 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000145 }
Matt Kraai24ac0172000-12-18 21:38:57 +0000146 }
Eric Andersenddea3682000-11-29 22:33:02 +0000147
Matt Kraai24ac0172000-12-18 21:38:57 +0000148 if (seek) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000149 if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
150 goto die_outfile;
Matt Kraai24ac0172000-12-18 21:38:57 +0000151 }
Eric Andersenddea3682000-11-29 22:33:02 +0000152
Matt Kraai24ac0172000-12-18 21:38:57 +0000153 while (in_full + in_part != count) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000154 if (flags & noerror) {
Eric Andersenef38b392002-04-27 01:31:43 +0000155 /* Pre-zero the buffer when doing the noerror thing */
Rob Landley2686d3b2006-05-16 16:52:12 +0000156 memset(ibuf, '\0', ibs);
Eric Andersenef38b392002-04-27 01:31:43 +0000157 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000158
159 n = safe_read(ifd, ibuf, ibs);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000160 if (n == 0)
Rob Landley2686d3b2006-05-16 16:52:12 +0000161 break;
Eric Andersenef38b392002-04-27 01:31:43 +0000162 if (n < 0) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000163 if (flags & noerror) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000164 n = ibs;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000165 bb_perror_msg("%s", infile);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000166 } else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000167 bb_perror_msg_and_die("%s", infile);
Eric Andersenef38b392002-04-27 01:31:43 +0000168 }
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000169 if ((size_t)n == ibs)
Matt Kraai24ac0172000-12-18 21:38:57 +0000170 in_full++;
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000171 else {
Matt Kraai24ac0172000-12-18 21:38:57 +0000172 in_part++;
Rob Landley2686d3b2006-05-16 16:52:12 +0000173 if (sync_flag) {
174 memset(ibuf + n, '\0', ibs - n);
175 n = ibs;
176 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000177 }
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000178 if (flags & twobufs_flag) {
Rob Landley2686d3b2006-05-16 16:52:12 +0000179 char *tmp = ibuf;
180 while (n) {
181 size_t d = obs - oc;
182
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000183 if (d > n)
184 d = n;
Rob Landley2686d3b2006-05-16 16:52:12 +0000185 memcpy(obuf + oc, tmp, d);
186 n -= d;
187 tmp += d;
188 oc += d;
189 if (oc == obs) {
Rob Landley53437472006-07-16 08:14:35 +0000190 xwrite(ofd, obuf, obs);
Rob Landley2686d3b2006-05-16 16:52:12 +0000191 out_full++;
192 oc = 0;
193 }
194 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000195 } else {
Rob Landley53437472006-07-16 08:14:35 +0000196 xwrite(ofd, ibuf, n);
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000197 if (n == ibs)
198 out_full++;
199 else
200 out_part++;
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000201 }
Glenn L McGrathf0b073f2000-09-11 00:32:13 +0000202 }
Rob Landley2686d3b2006-05-16 16:52:12 +0000203
204 if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
Rob Landley53437472006-07-16 08:14:35 +0000205 xwrite(ofd, obuf, oc);
Rob Landley2686d3b2006-05-16 16:52:12 +0000206 out_part++;
207 }
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000208 if (close (ifd) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000209 bb_perror_msg_and_die("%s", infile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000210 }
Matt Kraai3eeab3b2001-12-07 16:27:37 +0000211
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000212 if (close (ofd) < 0) {
Bernhard Reutner-Fischer73561cc2006-08-28 23:31:54 +0000213die_outfile:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000214 bb_perror_msg_and_die("%s", outfile);
Glenn L McGratheaed78a2002-11-28 11:05:28 +0000215 }
Matt Kraai3eeab3b2001-12-07 16:27:37 +0000216
Rob Landleyc5598172006-05-02 22:44:04 +0000217 dd_output_status(0);
Matt Kraai24ac0172000-12-18 21:38:57 +0000218
Matt Kraai3e856ce2000-12-01 02:55:13 +0000219 return EXIT_SUCCESS;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000220}