1/*	$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $	*/
2
3/*-
4 * Copyright (c) 1991, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Keith Muller of the University of California, San Diego and Lance
9 * Visser of Convex Computer Corporation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37#ifndef lint
38__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\
39 The Regents of the University of California.  All rights reserved.");
40#endif /* not lint */
41
42#ifndef lint
43#if 0
44static char sccsid[] = "@(#)dd.c	8.5 (Berkeley) 4/2/94";
45#else
46__RCSID("$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $");
47#endif
48#endif /* not lint */
49
50#include <sys/param.h>
51#include <sys/stat.h>
52#include <sys/ioctl.h>
53#include <sys/mtio.h>
54#include <sys/time.h>
55
56#include <ctype.h>
57#include <err.h>
58#include <errno.h>
59#include <fcntl.h>
60#include <locale.h>
61#include <signal.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 redup_clean_fd(IO *);
74static void setup(void);
75
76int main(int, char *[]);
77
78IO		in, out;		/* input/output state */
79STAT		st;			/* statistics */
80void		(*cfunc)(void);		/* conversion function */
81uint64_t	cpy_cnt;		/* # of blocks to copy */
82static off_t	pending = 0;		/* pending seek if sparse */
83u_int		ddflags;		/* conversion options */
84uint64_t	cbsz;			/* conversion block size */
85u_int		files_cnt = 1;		/* # of files to copy */
86uint64_t	progress = 0;		/* display sign of life */
87const u_char	*ctab;			/* conversion table */
88sigset_t	infoset;		/* a set blocking SIGINFO */
89const char	*msgfmt = "posix";	/* default summary() message format */
90
91/*
92 * Ops for stdin/stdout and crunch'd dd.  These are always host ops.
93 */
94static const struct ddfops ddfops_stdfd = {
95	.op_open = open,
96	.op_close = close,
97	.op_fcntl = fcntl,
98	.op_ioctl = ioctl,
99	.op_fstat = fstat,
100	.op_fsync = fsync,
101	.op_ftruncate = ftruncate,
102	.op_lseek = lseek,
103	.op_read = read,
104	.op_write = write,
105};
106extern const struct ddfops ddfops_prog;
107
108int
109main(int argc, char *argv[])
110{
111	int ch;
112
113	setprogname(argv[0]);
114	(void)setlocale(LC_ALL, "");
115
116	while ((ch = getopt(argc, argv, "")) != -1) {
117		switch (ch) {
118		default:
119			errx(EXIT_FAILURE, "usage: dd [operand ...]");
120			/* NOTREACHED */
121		}
122	}
123	argc -= (optind - 1);
124	argv += (optind - 1);
125
126	jcl(argv);
127#ifndef CRUNCHOPS
128	if (ddfops_prog.op_init && ddfops_prog.op_init() == -1)
129		err(1, "prog init");
130#endif
131	setup();
132
133	(void)signal(SIGINFO, summaryx);
134	(void)signal(SIGINT, terminate);
135	(void)sigemptyset(&infoset);
136	(void)sigaddset(&infoset, SIGINFO);
137
138	(void)atexit(summary);
139
140	while (files_cnt--)
141		dd_in();
142
143	dd_close();
144	exit(0);
145	/* NOTREACHED */
146}
147
148static void
149setup(void)
150{
151#ifdef CRUNCHOPS
152	const struct ddfops *prog_ops = &ddfops_stdfd;
153#else
154	const struct ddfops *prog_ops = &ddfops_prog;
155#endif
156
157	if (in.name == NULL) {
158		in.name = "stdin";
159		in.fd = STDIN_FILENO;
160		in.ops = &ddfops_stdfd;
161	} else {
162		in.ops = prog_ops;
163		in.fd = ddop_open(in, in.name, O_RDONLY, 0);
164		if (in.fd < 0)
165			err(EXIT_FAILURE, "%s", in.name);
166			/* NOTREACHED */
167
168		/* Ensure in.fd is outside the stdio descriptor range */
169		redup_clean_fd(&in);
170	}
171
172	getfdtype(&in);
173
174	if (files_cnt > 1 && !(in.flags & ISTAPE)) {
175		errx(EXIT_FAILURE, "files is not supported for non-tape devices");
176		/* NOTREACHED */
177	}
178
179	if (out.name == NULL) {
180		/* No way to check for read access here. */
181		out.fd = STDOUT_FILENO;
182		out.name = "stdout";
183		out.ops = &ddfops_stdfd;
184	} else {
185		out.ops = prog_ops;
186#define	OFLAGS \
187    (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
188		out.fd = ddop_open(out, out.name, O_RDWR | OFLAGS, DEFFILEMODE);
189		/*
190		 * May not have read access, so try again with write only.
191		 * Without read we may have a problem if output also does
192		 * not support seeks.
193		 */
194		if (out.fd < 0) {
195			out.fd = ddop_open(out, out.name, O_WRONLY | OFLAGS,
196			    DEFFILEMODE);
197			out.flags |= NOREAD;
198		}
199		if (out.fd < 0) {
200			err(EXIT_FAILURE, "%s", out.name);
201			/* NOTREACHED */
202		}
203
204		/* Ensure out.fd is outside the stdio descriptor range */
205		redup_clean_fd(&out);
206	}
207
208	getfdtype(&out);
209
210	/*
211	 * Allocate space for the input and output buffers.  If not doing
212	 * record oriented I/O, only need a single buffer.
213	 */
214	if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
215		size_t dbsz = out.dbsz;
216		if (!(ddflags & C_BS))
217			dbsz += in.dbsz - 1;
218		if ((in.db = malloc(dbsz)) == NULL) {
219			err(EXIT_FAILURE, NULL);
220			/* NOTREACHED */
221		}
222		out.db = in.db;
223	} else if ((in.db =
224	    malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
225	    (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
226		err(EXIT_FAILURE, NULL);
227		/* NOTREACHED */
228	}
229	in.dbp = in.db;
230	out.dbp = out.db;
231
232	/* Position the input/output streams. */
233	if (in.offset)
234		pos_in();
235	if (out.offset)
236		pos_out();
237
238	/*
239	 * Truncate the output file; ignore errors because it fails on some
240	 * kinds of output files, tapes, for example.
241	 */
242	if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
243		(void)ddop_ftruncate(out, out.fd, (off_t)out.offset * out.dbsz);
244
245	/*
246	 * If converting case at the same time as another conversion, build a
247	 * table that does both at once.  If just converting case, use the
248	 * built-in tables.
249	 */
250	if (ddflags & (C_LCASE|C_UCASE)) {
251#ifdef	NO_CONV
252		/* Should not get here, but just in case... */
253		errx(EXIT_FAILURE, "case conv and -DNO_CONV");
254		/* NOTREACHED */
255#else	/* NO_CONV */
256		u_int cnt;
257
258		if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
259			if (ddflags & C_LCASE) {
260				for (cnt = 0; cnt < 256; ++cnt)
261					casetab[cnt] = tolower(ctab[cnt]);
262			} else {
263				for (cnt = 0; cnt < 256; ++cnt)
264					casetab[cnt] = toupper(ctab[cnt]);
265			}
266		} else {
267			if (ddflags & C_LCASE) {
268				for (cnt = 0; cnt < 256; ++cnt)
269					casetab[cnt] = tolower(cnt);
270			} else {
271				for (cnt = 0; cnt < 256; ++cnt)
272					casetab[cnt] = toupper(cnt);
273			}
274		}
275
276		ctab = casetab;
277#endif	/* NO_CONV */
278	}
279
280	(void)gettimeofday(&st.start, NULL);	/* Statistics timestamp. */
281}
282
283static void
284getfdtype(IO *io)
285{
286	struct mtget mt;
287	struct stat sb;
288
289	if (io->ops->op_fstat(io->fd, &sb)) {
290		err(EXIT_FAILURE, "%s", io->name);
291		/* NOTREACHED */
292	}
293	if (S_ISCHR(sb.st_mode))
294		io->flags |= io->ops->op_ioctl(io->fd, MTIOCGET, &mt)
295		    ? ISCHR : ISTAPE;
296	else if (io->ops->op_lseek(io->fd, (off_t)0, SEEK_CUR) == -1
297	    && errno == ESPIPE)
298		io->flags |= ISPIPE;		/* XXX fixed in 4.4BSD */
299}
300
301/*
302 * Move the parameter file descriptor to a descriptor that is outside the
303 * stdio descriptor range, if necessary.  This is required to avoid
304 * accidentally outputting completion or error messages into the
305 * output file that were intended for the tty.
306 */
307static void
308redup_clean_fd(IO *io)
309{
310	int fd = io->fd;
311	int newfd;
312
313	if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
314	    fd != STDERR_FILENO)
315		/* File descriptor is ok, return immediately. */
316		return;
317
318	/*
319	 * 3 is the first descriptor greater than STD*_FILENO.  Any
320	 * free descriptor valued 3 or above is acceptable...
321	 */
322	newfd = io->ops->op_fcntl(fd, F_DUPFD, 3);
323	if (newfd < 0) {
324		err(EXIT_FAILURE, "dupfd IO");
325		/* NOTREACHED */
326	}
327
328	io->ops->op_close(fd);
329	io->fd = newfd;
330}
331
332static void
333dd_in(void)
334{
335	int flags;
336	int64_t n;
337
338	for (flags = ddflags;;) {
339		if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
340			return;
341
342		/*
343		 * Clear the buffer first if doing "sync" on input.
344		 * If doing block operations use spaces.  This will
345		 * affect not only the C_NOERROR case, but also the
346		 * last partial input block which should be padded
347		 * with zero and not garbage.
348		 */
349		if (flags & C_SYNC) {
350			if (flags & (C_BLOCK|C_UNBLOCK))
351				(void)memset(in.dbp, ' ', in.dbsz);
352			else
353				(void)memset(in.dbp, 0, in.dbsz);
354		}
355
356		n = ddop_read(in, in.fd, in.dbp, in.dbsz);
357		if (n == 0) {
358			in.dbrcnt = 0;
359			return;
360		}
361
362		/* Read error. */
363		if (n < 0) {
364
365			/*
366			 * If noerror not specified, die.  POSIX requires that
367			 * the warning message be followed by an I/O display.
368			 */
369			if (!(flags & C_NOERROR)) {
370				err(EXIT_FAILURE, "%s", in.name);
371				/* NOTREACHED */
372			}
373			warn("%s", in.name);
374			summary();
375
376			/*
377			 * If it's not a tape drive or a pipe, seek past the
378			 * error.  If your OS doesn't do the right thing for
379			 * raw disks this section should be modified to re-read
380			 * in sector size chunks.
381			 */
382			if (!(in.flags & (ISPIPE|ISTAPE)) &&
383			    ddop_lseek(in, in.fd, (off_t)in.dbsz, SEEK_CUR))
384				warn("%s", in.name);
385
386			/* If sync not specified, omit block and continue. */
387			if (!(ddflags & C_SYNC))
388				continue;
389
390			/* Read errors count as full blocks. */
391			in.dbcnt += in.dbrcnt = in.dbsz;
392			++st.in_full;
393
394		/* Handle full input blocks. */
395		} else if ((uint64_t)n == in.dbsz) {
396			in.dbcnt += in.dbrcnt = n;
397			++st.in_full;
398
399		/* Handle partial input blocks. */
400		} else {
401			/* If sync, use the entire block. */
402			if (ddflags & C_SYNC)
403				in.dbcnt += in.dbrcnt = in.dbsz;
404			else
405				in.dbcnt += in.dbrcnt = n;
406			++st.in_part;
407		}
408
409		/*
410		 * POSIX states that if bs is set and no other conversions
411		 * than noerror, notrunc or sync are specified, the block
412		 * is output without buffering as it is read.
413		 */
414		if (ddflags & C_BS) {
415			out.dbcnt = in.dbcnt;
416			dd_out(1);
417			in.dbcnt = 0;
418			continue;
419		}
420
421		if (ddflags & C_SWAB) {
422			if ((n = in.dbrcnt) & 1) {
423				++st.swab;
424				--n;
425			}
426			swab(in.dbp, in.dbp, n);
427		}
428
429		in.dbp += in.dbrcnt;
430		(*cfunc)();
431	}
432}
433
434/*
435 * Cleanup any remaining I/O and flush output.  If necessary, output file
436 * is truncated.
437 */
438static void
439dd_close(void)
440{
441
442	if (cfunc == def)
443		def_close();
444	else if (cfunc == block)
445		block_close();
446	else if (cfunc == unblock)
447		unblock_close();
448	if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
449		(void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
450		out.dbcnt = out.dbsz;
451	}
452	/* If there are pending sparse blocks, make sure
453	 * to write out the final block un-sparse
454	 */
455	if ((out.dbcnt == 0) && pending) {
456		memset(out.db, 0, out.dbsz);
457		out.dbcnt = out.dbsz;
458		out.dbp = out.db + out.dbcnt;
459		pending -= out.dbsz;
460	}
461	if (out.dbcnt)
462		dd_out(1);
463
464	/*
465	 * Reporting nfs write error may be deferred until next
466	 * write(2) or close(2) system call.  So, we need to do an
467	 * extra check.  If an output is stdout, the file structure
468	 * may be shared with other processes and close(2) just
469	 * decreases the reference count.
470	 */
471	if (out.fd == STDOUT_FILENO && ddop_fsync(out, out.fd) == -1
472	    && errno != EINVAL) {
473		err(EXIT_FAILURE, "fsync stdout");
474		/* NOTREACHED */
475	}
476	if (ddop_close(out, out.fd) == -1) {
477		err(EXIT_FAILURE, "close");
478		/* NOTREACHED */
479	}
480}
481
482void
483dd_out(int force)
484{
485	static int warned;
486	int64_t cnt, n, nw;
487	u_char *outp;
488
489	/*
490	 * Write one or more blocks out.  The common case is writing a full
491	 * output block in a single write; increment the full block stats.
492	 * Otherwise, we're into partial block writes.  If a partial write,
493	 * and it's a character device, just warn.  If a tape device, quit.
494	 *
495	 * The partial writes represent two cases.  1: Where the input block
496	 * was less than expected so the output block was less than expected.
497	 * 2: Where the input block was the right size but we were forced to
498	 * write the block in multiple chunks.  The original versions of dd(1)
499	 * never wrote a block in more than a single write, so the latter case
500	 * never happened.
501	 *
502	 * One special case is if we're forced to do the write -- in that case
503	 * we play games with the buffer size, and it's usually a partial write.
504	 */
505	outp = out.db;
506	for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
507		for (cnt = n;; cnt -= nw) {
508
509			if (!force && ddflags & C_SPARSE) {
510				int sparse, i;
511				sparse = 1;	/* Is buffer sparse? */
512				for (i = 0; i < cnt; i++)
513					if (outp[i] != 0) {
514						sparse = 0;
515						break;
516					}
517				if (sparse) {
518					pending += cnt;
519					outp += cnt;
520					nw = 0;
521					break;
522				}
523			}
524			if (pending != 0) {
525				if (ddop_lseek(out,
526				    out.fd, pending, SEEK_CUR) == -1)
527					err(EXIT_FAILURE, "%s: seek error creating sparse file",
528					    out.name);
529			}
530			nw = bwrite(&out, outp, cnt);
531			if (nw <= 0) {
532				if (nw == 0)
533					errx(EXIT_FAILURE,
534						"%s: end of device", out.name);
535					/* NOTREACHED */
536				if (errno != EINTR)
537					err(EXIT_FAILURE, "%s", out.name);
538					/* NOTREACHED */
539				nw = 0;
540			}
541			if (pending) {
542				st.bytes += pending;
543				st.sparse += pending/out.dbsz;
544				st.out_full += pending/out.dbsz;
545				pending = 0;
546			}
547			outp += nw;
548			st.bytes += nw;
549			if (nw == n) {
550				if ((uint64_t)n != out.dbsz)
551					++st.out_part;
552				else
553					++st.out_full;
554				break;
555			}
556			++st.out_part;
557			if (nw == cnt)
558				break;
559			if (out.flags & ISCHR && !warned) {
560				warned = 1;
561				warnx("%s: short write on character device", out.name);
562			}
563			if (out.flags & ISTAPE)
564				errx(EXIT_FAILURE,
565					"%s: short write on tape device", out.name);
566				/* NOTREACHED */
567
568		}
569		if ((out.dbcnt -= n) < out.dbsz)
570			break;
571	}
572
573	/* Reassemble the output block. */
574	if (out.dbcnt)
575		(void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
576	out.dbp = out.db + out.dbcnt;
577
578	if (progress && (st.out_full + st.out_part) % progress == 0)
579		(void)write(STDERR_FILENO, ".", 1);
580}
581
582/*
583 * A protected against SIGINFO write
584 */
585ssize_t
586bwrite(IO *io, const void *buf, size_t len)
587{
588	sigset_t oset;
589	ssize_t rv;
590	int oerrno;
591
592	(void)sigprocmask(SIG_BLOCK, &infoset, &oset);
593	rv = io->ops->op_write(io->fd, buf, len);
594	oerrno = errno;
595	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
596	errno = oerrno;
597	return (rv);
598}
599