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