17bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes/*	$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $	*/
27bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
37bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes/*-
47bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Copyright (c) 1991, 1993, 1994
57bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *	The Regents of the University of California.  All rights reserved.
67bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *
77bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * This code is derived from software contributed to Berkeley by
87bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Keith Muller of the University of California, San Diego and Lance
97bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Visser of Convex Computer Corporation.
107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *
117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Redistribution and use in source and binary forms, with or without
127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * modification, are permitted provided that the following conditions
137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * are met:
147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * 1. Redistributions of source code must retain the above copyright
157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    notice, this list of conditions and the following disclaimer.
167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * 2. Redistributions in binary form must reproduce the above copyright
177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    notice, this list of conditions and the following disclaimer in the
187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    documentation and/or other materials provided with the distribution.
197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * 3. Neither the name of the University nor the names of its contributors
207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    may be used to endorse or promote products derived from this software
217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    without specific prior written permission.
227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *
237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * SUCH DAMAGE.
347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes */
357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/cdefs.h>
377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifndef lint
387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\
397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes The Regents of the University of California.  All rights reserved.");
407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif /* not lint */
417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifndef lint
437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#if 0
447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic char sccsid[] = "@(#)dd.c	8.5 (Berkeley) 4/2/94";
457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#else
467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes__RCSID("$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $");
477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif
487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif /* not lint */
497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/param.h>
517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/stat.h>
527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/ioctl.h>
537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/mtio.h>
547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/time.h>
557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <ctype.h>
577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <err.h>
587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <errno.h>
597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <fcntl.h>
607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <locale.h>
617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <signal.h>
627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <stdio.h>
637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <stdlib.h>
647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <string.h>
657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <unistd.h>
667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include "dd.h"
687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include "extern.h"
697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void dd_close(void);
717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void dd_in(void);
727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void getfdtype(IO *);
737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void redup_clean_fd(IO *);
747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void setup(void);
757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesint main(int, char *[]);
777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
787bb5660647d0106f96b000c25f5690a45734c38cElliott HughesIO		in, out;		/* input/output state */
797bb5660647d0106f96b000c25f5690a45734c38cElliott HughesSTAT		st;			/* statistics */
807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesvoid		(*cfunc)(void);		/* conversion function */
817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesuint64_t	cpy_cnt;		/* # of blocks to copy */
827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic off_t	pending = 0;		/* pending seek if sparse */
837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesu_int		ddflags;		/* conversion options */
847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesuint64_t	cbsz;			/* conversion block size */
857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesu_int		files_cnt = 1;		/* # of files to copy */
867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesuint64_t	progress = 0;		/* display sign of life */
877bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesconst u_char	*ctab;			/* conversion table */
887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughessigset_t	infoset;		/* a set blocking SIGINFO */
897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesconst char	*msgfmt = "posix";	/* default summary() message format */
907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes/*
927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Ops for stdin/stdout and crunch'd dd.  These are always host ops.
937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes */
947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic const struct ddfops ddfops_stdfd = {
957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_open = open,
967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_close = close,
977bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_fcntl = fcntl,
987bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_ioctl = ioctl,
997bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_fstat = fstat,
1007bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_fsync = fsync,
1017bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_ftruncate = ftruncate,
1027bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_lseek = lseek,
1037bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_read = read,
1047bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	.op_write = write,
1057bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes};
1067bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesextern const struct ddfops ddfops_prog;
1077bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1087bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesint
1097bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesmain(int argc, char *argv[])
1107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
1117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int ch;
1127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	setprogname(argv[0]);
1147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)setlocale(LC_ALL, "");
1157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	while ((ch = getopt(argc, argv, "")) != -1) {
1177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		switch (ch) {
1187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		default:
1197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			errx(EXIT_FAILURE, "usage: dd [operand ...]");
1207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			/* NOTREACHED */
1217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
1227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
1237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	argc -= (optind - 1);
1247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	argv += (optind - 1);
1257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	jcl(argv);
1277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifndef CRUNCHOPS
1287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (ddfops_prog.op_init && ddfops_prog.op_init() == -1)
1297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		err(1, "prog init");
1307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif
1317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	setup();
1327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)signal(SIGINFO, summaryx);
1347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)signal(SIGINT, terminate);
1357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)sigemptyset(&infoset);
1367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)sigaddset(&infoset, SIGINFO);
1377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)atexit(summary);
1397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	while (files_cnt--)
1417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		dd_in();
1427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	dd_close();
1447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	exit(0);
1457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/* NOTREACHED */
1467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
1477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void
1497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughessetup(void)
1507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
1517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifdef CRUNCHOPS
1527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	const struct ddfops *prog_ops = &ddfops_stdfd;
1537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#else
1547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	const struct ddfops *prog_ops = &ddfops_prog;
1557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif
1567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (in.name == NULL) {
1587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		in.name = "stdin";
1597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		in.fd = STDIN_FILENO;
1607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		in.ops = &ddfops_stdfd;
1617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	} else {
1627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		in.ops = prog_ops;
1637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		in.fd = ddop_open(in, in.name, O_RDONLY, 0);
1647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (in.fd < 0)
1657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			err(EXIT_FAILURE, "%s", in.name);
1667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			/* NOTREACHED */
1677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* Ensure in.fd is outside the stdio descriptor range */
1697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		redup_clean_fd(&in);
1707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
1717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	getfdtype(&in);
1737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (files_cnt > 1 && !(in.flags & ISTAPE)) {
1757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		errx(EXIT_FAILURE, "files is not supported for non-tape devices");
1767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* NOTREACHED */
1777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
1787bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1797bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (out.name == NULL) {
1807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* No way to check for read access here. */
1817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		out.fd = STDOUT_FILENO;
1827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		out.name = "stdout";
1837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		out.ops = &ddfops_stdfd;
1847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	} else {
1857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		out.ops = prog_ops;
1867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#define	OFLAGS \
1877bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes    (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
1887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		out.fd = ddop_open(out, out.name, O_RDWR | OFLAGS, DEFFILEMODE);
1897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/*
1907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * May not have read access, so try again with write only.
1917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * Without read we may have a problem if output also does
1927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * not support seeks.
1937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 */
1947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (out.fd < 0) {
1957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			out.fd = ddop_open(out, out.name, O_WRONLY | OFLAGS,
1967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			    DEFFILEMODE);
1977bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			out.flags |= NOREAD;
1987bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
1997bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (out.fd < 0) {
2007bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			err(EXIT_FAILURE, "%s", out.name);
2017bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			/* NOTREACHED */
2027bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
2037bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2047bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* Ensure out.fd is outside the stdio descriptor range */
2057bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		redup_clean_fd(&out);
2067bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2077bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2087bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	getfdtype(&out);
2097bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
2117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * Allocate space for the input and output buffers.  If not doing
2127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * record oriented I/O, only need a single buffer.
2137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
2147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
2157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		size_t dbsz = out.dbsz;
2167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (!(ddflags & C_BS))
2177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			dbsz += in.dbsz - 1;
2187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if ((in.db = malloc(dbsz)) == NULL) {
2197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			err(EXIT_FAILURE, NULL);
2207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			/* NOTREACHED */
2217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
2227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		out.db = in.db;
2237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	} else if ((in.db =
2247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	    malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
2257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	    (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
2267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		err(EXIT_FAILURE, NULL);
2277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* NOTREACHED */
2287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	in.dbp = in.db;
2307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	out.dbp = out.db;
2317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/* Position the input/output streams. */
2337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (in.offset)
2347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		pos_in();
2357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (out.offset)
2367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		pos_out();
2377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
2397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * Truncate the output file; ignore errors because it fails on some
2407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * kinds of output files, tapes, for example.
2417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
2427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
2437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(void)ddop_ftruncate(out, out.fd, (off_t)out.offset * out.dbsz);
2447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
2467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * If converting case at the same time as another conversion, build a
2477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * table that does both at once.  If just converting case, use the
2487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * built-in tables.
2497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
2507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (ddflags & (C_LCASE|C_UCASE)) {
2517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifdef	NO_CONV
2527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* Should not get here, but just in case... */
2537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		errx(EXIT_FAILURE, "case conv and -DNO_CONV");
2547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* NOTREACHED */
2557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#else	/* NO_CONV */
2567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		u_int cnt;
2577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
2597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (ddflags & C_LCASE) {
2607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				for (cnt = 0; cnt < 256; ++cnt)
2617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					casetab[cnt] = tolower(ctab[cnt]);
2627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			} else {
2637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				for (cnt = 0; cnt < 256; ++cnt)
2647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					casetab[cnt] = toupper(ctab[cnt]);
2657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
2667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		} else {
2677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (ddflags & C_LCASE) {
2687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				for (cnt = 0; cnt < 256; ++cnt)
2697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					casetab[cnt] = tolower(cnt);
2707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			} else {
2717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				for (cnt = 0; cnt < 256; ++cnt)
2727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					casetab[cnt] = toupper(cnt);
2737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
2747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
2757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		ctab = casetab;
2777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif	/* NO_CONV */
2787bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2797bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)gettimeofday(&st.start, NULL);	/* Statistics timestamp. */
2817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
2827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void
2847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesgetfdtype(IO *io)
2857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
2867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	struct mtget mt;
2877bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	struct stat sb;
2887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (io->ops->op_fstat(io->fd, &sb)) {
2907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		err(EXIT_FAILURE, "%s", io->name);
2917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* NOTREACHED */
2927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (S_ISCHR(sb.st_mode))
2947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		io->flags |= io->ops->op_ioctl(io->fd, MTIOCGET, &mt)
2957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		    ? ISCHR : ISTAPE;
2967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	else if (io->ops->op_lseek(io->fd, (off_t)0, SEEK_CUR) == -1
2977bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	    && errno == ESPIPE)
2987bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		io->flags |= ISPIPE;		/* XXX fixed in 4.4BSD */
2997bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
3007bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3017bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes/*
3027bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Move the parameter file descriptor to a descriptor that is outside the
3037bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * stdio descriptor range, if necessary.  This is required to avoid
3047bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * accidentally outputting completion or error messages into the
3057bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * output file that were intended for the tty.
3067bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes */
3077bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void
3087bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesredup_clean_fd(IO *io)
3097bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
3107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int fd = io->fd;
3117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int newfd;
3127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
3147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	    fd != STDERR_FILENO)
3157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* File descriptor is ok, return immediately. */
3167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return;
3177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
3197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * 3 is the first descriptor greater than STD*_FILENO.  Any
3207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * free descriptor valued 3 or above is acceptable...
3217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
3227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	newfd = io->ops->op_fcntl(fd, F_DUPFD, 3);
3237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (newfd < 0) {
3247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		err(EXIT_FAILURE, "dupfd IO");
3257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* NOTREACHED */
3267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	io->ops->op_close(fd);
3297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	io->fd = newfd;
3307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
3317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void
3337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesdd_in(void)
3347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
3357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int flags;
3367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int64_t n;
3377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	for (flags = ddflags;;) {
3397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
3407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			return;
3417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/*
3437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * Clear the buffer first if doing "sync" on input.
3447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * If doing block operations use spaces.  This will
3457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * affect not only the C_NOERROR case, but also the
3467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * last partial input block which should be padded
3477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * with zero and not garbage.
3487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 */
3497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (flags & C_SYNC) {
3507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (flags & (C_BLOCK|C_UNBLOCK))
3517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				(void)memset(in.dbp, ' ', in.dbsz);
3527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			else
3537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				(void)memset(in.dbp, 0, in.dbsz);
3547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
3557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		n = ddop_read(in, in.fd, in.dbp, in.dbsz);
3577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (n == 0) {
3587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			in.dbrcnt = 0;
3597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			return;
3607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
3617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* Read error. */
3637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (n < 0) {
3647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			/*
3667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			 * If noerror not specified, die.  POSIX requires that
3677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			 * the warning message be followed by an I/O display.
3687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			 */
3697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (!(flags & C_NOERROR)) {
3707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				err(EXIT_FAILURE, "%s", in.name);
3717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				/* NOTREACHED */
3727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
3737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			warn("%s", in.name);
3747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			summary();
3757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			/*
3777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			 * If it's not a tape drive or a pipe, seek past the
3787bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			 * error.  If your OS doesn't do the right thing for
3797bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			 * raw disks this section should be modified to re-read
3807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			 * in sector size chunks.
3817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			 */
3827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (!(in.flags & (ISPIPE|ISTAPE)) &&
3837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			    ddop_lseek(in, in.fd, (off_t)in.dbsz, SEEK_CUR))
3847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				warn("%s", in.name);
3857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			/* If sync not specified, omit block and continue. */
3877bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (!(ddflags & C_SYNC))
3887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				continue;
3897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			/* Read errors count as full blocks. */
3917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			in.dbcnt += in.dbrcnt = in.dbsz;
3927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			++st.in_full;
3937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* Handle full input blocks. */
3957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		} else if ((uint64_t)n == in.dbsz) {
3967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			in.dbcnt += in.dbrcnt = n;
3977bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			++st.in_full;
3987bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3997bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* Handle partial input blocks. */
4007bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		} else {
4017bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			/* If sync, use the entire block. */
4027bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (ddflags & C_SYNC)
4037bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				in.dbcnt += in.dbrcnt = in.dbsz;
4047bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			else
4057bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				in.dbcnt += in.dbrcnt = n;
4067bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			++st.in_part;
4077bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
4087bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
4097bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/*
4107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * POSIX states that if bs is set and no other conversions
4117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * than noerror, notrunc or sync are specified, the block
4127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 * is output without buffering as it is read.
4137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		 */
4147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (ddflags & C_BS) {
4157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			out.dbcnt = in.dbcnt;
4167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			dd_out(1);
4177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			in.dbcnt = 0;
4187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			continue;
4197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
4207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
4217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (ddflags & C_SWAB) {
4227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if ((n = in.dbrcnt) & 1) {
4237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				++st.swab;
4247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				--n;
4257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
4267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			swab(in.dbp, in.dbp, n);
4277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
4287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
4297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		in.dbp += in.dbrcnt;
4307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(*cfunc)();
4317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
4327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
4337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
4347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes/*
4357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Cleanup any remaining I/O and flush output.  If necessary, output file
4367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * is truncated.
4377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes */
4387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void
4397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesdd_close(void)
4407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
4417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
4427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (cfunc == def)
4437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		def_close();
4447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	else if (cfunc == block)
4457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		block_close();
4467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	else if (cfunc == unblock)
4477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		unblock_close();
4487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
4497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
4507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		out.dbcnt = out.dbsz;
4517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
4527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/* If there are pending sparse blocks, make sure
4537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * to write out the final block un-sparse
4547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
4557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if ((out.dbcnt == 0) && pending) {
4567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		memset(out.db, 0, out.dbsz);
4577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		out.dbcnt = out.dbsz;
4587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		out.dbp = out.db + out.dbcnt;
4597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		pending -= out.dbsz;
4607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
4617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (out.dbcnt)
4627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		dd_out(1);
4637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
4647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
4657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * Reporting nfs write error may be deferred until next
4667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * write(2) or close(2) system call.  So, we need to do an
4677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * extra check.  If an output is stdout, the file structure
4687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * may be shared with other processes and close(2) just
4697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * decreases the reference count.
4707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
4717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (out.fd == STDOUT_FILENO && ddop_fsync(out, out.fd) == -1
4727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	    && errno != EINVAL) {
4737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		err(EXIT_FAILURE, "fsync stdout");
4747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* NOTREACHED */
4757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
4767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (ddop_close(out, out.fd) == -1) {
4777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		err(EXIT_FAILURE, "close");
4787bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		/* NOTREACHED */
4797bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
4807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
4817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
4827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesvoid
4837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesdd_out(int force)
4847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
4857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	static int warned;
4867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int64_t cnt, n, nw;
4877bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	u_char *outp;
4887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
4897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
4907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * Write one or more blocks out.  The common case is writing a full
4917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * output block in a single write; increment the full block stats.
4927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * Otherwise, we're into partial block writes.  If a partial write,
4937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * and it's a character device, just warn.  If a tape device, quit.
4947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *
4957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * The partial writes represent two cases.  1: Where the input block
4967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * was less than expected so the output block was less than expected.
4977bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * 2: Where the input block was the right size but we were forced to
4987bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * write the block in multiple chunks.  The original versions of dd(1)
4997bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * never wrote a block in more than a single write, so the latter case
5007bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * never happened.
5017bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *
5027bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * One special case is if we're forced to do the write -- in that case
5037bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * we play games with the buffer size, and it's usually a partial write.
5047bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
5057bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	outp = out.db;
5067bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
5077bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		for (cnt = n;; cnt -= nw) {
5087bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
5097bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (!force && ddflags & C_SPARSE) {
5107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				int sparse, i;
5117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				sparse = 1;	/* Is buffer sparse? */
5127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				for (i = 0; i < cnt; i++)
5137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					if (outp[i] != 0) {
5147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes						sparse = 0;
5157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes						break;
5167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					}
5177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				if (sparse) {
5187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					pending += cnt;
5197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					outp += cnt;
5207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					nw = 0;
5217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					break;
5227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				}
5237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
5247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (pending != 0) {
5257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				if (ddop_lseek(out,
5267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				    out.fd, pending, SEEK_CUR) == -1)
5277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					err(EXIT_FAILURE, "%s: seek error creating sparse file",
5287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					    out.name);
5297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
5307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			nw = bwrite(&out, outp, cnt);
5317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (nw <= 0) {
5327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				if (nw == 0)
5337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					errx(EXIT_FAILURE,
5347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes						"%s: end of device", out.name);
5357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					/* NOTREACHED */
5367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				if (errno != EINTR)
5377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					err(EXIT_FAILURE, "%s", out.name);
5387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					/* NOTREACHED */
5397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				nw = 0;
5407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
5417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (pending) {
5427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				st.bytes += pending;
5437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				st.sparse += pending/out.dbsz;
5447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				st.out_full += pending/out.dbsz;
5457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				pending = 0;
5467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
5477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			outp += nw;
5487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			st.bytes += nw;
5497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (nw == n) {
5507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				if ((uint64_t)n != out.dbsz)
5517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					++st.out_part;
5527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				else
5537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					++st.out_full;
5547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				break;
5557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
5567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			++st.out_part;
5577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (nw == cnt)
5587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				break;
5597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (out.flags & ISCHR && !warned) {
5607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				warned = 1;
5617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				warnx("%s: short write on character device", out.name);
5627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
5637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (out.flags & ISTAPE)
5647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				errx(EXIT_FAILURE,
5657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					"%s: short write on tape device", out.name);
5667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				/* NOTREACHED */
5677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
5687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
5697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if ((out.dbcnt -= n) < out.dbsz)
5707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			break;
5717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
5727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
5737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/* Reassemble the output block. */
5747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (out.dbcnt)
5757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
5767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	out.dbp = out.db + out.dbcnt;
5777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
5787bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (progress && (st.out_full + st.out_part) % progress == 0)
5797bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(void)write(STDERR_FILENO, ".", 1);
5807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
5817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
5827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes/*
5837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * A protected against SIGINFO write
5847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes */
5857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesssize_t
5867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesbwrite(IO *io, const void *buf, size_t len)
5877bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
5887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	sigset_t oset;
5897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	ssize_t rv;
5907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int oerrno;
5917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
5927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)sigprocmask(SIG_BLOCK, &infoset, &oset);
5937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	rv = io->ops->op_write(io->fd, buf, len);
5947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	oerrno = errno;
5957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
5967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	errno = oerrno;
5977bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	return (rv);
5987bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
599