xref: /illumos-gate/usr/src/cmd/dd/dd.c (revision 16b76d3cb933ff92018a2a75594449010192eacb)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  * Copyright 2012, Josef 'Jeff' Sipek <jeffpc@31bits.net>. All rights reserved.
27  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
28  * Copyright (c) 2014 by Delphix. All rights reserved.
29  * Copyright 2021 Oxide Computer Company
30  */
31 
32 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
33 /*		All Rights Reserved	*/
34 
35 /*
36  *	convert and copy
37  */
38 
39 #include	<stdio.h>
40 #include	<signal.h>
41 #include	<fcntl.h>
42 #include	<sys/param.h>
43 #include	<sys/types.h>
44 #include	<sys/sysmacros.h>
45 #include	<sys/stat.h>
46 #include	<unistd.h>
47 #include	<stdlib.h>
48 #include	<locale.h>
49 #include	<string.h>
50 #include	<sys/time.h>
51 #include	<errno.h>
52 #include	<strings.h>
53 #include	<libcmdutils.h>
54 
55 /* The BIG parameter is machine dependent.  It should be a long integer	*/
56 /* constant that can be used by the number parser to check the validity	*/
57 /* of numeric parameters.  On 16-bit machines, it should probably be	*/
58 /* the maximum unsigned integer, 0177777L.  On 32-bit machines where	*/
59 /* longs are the same size as ints, the maximum signed integer is more	*/
60 /* appropriate.  This value is 017777777777L. In 64 bit environments,   */
61 /* the maximum signed integer value is 0777777777777777777777LL		*/
62 
63 #define	BIG	0777777777777777777777LL
64 
65 #define	BSIZE	512
66 
67 /* Option parameters */
68 
69 #define	COPY		0	/* file copy, preserve input block size */
70 #define	REBLOCK		1	/* file copy, change block size */
71 #define	LCREBLOCK	2	/* file copy, convert to lower case */
72 #define	UCREBLOCK	3	/* file copy, convert to upper case */
73 #define	NBASCII		4	/* file copy, convert from EBCDIC to ASCII */
74 #define	LCNBASCII	5	/* file copy, EBCDIC to lower case ASCII */
75 #define	UCNBASCII	6	/* file copy, EBCDIC to upper case ASCII */
76 #define	NBEBCDIC	7	/* file copy, convert from ASCII to EBCDIC */
77 #define	LCNBEBCDIC	8	/* file copy, ASCII to lower case EBCDIC */
78 #define	UCNBEBCDIC	9	/* file copy, ASCII to upper case EBCDIC */
79 #define	NBIBM		10	/* file copy, convert from ASCII to IBM */
80 #define	LCNBIBM		11	/* file copy, ASCII to lower case IBM */
81 #define	UCNBIBM		12	/* file copy, ASCII to upper case IBM */
82 #define	UNBLOCK		13	/* convert blocked ASCII to ASCII */
83 #define	LCUNBLOCK	14	/* convert blocked ASCII to lower case ASCII */
84 #define	UCUNBLOCK	15	/* convert blocked ASCII to upper case ASCII */
85 #define	ASCII		16	/* convert blocked EBCDIC to ASCII */
86 #define	LCASCII		17	/* convert blocked EBCDIC to lower case ASCII */
87 #define	UCASCII		18	/* convert blocked EBCDIC to upper case ASCII */
88 #define	BLOCK		19	/* convert ASCII to blocked ASCII */
89 #define	LCBLOCK		20	/* convert ASCII to lower case blocked ASCII */
90 #define	UCBLOCK		21	/* convert ASCII to upper case blocked ASCII */
91 #define	EBCDIC		22	/* convert ASCII to blocked EBCDIC */
92 #define	LCEBCDIC	23	/* convert ASCII to lower case blocked EBCDIC */
93 #define	UCEBCDIC	24	/* convert ASCII to upper case blocked EBCDIC */
94 #define	IBM		25	/* convert ASCII to blocked IBM */
95 #define	LCIBM		26	/* convert ASCII to lower case blocked IBM */
96 #define	UCIBM		27	/* convert ASCII to upper case blocked IBM */
97 #define	LCASE		01	/* flag - convert to lower case */
98 #define	UCASE		02	/* flag - convert to upper case */
99 #define	SWAB		04	/* flag - swap bytes before conversion */
100 #define	NERR		010	/* flag - proceed on input errors */
101 #define	SYNC		020	/* flag - pad short input blocks with nulls */
102 #define	FULLBLOCK	040	/* flag - accumulate full blocks of input */
103 #define	BADLIMIT	5	/* give up if no progress after BADLIMIT trys */
104 #define	SVR4XLATE	0	/* use default EBCDIC translation */
105 #define	BSDXLATE	1	/* use BSD-compatible EBCDIC translation */
106 
107 #define	USAGE\
108 	"usage: dd [if=file] [of=file] [ibs=n|nk|nb|nxm] [obs=n|nk|nb|nxm]\n"\
109 	"	   [bs=n|nk|nb|nxm] [cbs=n|nk|nb|nxm] [files=n] [skip=n]\n"\
110 	"	   [iseek=n] [oseek=n] [seek=n] [stride=n] [istride=n]\n"\
111 	"	   [ostride=n] [count=n] [conv=[ascii][,ebcdic][,ibm]\n"\
112 	"	   [,asciib][,ebcdicb][,ibmb][,block|unblock][,lcase|ucase]\n"\
113 	"	   [,swab][,noerror][,notrunc][,sync]]\n"\
114 	"	   [iflag=[fullblock]] [oflag=[dsync][sync]]\n"
115 
116 /* Global references */
117 
118 /* Local routine declarations */
119 
120 static int	match(char *);
121 static void		term(int);
122 static unsigned long long	number(long long);
123 static unsigned char	*flsh(void);
124 static void		stats(boolean_t);
125 
126 /* Local data definitions */
127 
128 static unsigned ibs;	/* input buffer size */
129 static unsigned obs;	/* output buffer size */
130 static unsigned bs;	/* buffer size, overrules ibs and obs */
131 static unsigned cbs;	/* conversion buffer size, used for block conversions */
132 static unsigned ibc;	/* number of bytes still in the input buffer */
133 static unsigned obc;	/* number of bytes in the output buffer */
134 static unsigned cbc;	/* number of bytes in the conversion buffer */
135 
136 static int	ibf;	/* input file descriptor */
137 static int	obf;	/* output file descriptor */
138 static int	cflag;	/* conversion option flags */
139 static int	iflag;	/* input flag options */
140 static int	oflag;	/* output flag options */
141 static int	skipf;	/* if skipf == 1, skip rest of input line */
142 static unsigned long long	nifr;	/* count of full input records */
143 static unsigned long long	nipr;	/* count of partial input records */
144 static unsigned long long	nofr;	/* count of full output records */
145 static unsigned long long	nopr;	/* count of partial output records */
146 static unsigned long long	ntrunc;	/* count of truncated input lines */
147 static unsigned long long	nbad;	/* count of bad records since last */
148 					/* good one */
149 static int	files;	/* number of input files to concatenate (tape only) */
150 static off_t	skip;	/* number of input records to skip */
151 static off_t	iseekn;	/* number of input records to seek past */
152 static off_t	oseekn;	/* number of output records to seek past */
153 static unsigned long long	count;	/* number of input records to copy */
154 			/* (0 = all) */
155 static boolean_t ecount;	/* explicit count given */
156 static off_t	ostriden;	/* number of output blocks to skip between */
157 				/* records */
158 static off_t	istriden;	/* number of input blocks to skip between */
159 				/* records */
160 
161 static int	trantype; /* BSD or SVr4 compatible EBCDIC */
162 
163 static char		*string;	/* command arg pointer */
164 static char		*ifile;		/* input file name pointer */
165 static char		*ofile;		/* output file name pointer */
166 static unsigned char	*ibuf;		/* input buffer pointer */
167 static unsigned char	*obuf;		/* output buffer pointer */
168 
169 static hrtime_t		startt;		/* hrtime copy started */
170 static uint64_t		prog_secs;	/* number of seconds of progress */
171 static unsigned long long	obytes;	/* output bytes */
172 static sig_atomic_t	nstats;		/* do we need to output stats */
173 
174 typedef enum dd_status {
175 	DD_STATUS_DEFAULT	= 0,
176 	DD_STATUS_NONE		= 1 << 0,
177 	DD_STATUS_PROGRESS	= 1 << 1,
178 	DD_STATUS_NOXFER	= 1 << 2
179 } dd_status_t;
180 
181 static dd_status_t	status_arg = DD_STATUS_DEFAULT;
182 static boolean_t	stderr_tty = B_FALSE;
183 static boolean_t	progress_printed = B_FALSE;
184 
185 /* This is an EBCDIC to ASCII conversion table	*/
186 /* from a proposed BTL standard April 16, 1979	*/
187 
188 static unsigned char svr4_etoa[] =
189 {
190 	0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
191 	0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
192 	0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
193 	0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
194 	0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
195 	0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
196 	0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
197 	0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
198 	0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
199 	0247, 0250, 0325, 0056, 0074, 0050, 0053, 0174,
200 	0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
201 	0260, 0261, 0041, 0044, 0052, 0051, 0073, 0176,
202 	0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
203 	0270, 0271, 0313, 0054, 0045, 0137, 0076, 0077,
204 	0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
205 	0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
206 	0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
207 	0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
208 	0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
209 	0161, 0162, 0136, 0314, 0315, 0316, 0317, 0320,
210 	0321, 0345, 0163, 0164, 0165, 0166, 0167, 0170,
211 	0171, 0172, 0322, 0323, 0324, 0133, 0326, 0327,
212 	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
213 	0340, 0341, 0342, 0343, 0344, 0135, 0346, 0347,
214 	0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
215 	0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
216 	0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
217 	0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
218 	0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
219 	0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
220 	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
221 	0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
222 };
223 
224 /* This is an ASCII to EBCDIC conversion table	*/
225 /* from a proposed BTL standard April 16, 1979	*/
226 
227 static unsigned char svr4_atoe[] =
228 {
229 	0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057,
230 	0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017,
231 	0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046,
232 	0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037,
233 	0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175,
234 	0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,
235 	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
236 	0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,
237 	0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
238 	0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,
239 	0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,
240 	0347, 0350, 0351, 0255, 0340, 0275, 0232, 0155,
241 	0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
242 	0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,
243 	0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,
244 	0247, 0250, 0251, 0300, 0117, 0320, 0137, 0007,
245 	0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027,
246 	0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033,
247 	0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010,
248 	0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341,
249 	0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,
250 	0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
251 	0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,
252 	0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,
253 	0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,
254 	0216, 0217, 0220, 0152, 0233, 0234, 0235, 0236,
255 	0237, 0240, 0252, 0253, 0254, 0112, 0256, 0257,
256 	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
257 	0270, 0271, 0272, 0273, 0274, 0241, 0276, 0277,
258 	0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,
259 	0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,
260 	0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,
261 };
262 
263 /* Table for ASCII to IBM (alternate EBCDIC) code conversion	*/
264 
265 static unsigned char svr4_atoibm[] =
266 {
267 	0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057,
268 	0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017,
269 	0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046,
270 	0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037,
271 	0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175,
272 	0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,
273 	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
274 	0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,
275 	0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
276 	0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,
277 	0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,
278 	0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155,
279 	0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
280 	0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,
281 	0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,
282 	0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007,
283 	0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027,
284 	0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033,
285 	0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010,
286 	0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341,
287 	0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,
288 	0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
289 	0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,
290 	0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,
291 	0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,
292 	0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,
293 	0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,
294 	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
295 	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
296 	0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,
297 	0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,
298 	0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,
299 };
300 
301 /* Table for conversion of ASCII to lower case ASCII	*/
302 
303 static unsigned char utol[] =
304 {
305 	0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
306 	0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
307 	0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
308 	0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
309 	0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
310 	0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
311 	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
312 	0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
313 	0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
314 	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
315 	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
316 	0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
317 	0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
318 	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
319 	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
320 	0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
321 	0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
322 	0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
323 	0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
324 	0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
325 	0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
326 	0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
327 	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
328 	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
329 	0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
330 	0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
331 	0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
332 	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
333 	0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
334 	0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
335 	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
336 	0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
337 };
338 
339 /* Table for conversion of ASCII to upper case ASCII	*/
340 
341 static unsigned char ltou[] =
342 {
343 	0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
344 	0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
345 	0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
346 	0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
347 	0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
348 	0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
349 	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
350 	0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
351 	0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
352 	0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
353 	0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
354 	0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
355 	0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
356 	0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
357 	0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
358 	0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
359 	0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
360 	0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
361 	0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
362 	0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
363 	0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
364 	0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
365 	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
366 	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
367 	0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
368 	0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
369 	0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
370 	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
371 	0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
372 	0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
373 	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
374 	0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
375 };
376 
377 /* BSD-compatible EBCDIC to ASCII translate table */
378 
379 static unsigned char bsd_etoa[] =
380 {
381 	0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
382 	0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
383 	0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
384 	0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
385 	0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
386 	0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
387 	0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
388 	0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
389 	0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
390 	0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
391 	0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
392 	0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
393 	0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
394 	0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
395 	0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
396 	0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
397 	0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
398 	0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
399 	0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
400 	0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
401 	0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
402 	0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
403 	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
404 	0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
405 	0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
406 	0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
407 	0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
408 	0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
409 	0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
410 	0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
411 	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
412 	0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
413 };
414 
415 /* BSD-compatible ASCII to EBCDIC translate table */
416 
417 static unsigned char bsd_atoe[] =
418 {
419 	0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057,
420 	0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017,
421 	0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046,
422 	0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037,
423 	0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175,
424 	0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,
425 	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
426 	0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,
427 	0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
428 	0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,
429 	0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,
430 	0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155,
431 	0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
432 	0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,
433 	0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,
434 	0247, 0250, 0251, 0300, 0152, 0320, 0241, 0007,
435 	0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027,
436 	0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033,
437 	0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010,
438 	0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341,
439 	0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,
440 	0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
441 	0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,
442 	0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,
443 	0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,
444 	0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,
445 	0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,
446 	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
447 	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
448 	0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,
449 	0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,
450 	0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,
451 };
452 
453 /* BSD-compatible ASCII to IBM translate table */
454 
455 static unsigned char bsd_atoibm[] =
456 {
457 	0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057,
458 	0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017,
459 	0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046,
460 	0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037,
461 	0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175,
462 	0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,
463 	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
464 	0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,
465 	0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
466 	0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,
467 	0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,
468 	0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155,
469 	0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
470 	0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,
471 	0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,
472 	0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007,
473 	0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027,
474 	0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033,
475 	0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010,
476 	0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341,
477 	0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,
478 	0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
479 	0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,
480 	0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,
481 	0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,
482 	0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,
483 	0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,
484 	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
485 	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
486 	0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,
487 	0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,
488 	0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,
489 };
490 
491 /* set up to use SVr4 ascii-ebcdic translation by default */
492 
493 static unsigned char *atoe = svr4_atoe;
494 static unsigned char *etoa = svr4_etoa;
495 static unsigned char *atoibm = svr4_atoibm;
496 
497 /*ARGSUSED*/
498 static void
499 siginfo_handler(int sig, siginfo_t *sip, void *ucp)
500 {
501 	nstats = 1;
502 }
503 
504 static ssize_t
505 iread(int fd, char *buf, size_t nbyte)
506 {
507 	ssize_t count;
508 
509 	count = 0;
510 	while (nbyte != 0) {
511 		ssize_t nr = read(fd, buf, nbyte);
512 
513 		if (nr < 0)
514 			return (nr);
515 
516 		if (nr == 0)
517 			break;
518 		buf += nr;
519 		count += nr;
520 		nbyte -= nr;
521 
522 		if ((iflag & FULLBLOCK) == 0)
523 			break;
524 	}
525 	return (count);
526 }
527 
528 int
529 main(int argc, char **argv)
530 {
531 	unsigned char *ip, *op; /* input and output buffer pointers */
532 	int c;		/* character counter */
533 	int ic;		/* input character */
534 	int conv;		/* conversion option code */
535 	int trunc;		/* whether output file is truncated */
536 	struct stat file_stat;
537 	struct sigaction sact;
538 
539 	/* Set option defaults */
540 
541 	ibs = BSIZE;
542 	obs = BSIZE;
543 	files = 1;
544 	conv = COPY;
545 	trunc = 1;			/* default: truncate output file */
546 	trantype = SVR4XLATE;  /* use SVR4 EBCDIC by default */
547 
548 	/* Parse command options */
549 
550 	(void) setlocale(LC_ALL, "");
551 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
552 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
553 #endif
554 	(void) textdomain(TEXT_DOMAIN);
555 
556 	while ((c = getopt(argc, argv, "")) != EOF)
557 		switch (c) {
558 			case '?':
559 			(void) fprintf(stderr, USAGE);
560 			exit(2);
561 		}
562 
563 	/* not getopt()'ed because dd has no options but only operand(s) */
564 
565 	for (c = optind; c < argc; c++) {
566 		string = argv[c];
567 		if (match("ibs=")) {
568 			ibs = (unsigned)number(BIG);
569 			continue;
570 		}
571 		if (match("obs=")) {
572 			obs = (unsigned)number(BIG);
573 			continue;
574 		}
575 		if (match("cbs=")) {
576 			cbs = (unsigned)number(BIG);
577 			continue;
578 		}
579 		if (match("bs=")) {
580 			bs = (unsigned)number(BIG);
581 			continue;
582 		}
583 		if (match("if=")) {
584 			ifile = string;
585 			continue;
586 		}
587 		if (match("of=")) {
588 			ofile = string;
589 			continue;
590 		}
591 		if (match("skip=")) {
592 			skip = number(BIG);
593 			continue;
594 		}
595 		if (match("iseek=")) {
596 			iseekn = number(BIG);
597 			continue;
598 		}
599 		if (match("oseek=")) {
600 			oseekn = number(BIG);
601 			continue;
602 		}
603 		if (match("seek=")) {		/* retained for compatibility */
604 			oseekn = number(BIG);
605 			continue;
606 		}
607 		if (match("ostride=")) {
608 			ostriden = ((off_t)number(BIG)) - 1;
609 			continue;
610 		}
611 		if (match("istride=")) {
612 			istriden = ((off_t)number(BIG)) - 1;
613 			continue;
614 		}
615 		if (match("stride=")) {
616 			istriden = ostriden = ((off_t)number(BIG)) - 1;
617 			continue;
618 		}
619 		if (match("count=")) {
620 			count = number(BIG);
621 			ecount = B_TRUE;
622 			continue;
623 		}
624 		if (match("files=")) {
625 			files = (int)number(BIG);
626 			continue;
627 		}
628 		if (match("conv=")) {
629 			for (;;) {
630 				if (match(",")) {
631 					continue;
632 				}
633 				if (*string == '\0') {
634 					break;
635 				}
636 				if (match("block")) {
637 					conv = BLOCK;
638 					continue;
639 				}
640 				if (match("unblock")) {
641 					conv = UNBLOCK;
642 					continue;
643 				}
644 
645 				/* ebcdicb, ibmb, and asciib must precede */
646 				/* ebcdic, ibm, and ascii in this test */
647 
648 				if (match("ebcdicb")) {
649 					conv = EBCDIC;
650 					trantype = BSDXLATE;
651 					continue;
652 				}
653 				if (match("ibmb")) {
654 					conv = IBM;
655 					trantype = BSDXLATE;
656 					continue;
657 				}
658 				if (match("asciib")) {
659 					conv = ASCII;
660 					trantype = BSDXLATE;
661 					continue;
662 				}
663 				if (match("ebcdic")) {
664 					conv = EBCDIC;
665 					trantype = SVR4XLATE;
666 					continue;
667 				}
668 				if (match("ibm")) {
669 					conv = IBM;
670 					trantype = SVR4XLATE;
671 					continue;
672 				}
673 				if (match("ascii")) {
674 					conv = ASCII;
675 					trantype = SVR4XLATE;
676 					continue;
677 				}
678 				if (match("lcase")) {
679 					cflag |= LCASE;
680 					continue;
681 				}
682 				if (match("ucase")) {
683 					cflag |= UCASE;
684 					continue;
685 				}
686 				if (match("swab")) {
687 					cflag |= SWAB;
688 					continue;
689 				}
690 				if (match("noerror")) {
691 					cflag |= NERR;
692 					continue;
693 				}
694 				if (match("notrunc")) {
695 					trunc = 0;
696 					continue;
697 				}
698 				if (match("sync")) {
699 					cflag |= SYNC;
700 					continue;
701 				}
702 				goto badarg;
703 			}
704 			continue;
705 		}
706 		if (match("iflag=")) {
707 			for (;;) {
708 				if (match(",")) {
709 					continue;
710 				}
711 				if (*string == '\0') {
712 					break;
713 				}
714 				if (match("fullblock")) {
715 					iflag |= FULLBLOCK;
716 					continue;
717 				}
718 				goto badarg;
719 			}
720 			continue;
721 		}
722 		if (match("oflag=")) {
723 			for (;;) {
724 				if (match(",")) {
725 					continue;
726 				}
727 				if (*string == '\0') {
728 					break;
729 				}
730 				if (match("dsync")) {
731 					oflag |= O_DSYNC;
732 					continue;
733 				}
734 				if (match("sync")) {
735 					oflag |= O_SYNC;
736 					continue;
737 				}
738 				goto badarg;
739 			}
740 			continue;
741 		}
742 		if (match("status=")) {
743 			if (match("none")) {
744 				status_arg = DD_STATUS_NONE;
745 			} else if (match("noxfer")) {
746 				status_arg = DD_STATUS_NOXFER;
747 			} else if (match("progress")) {
748 				status_arg = DD_STATUS_PROGRESS;
749 			} else {
750 				goto badarg;
751 			}
752 			continue;
753 		}
754 		badarg:
755 		(void) fprintf(stderr, "dd: %s \"%s\"\n",
756 		    gettext("bad argument:"), string);
757 		exit(2);
758 	}
759 
760 	/* Perform consistency checks on options, decode strange conventions */
761 
762 	if (bs) {
763 		ibs = obs = bs;
764 	}
765 	if ((ibs == 0) || (obs == 0)) {
766 		(void) fprintf(stderr, "dd: %s\n",
767 		    gettext("buffer sizes cannot be zero"));
768 		exit(2);
769 	}
770 	if (ostriden == (off_t)-1) {
771 		(void) fprintf(stderr, "dd: %s\n",
772 		    gettext("stride must be greater than zero"));
773 		exit(2);
774 	}
775 	if (istriden == (off_t)-1) {
776 		(void) fprintf(stderr, "dd: %s\n",
777 		    gettext("stride must be greater than zero"));
778 		exit(2);
779 	}
780 	if (conv == COPY) {
781 		if ((bs == 0) || (cflag & (LCASE | UCASE))) {
782 			conv = REBLOCK;
783 		}
784 	}
785 	if (cbs == 0) {
786 		switch (conv) {
787 		case BLOCK:
788 		case UNBLOCK:
789 			conv = REBLOCK;
790 			break;
791 
792 		case ASCII:
793 			conv = NBASCII;
794 			break;
795 
796 		case EBCDIC:
797 			conv = NBEBCDIC;
798 			break;
799 
800 		case IBM:
801 			conv = NBIBM;
802 			break;
803 		}
804 	}
805 
806 	/* Expand options into lower and upper case versions if necessary */
807 
808 	switch (conv) {
809 	case REBLOCK:
810 		if (cflag & LCASE)
811 			conv = LCREBLOCK;
812 		else if (cflag & UCASE)
813 			conv = UCREBLOCK;
814 		break;
815 
816 	case UNBLOCK:
817 		if (cflag & LCASE)
818 			conv = LCUNBLOCK;
819 		else if (cflag & UCASE)
820 			conv = UCUNBLOCK;
821 		break;
822 
823 	case BLOCK:
824 		if (cflag & LCASE)
825 			conv = LCBLOCK;
826 		else if (cflag & UCASE)
827 			conv = UCBLOCK;
828 		break;
829 
830 	case ASCII:
831 		if (cflag & LCASE)
832 			conv = LCASCII;
833 		else if (cflag & UCASE)
834 			conv = UCASCII;
835 		break;
836 
837 	case NBASCII:
838 		if (cflag & LCASE)
839 			conv = LCNBASCII;
840 		else if (cflag & UCASE)
841 			conv = UCNBASCII;
842 		break;
843 
844 	case EBCDIC:
845 		if (cflag & LCASE)
846 			conv = LCEBCDIC;
847 		else if (cflag & UCASE)
848 			conv = UCEBCDIC;
849 		break;
850 
851 	case NBEBCDIC:
852 		if (cflag & LCASE)
853 			conv = LCNBEBCDIC;
854 		else if (cflag & UCASE)
855 			conv = UCNBEBCDIC;
856 		break;
857 
858 	case IBM:
859 		if (cflag & LCASE)
860 			conv = LCIBM;
861 		else if (cflag & UCASE)
862 			conv = UCIBM;
863 		break;
864 
865 	case NBIBM:
866 		if (cflag & LCASE)
867 			conv = LCNBIBM;
868 		else if (cflag & UCASE)
869 			conv = UCNBIBM;
870 		break;
871 	}
872 
873 	/* If BSD-compatible translation is selected, change the tables */
874 
875 	if (trantype == BSDXLATE) {
876 		atoe = bsd_atoe;
877 		atoibm = bsd_atoibm;
878 		etoa = bsd_etoa;
879 	}
880 	/* Open the input file, or duplicate standard input */
881 
882 	ibf = -1;
883 	if (ifile) {
884 		ibf = open(ifile, 0);
885 	} else {
886 		ifile = "";
887 		ibf = dup(STDIN_FILENO);
888 	}
889 
890 	if (ibf == -1) {
891 		(void) fprintf(stderr, "dd: %s: ", ifile);
892 		perror("open");
893 		exit(2);
894 	}
895 
896 	/* Open the output file, or duplicate standard output */
897 
898 	obf = -1;
899 	if (ofile) {
900 		if (trunc == 0)	{	/* do not truncate output file */
901 			obf = open(ofile, (O_WRONLY | O_CREAT | oflag),
902 			    (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
903 			    S_IROTH | S_IWOTH));
904 		} else if (oseekn && (trunc == 1)) {
905 			obf = open(ofile, O_WRONLY | O_CREAT | oflag,
906 			    (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
907 			    S_IROTH | S_IWOTH));
908 			if (obf == -1) {
909 				(void) fprintf(stderr, "dd: %s: ", ofile);
910 				perror("open");
911 				exit(2);
912 			}
913 			(void) fstat(obf, &file_stat);
914 			if (((file_stat.st_mode & S_IFMT) == S_IFREG) &&
915 			    (ftruncate(obf, (((off_t)oseekn) * ((off_t)obs)))
916 			    == -1)) {
917 				perror("ftruncate");
918 				exit(2);
919 			}
920 		} else {
921 			obf = open(ofile, O_WRONLY | O_CREAT | O_TRUNC | oflag,
922 			    (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
923 			    S_IROTH | S_IWOTH));
924 		}
925 	} else {
926 		ofile = "";
927 		obf = dup(STDOUT_FILENO);
928 	}
929 
930 	if (obf == -1) {
931 		(void) fprintf(stderr, "dd: %s: ", ofile);
932 		perror("open");
933 		exit(2);
934 	}
935 
936 	/* Expand memory to get an input buffer */
937 
938 	ibuf = (unsigned char *)valloc(ibs + 10);
939 
940 	/* If no conversions, the input buffer is the output buffer */
941 
942 	if (conv == COPY) {
943 		obuf = ibuf;
944 	} else {
945 
946 		/*
947 		 * Expand memory to get an output buffer. Leave enough room
948 		 * at the end to convert a logical record when doing block
949 		 * conversions.
950 		 */
951 
952 		obuf = (unsigned char *)valloc(obs + cbs + 10);
953 	}
954 	if ((ibuf == NULL) || (obuf == NULL)) {
955 		(void) fprintf(stderr,
956 		    "dd: %s\n", gettext("not enough memory"));
957 		exit(2);
958 	}
959 
960 	/*
961 	 * Enable a statistics message when we terminate on SIGINT
962 	 * Also enable it to be queried via SIGINFO and SIGUSR1
963 	 */
964 
965 	if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
966 		(void) signal(SIGINT, term);
967 	}
968 
969 	bzero(&sact, sizeof (struct sigaction));
970 	sact.sa_flags = SA_SIGINFO;
971 	sact.sa_sigaction = siginfo_handler;
972 	(void) sigemptyset(&sact.sa_mask);
973 	if (sigaction(SIGINFO, &sact, NULL) != 0) {
974 		(void) fprintf(stderr, "dd: %s: %s\n",
975 		    gettext("failed to enable siginfo handler"),
976 		    gettext(strerror(errno)));
977 		exit(2);
978 	}
979 	if (sigaction(SIGUSR1, &sact, NULL) != 0) {
980 		(void) fprintf(stderr, "dd: %s: %s\n",
981 		    gettext("failed to enable sigusr1 handler"),
982 		    gettext(strerror(errno)));
983 		exit(2);
984 	}
985 
986 	/*
987 	 * Determine if stderr is a tty in case someone has invoked
988 	 * status=progress
989 	 */
990 	if (isatty(STDERR_FILENO) == 1) {
991 		stderr_tty = B_TRUE;
992 	}
993 
994 	/* Skip input blocks */
995 
996 	while (skip) {
997 		ibc = iread(ibf, (char *)ibuf, ibs);
998 		if (ibc == (unsigned)-1) {
999 			if (++nbad > BADLIMIT) {
1000 				(void) fprintf(stderr, "dd: %s\n",
1001 				    gettext("skip failed"));
1002 				exit(2);
1003 			} else {
1004 				perror("read");
1005 			}
1006 		} else {
1007 			if (ibc == 0) {
1008 				(void) fprintf(stderr, "dd: %s\n",
1009 				gettext("cannot skip past end-of-file"));
1010 				exit(3);
1011 			} else {
1012 				nbad = 0;
1013 			}
1014 		}
1015 		skip--;
1016 	}
1017 
1018 	/* Seek past input blocks */
1019 
1020 	if (iseekn && lseek(ibf, (((off_t)iseekn) * ((off_t)ibs)), 1) == -1) {
1021 		perror("lseek");
1022 		exit(2);
1023 	}
1024 
1025 	/* Seek past output blocks */
1026 
1027 	if (oseekn && lseek(obf, (((off_t)oseekn) * ((off_t)obs)), 1) == -1) {
1028 		perror("lseek");
1029 		exit(2);
1030 	}
1031 
1032 	/* Initialize all buffer pointers */
1033 
1034 	skipf = 0;	/* not skipping an input line */
1035 	ibc = 0;	/* no input characters yet */
1036 	obc = 0;	/* no output characters yet */
1037 	cbc = 0;	/* the conversion buffer is empty */
1038 	op = obuf;	/* point to the output buffer */
1039 
1040 	/* Read and convert input blocks until end of file(s) */
1041 
1042 	/* Grab our start time for siginfo purposes */
1043 	startt = gethrtime();
1044 
1045 	for (;;) {
1046 		/*
1047 		 * Always call into the stats function which will check for
1048 		 * siginfo and related processing that needs to happen.
1049 		 */
1050 		stats(B_TRUE);
1051 
1052 		if ((count == 0 && ecount == B_FALSE) || (nifr+nipr < count)) {
1053 		/* If proceed on error is enabled, zero the input buffer */
1054 
1055 			if (cflag & NERR) {
1056 				ip = ibuf + ibs;
1057 				c = ibs;
1058 				if (c & 1)	/* if the size is odd, */
1059 				{
1060 					*--ip = 0;	/* clear the odd byte */
1061 				}
1062 				if (c >>= 1)		/* divide by two */
1063 				{
1064 					do {	/* clear two at a time */
1065 						*--ip = 0;
1066 						*--ip = 0;
1067 					} while (--c);
1068 				}
1069 			}
1070 
1071 			/* Read the next input block */
1072 
1073 			ibc = iread(ibf, (char *)ibuf, ibs);
1074 
1075 			if (istriden > 0 && lseek(ibf, istriden * ((off_t)ibs),
1076 			    SEEK_CUR) == -1) {
1077 				perror("lseek");
1078 				exit(2);
1079 			}
1080 
1081 			/* Process input errors */
1082 
1083 			if (ibc == (unsigned)-1) {
1084 				perror("read");
1085 				if (((cflag & NERR) == 0) ||
1086 				    (++nbad > BADLIMIT)) {
1087 					while (obc) {
1088 						(void) flsh();
1089 					}
1090 					term(2);
1091 				} else {
1092 					stats(B_FALSE);
1093 					ibc = ibs; /* assume a full block */
1094 				}
1095 			} else {
1096 				nbad = 0;
1097 			}
1098 		} else {
1099 			/* Record count satisfied, simulate end of file */
1100 			ibc = 0;
1101 			files = 1;
1102 		}
1103 
1104 		/* Process end of file */
1105 
1106 		if (ibc == 0) {
1107 			switch (conv) {
1108 			case UNBLOCK:
1109 			case LCUNBLOCK:
1110 			case UCUNBLOCK:
1111 			case ASCII:
1112 			case LCASCII:
1113 			case UCASCII:
1114 
1115 				/* Trim trailing blanks from the last line */
1116 
1117 				if ((c = cbc) != 0) {
1118 					do {
1119 						if ((*--op) != ' ') {
1120 							op++;
1121 							break;
1122 						}
1123 					} while (--c);
1124 					*op++ = '\n';
1125 					obc -= cbc - c - 1;
1126 					cbc = 0;
1127 
1128 					/* Flush the output buffer if full */
1129 
1130 					while (obc >= obs) {
1131 						op = flsh();
1132 					}
1133 				}
1134 				break;
1135 
1136 			case BLOCK:
1137 			case LCBLOCK:
1138 			case UCBLOCK:
1139 			case EBCDIC:
1140 			case LCEBCDIC:
1141 			case UCEBCDIC:
1142 			case IBM:
1143 			case LCIBM:
1144 			case UCIBM:
1145 
1146 			/* Pad trailing blanks if the last line is short */
1147 
1148 				if (cbc) {
1149 					obc += c = cbs - cbc;
1150 					cbc = 0;
1151 					if (c > 0) {
1152 					/* Use the right kind of blank */
1153 
1154 						switch (conv) {
1155 						case BLOCK:
1156 						case LCBLOCK:
1157 						case UCBLOCK:
1158 							ic = ' ';
1159 							break;
1160 
1161 						case EBCDIC:
1162 						case LCEBCDIC:
1163 						case UCEBCDIC:
1164 							ic = atoe[' '];
1165 							break;
1166 
1167 						case IBM:
1168 						case LCIBM:
1169 						case UCIBM:
1170 							ic = atoibm[' '];
1171 							break;
1172 						}
1173 
1174 						/* Pad with trailing blanks */
1175 
1176 						do {
1177 							*op++ = ic;
1178 						} while (--c);
1179 					}
1180 				}
1181 
1182 
1183 				/* Flush the output buffer if full */
1184 
1185 				while (obc >= obs) {
1186 					op = flsh();
1187 				}
1188 				break;
1189 			}
1190 
1191 			/* If no more files to read, flush the output buffer */
1192 
1193 			if (--files <= 0) {
1194 				(void) flsh();
1195 				if ((close(obf) != 0) ||
1196 				    (fclose(stdout) != 0)) {
1197 					perror(gettext("dd: close error"));
1198 					exit(2);
1199 				}
1200 				term(0);	/* successful exit */
1201 			} else {
1202 				continue;	/* read the next file */
1203 			}
1204 		} else if (ibc == ibs) {
1205 			/* Normal read, check for special cases */
1206 			nifr++;		/* count another full input record */
1207 		} else {
1208 			nipr++;		/* count a partial input record */
1209 
1210 			/* If `sync' enabled, pad nulls */
1211 
1212 			if ((cflag & SYNC) && ((cflag & NERR) == 0)) {
1213 				c = ibs - ibc;
1214 				ip = ibuf + ibs;
1215 				do {
1216 					if ((conv == BLOCK) ||
1217 					    (conv == UNBLOCK))
1218 						*--ip = ' ';
1219 					else
1220 						*--ip = '\0';
1221 				} while (--c);
1222 				ibc = ibs;
1223 			}
1224 		}
1225 
1226 		/* Swap the bytes in the input buffer if necessary */
1227 
1228 		if (cflag & SWAB) {
1229 			ip = ibuf;
1230 			if (ibc & 1) {	/* if the byte count is odd, */
1231 				ip[ibc] = 0;  /* make it even, pad with zero */
1232 			}
1233 			c = ibc >> 1;	/* compute the pair count */
1234 			do {
1235 				ic = *ip++;
1236 				ip[-1] = *ip;
1237 				*ip++ = ic;
1238 			} while (--c);		/* do two bytes at a time */
1239 		}
1240 
1241 		/* Select the appropriate conversion loop */
1242 
1243 		ip = ibuf;
1244 		switch (conv) {
1245 
1246 		/* Simple copy: no conversion, preserve the input block size */
1247 
1248 		case COPY:
1249 			obc = ibc;
1250 			(void) flsh();
1251 			break;
1252 
1253 		/* Simple copy: pack all output into equal sized blocks */
1254 
1255 		case REBLOCK:
1256 		case LCREBLOCK:
1257 		case UCREBLOCK:
1258 		case NBASCII:
1259 		case LCNBASCII:
1260 		case UCNBASCII:
1261 		case NBEBCDIC:
1262 		case LCNBEBCDIC:
1263 		case UCNBEBCDIC:
1264 		case NBIBM:
1265 		case LCNBIBM:
1266 		case UCNBIBM:
1267 			while ((c = ibc) != 0) {
1268 				if (c > (obs - obc)) {
1269 					c = obs - obc;
1270 				}
1271 				ibc -= c;
1272 				obc += c;
1273 				switch (conv) {
1274 				case REBLOCK:
1275 					do {
1276 						*op++ = *ip++;
1277 					} while (--c);
1278 					break;
1279 
1280 				case LCREBLOCK:
1281 					do {
1282 						*op++ = utol[*ip++];
1283 					} while (--c);
1284 					break;
1285 
1286 				case UCREBLOCK:
1287 					do {
1288 						*op++ = ltou[*ip++];
1289 					} while (--c);
1290 					break;
1291 
1292 				case NBASCII:
1293 					do {
1294 						*op++ = etoa[*ip++];
1295 					} while (--c);
1296 					break;
1297 
1298 				case LCNBASCII:
1299 					do {
1300 						*op++ = utol[etoa[*ip++]];
1301 					} while (--c);
1302 					break;
1303 
1304 				case UCNBASCII:
1305 					do {
1306 						*op++ = ltou[etoa[*ip++]];
1307 					} while (--c);
1308 					break;
1309 
1310 				case NBEBCDIC:
1311 					do {
1312 						*op++ = atoe[*ip++];
1313 					} while (--c);
1314 					break;
1315 
1316 				case LCNBEBCDIC:
1317 					do {
1318 						*op++ = atoe[utol[*ip++]];
1319 					} while (--c);
1320 					break;
1321 
1322 				case UCNBEBCDIC:
1323 					do {
1324 						*op++ = atoe[ltou[*ip++]];
1325 					} while (--c);
1326 					break;
1327 
1328 				case NBIBM:
1329 					do {
1330 						*op++ = atoibm[*ip++];
1331 					} while (--c);
1332 					break;
1333 
1334 				case LCNBIBM:
1335 					do {
1336 						*op++ = atoibm[utol[*ip++]];
1337 					} while (--c);
1338 					break;
1339 
1340 				case UCNBIBM:
1341 					do {
1342 						*op++ = atoibm[ltou[*ip++]];
1343 					} while (--c);
1344 					break;
1345 				}
1346 				if (obc >= obs) {
1347 					op = flsh();
1348 				}
1349 			}
1350 			break;
1351 
1352 	/* Convert from blocked records to lines terminated by newline */
1353 
1354 		case UNBLOCK:
1355 		case LCUNBLOCK:
1356 		case UCUNBLOCK:
1357 		case ASCII:
1358 		case LCASCII:
1359 		case UCASCII:
1360 			while ((c = ibc) != 0) {
1361 				if (c > (cbs - cbc)) {
1362 					/* if more than one record, */
1363 					c = cbs - cbc;
1364 					/* only copy one record */
1365 				}
1366 				ibc -= c;
1367 				cbc += c;
1368 				obc += c;
1369 				switch (conv) {
1370 				case UNBLOCK:
1371 					do {
1372 						*op++ = *ip++;
1373 					} while (--c);
1374 					break;
1375 
1376 				case LCUNBLOCK:
1377 					do {
1378 						*op++ = utol[*ip++];
1379 					} while (--c);
1380 					break;
1381 
1382 				case UCUNBLOCK:
1383 					do {
1384 						*op++ = ltou[*ip++];
1385 					} while (--c);
1386 					break;
1387 
1388 				case ASCII:
1389 					do {
1390 						*op++ = etoa[*ip++];
1391 					} while (--c);
1392 					break;
1393 
1394 				case LCASCII:
1395 					do {
1396 						*op++ = utol[etoa[*ip++]];
1397 					} while (--c);
1398 					break;
1399 
1400 				case UCASCII:
1401 					do {
1402 						*op++ = ltou[etoa[*ip++]];
1403 					} while (--c);
1404 					break;
1405 				}
1406 
1407 				/* Trim trailing blanks if the line is full */
1408 
1409 				if (cbc == cbs) {
1410 					c = cbs; /* `do - while' is usually */
1411 					do {		/* faster than `for' */
1412 						if ((*--op) != ' ') {
1413 							op++;
1414 							break;
1415 						}
1416 					} while (--c);
1417 					*op++ = '\n';
1418 					obc -= cbs - c - 1;
1419 					cbc = 0;
1420 
1421 					/* Flush the output buffer if full */
1422 
1423 					while (obc >= obs) {
1424 						op = flsh();
1425 					}
1426 				}
1427 			}
1428 			break;
1429 
1430 		/* Convert to blocked records */
1431 
1432 		case BLOCK:
1433 		case LCBLOCK:
1434 		case UCBLOCK:
1435 		case EBCDIC:
1436 		case LCEBCDIC:
1437 		case UCEBCDIC:
1438 		case IBM:
1439 		case LCIBM:
1440 		case UCIBM:
1441 			while ((c = ibc) != 0) {
1442 				int nlflag = 0;
1443 
1444 				/*
1445 				 * We may have to skip to the end of a long
1446 				 * line.
1447 				 */
1448 
1449 				if (skipf) {
1450 					do {
1451 						if ((ic = *ip++) == '\n') {
1452 							skipf = 0;
1453 							c--;
1454 							break;
1455 						}
1456 					} while (--c);
1457 					if ((ibc = c) == 0) {
1458 						continue;
1459 						/* read another block */
1460 					}
1461 				}
1462 
1463 				/* If anything left, copy until newline */
1464 
1465 				if (c > (cbs - cbc + 1)) {
1466 					c = cbs - cbc + 1;
1467 				}
1468 				ibc -= c;
1469 				cbc += c;
1470 				obc += c;
1471 
1472 				switch (conv) {
1473 				case BLOCK:
1474 					do {
1475 						if ((ic = *ip++) != '\n') {
1476 							*op++ = ic;
1477 						} else {
1478 							nlflag = 1;
1479 							break;
1480 						}
1481 					} while (--c);
1482 					break;
1483 
1484 				case LCBLOCK:
1485 					do {
1486 						if ((ic = *ip++) != '\n') {
1487 							*op++ = utol[ic];
1488 						} else {
1489 							nlflag = 1;
1490 							break;
1491 						}
1492 					} while (--c);
1493 					break;
1494 
1495 				case UCBLOCK:
1496 					do {
1497 						if ((ic = *ip++) != '\n') {
1498 							*op++ = ltou[ic];
1499 						} else {
1500 							nlflag = 1;
1501 							break;
1502 						}
1503 					} while (--c);
1504 					break;
1505 
1506 				case EBCDIC:
1507 					do {
1508 						if ((ic = *ip++) != '\n') {
1509 							*op++ = atoe[ic];
1510 						} else {
1511 							nlflag = 1;
1512 							break;
1513 						}
1514 					} while (--c);
1515 					break;
1516 
1517 				case LCEBCDIC:
1518 					do {
1519 						if ((ic = *ip++) != '\n') {
1520 							*op++ = atoe[utol[ic]];
1521 						} else {
1522 							nlflag = 1;
1523 							break;
1524 						}
1525 					} while (--c);
1526 					break;
1527 
1528 				case UCEBCDIC:
1529 					do {
1530 						if ((ic = *ip++) != '\n') {
1531 							*op++ = atoe[ltou[ic]];
1532 						} else {
1533 							nlflag = 1;
1534 							break;
1535 						}
1536 					} while (--c);
1537 					break;
1538 
1539 				case IBM:
1540 					do {
1541 						if ((ic = *ip++) != '\n') {
1542 							*op++ = atoibm[ic];
1543 						} else {
1544 							nlflag = 1;
1545 							break;
1546 						}
1547 					} while (--c);
1548 					break;
1549 
1550 				case LCIBM:
1551 					do {
1552 						if ((ic = *ip++) != '\n') {
1553 							*op++ =
1554 							    atoibm[utol[ic]];
1555 						} else {
1556 							nlflag = 1;
1557 							break;
1558 						}
1559 					} while (--c);
1560 					break;
1561 
1562 				case UCIBM:
1563 					do {
1564 						if ((ic = *ip++) != '\n') {
1565 							*op++ =
1566 							    atoibm[ltou[ic]];
1567 						} else {
1568 							nlflag = 1;
1569 							break;
1570 						}
1571 					} while (--c);
1572 					break;
1573 				}
1574 
1575 			/* If newline found, update all the counters and */
1576 			/* pointers, pad with trailing blanks if necessary */
1577 
1578 				if (nlflag) {
1579 					ibc += c - 1;
1580 					obc += cbs - cbc;
1581 					c += cbs - cbc;
1582 					cbc = 0;
1583 					if (c > 0) {
1584 					/* Use the right kind of blank */
1585 
1586 						switch (conv) {
1587 						case BLOCK:
1588 						case LCBLOCK:
1589 						case UCBLOCK:
1590 							ic = ' ';
1591 							break;
1592 
1593 						case EBCDIC:
1594 						case LCEBCDIC:
1595 						case UCEBCDIC:
1596 							ic = atoe[' '];
1597 							break;
1598 
1599 						case IBM:
1600 						case LCIBM:
1601 						case UCIBM:
1602 							ic = atoibm[' '];
1603 							break;
1604 						}
1605 
1606 						/* Pad with trailing blanks */
1607 
1608 						do {
1609 							*op++ = ic;
1610 						} while (--c);
1611 					}
1612 				}
1613 
1614 			/* If not end of line, this line may be too long */
1615 
1616 				else if (cbc > cbs) {
1617 					skipf = 1; /* note skip in progress */
1618 					obc--;
1619 					op--;
1620 					cbc = 0;
1621 					ntrunc++;  /* count another long line */
1622 				}
1623 
1624 				/* Flush the output buffer if full */
1625 
1626 				while (obc >= obs) {
1627 					op = flsh();
1628 				}
1629 			}
1630 			break;
1631 		}
1632 	}
1633 	/* NOTREACHED */
1634 	return (0);
1635 }
1636 
1637 /* match ************************************************************** */
1638 /*									*/
1639 /* Compare two text strings for equality				*/
1640 /*									*/
1641 /* Arg:		s - pointer to string to match with a command arg	*/
1642 /* Global arg:	string - pointer to command arg				*/
1643 /*									*/
1644 /* Return:	1 if match, 0 if no match				*/
1645 /*		If match, also reset `string' to point to the text	*/
1646 /*		that follows the matching text.				*/
1647 /*									*/
1648 /* ********************************************************************	*/
1649 
1650 static int
1651 match(char *s)
1652 {
1653 	char *cs;
1654 
1655 	cs = string;
1656 	while (*cs++ == *s) {
1657 		if (*s++ == '\0') {
1658 			goto true;
1659 		}
1660 	}
1661 	if (*s != '\0') {
1662 		return (0);
1663 	}
1664 
1665 true:
1666 	cs--;
1667 	string = cs;
1668 	return (1);
1669 }
1670 
1671 /* number ************************************************************* */
1672 /*									*/
1673 /* Convert a numeric arg to binary					*/
1674 /*									*/
1675 /* Arg:		big - maximum valid input number			*/
1676 /* Global arg:	string - pointer to command arg				*/
1677 /*									*/
1678 /* Valid forms:	123 | 123k | 123M | 123G | 123T | 123P | 123E | 123Z |	*/
1679 /*		123w | 123b | 123*123 | 123x123				*/
1680 /*		plus combinations such as 2b*3kw*4w			*/
1681 /*									*/
1682 /* Return:	converted number					*/
1683 /*									*/
1684 /* ********************************************************************	*/
1685 
1686 static unsigned long long
1687 number(long long big)
1688 {
1689 	char *cs;
1690 	long long n;
1691 	long long cut = BIG / 10;	/* limit to avoid overflow */
1692 
1693 	cs = string;
1694 	n = 0;
1695 	while ((*cs >= '0') && (*cs <= '9') && (n <= cut)) {
1696 		n = n * 10 + *cs++ - '0';
1697 	}
1698 	for (;;) {
1699 		switch (*cs++) {
1700 
1701 		case 'Z':
1702 			n *= 1024;
1703 			/* FALLTHROUGH */
1704 
1705 		case 'E':
1706 			n *= 1024;
1707 			/* FALLTHROUGH */
1708 
1709 		case 'P':
1710 			n *= 1024;
1711 			/* FALLTHROUGH */
1712 
1713 		case 'T':
1714 			n *= 1024;
1715 			/* FALLTHROUGH */
1716 
1717 		case 'G':
1718 			n *= 1024;
1719 			/* FALLTHROUGH */
1720 
1721 		case 'M':
1722 			n *= 1024;
1723 			/* FALLTHROUGH */
1724 
1725 		case 'k':
1726 			n *= 1024;
1727 			continue;
1728 
1729 		case 'w':
1730 			n *= 2;
1731 			continue;
1732 
1733 		case 'b':
1734 			n *= BSIZE;
1735 			continue;
1736 
1737 		case '*':
1738 		case 'x':
1739 			string = cs;
1740 			n *= number(BIG);
1741 
1742 		/* FALLTHROUGH */
1743 		/* Fall into exit test, recursion has read rest of string */
1744 		/* End of string, check for a valid number */
1745 
1746 		case '\0':
1747 			if ((n > big) || (n < 0)) {
1748 				(void) fprintf(stderr, "dd: %s \"%llu\"\n",
1749 				    gettext("argument out of range:"), n);
1750 				exit(2);
1751 			}
1752 			return (n);
1753 
1754 		default:
1755 			(void) fprintf(stderr, "dd: %s \"%s\"\n",
1756 			    gettext("bad numeric argument:"), string);
1757 			exit(2);
1758 		}
1759 	} /* never gets here */
1760 }
1761 
1762 /* flsh *************************************************************** */
1763 /*									*/
1764 /* Flush the output buffer, move any excess bytes down to the beginning	*/
1765 /*									*/
1766 /* Arg:		none							*/
1767 /* Global args:	obuf, obc, obs, nofr, nopr, ostriden			*/
1768 /*									*/
1769 /* Return:	Pointer to the first free byte in the output buffer.	*/
1770 /*		Also reset `obc' to account for moved bytes.		*/
1771 /*									*/
1772 /* ********************************************************************	*/
1773 
1774 static unsigned char *
1775 flsh(void)
1776 {
1777 	unsigned char *op, *cp;
1778 	int bc;
1779 	unsigned int oc;
1780 
1781 	if (obc) {			/* don't flush if the buffer is empty */
1782 		if (obc >= obs) {
1783 			oc = obs;
1784 			nofr++;		/* count a full output buffer */
1785 		} else {
1786 			oc = obc;
1787 			nopr++;		/* count a partial output buffer */
1788 		}
1789 		bc = write(obf, (char *)obuf, oc);
1790 		if (bc != oc) {
1791 			if (bc < 0) {
1792 				perror("write");
1793 			} else {
1794 				(void) fprintf(stderr,
1795 				    gettext("dd: unexpected short write, "
1796 				    "wrote %d bytes, expected %d\n"), bc, oc);
1797 			}
1798 			term(2);
1799 		}
1800 
1801 		if (ostriden > 0 && lseek(obf, ostriden * ((off_t)obs),
1802 		    SEEK_CUR) == -1) {
1803 			perror("lseek");
1804 			exit(2);
1805 		}
1806 
1807 		obc -= oc;
1808 		op = obuf;
1809 		obytes += bc;
1810 
1811 		/* If any data in the conversion buffer, move it into */
1812 		/* the output buffer */
1813 
1814 		if (obc) {
1815 			cp = obuf + obs;
1816 			bc = obc;
1817 			do {
1818 				*op++ = *cp++;
1819 			} while (--bc);
1820 		}
1821 		return (op);
1822 	}
1823 	return (obuf);
1824 }
1825 
1826 /* term *************************************************************** */
1827 /*									*/
1828 /* Write record statistics, then exit					*/
1829 /*									*/
1830 /* Arg:		c - exit status code					*/
1831 /*									*/
1832 /* Return:	no return, calls exit					*/
1833 /*									*/
1834 /* ********************************************************************	*/
1835 
1836 static void
1837 term(int c)
1838 {
1839 	stats(B_FALSE);
1840 	exit(c);
1841 }
1842 
1843 /* stats ************************************************************** */
1844 /*									*/
1845 /* Write record statistics onto standard error				*/
1846 /*									*/
1847 /* Args:	main_loop - whether or not we were called from the main */
1848 /*			    loop and need to consider the siginfo	*/
1849 /*			    handler or status=progress output		*/
1850 /* Global args:	nifr, nipr, nofr, nopr, ntrunc, obytes			*/
1851 /*									*/
1852 /* Return:	void							*/
1853 /*									*/
1854 /* ********************************************************************	*/
1855 
1856 static void
1857 stats(boolean_t main_loop)
1858 {
1859 	hrtime_t delta = gethrtime() - startt;
1860 	double secs = delta * 1e-9;
1861 	char bps[NN_NUMBUF_SZ], hobytes[NN_NUMBUF_SZ];
1862 	boolean_t is_progress = B_FALSE;
1863 	const char *head = "";
1864 	const char *tail = "\n";
1865 
1866 	/*
1867 	 * If we've been asked to not print this, then never do.
1868 	 */
1869 	if (status_arg == DD_STATUS_NONE) {
1870 		return;
1871 	}
1872 
1873 	/*
1874 	 * If we came here from the main loop, then we need to go through and
1875 	 * determine if we need to do anything at all. There are two cases that
1876 	 * we will have to do something:
1877 	 *
1878 	 * 1) We were asked to by the siginfo handler
1879 	 * 2) We are here from the status=progress handler and enough time has
1880 	 *    elapsed since the last time we printed (e.g. 1s)
1881 	 *
1882 	 * We always let the siginfo handler take priority here.
1883 	 */
1884 	if (main_loop) {
1885 		if (nstats == 0 && status_arg != DD_STATUS_PROGRESS) {
1886 			return;
1887 		}
1888 
1889 		if (nstats == 0 && status_arg == DD_STATUS_PROGRESS) {
1890 			uint64_t num_secs = delta / NANOSEC;
1891 
1892 			if (num_secs <= prog_secs) {
1893 				return;
1894 			}
1895 
1896 			prog_secs = num_secs;
1897 			is_progress = B_TRUE;
1898 			if (stderr_tty) {
1899 				head = "\r";
1900 				tail = "";
1901 			}
1902 		}
1903 
1904 		if (nstats == 1) {
1905 			nstats = 0;
1906 		}
1907 	}
1908 
1909 	/*
1910 	 * When we output to a tty with status=progress we do so by only
1911 	 * emitting carriage returns and overwriting. This means that when we
1912 	 * come in here for any other reason we need to emit a new line so we
1913 	 * don't end up clobbering anything.
1914 	 *
1915 	 * The progress_printed boolean is basically here to make sure we have
1916 	 * actually printed out a status line that would cause us to need a new
1917 	 * line. If we finished say after a SIGINFO output but before the next
1918 	 * progress output this would result in an extraneous newline.
1919 	 */
1920 	if (!is_progress && status_arg == DD_STATUS_PROGRESS && stderr_tty &&
1921 	    progress_printed) {
1922 		(void) fputc('\n', stderr);
1923 	}
1924 
1925 	if (!is_progress) {
1926 		(void) fprintf(stderr, gettext("%llu+%llu records in\n"),
1927 		    nifr, nipr);
1928 		(void) fprintf(stderr, gettext("%llu+%llu records out\n"),
1929 		    nofr, nopr);
1930 		if (ntrunc) {
1931 			(void) fprintf(stderr,
1932 			    gettext("%llu truncated record(s)\n"), ntrunc);
1933 		}
1934 	}
1935 
1936 	/*
1937 	 * If we got here before we started copying somehow, don't bother
1938 	 * printing the rest.
1939 	 */
1940 	if (startt == 0 || status_arg == DD_STATUS_NOXFER)
1941 		return;
1942 
1943 	nicenum_scale((uint64_t)obytes / secs, 1, bps, sizeof (bps),
1944 	    NN_UNIT_SPACE);
1945 	nicenum_scale(obytes, 1, hobytes, sizeof (hobytes), NN_UNIT_SPACE);
1946 	(void) fprintf(stderr,
1947 	    gettext("%s%llu bytes (%siB) transferred in %.6f secs "
1948 	    "(%siB/sec)%s"), head, obytes, hobytes, secs, bps, tail);
1949 
1950 	progress_printed = is_progress;
1951 }
1952