This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / bin / dd / dd.c
CommitLineData
78ed81a3 1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
15637ed4 4 *
78ed81a3 5 * This code is derived from software contributed to Berkeley by
6 * Keith Muller of the University of California, San Diego and Lance
7 * Visser of Convex Computer Corporation.
15637ed4 8 *
78ed81a3 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
15637ed4 24 *
78ed81a3 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
15637ed4
RG
36 */
37
78ed81a3 38#ifndef lint
39char copyright[] =
40"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
41 All rights reserved.\n";
42#endif /* not lint */
15637ed4 43
78ed81a3 44#ifndef lint
45static char sccsid[] = "@(#)dd.c 5.16 (Berkeley) 4/28/93";
46#endif /* not lint */
15637ed4 47
78ed81a3 48#include <sys/param.h>
49#include <sys/stat.h>
50#include <sys/ioctl.h>
51#include <sys/mtio.h>
15637ed4 52
15637ed4 53#include <ctype.h>
15637ed4 54#include <errno.h>
15637ed4 55#include <fcntl.h>
78ed81a3 56#include <signal.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <unistd.h>
15637ed4 61
78ed81a3 62#include "dd.h"
63#include "extern.h"
15637ed4 64
78ed81a3 65static void dd_close __P((void));
66static void dd_in __P((void));
67static void setup __P((void));
15637ed4 68
78ed81a3 69IO in, out; /* input/output state */
70STAT st; /* statistics */
71void (*cfunc) __P((void)); /* conversion function */
72u_long cpy_cnt; /* # of blocks to copy */
73u_int ddflags; /* conversion options */
74u_int cbsz; /* conversion block size */
75u_int files_cnt = 1; /* # of files to copy */
76int errstats; /* show statistics on error */
77u_char *ctab; /* conversion table */
15637ed4 78
78ed81a3 79int
80main(argc, argv)
81 int argc;
82 char *argv[];
15637ed4 83{
78ed81a3 84 jcl(argv);
85 setup();
15637ed4 86
78ed81a3 87 (void)signal(SIGINFO, summary);
88 (void)signal(SIGINT, terminate);
15637ed4 89
78ed81a3 90 for (errstats = 1; files_cnt--;)
91 dd_in();
15637ed4 92
78ed81a3 93 dd_close();
94 summary(0);
95 exit(0);
15637ed4
RG
96}
97
78ed81a3 98static void
99setup()
15637ed4 100{
78ed81a3 101 register u_int cnt;
102 struct stat sb;
103 struct mtget mt;
104
105 if (in.name == NULL) {
106 in.name = "stdin";
107 in.fd = STDIN_FILENO;
108 } else {
109 in.fd = open(in.name, O_RDONLY, 0);
110 if (in.fd < 0)
111 err("%s: %s", in.name, strerror(errno));
15637ed4 112 }
15637ed4 113
78ed81a3 114 if (fstat(in.fd, &sb))
115 err("%s: %s", in.name, strerror(errno));
116 if (S_ISCHR(sb.st_mode))
117 in.flags |= ioctl(in.fd, MTIOCGET, &mt) ? ISCHR : ISTAPE;
118 else if (lseek(in.fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
119 in.flags |= ISPIPE; /* XXX fixed in 4.4BSD */
120
121 if (files_cnt > 1 && !(in.flags & ISTAPE))
122 err("files is not supported for non-tape devices");
123
124 if (out.name == NULL) {
125 /* No way to check for read access here. */
126 out.fd = STDOUT_FILENO;
127 out.name = "stdout";
128 } else {
129#define OFLAGS \
130 (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
131 out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
132 /*
133 * May not have read access, so try again with write only.
134 * Without read we may have a problem if output also does
135 * not support seeks.
136 */
137 if (out.fd < 0) {
138 out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
139 out.flags |= NOREAD;
140 }
141 if (out.fd < 0)
142 err("%s: %s", out.name, strerror(errno));
15637ed4
RG
143 }
144
78ed81a3 145 if (fstat(out.fd, &sb))
146 err("%s: %s", out.name, strerror(errno));
147 if (S_ISCHR(sb.st_mode))
148 out.flags |= ioctl(out.fd, MTIOCGET, &mt) ? ISCHR : ISTAPE;
149 else if (lseek(out.fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
150 out.flags |= ISPIPE; /* XXX fixed in 4.4BSD */
151
152 /*
153 * Allocate space for the input and output buffers. If not doing
154 * record oriented I/O, only need a single buffer.
155 */
156 if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
157 if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
158 err("%s", strerror(errno));
159 out.db = in.db;
160 } else if ((in.db =
161 malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
162 (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL)
163 err("%s", strerror(errno));
164 in.dbp = in.db;
165 out.dbp = out.db;
166
167 /* Position the input/output streams. */
168 if (in.offset)
169 pos_in();
170 if (out.offset)
171 pos_out();
172
173 /*
174 * Truncate the output file; ignore errors because it fails on some
175 * kinds of output files, tapes, for example.
176 */
177 if (ddflags & (C_OF | C_SEEK | C_NOTRUNC) == (C_OF | C_SEEK))
178 (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
179
180 /*
181 * If converting case at the same time as another conversion, build a
182 * table that does both at once. If just converting case, use the
183 * built-in tables.
184 */
185 if (ddflags & (C_LCASE|C_UCASE))
186 if (ddflags & C_ASCII)
187 if (ddflags & C_LCASE) {
188 for (cnt = 0; cnt < 0377; ++cnt)
189 if (isupper(ctab[cnt]))
190 ctab[cnt] = tolower(ctab[cnt]);
191 } else {
192 for (cnt = 0; cnt < 0377; ++cnt)
193 if (islower(ctab[cnt]))
194 ctab[cnt] = toupper(ctab[cnt]);
195 }
196 else if (ddflags & C_EBCDIC)
197 if (ddflags & C_LCASE) {
198 for (cnt = 0; cnt < 0377; ++cnt)
199 if (isupper(cnt))
200 ctab[cnt] = ctab[tolower(cnt)];
201 } else {
202 for (cnt = 0; cnt < 0377; ++cnt)
203 if (islower(cnt))
204 ctab[cnt] = ctab[toupper(cnt)];
205 }
206 else
207 ctab = ddflags & C_LCASE ? u2l : l2u;
208 (void)time(&st.start); /* Statistics timestamp. */
15637ed4
RG
209}
210
78ed81a3 211static void
212dd_in()
15637ed4 213{
78ed81a3 214 register int flags, n;
215
216 for (flags = ddflags;;) {
217 if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
218 return;
219
220 /*
221 * Zero the buffer first if trying to recover from errors so
222 * lose the minimum amount of data. If doing block operations
223 * use spaces.
224 */
225 if (flags & (C_NOERROR|C_SYNC))
226 if (flags & (C_BLOCK|C_UNBLOCK))
227 memset(in.dbp, ' ', in.dbsz);
228 else
229 memset(in.dbp, 0, in.dbsz);
230
231 n = read(in.fd, in.dbp, in.dbsz);
232 if (n == 0) {
233 in.dbrcnt = 0;
234 return;
235 }
236
237 /* Read error. */
238 if (n < 0) {
239 /*
240 * If noerror not specified, die. POSIX requires that
241 * the warning message be followed by an I/O display.
242 */
243 if (!(flags & C_NOERROR))
244 err("%s: %s", in.name, strerror(errno));
245 warn("%s: %s", in.name, strerror(errno));
246 summary(0);
247
248 /*
249 * If it's not a tape drive or a pipe, seek past the
250 * error. If your OS doesn't do the right thing for
251 * raw disks this section should be modified to re-read
252 * in sector size chunks.
253 */
254 if (!(in.flags & (ISPIPE|ISTAPE)) &&
255 lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
256 warn("%s: %s", in.name, strerror(errno));
257
258 /* If sync not specified, omit block and continue. */
259 if (!(ddflags & C_SYNC))
260 continue;
261
262 /* Read errors count as full blocks. */
263 in.dbcnt += in.dbrcnt = in.dbsz;
264 ++st.in_full;
265
266 /* Handle full input blocks. */
267 } else if (n == in.dbsz) {
268 in.dbcnt += in.dbrcnt = n;
269 ++st.in_full;
270
271 /* Handle partial input blocks. */
272 } else {
273 /* If sync, use the entire block. */
274 if (ddflags & C_SYNC)
275 in.dbcnt += in.dbrcnt = in.dbsz;
276 else
277 in.dbcnt += in.dbrcnt = n;
278 ++st.in_part;
279 }
280
281 /*
282 * POSIX states that if bs is set and no other conversions
283 * than noerror, notrunc or sync are specified, the block
284 * is output without buffering as it is read.
285 */
286 if (ddflags & C_BS) {
287 out.dbcnt = in.dbcnt;
288 dd_out(1);
289 in.dbcnt = 0;
290 continue;
291 }
292
293 if (ddflags & C_SWAB) {
294 if ((n = in.dbcnt) & 1) {
295 ++st.swab;
296 --n;
297 }
298 swab(in.dbp, in.dbp, n);
299 }
300
301 in.dbp += in.dbrcnt;
302 (*cfunc)();
15637ed4 303 }
15637ed4
RG
304}
305
78ed81a3 306/*
307 * Cleanup any remaining I/O and flush output. If necesssary, output file
308 * is truncated.
309 */
310static void
311dd_close()
15637ed4 312{
78ed81a3 313 if (cfunc == def)
314 def_close();
315 else if (cfunc == block)
316 block_close();
317 else if (cfunc == unblock)
318 unblock_close();
319 if (out.dbcnt)
320 dd_out(1);
15637ed4
RG
321}
322
15637ed4 323void
78ed81a3 324dd_out(force)
325 int force;
15637ed4 326{
78ed81a3 327 static int warned;
328 register int cnt, n, nw;
329 register u_char *outp;
330
331 /*
332 * Write one or more blocks out. The common case is writing a full
333 * output block in a single write; increment the full block stats.
334 * Otherwise, we're into partial block writes. If a partial write,
335 * and it's a character device, just warn. If a tape device, quit.
336 *
337 * The partial writes represent two cases. 1: Where the input block
338 * was less than expected so the output block was less than expected.
339 * 2: Where the input block was the right size but we were forced to
340 * write the block in multiple chunks. The original versions of dd(1)
341 * never wrote a block in more than a single write, so the latter case
342 * never happened.
343 *
344 * One special case is if we're forced to do the write -- in that case
345 * we play games with the buffer size, and it's usually a partial write.
346 */
347 outp = out.db;
348 for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
349 for (cnt = n;; cnt -= nw) {
350 nw = write(out.fd, outp, cnt);
351 if (nw < 0)
352 err("%s: %s", out.name, strerror(errno));
353 outp += nw;
354 st.bytes += nw;
355 if (nw == n) {
356 if (n != out.dbsz)
357 ++st.out_part;
358 else
359 ++st.out_full;
360 break;
361 }
362 ++st.out_part;
363 if (nw == cnt)
364 break;
365 if (out.flags & ISCHR && !warned) {
366 warned = 1;
367 warn("%s: short write on character device",
368 out.name);
369 }
370 if (out.flags & ISTAPE)
371 err("%s: short write on tape device", out.name);
372 }
373 if ((out.dbcnt -= n) < out.dbsz)
374 break;
15637ed4 375 }
15637ed4 376
78ed81a3 377 /* Reassemble the output block. */
378 if (out.dbcnt)
379 memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
380 out.dbp = out.db + out.dbcnt;
15637ed4 381}