dd.c revision 298258
1/*-
2 * Copyright (c) 1991, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
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.
8 *
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 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if 0
35#ifndef lint
36static char const copyright[] =
37"@(#) Copyright (c) 1991, 1993, 1994\n\
38	The Regents of the University of California.  All rights reserved.\n";
39#endif /* not lint */
40
41#ifndef lint
42static char sccsid[] = "@(#)dd.c	8.5 (Berkeley) 4/2/94";
43#endif /* not lint */
44#endif
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: stable/10/bin/dd/dd.c 298258 2016-04-19 07:34:31Z thomas $");
47
48#include <sys/param.h>
49#include <sys/stat.h>
50#include <sys/conf.h>
51#include <sys/disklabel.h>
52#include <sys/filio.h>
53#include <sys/time.h>
54
55#include <assert.h>
56#include <ctype.h>
57#include <err.h>
58#include <errno.h>
59#include <fcntl.h>
60#include <inttypes.h>
61#include <locale.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <unistd.h>
66
67#include "dd.h"
68#include "extern.h"
69
70static void dd_close(void);
71static void dd_in(void);
72static void getfdtype(IO *);
73static void setup(void);
74
75IO	in, out;		/* input/output state */
76STAT	st;			/* statistics */
77void	(*cfunc)(void);		/* conversion function */
78uintmax_t cpy_cnt;		/* # of blocks to copy */
79static off_t	pending = 0;	/* pending seek if sparse */
80u_int	ddflags = 0;		/* conversion options */
81size_t	cbsz;			/* conversion block size */
82uintmax_t files_cnt = 1;	/* # of files to copy */
83const	u_char *ctab;		/* conversion table */
84char	fill_char;		/* Character to fill with if defined */
85volatile sig_atomic_t need_summary;
86
87int
88main(int argc __unused, char *argv[])
89{
90	(void)setlocale(LC_CTYPE, "");
91	jcl(argv);
92	setup();
93
94	(void)signal(SIGINFO, siginfo_handler);
95	(void)signal(SIGINT, terminate);
96
97	atexit(summary);
98
99	while (files_cnt--)
100		dd_in();
101
102	dd_close();
103	/*
104	 * Some devices such as cfi(4) may perform significant amounts
105	 * of work when a write descriptor is closed.  Close the out
106	 * descriptor explicitly so that the summary handler (called
107	 * from an atexit() hook) includes this work.
108	 */
109	close(out.fd);
110	exit(0);
111}
112
113static int
114parity(u_char c)
115{
116	int i;
117
118	i = c ^ (c >> 1) ^ (c >> 2) ^ (c >> 3) ^
119	    (c >> 4) ^ (c >> 5) ^ (c >> 6) ^ (c >> 7);
120	return (i & 1);
121}
122
123static void
124setup(void)
125{
126	u_int cnt;
127	struct timeval tv;
128
129	if (in.name == NULL) {
130		in.name = "stdin";
131		in.fd = STDIN_FILENO;
132	} else {
133		in.fd = open(in.name, O_RDONLY, 0);
134		if (in.fd == -1)
135			err(1, "%s", in.name);
136	}
137
138	getfdtype(&in);
139
140	if (files_cnt > 1 && !(in.flags & ISTAPE))
141		errx(1, "files is not supported for non-tape devices");
142
143	if (out.name == NULL) {
144		/* No way to check for read access here. */
145		out.fd = STDOUT_FILENO;
146		out.name = "stdout";
147	} else {
148#define	OFLAGS \
149    (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
150		out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
151		/*
152		 * May not have read access, so try again with write only.
153		 * Without read we may have a problem if output also does
154		 * not support seeks.
155		 */
156		if (out.fd == -1) {
157			out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
158			out.flags |= NOREAD;
159		}
160		if (out.fd == -1)
161			err(1, "%s", out.name);
162	}
163
164	getfdtype(&out);
165
166	/*
167	 * Allocate space for the input and output buffers.  If not doing
168	 * record oriented I/O, only need a single buffer.
169	 */
170	if (!(ddflags & (C_BLOCK | C_UNBLOCK))) {
171		if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
172			err(1, "input buffer");
173		out.db = in.db;
174	} else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL ||
175	    (out.db = malloc(out.dbsz + cbsz)) == NULL)
176		err(1, "output buffer");
177
178	/* dbp is the first free position in each buffer. */
179	in.dbp = in.db;
180	out.dbp = out.db;
181
182	/* Position the input/output streams. */
183	if (in.offset)
184		pos_in();
185	if (out.offset)
186		pos_out();
187
188	/*
189	 * Truncate the output file.  If it fails on a type of output file
190	 * that it should _not_ fail on, error out.
191	 */
192	if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) &&
193	    out.flags & ISTRUNC)
194		if (ftruncate(out.fd, out.offset * out.dbsz) == -1)
195			err(1, "truncating %s", out.name);
196
197	if (ddflags & (C_LCASE  | C_UCASE | C_ASCII | C_EBCDIC | C_PARITY)) {
198		if (ctab != NULL) {
199			for (cnt = 0; cnt <= 0377; ++cnt)
200				casetab[cnt] = ctab[cnt];
201		} else {
202			for (cnt = 0; cnt <= 0377; ++cnt)
203				casetab[cnt] = cnt;
204		}
205		if ((ddflags & C_PARITY) && !(ddflags & C_ASCII)) {
206			/*
207			 * If the input is not EBCDIC, and we do parity
208			 * processing, strip input parity.
209			 */
210			for (cnt = 200; cnt <= 0377; ++cnt)
211				casetab[cnt] = casetab[cnt & 0x7f];
212		}
213		if (ddflags & C_LCASE) {
214			for (cnt = 0; cnt <= 0377; ++cnt)
215				casetab[cnt] = tolower(casetab[cnt]);
216		} else if (ddflags & C_UCASE) {
217			for (cnt = 0; cnt <= 0377; ++cnt)
218				casetab[cnt] = toupper(casetab[cnt]);
219		}
220		if ((ddflags & C_PARITY)) {
221			/*
222			 * This should strictly speaking be a no-op, but I
223			 * wonder what funny LANG settings could get us.
224			 */
225			for (cnt = 0; cnt <= 0377; ++cnt)
226				casetab[cnt] = casetab[cnt] & 0x7f;
227		}
228		if ((ddflags & C_PARSET)) {
229			for (cnt = 0; cnt <= 0377; ++cnt)
230				casetab[cnt] = casetab[cnt] | 0x80;
231		}
232		if ((ddflags & C_PAREVEN)) {
233			for (cnt = 0; cnt <= 0377; ++cnt)
234				if (parity(casetab[cnt]))
235					casetab[cnt] = casetab[cnt] | 0x80;
236		}
237		if ((ddflags & C_PARODD)) {
238			for (cnt = 0; cnt <= 0377; ++cnt)
239				if (!parity(casetab[cnt]))
240					casetab[cnt] = casetab[cnt] | 0x80;
241		}
242
243		ctab = casetab;
244	}
245
246	(void)gettimeofday(&tv, NULL);
247	st.start = tv.tv_sec + tv.tv_usec * 1e-6;
248}
249
250static void
251getfdtype(IO *io)
252{
253	struct stat sb;
254	int type;
255
256	if (fstat(io->fd, &sb) == -1)
257		err(1, "%s", io->name);
258	if (S_ISREG(sb.st_mode))
259		io->flags |= ISTRUNC;
260	if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) {
261		if (ioctl(io->fd, FIODTYPE, &type) == -1) {
262			err(1, "%s", io->name);
263		} else {
264			if (type & D_TAPE)
265				io->flags |= ISTAPE;
266			else if (type & (D_DISK | D_MEM))
267				io->flags |= ISSEEK;
268			if (S_ISCHR(sb.st_mode) && (type & D_TAPE) == 0)
269				io->flags |= ISCHR;
270		}
271		return;
272	}
273	errno = 0;
274	if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
275		io->flags |= ISPIPE;
276	else
277		io->flags |= ISSEEK;
278}
279
280static void
281dd_in(void)
282{
283	ssize_t n;
284
285	for (;;) {
286		switch (cpy_cnt) {
287		case -1:			/* count=0 was specified */
288			return;
289		case 0:
290			break;
291		default:
292			if (st.in_full + st.in_part >= (uintmax_t)cpy_cnt)
293				return;
294			break;
295		}
296
297		/*
298		 * Zero the buffer first if sync; if doing block operations,
299		 * use spaces.
300		 */
301		if (ddflags & C_SYNC) {
302			if (ddflags & C_FILL)
303				memset(in.dbp, fill_char, in.dbsz);
304			else if (ddflags & (C_BLOCK | C_UNBLOCK))
305				memset(in.dbp, ' ', in.dbsz);
306			else
307				memset(in.dbp, 0, in.dbsz);
308		}
309
310		n = read(in.fd, in.dbp, in.dbsz);
311		if (n == 0) {
312			in.dbrcnt = 0;
313			return;
314		}
315
316		/* Read error. */
317		if (n == -1) {
318			/*
319			 * If noerror not specified, die.  POSIX requires that
320			 * the warning message be followed by an I/O display.
321			 */
322			if (!(ddflags & C_NOERROR))
323				err(1, "%s", in.name);
324			warn("%s", in.name);
325			summary();
326
327			/*
328			 * If it's a seekable file descriptor, seek past the
329			 * error.  If your OS doesn't do the right thing for
330			 * raw disks this section should be modified to re-read
331			 * in sector size chunks.
332			 */
333			if (in.flags & ISSEEK &&
334			    lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
335				warn("%s", in.name);
336
337			/* If sync not specified, omit block and continue. */
338			if (!(ddflags & C_SYNC))
339				continue;
340
341			/* Read errors count as full blocks. */
342			in.dbcnt += in.dbrcnt = in.dbsz;
343			++st.in_full;
344
345		/* Handle full input blocks. */
346		} else if ((size_t)n == in.dbsz) {
347			in.dbcnt += in.dbrcnt = n;
348			++st.in_full;
349
350		/* Handle partial input blocks. */
351		} else {
352			/* If sync, use the entire block. */
353			if (ddflags & C_SYNC)
354				in.dbcnt += in.dbrcnt = in.dbsz;
355			else
356				in.dbcnt += in.dbrcnt = n;
357			++st.in_part;
358		}
359
360		/*
361		 * POSIX states that if bs is set and no other conversions
362		 * than noerror, notrunc or sync are specified, the block
363		 * is output without buffering as it is read.
364		 */
365		if ((ddflags & ~(C_NOERROR | C_NOTRUNC | C_SYNC)) == C_BS) {
366			out.dbcnt = in.dbcnt;
367			dd_out(1);
368			in.dbcnt = 0;
369			continue;
370		}
371
372		if (ddflags & C_SWAB) {
373			if ((n = in.dbrcnt) & 1) {
374				++st.swab;
375				--n;
376			}
377			swab(in.dbp, in.dbp, (size_t)n);
378		}
379
380		in.dbp += in.dbrcnt;
381		(*cfunc)();
382		if (need_summary) {
383			summary();
384		}
385	}
386}
387
388/*
389 * Clean up any remaining I/O and flush output.  If necessary, the output file
390 * is truncated.
391 */
392static void
393dd_close(void)
394{
395	if (cfunc == def)
396		def_close();
397	else if (cfunc == block)
398		block_close();
399	else if (cfunc == unblock)
400		unblock_close();
401	if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) {
402		if (ddflags & C_FILL)
403			memset(out.dbp, fill_char, out.dbsz - out.dbcnt);
404		else if (ddflags & (C_BLOCK | C_UNBLOCK))
405			memset(out.dbp, ' ', out.dbsz - out.dbcnt);
406		else
407			memset(out.dbp, 0, out.dbsz - out.dbcnt);
408		out.dbcnt = out.dbsz;
409	}
410	if (out.dbcnt || pending)
411		dd_out(1);
412
413	/*
414	 * If the file ends with a hole, ftruncate it to extend its size
415	 * up to the end of the hole (without having to write any data).
416	 */
417	if (out.seek_offset > 0 && (out.flags & ISTRUNC)) {
418		if (ftruncate(out.fd, out.seek_offset) == -1)
419			err(1, "truncating %s", out.name);
420	}
421}
422
423void
424dd_out(int force)
425{
426	u_char *outp;
427	size_t cnt, i, n;
428	ssize_t nw;
429	static int warned;
430	int sparse;
431
432	/*
433	 * Write one or more blocks out.  The common case is writing a full
434	 * output block in a single write; increment the full block stats.
435	 * Otherwise, we're into partial block writes.  If a partial write,
436	 * and it's a character device, just warn.  If a tape device, quit.
437	 *
438	 * The partial writes represent two cases.  1: Where the input block
439	 * was less than expected so the output block was less than expected.
440	 * 2: Where the input block was the right size but we were forced to
441	 * write the block in multiple chunks.  The original versions of dd(1)
442	 * never wrote a block in more than a single write, so the latter case
443	 * never happened.
444	 *
445	 * One special case is if we're forced to do the write -- in that case
446	 * we play games with the buffer size, and it's usually a partial write.
447	 */
448	outp = out.db;
449
450	/*
451	 * If force, first try to write all pending data, else try to write
452	 * just one block. Subsequently always write data one full block at
453	 * a time at most.
454	 */
455	for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
456		cnt = n;
457		do {
458			sparse = 0;
459			if (ddflags & C_SPARSE) {
460				sparse = 1;	/* Is buffer sparse? */
461				for (i = 0; i < cnt; i++)
462					if (outp[i] != 0) {
463						sparse = 0;
464						break;
465					}
466			}
467			if (sparse && !force) {
468				pending += cnt;
469				nw = cnt;
470			} else {
471				if (pending != 0) {
472					/*
473					 * Seek past hole.  Note that we need to record the
474					 * reached offset, because we might have no more data
475					 * to write, in which case we'll need to call
476					 * ftruncate to extend the file size.
477					 */
478					out.seek_offset = lseek(out.fd, pending, SEEK_CUR);
479					if (out.seek_offset == -1)
480						err(2, "%s: seek error creating sparse file",
481						    out.name);
482					pending = 0;
483				}
484				if (cnt) {
485					nw = write(out.fd, outp, cnt);
486					out.seek_offset = 0;
487				} else {
488					return;
489				}
490			}
491
492			if (nw <= 0) {
493				if (nw == 0)
494					errx(1, "%s: end of device", out.name);
495				if (errno != EINTR)
496					err(1, "%s", out.name);
497				nw = 0;
498			}
499
500			outp += nw;
501			st.bytes += nw;
502
503			if ((size_t)nw == n && n == out.dbsz)
504				++st.out_full;
505			else
506				++st.out_part;
507
508			if ((size_t) nw != cnt) {
509				if (out.flags & ISTAPE)
510					errx(1, "%s: short write on tape device",
511				    	out.name);
512				if (out.flags & ISCHR && !warned) {
513					warned = 1;
514					warnx("%s: short write on character device",
515				    	out.name);
516				}
517			}
518
519			cnt -= nw;
520		} while (cnt != 0);
521
522		if ((out.dbcnt -= n) < out.dbsz)
523			break;
524	}
525
526	/* Reassemble the output block. */
527	if (out.dbcnt)
528		(void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
529	out.dbp = out.db + out.dbcnt;
530}
531