dd.c revision 109873
1228753Smm/*-
2232153Smm * Copyright (c) 1991, 1993, 1994
3228753Smm *	The Regents of the University of California.  All rights reserved.
4228753Smm *
5228753Smm * This code is derived from software contributed to Berkeley by
6228753Smm * Keith Muller of the University of California, San Diego and Lance
7228753Smm * Visser of Convex Computer Corporation.
8228753Smm *
9228753Smm * Redistribution and use in source and binary forms, with or without
10228753Smm * modification, are permitted provided that the following conditions
11228753Smm * are met:
12228753Smm * 1. Redistributions of source code must retain the above copyright
13228753Smm *    notice, this list of conditions and the following disclaimer.
14228753Smm * 2. Redistributions in binary form must reproduce the above copyright
15228753Smm *    notice, this list of conditions and the following disclaimer in the
16228753Smm *    documentation and/or other materials provided with the distribution.
17228753Smm * 3. All advertising materials mentioning features or use of this software
18228753Smm *    must display the following acknowledgement:
19228753Smm *	This product includes software developed by the University of
20228753Smm *	California, Berkeley and its contributors.
21228753Smm * 4. Neither the name of the University nor the names of its contributors
22228753Smm *    may be used to endorse or promote products derived from this software
23228753Smm *    without specific prior written permission.
24228753Smm *
25228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26228763Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28228753Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33228753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35228753Smm * SUCH DAMAGE.
36228753Smm */
37228753Smm
38228753Smm#ifndef lint
39228753Smmstatic char const copyright[] =
40228753Smm"@(#) Copyright (c) 1991, 1993, 1994\n\
41228753Smm	The Regents of the University of California.  All rights reserved.\n";
42228753Smm#endif /* not lint */
43232153Smm
44232153Smm#ifndef lint
45232153Smm#if 0
46248616Smmstatic char sccsid[] = "@(#)dd.c	8.5 (Berkeley) 4/2/94";
47232153Smm#endif
48232153Smm#endif /* not lint */
49232153Smm#include <sys/cdefs.h>
50232153Smm__FBSDID("$FreeBSD: head/bin/dd/dd.c 109873 2003-01-26 11:13:40Z phk $");
51232153Smm
52232153Smm#include <sys/param.h>
53232153Smm#include <sys/stat.h>
54232153Smm#include <sys/conf.h>
55232153Smm#include <sys/disklabel.h>
56232153Smm#include <sys/filio.h>
57228753Smm#include <sys/time.h>
58228753Smm
59228753Smm#include <ctype.h>
60228753Smm#include <err.h>
61228753Smm#include <errno.h>
62228753Smm#include <fcntl.h>
63232153Smm#include <locale.h>
64232153Smm#include <stdio.h>
65228753Smm#include <stdlib.h>
66228753Smm#include <string.h>
67228753Smm#include <unistd.h>
68228753Smm
69228753Smm#include "dd.h"
70228753Smm#include "extern.h"
71232153Smm
72228753Smmstatic void dd_close(void);
73228753Smmstatic void dd_in(void);
74232153Smmstatic void getfdtype(IO *);
75228753Smmstatic void setup(void);
76232153Smm
77228753SmmIO	in, out;		/* input/output state */
78228753SmmSTAT	st;			/* statistics */
79232153Smmvoid	(*cfunc)(void);		/* conversion function */
80232153Smmu_quad_t cpy_cnt;		/* # of blocks to copy */
81232153Smmstatic off_t	pending = 0;	/* pending seek if sparse */
82228753Smmu_int	ddflags;		/* conversion options */
83228753Smmsize_t	cbsz;			/* conversion block size */
84232153Smmquad_t	files_cnt = 1;		/* # of files to copy */
85232153Smmconst	u_char *ctab;		/* conversion table */
86228753Smm
87228753Smmint
88228753Smmmain(int argc __unused, char *argv[])
89228753Smm{
90228753Smm	(void)setlocale(LC_CTYPE, "");
91232153Smm	jcl(argv);
92232153Smm	setup();
93232153Smm
94232153Smm	(void)signal(SIGINFO, summaryx);
95232153Smm	(void)signal(SIGINT, terminate);
96232153Smm
97228753Smm	atexit(summary);
98232153Smm
99232153Smm	while (files_cnt--)
100228753Smm		dd_in();
101232153Smm
102228753Smm	dd_close();
103232153Smm	exit(0);
104232153Smm}
105232153Smm
106228753Smmstatic void
107232153Smmsetup(void)
108232153Smm{
109232153Smm	u_int cnt;
110232153Smm	struct timeval tv;
111232153Smm
112228753Smm	if (in.name == NULL) {
113228753Smm		in.name = "stdin";
114232153Smm		in.fd = STDIN_FILENO;
115232153Smm	} else {
116232153Smm		in.fd = open(in.name, O_RDONLY, 0);
117232153Smm		if (in.fd == -1)
118228753Smm			err(1, "%s", in.name);
119228753Smm	}
120
121	getfdtype(&in);
122
123	if (files_cnt > 1 && !(in.flags & ISTAPE))
124		errx(1, "files is not supported for non-tape devices");
125
126	if (out.name == NULL) {
127		/* No way to check for read access here. */
128		out.fd = STDOUT_FILENO;
129		out.name = "stdout";
130	} else {
131#define	OFLAGS \
132    (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
133		out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
134		/*
135		 * May not have read access, so try again with write only.
136		 * Without read we may have a problem if output also does
137		 * not support seeks.
138		 */
139		if (out.fd == -1) {
140			out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
141			out.flags |= NOREAD;
142		}
143		if (out.fd == -1)
144			err(1, "%s", out.name);
145	}
146
147	getfdtype(&out);
148
149	/*
150	 * Allocate space for the input and output buffers.  If not doing
151	 * record oriented I/O, only need a single buffer.
152	 */
153	if (!(ddflags & (C_BLOCK | C_UNBLOCK))) {
154		if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
155			err(1, "input buffer");
156		out.db = in.db;
157	} else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL ||
158	    (out.db = malloc(out.dbsz + cbsz)) == NULL)
159		err(1, "output buffer");
160	in.dbp = in.db;
161	out.dbp = out.db;
162
163	/* Position the input/output streams. */
164	if (in.offset)
165		pos_in();
166	if (out.offset)
167		pos_out();
168
169	/*
170	 * Truncate the output file.  If it fails on a type of output file
171	 * that it should _not_ fail on, error out.
172	 */
173	if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) &&
174	    out.flags & ISTRUNC)
175		if (ftruncate(out.fd, out.offset * out.dbsz) == -1)
176			err(1, "truncating %s", out.name);
177
178	/*
179	 * If converting case at the same time as another conversion, build a
180	 * table that does both at once.  If just converting case, use the
181	 * built-in tables.
182	 */
183	if (ddflags & (C_LCASE | C_UCASE)) {
184		if (ddflags & (C_ASCII | C_EBCDIC)) {
185			if (ddflags & C_LCASE) {
186				for (cnt = 0; cnt <= 0377; ++cnt)
187					casetab[cnt] = tolower(ctab[cnt]);
188			} else {
189				for (cnt = 0; cnt <= 0377; ++cnt)
190					casetab[cnt] = toupper(ctab[cnt]);
191			}
192		} else {
193			if (ddflags & C_LCASE) {
194				for (cnt = 0; cnt <= 0377; ++cnt)
195					casetab[cnt] = tolower((int)cnt);
196			} else {
197				for (cnt = 0; cnt <= 0377; ++cnt)
198					casetab[cnt] = toupper((int)cnt);
199			}
200		}
201		ctab = casetab;
202	}
203
204	(void)gettimeofday(&tv, (struct timezone *)NULL);
205	st.start = tv.tv_sec + tv.tv_usec * 1e-6;
206}
207
208static void
209getfdtype(IO *io)
210{
211	struct stat sb;
212	int type;
213
214	if (fstat(io->fd, &sb) == -1)
215		err(1, "%s", io->name);
216	if (S_ISREG(sb.st_mode))
217		io->flags |= ISTRUNC;
218	if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) {
219		if (ioctl(io->fd, FIODTYPE, &type) == -1) {
220			err(1, "%s", io->name);
221		} else {
222			if (type & D_TAPE)
223				io->flags |= ISTAPE;
224			else if (type & (D_DISK | D_MEM))
225				io->flags |= ISSEEK;
226			if (S_ISCHR(sb.st_mode) && (type & D_TAPE) == 0)
227				io->flags |= ISCHR;
228		}
229		return;
230	}
231	errno = 0;
232	if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
233		io->flags |= ISPIPE;
234	else
235		io->flags |= ISSEEK;
236}
237
238static void
239dd_in(void)
240{
241	ssize_t n;
242
243	for (;;) {
244		switch (cpy_cnt) {
245		case -1:			/* count=0 was specified */
246			return;
247		case 0:
248			break;
249		default:
250			if (st.in_full + st.in_part >= (u_quad_t)cpy_cnt)
251				return;
252			break;
253		}
254
255		/*
256		 * Zero the buffer first if sync; if doing block operations,
257		 * use spaces.
258		 */
259		if (ddflags & C_SYNC) {
260			if (ddflags & (C_BLOCK | C_UNBLOCK))
261				memset(in.dbp, ' ', in.dbsz);
262			else
263				memset(in.dbp, 0, in.dbsz);
264		}
265
266		n = read(in.fd, in.dbp, in.dbsz);
267		if (n == 0) {
268			in.dbrcnt = 0;
269			return;
270		}
271
272		/* Read error. */
273		if (n == -1) {
274			/*
275			 * If noerror not specified, die.  POSIX requires that
276			 * the warning message be followed by an I/O display.
277			 */
278			if (!(ddflags & C_NOERROR))
279				err(1, "%s", in.name);
280			warn("%s", in.name);
281			summary();
282
283			/*
284			 * If it's a seekable file descriptor, seek past the
285			 * error.  If your OS doesn't do the right thing for
286			 * raw disks this section should be modified to re-read
287			 * in sector size chunks.
288			 */
289			if (in.flags & ISSEEK &&
290			    lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
291				warn("%s", in.name);
292
293			/* If sync not specified, omit block and continue. */
294			if (!(ddflags & C_SYNC))
295				continue;
296
297			/* Read errors count as full blocks. */
298			in.dbcnt += in.dbrcnt = in.dbsz;
299			++st.in_full;
300
301		/* Handle full input blocks. */
302		} else if ((size_t)n == in.dbsz) {
303			in.dbcnt += in.dbrcnt = n;
304			++st.in_full;
305
306		/* Handle partial input blocks. */
307		} else {
308			/* If sync, use the entire block. */
309			if (ddflags & C_SYNC)
310				in.dbcnt += in.dbrcnt = in.dbsz;
311			else
312				in.dbcnt += in.dbrcnt = n;
313			++st.in_part;
314		}
315
316		/*
317		 * POSIX states that if bs is set and no other conversions
318		 * than noerror, notrunc or sync are specified, the block
319		 * is output without buffering as it is read.
320		 */
321		if (ddflags & C_BS) {
322			out.dbcnt = in.dbcnt;
323			dd_out(1);
324			in.dbcnt = 0;
325			continue;
326		}
327
328		if (ddflags & C_SWAB) {
329			if ((n = in.dbrcnt) & 1) {
330				++st.swab;
331				--n;
332			}
333			swab(in.dbp, in.dbp, (size_t)n);
334		}
335
336		in.dbp += in.dbrcnt;
337		(*cfunc)();
338	}
339}
340
341/*
342 * Clean up any remaining I/O and flush output.  If necessary, the output file
343 * is truncated.
344 */
345static void
346dd_close(void)
347{
348	if (cfunc == def)
349		def_close();
350	else if (cfunc == block)
351		block_close();
352	else if (cfunc == unblock)
353		unblock_close();
354	if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) {
355		if (ddflags & (C_BLOCK | C_UNBLOCK))
356			memset(out.dbp, ' ', out.dbsz - out.dbcnt);
357		else
358			memset(out.dbp, 0, out.dbsz - out.dbcnt);
359		out.dbcnt = out.dbsz;
360	}
361	if (out.dbcnt || pending)
362		dd_out(1);
363}
364
365void
366dd_out(int force)
367{
368	u_char *outp;
369	size_t cnt, i, n;
370	ssize_t nw;
371	static int warned;
372	int sparse;
373
374	/*
375	 * Write one or more blocks out.  The common case is writing a full
376	 * output block in a single write; increment the full block stats.
377	 * Otherwise, we're into partial block writes.  If a partial write,
378	 * and it's a character device, just warn.  If a tape device, quit.
379	 *
380	 * The partial writes represent two cases.  1: Where the input block
381	 * was less than expected so the output block was less than expected.
382	 * 2: Where the input block was the right size but we were forced to
383	 * write the block in multiple chunks.  The original versions of dd(1)
384	 * never wrote a block in more than a single write, so the latter case
385	 * never happened.
386	 *
387	 * One special case is if we're forced to do the write -- in that case
388	 * we play games with the buffer size, and it's usually a partial write.
389	 */
390	outp = out.db;
391	for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
392		for (cnt = n;; cnt -= nw) {
393			sparse = 0;
394			if (ddflags & C_SPARSE) {
395				sparse = 1;	/* Is buffer sparse? */
396				for (i = 0; i < cnt; i++)
397					if (outp[i] != 0) {
398						sparse = 0;
399						break;
400					}
401			}
402			if (sparse && !force) {
403				pending += cnt;
404				nw = cnt;
405			} else {
406				if (pending != 0) {
407					if (force)
408						pending--;
409					if (lseek(out.fd, pending, SEEK_CUR) ==
410					    -1)
411						err(2, "%s: seek error creating sparse file",
412						    out.name);
413					if (force)
414						write(out.fd, outp, 1);
415					pending = 0;
416				}
417				if (cnt)
418					nw = write(out.fd, outp, cnt);
419				else
420					return;
421			}
422
423			if (nw <= 0) {
424				if (nw == 0)
425					errx(1, "%s: end of device", out.name);
426				if (errno != EINTR)
427					err(1, "%s", out.name);
428				nw = 0;
429			}
430			outp += nw;
431			st.bytes += nw;
432			if ((size_t)nw == n) {
433				if (n != out.dbsz)
434					++st.out_part;
435				else
436					++st.out_full;
437				break;
438			}
439			++st.out_part;
440			if ((size_t)nw == cnt)
441				break;
442			if (out.flags & ISTAPE)
443				errx(1, "%s: short write on tape device",
444				    out.name);
445			if (out.flags & ISCHR && !warned) {
446				warned = 1;
447				warnx("%s: short write on character device",
448				    out.name);
449			}
450		}
451		if ((out.dbcnt -= n) < out.dbsz)
452			break;
453	}
454
455	/* Reassemble the output block. */
456	if (out.dbcnt)
457		(void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
458	out.dbp = out.db + out.dbcnt;
459}
460