1 /* @(#)sdd.c	1.72 21/08/20 Copyright 1984-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)sdd.c	1.72 21/08/20 Copyright 1984-2021 J. Schilling";
6 #endif
7 /*
8  *	sdd	Disk and Tape copy
9  *
10  *	Large File remarks:
11  *
12  *	Even platforms without large file support don't limit the
13  *	amount of data that may be read/written to io-streams
14  *	(e.g. stdin/stdout) and tapes. It makes no sense to use
15  *	off_t for several data types. As more platforms support long long
16  *	than large files, we use long long for several important
17  *	variables that should not overflow.
18  *
19  *	Copyright (c) 1984-2021 J. Schilling
20  */
21 /*
22  * The contents of this file are subject to the terms of the
23  * Common Development and Distribution License, Version 1.0 only
24  * (the "License").  You may not use this file except in compliance
25  * with the License.
26  *
27  * See the file CDDL.Schily.txt in this distribution for details.
28  * A copy of the CDDL is also available via the Internet at
29  * http://www.opensource.org/licenses/cddl1.txt
30  *
31  * When distributing Covered Code, include this CDDL HEADER in each
32  * file and include the License file CDDL.Schily.txt from this distribution.
33  */
34 
35 #include <schily/mconfig.h>
36 
37 /*
38  * XXX Until we find a better way, the next definitions must be in sync
39  * XXX with the definitions in librmt/remote.c
40  */
41 #if !defined(HAVE_FORK) || !defined(HAVE_SOCKETPAIR) || !defined(HAVE_DUP2)
42 #undef	USE_RCMD_RSH
43 #endif
44 #if !defined(HAVE_GETSERVBYNAME)
45 #undef	USE_REMOTE				/* Cannot get rcmd() port # */
46 #endif
47 #if (!defined(HAVE_NETDB_H) || !defined(HAVE_RCMD)) && !defined(USE_RCMD_RSH)
48 #undef	USE_REMOTE				/* There is no rcmd() */
49 #endif
50 
51 #include <schily/stdio.h>
52 #include <schily/stdlib.h>
53 #include <schily/unistd.h>
54 #include <schily/signal.h>
55 #include <schily/utypes.h>
56 #include <schily/time.h>
57 #include <schily/standard.h>
58 #include <schily/fcntl.h>
59 #include <schily/string.h>
60 #define	GT_COMERR		/* #define comerr gtcomerr */
61 #define	GT_ERROR		/* #define error gterror   */
62 #include <schily/schily.h>
63 #include <schily/librmt.h>
64 #include <schily/errno.h>
65 #include <schily/md5.h>
66 #include <schily/nlsdefs.h>
67 
68 #ifdef	SIGRELSE
69 #	define	signal	sigset	/* reliable signal */
70 #endif
71 
72 EXPORT	int	main		__PR((int ac, char **av));
73 LOCAL	void	set_signal	__PR((int sig, RETSIGTYPE (*handler)(int)));
74 LOCAL	void	intr		__PR((int sig));
75 LOCAL	FILE 	*openfile	__PR((char *name, char *mode));
76 LOCAL	char	*memalloc	__PR((long size));
77 LOCAL	void	simple_copy	__PR((void));
78 LOCAL	void	copy_reblocked	__PR((void));
79 LOCAL	long	readvol		__PR((char *buf, long len));
80 LOCAL	long	writevol	__PR((char *buf, long len));
81 LOCAL	BOOL	next_in		__PR((void));
82 LOCAL	BOOL	next_out	__PR((void));
83 LOCAL	BOOL	next		__PR((char *fname, char *inout, int fd, long pos, int volnum));
84 LOCAL	BOOL	cont		__PR((char *inout, int num));
85 LOCAL	void	makelower	__PR((char *s));
86 LOCAL	long	readbuf		__PR((char *buf, long len));
87 LOCAL	long	writebuf	__PR((char *buf, long len));
88 LOCAL	long	readblocks	__PR((char *buf, long len));
89 LOCAL	long	writeblocks	__PR((char *buf, long len));
90 LOCAL	void	fill		__PR((char *bp, long start, long end));
91 LOCAL	void	swabb		__PR((char *bp, long cnt));
92 LOCAL	void	lcase		__PR((char *bp, long cnt));
93 LOCAL	void	ucase		__PR((char *bp, long cnt));
94 LOCAL	long	block		__PR((char *bp, long cnt));
95 LOCAL	long	unblock		__PR((char *bp, long cnt));
96 LOCAL	void	conv		__PR((char *bp, long cnt, unsigned char *tab));
97 LOCAL	void	term		__PR((int ret));
98 LOCAL	void	getstarttime	__PR((void));
99 LOCAL	void	prstats		__PR((void));
100 LOCAL	void	getopts		__PR((int ac, char **av));
101 LOCAL	void	usage		__PR((int ex));
102 LOCAL	int	openremote	__PR((char *filename, long iosize));
103 LOCAL	int	ropenfile	__PR((int rfd, char *name, int mode));
104 LOCAL	ssize_t	rread		__PR((void *buf, size_t cnt));
105 LOCAL	ssize_t	rwrite		__PR((void *buf, size_t cnt));
106 LOCAL	off_t	riseek		__PR((off_t pos));
107 LOCAL	off_t	roseek		__PR((off_t pos));
108 LOCAL	off_t	ifsize		__PR((void));
109 
110 LOCAL	void	mdinit		__PR((void));
111 LOCAL	void	mdupdate	__PR((void *a, size_t s));
112 LOCAL	void	mdfinal		__PR((void));
113 
114 #undef	min
115 #define	min(a, b)	((a) < (b) ? (a) : (b))
116 
117 #define	SDD_BSIZE	512L
118 
119 #define	FILL		000001
120 #define	SWAB		000002
121 #define	LCASE		000004
122 #define	UCASE		000010
123 #define	BLOCK		000020
124 #define	UNBLOCK		000040
125 #define	ASCII		000100
126 #define	EBCDIC		000200
127 #define	IBM		000400
128 #define	NULLIN		010000
129 #define	NULLOUT		020000
130 #define	MD5SUM		040000
131 
132 LOCAL	char	*infile;
133 LOCAL	char	*outfile;
134 LOCAL	char	*rmtin;
135 LOCAL	char	*rmtout;
136 
137 LOCAL	FILE	*tty;
138 LOCAL	FILE	*fin;
139 LOCAL	FILE	*fout;
140 LOCAL	int	ifd;
141 LOCAL	int	ofd;
142 LOCAL	int	rmtifd = -1;
143 LOCAL	int	rmtofd = -1;
144 
145 LOCAL	long	ibs;
146 LOCAL	long	obs;
147 LOCAL	long	bs;
148 LOCAL	long	cbs;
149 LOCAL	long	sdd_bsize = SDD_BSIZE;	/* Sector size */
150 LOCAL	Llong	count;
151 LOCAL	off_t	iseek;
152 LOCAL	off_t	oseek;
153 LOCAL	off_t	seek;
154 LOCAL	Llong	iskip;	/* May skip on stdin so it may be more than off_t */
155 LOCAL	Llong	oskip;	/* May skip on stdin so it may be more than off_t */
156 LOCAL	Llong	skip;	/* May skip on stdin so it may be more than off_t */
157 LOCAL	off_t	ivseek;
158 LOCAL	off_t	ovseek;
159 LOCAL	Llong	ivsize;	/* If volume is a tape, it may be more than off_t */
160 LOCAL	Llong	ovsize;	/* If volume is a tape, it may be more than off_t */
161 LOCAL	int	try	= 2;
162 
163 LOCAL	Llong	irec;
164 LOCAL	Llong	orec;
165 LOCAL	Llong	iparts;
166 LOCAL	Llong	oparts;
167 LOCAL	off_t	ivpos;
168 LOCAL	off_t	ovpos;
169 LOCAL	int	ivolnum = 1;
170 LOCAL	int	ovolnum = 1;
171 LOCAL	Llong	readerrs;
172 LOCAL	Llong	writeerrs;
173 LOCAL	Llong	lastreaderrs;
174 #ifdef	timerclear
175 LOCAL	struct	timeval	starttime;
176 LOCAL	struct	timeval	stoptime;
177 #endif
178 
179 LOCAL	int	flags;
180 LOCAL	BOOL	notrunc;
181 LOCAL	BOOL	progress;
182 LOCAL	BOOL	noerror;
183 LOCAL	BOOL	noerrwrite;
184 LOCAL	BOOL	noseek;
185 LOCAL	BOOL	debug;
186 LOCAL	BOOL	showtime;
187 
188 /* ebcdic to ascii */
189 LOCAL	unsigned char	asctab[] = {
190 /*  0 */	0x00,	0x01,	0x02,	0x03,	0x9C,	0x09,	0x86,	0x7F,
191 /*  8 */	0x97,	0x8D,	0x8E,	0x0B,	0x0C,	0x0D,	0x0E,	0x0F,
192 /* 10 */	0x10,	0x11,	0x12,	0x13,	0x9D,	0x85,	0x08,	0x87,
193 /* 18 */	0x18,	0x19,	0x92,	0x8F,	0x1C,	0x1D,	0x1E,	0x1F,
194 /* 20 */	0x80,	0x81,	0x82,	0x83,	0x84,	0x0A,	0x17,	0x1B,
195 /* 28 */	0x88,	0x89,	0x8A,	0x8B,	0x8C,	0x05,	0x06,	0x07,
196 /* 30 */	0x90,	0x91,	0x16,	0x93,	0x94,	0x95,	0x96,	0x04,
197 /* 38 */	0x98,	0x99,	0x9A,	0x9B,	0x14,	0x15,	0x9E,	0x1A,
198 /* 40 */	0x20,	0xA0,	0xA1,	0xA2,	0xA3,	0xA4,	0xA5,	0xA6,
199 /* 48 */	0xA7,	0xA8,	0xD5,	0x2E,	0x3C,	0x28,	0x2B,	0x7C,
200 /* 50 */	0x26,	0xA9,	0xAA,	0xAB,	0xAC,	0xAD,	0xAE,	0xAF,
201 /* 58 */	0xB0,	0xB1,	0x21,	0x24,	0x2A,	0x29,	0x3B,	0x7E,
202 /* 60 */	0x2D,	0x2F,	0xB2,	0xB3,	0xB4,	0xB5,	0xB6,	0xB7,
203 /* 68 */	0xB8,	0xB9,	0xCB,	0x2C,	0x25,	0x5F,	0x3E,	0x3F,
204 /* 70 */	0xBA,	0xBB,	0xBC,	0xBD,	0xBE,	0xBF,	0xC0,	0xC1,
205 /* 78 */	0xC2,	0x60,	0x3A,	0x23,	0x40,	0x27,	0x3D,	0x22,
206 /* 80 */	0xC3,	0x61,	0x62,	0x63,	0x64,	0x65,	0x66,	0x67,
207 /* 88 */	0x68,	0x69,	0xC4,	0xC5,	0xC6,	0xC7,	0xC8,	0xC9,
208 /* 90 */	0xCA,	0x6A,	0x6B,	0x6C,	0x6D,	0x6E,	0x6F,	0x70,
209 /* 98 */	0x71,	0x72,	0x5E,	0xCC,	0xCD,	0xCE,	0xCF,	0xD0,
210 /* A0 */	0xD1,	0xE5,	0x73,	0x74,	0x75,	0x76,	0x77,	0x78,
211 /* A8 */	0x79,	0x7A,	0xD2,	0xD3,	0xD4,	0x5B,	0xD6,	0xD7,
212 /* B0 */	0xD8,	0xD9,	0xDA,	0xDB,	0xDC,	0xDD,	0xDE,	0xDF,
213 /* B8 */	0xE0,	0xE1,	0xE2,	0xE3,	0xE4,	0x5D,	0xE6,	0xE7,
214 /* C0 */	0x7B,	0x41,	0x42,	0x43,	0x44,	0x45,	0x46,	0x47,
215 /* C8 */	0x48,	0x49,	0xE8,	0xE9,	0xEA,	0xEB,	0xEC,	0xED,
216 /* D0 */	0x7D,	0x4A,	0x4B,	0x4C,	0x4D,	0x4E,	0x4F,	0x50,
217 /* D8 */	0x51,	0x52,	0xEE,	0xEF,	0xF0,	0xF1,	0xF2,	0xF3,
218 /* E0 */	0x5C,	0x9F,	0x53,	0x54,	0x55,	0x56,	0x57,	0x58,
219 /* E8 */	0x59,	0x5A,	0xF4,	0xF5,	0xF6,	0xF7,	0xF8,	0xF9,
220 /* F0 */	0x30,	0x31,	0x32,	0x33,	0x34,	0x35,	0x36,	0x37,
221 /* F8 */	0x38,	0x39,	0xFA,	0xFB,	0xFC,	0xFD,	0xFE,	0xFF,
222 };
223 
224 /* ascii to ebcdic */
225 
226 LOCAL	unsigned char	ebctab[] = {
227 
228 /*	0	1	2	3	4	5	6	7	*/
229 /*  0	NUL(@)	SOH(A)	STX(B)	ETX(C)	EOT(D)	ENQ(E)	ACK(F)	BEL(G)	*/
230 	0x00,	0x01,	0x02,	0x03,	0x37,	0x2D,	0x2E,	0x2F,
231 
232 /*  8	BS(H)	HT(I)	LF(J)	VT(K)	FF(L)	CR(M)	SO(N)	SI(O)	*/
233 	0x16,	0x05,	0x25,	0x0B,	0x0C,	0x0D,	0x0E,	0x0F,
234 
235 /* 10	DLE(P)	DC1(Q)	DC2(R)	DC3(S)	DC4(T)	NAK(U)	SYN(V)	ETB(W)	*/
236 	0x10,	0x11,	0x12,	0x13,	0x3C,	0x3D,	0x32,	0x26,
237 
238 /* 18	CAN(X)	EM(Y)	SUB(Z)	ESC([)	FS(\)	GS(])	RS(^)	US(_)	*/
239 	0x18,	0x19,	0x3F,	0x27,	0x1C,	0x1D,	0x1E,	0x1F,
240 
241 /* 20	SP	!	"	#	$	%	&	'	*/
242 	0x40,	0x5A,	0x7F,	0x7B,	0x5B,	0x6C,	0x50,	0x7D,
243 
244 /* 28	(	)	*	+	,	-	.	/	*/
245 	0x4D,	0x5D,	0x5C,	0x4E,	0x6B,	0x60,	0x4B,	0x61,
246 
247 /* 30	0	1	2	3	4	5	6	7	*/
248 	0xF0,	0xF1,	0xF2,	0xF3,	0xF4,	0xF5,	0xF6,	0xF7,
249 
250 /* 38	8	9	:	;	<	=	>	?	*/
251 	0xF8,	0xF9,	0x7A,	0x5E,	0x4C,	0x7E,	0x6E,	0x6F,
252 
253 /* 40	@	A	B	C	D	E	F	G	*/
254 	0x7C,	0xC1,	0xC2,	0xC3,	0xC4,	0xC5,	0xC6,	0xC7,
255 
256 /* 48	H	I	J	K	L	M	N	O	*/
257 	0xC8,	0xC9,	0xD1,	0xD2,	0xD3,	0xD4,	0xD5,	0xD6,
258 
259 /* 50	P	Q	R	S	T	U	V	W	*/
260 	0xD7,	0xD8,	0xD9,	0xE2,	0xE3,	0xE4,	0xE5,	0xE6,
261 
262 /* 58	X	Y	Z	[	\	]	^ ??	_	*/
263 	0xE7,	0xE8,	0xE9,	0xAD,	0xE0,	0xBD,	0x9A,	0x6D,
264 
265 /* 60	`	a	b	c	d	e	f	g	*/
266 	0x79,	0x81,	0x82,	0x83,	0x84,	0x85,	0x86,	0x87,
267 
268 /* 68	h	i	j	k	l	m	n	o	*/
269 	0x88,	0x89,	0x91,	0x92,	0x93,	0x94,	0x95,	0x96,
270 
271 /* 70	p	q	r	s	t	u	v	w	*/
272 	0x97,	0x98,	0x99,	0xA2,	0xA3,	0xA4,	0xA5,	0xA6,
273 
274 /* 78	x	y	z	{	|	}	~ ??	DEL	*/
275 	0xA7,	0xA8,	0xA9,	0xC0,	0x4F,	0xD0,	0x5F,	0x07,
276 
277 /* 80	NUL(@)	SOH(A)	STX(B)	ETX(C)	EOT(D)	ENQ(E)	ACK(F)	BEL(G)	*/
278 	0xC3,	0x61,	0x62,	0x63,	0x64,	0x65,	0x66,	0x67,
279 
280 /* 88	BS(H)	HT(I)	LF(J)	VT(K)	FF(L)	CR(M)	SO(N)	SI(O)	*/
281 	0x68,	0x69,	0xC4,	0xC5,	0xC6,	0xC7,	0xC8,	0xC9,
282 
283 /* 90	DLE(P)	DC1(Q)	DC2(R)	DC3(S)	DC4(T)	NAK(U)	SYN(V)	ETB(W)	*/
284 	0xCA,	0x6A,	0x6B,	0x6C,	0x6D,	0x6E,	0x6F,	0x70,
285 
286 /* 98	CAN(X)	EM(Y)	SUB(Z)	ESC([)	FS(\)	GS(])	RS(^)	US(_)	*/
287 	0x71,	0x72,	0x5E,	0xCC,	0xCD,	0xCE,	0xCF,	0xD0,
288 
289 /* A0	SP	!	"	#	$	%	&	'	*/
290 	0xD1,	0xE5,	0x73,	0x74,	0x75,	0x76,	0x77,	0x78,
291 
292 /* A8	(	)	*	+	,	-	.	/	*/
293 	0x79,	0x7A,	0xD2,	0xD3,	0xD4,	0x5B,	0xD6,	0xD7,
294 
295 /* B0	0	1	2	3	4	5	6	7	*/
296 	0xD8,	0xD9,	0xDA,	0xDB,	0xDC,	0xDD,	0xDE,	0xDF,
297 
298 /* B8	8	9	:	;	<	=	>	?	*/
299 	0xE0,	0xE1,	0xE2,	0xE3,	0xE4,	0x5D,	0xE6,	0xE7,
300 
301 /* C0	@	A	B	C	D	E	F	G	*/
302 	0x7B,	0x41,	0x42,	0x43,	0x44,	0x45,	0x46,	0x47,
303 
304 /* C8	H	I	J	K	L	M	N	O	*/
305 	0x48,	0x49,	0xE8,	0xE9,	0xEA,	0xEB,	0xEC,	0xED,
306 
307 /* D0	P	Q	R	S	T	U	V	W	*/
308 	0x7D,	0x4A,	0x4B,	0x4C,	0x4D,	0x4E,	0x4F,	0x50,
309 
310 /* D8	X	Y	Z	[	\	]	^	_	*/
311 	0x51,	0x52,	0xEE,	0xEF,	0xF0,	0xF1,	0xF2,	0xF3,
312 
313 /* E0	`	a	b	c	d	e	f	g	*/
314 	0x5C,	0x9F,	0x53,	0x54,	0x55,	0x56,	0x57,	0x58,
315 
316 /* E8	h	i	j	k	l	m	n	o	*/
317 	0x59,	0x5A,	0xF4,	0xF5,	0xF6,	0xF7,	0xF8,	0xF9,
318 
319 /* F0	p	q	r	s	t	u	v	w	*/
320 	0x30,	0x31,	0x32,	0x33,	0x34,	0x35,	0x36,	0x37,
321 
322 /* F8	x	y	z	{	|	}	~	DEL	*/
323 	0x38,	0x39,	0xFA,	0xFB,	0xFC,	0xFD,	0xFE,	0xFF,
324 };
325 
326 /* ascii to ibm */
327 LOCAL	unsigned char	ibmtab[] = {
328 
329 /*	0	1	2	3	4	5	6	7	*/
330 /*  0	NUL(@)	SOH(A)	STX(B)	ETX(C)	EOT(D)	ENQ(E)	ACK(F)	BEL(G)	*/
331 	0x00,	0x01,	0x02,	0x03,	0x37,	0x2D,	0x2E,	0x2F,
332 
333 /*  8	BS(H)	HT(I)	LF(J)	VT(K)	FF(L)	CR(M)	SO(N)	SI(O)	*/
334 	0x16,	0x05,	0x25,	0x0B,	0x0C,	0x0D,	0x0E,	0x0F,
335 
336 /* 10	DLE(P)	DC1(Q)	DC2(R)	DC3(S)	DC4(T)	NAK(U)	SYN(V)	ETB(W)	*/
337 	0x10,	0x11,	0x12,	0x13,	0x3C,	0x3D,	0x32,	0x26,
338 
339 /* 18	CAN(X)	EM(Y)	SUB(Z)	ESC([)	FS(\)	GS(])	RS(^)	US(_)	*/
340 	0x18,	0x19,	0x3F,	0x27,	0x1C,	0x1D,	0x1E,	0x1F,
341 
342 /* 20	SP	!	"	#	$	%	&	'	*/
343 	0x40,	0x5A,	0x7F,	0x7B,	0x5B,	0x6C,	0x50,	0x7D,
344 
345 /* 28	(	)	*	+	,	-	.	/	*/
346 	0x4D,	0x5D,	0x5C,	0x4E,	0x6B,	0x60,	0x4B,	0x61,
347 
348 /* 30	0	1	2	3	4	5	6	7	*/
349 	0xF0,	0xF1,	0xF2,	0xF3,	0xF4,	0xF5,	0xF6,	0xF7,
350 
351 /* 38	8	9	:	;	<	=	>	?	*/
352 	0xF8,	0xF9,	0x7A,	0x5E,	0x4C,	0x7E,	0x6E,	0x6F,
353 
354 /* 40	@	A	B	C	D	E	F	G	*/
355 	0x7C,	0xC1,	0xC2,	0xC3,	0xC4,	0xC5,	0xC6,	0xC7,
356 
357 /* 48	H	I	J	K	L	M	N	O	*/
358 	0xC8,	0xC9,	0xD1,	0xD2,	0xD3,	0xD4,	0xD5,	0xD6,
359 
360 /* 50	P	Q	R	S	T	U	V	W	*/
361 	0xD7,	0xD8,	0xD9,	0xE2,	0xE3,	0xE4,	0xE5,	0xE6,
362 
363 /* 58	X	Y	Z	[	\	]	^	_	*/
364 	0xE7,	0xE8,	0xE9,	0xAD,	0xE0,	0xBD,	0x5F,	0x6D,
365 
366 /* 60	`	a	b	c	d	e	f	g	*/
367 	0x79,	0x81,	0x82,	0x83,	0x84,	0x85,	0x86,	0x87,
368 
369 /* 68	h	i	j	k	l	m	n	o	*/
370 	0x88,	0x89,	0x91,	0x92,	0x93,	0x94,	0x95,	0x96,
371 
372 /* 70	p	q	r	s	t	u	v	w	*/
373 	0x97,	0x98,	0x99,	0xA2,	0xA3,	0xA4,	0xA5,	0xA6,
374 
375 /* 78	x	y	z	{	|	}	~	DEL	*/
376 	0xA7,	0xA8,	0xA9,	0xC0,	0x4F,	0xD0,	0xA1,	0x07,
377 
378 /* 80	NUL(@)	SOH(A)	STX(B)	ETX(C)	EOT(D)	ENQ(E)	ACK(F)	BEL(G)	*/
379 	0x20,	0x21,	0x22,	0x23,	0x24,	0x15,	0x06,	0x17,
380 
381 /* 88	BS(H)	HT(I)	LF(J)	VT(K)	FF(L)	CR(M)	SO(N)	SI(O)	*/
382 	0x28,	0x29,	0x2A,	0x2B,	0x2C,	0x09,	0x0A,	0x1B,
383 
384 /* 90	DLE(P)	DC1(Q)	DC2(R)	DC3(S)	DC4(T)	NAK(U)	SYN(V)	ETB(W)	*/
385 	0x30,	0x31,	0x1A,	0x33,	0x34,	0x35,	0x36,	0x0B,
386 
387 /* 98	CAN(X)	EM(Y)	SUB(Z)	ESC([)	FS(\)	GS(])	RS(^)	US(_)	*/
388 	0x38,	0x39,	0x3A,	0x3B,	0x04,	0x14,	0x3E,	0xE1,
389 
390 /* A0	SP	!	"	#	$	%	&	'	*/
391 	0x41,	0x42,	0x43,	0x44,	0x45,	0x46,	0x47,	0x48,
392 
393 /* A8	(	)	*	+	,	-	.	/	*/
394 	0x49,	0x51,	0x52,	0x53,	0x54,	0x55,	0x56,	0x57,
395 
396 /* B0	0	1	2	3	4	5	6	7	*/
397 	0x58,	0x59,	0x62,	0x63,	0x64,	0x65,	0x66,	0x67,
398 
399 /* B8	8	9	:	;	<	=	>	?	*/
400 	0x68,	0x69,	0x70,	0x71,	0x72,	0x73,	0x74,	0x75,
401 
402 /* C0	@	A	B	C	D	E	F	G	*/
403 	0x76,	0x77,	0x78,	0x80,	0x8A,	0x8B,	0x8C,	0x8D,
404 
405 /* C8	H	I	J	K	L	M	N	O	*/
406 	0x8E,	0x8F,	0x90,	0x6A,	0x9B,	0x9C,	0x9D,	0x9E,
407 
408 /* D0	P	Q	R	S	T	U	V	W	*/
409 	0x9F,	0xA0,	0xAA,	0xAB,	0xAC,	0x4A,	0xAE,	0xAF,
410 
411 /* D8	X	Y	Z	[	\	]	^	_	*/
412 	0xB0,	0xB1,	0xB2,	0xB3,	0xB4,	0xB5,	0xB6,	0xB7,
413 
414 /* E0	`	a	b	c	d	e	f	g	*/
415 	0xB8,	0xB9,	0xBA,	0xBB,	0xBC,	0xA1,	0xBE,	0xBF,
416 
417 /* E8	h	i	j	k	l	m	n	o	*/
418 	0xCA,	0xCB,	0xCC,	0xCD,	0xCE,	0xCF,	0xDA,	0xDB,
419 
420 /* F0	p	q	r	s	t	u	v	w	*/
421 	0xDC,	0xDD,	0xDE,	0xDF,	0xEA,	0xEB,	0xEC,	0xED,
422 
423 /* F8	x	y	z	{	|	}	~	DEL	*/
424 	0xEE,	0xEF,	0xFA,	0xFB,	0xFC,	0xFD,	0xFE,	0xFF,
425 };
426 
427 
428 EXPORT int
main(ac,av)429 main(ac, av)
430 	int	ac;
431 	char	*av[];
432 {
433 	int	ret = 0;
434 
435 	save_args(ac, av);
436 
437 	(void) setlocale(LC_ALL, "");
438 
439 #ifdef  USE_NLS
440 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
441 #define	TEXT_DOMAIN "sdd"	/* Use this only if it weren't */
442 #endif
443 	{ char	*dir;
444 	dir = searchfileinpath("share/locale", F_OK,
445 					SIP_ANY_FILE|SIP_NO_PATH, NULL);
446 	if (dir)
447 		(void) bindtextdomain(TEXT_DOMAIN, dir);
448 	else
449 #if defined(PROTOTYPES) && defined(INS_BASE)
450 	(void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
451 #else
452 	(void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
453 #endif
454 	(void) textdomain(TEXT_DOMAIN);
455 	}
456 #endif 	/* USE_NLS */
457 
458 	getopts(ac, av);
459 	tty = stdin;
460 
461 	getstarttime();
462 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
463 		(void) set_signal(SIGINT, intr);
464 #ifdef	SIGQUIT
465 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
466 		(void) set_signal(SIGQUIT, intr);
467 #endif
468 #ifdef	SIGINFO
469 	/*
470 	 * Be polite to *BSD users.
471 	 * They copied our idea and implemented intermediate status
472 	 * printing in 'dd' in 1990.
473 	 */
474 	if (signal(SIGINFO, SIG_IGN) != SIG_IGN)
475 		(void) set_signal(SIGINFO, intr);
476 #endif
477 
478 #ifdef	USE_REMOTE
479 	rmtdebug(debug);
480 	if (infile)
481 		rmtin = rmtfilename(infile);
482 	if (outfile)
483 		rmtout = rmtfilename(outfile);
484 	if (rmtin)
485 		rmtifd = openremote(infile, ibs); /* Needs root privilleges */
486 
487 	if (rmtout)
488 		rmtofd = openremote(outfile, obs); /* Needs root privilleges */
489 #endif
490 
491 
492 	if (geteuid() != getuid()) {	/* AIX does not like to do this */
493 					/* If we are not root		*/
494 #ifdef	HAVE_SETREUID
495 		if (setreuid(-1, getuid()) < 0)
496 #else
497 #ifdef	HAVE_SETEUID
498 		if (seteuid(getuid()) < 0)
499 #else
500 		if (setuid(getuid()) < 0)
501 #endif
502 #endif
503 			comerr("Panic cannot set back effective uid.\n");
504 	}
505 
506 	if (infile) {
507 		if (rmtin) {
508 			ropenfile(rmtifd, rmtin, O_RDONLY);
509 		} else {
510 			fin = openfile(infile, "ru");
511 		}
512 	} else {
513 		fin = stdin;
514 		setbuf(fin, NULL);
515 		file_raise(fin, FALSE);
516 		infile = "stdin";
517 		if (ivsize != 0 || ovsize != 0)
518 #ifdef	HAVE__DEV_TTY
519 			tty = openfile("/dev/tty", "r");
520 #else
521 			tty = stderr;
522 #endif
523 	}
524 	if (outfile) {
525 		if (rmtout) {
526 			ropenfile(rmtofd, rmtout,
527 					notrunc ?
528 					(O_WRONLY|O_CREAT):
529 					(O_WRONLY|O_CREAT|O_TRUNC));
530 		} else {
531 			fout = openfile(outfile,
532 					notrunc ? "wcu" : "wctu");
533 		}
534 	} else {
535 		fout = stdout;
536 		setbuf(fout, NULL);
537 		file_raise(fout, FALSE);
538 		outfile = "stdout";
539 	}
540 	if (rmtin)
541 		ifd = rmtifd;
542 	else
543 		ifd = fdown(fin);
544 	if (rmtout)
545 		ofd = rmtofd;
546 	else
547 		ofd = fdown(fout);
548 
549 	ivpos = iseek + ivseek;
550 	ovpos = oseek + ovseek;
551 	(void) riseek(ivpos);
552 	(void) roseek(ovpos);
553 
554 	if (flags & MD5SUM)
555 		mdinit();
556 
557 	getstarttime();
558 
559 	if ((obs != ibs) ||
560 	    (flags & (BLOCK|UNBLOCK)) ||	/* Reblock forced uncond.   */
561 	    (ivsize && !(flags & NULLOUT)) ||	/* Reblock at end of vol    */
562 	    (ovsize &&
563 	    (((ovsize - ovpos) % obs) ||	/* Reblock at end of 1st vol */
564 	    ((ovsize - ovseek) % obs))))	/* Reblock at end of 2nd vol */
565 		copy_reblocked();
566 	else
567 		simple_copy();
568 
569 	term(ret);
570 	return (0);	/* Keep lint happy */
571 }
572 
573 LOCAL void
set_signal(sig,handler)574 set_signal(sig, handler)
575 	int		sig;
576 	RETSIGTYPE	(*handler)	__PR((int));
577 {
578 #if	defined(HAVE_SIGPROCMASK) && defined(SA_RESTART)
579 	struct sigaction sa;
580 
581 	sigemptyset(&sa.sa_mask);
582 	sa.sa_handler = handler;
583 	sa.sa_flags = SA_RESTART;
584 	(void) sigaction(sig, &sa, (struct sigaction *)0);
585 #else
586 #ifdef	HAVE_SIGSETMASK
587 	struct sigvec	sv;
588 
589 	sv.sv_mask = 0;
590 	sv.sv_handler = handler;
591 	sv.sv_flags = 0;
592 	(void) sigvec(sig, &sv, (struct sigvec *)0);
593 #else
594 	(void) signal(sig, handler);
595 #endif
596 #endif
597 }
598 
599 LOCAL void
intr(sig)600 intr(sig)
601 	int	sig;
602 {
603 	(void) signal(sig, intr);
604 	prstats();
605 	if (sig == SIGINT) {
606 		errmsgno(EX_BAD, "KILLED by SIGINT.\n");
607 		exit(SIGINT);
608 	}
609 }
610 
611 LOCAL FILE *
openfile(name,mode)612 openfile(name, mode)
613 	char	*name;
614 	char	*mode;
615 {
616 	FILE	*f;
617 
618 	if ((f = fileopen(name, mode)) == (FILE *) NULL)
619 		comerr("Can't open '%s'.\n", name);
620 	file_raise(f, FALSE);
621 	return (f);
622 }
623 
624 #undef	roundup
625 #define	roundup(x, y)	((((x)+((y)-1))/(y))*(y))
626 
627 LOCAL char *
memalloc(size)628 memalloc(size)
629 	long	size;
630 {
631 	char	*ret;
632 	unsigned int pagesize = 512;
633 	UIntptr_t l;
634 
635 #ifdef	HAVE_GETPAGESIZE
636 	pagesize = getpagesize();
637 #else
638 #ifdef	_SC_PAGESIZE
639 	pagesize = sysconf(_SC_PAGESIZE);
640 #endif
641 #endif
642 	if ((ret = malloc((size_t)(size+pagesize))) == NULL)
643 		comerr("No memory.\n");
644 
645 	l = (UIntptr_t)ret;
646 	l = roundup(l, pagesize);
647 	ret = (char *)l;
648 
649 	return (ret);
650 }
651 
652 /*
653  * Simple copy
654  *
655  * Input buffer size == output buffer size.
656  */
657 LOCAL void
simple_copy()658 simple_copy()
659 {
660 	register long	obcnt;
661 	register long	cnt;
662 	register char	*obp;
663 	register int	rflags;
664 
665 	if (debug)
666 		error("Simple copy ...\n");
667 
668 	obp = memalloc(bs);	/* obs == ibs == bs */
669 	rflags = flags;
670 
671 	if (rflags & NULLIN)
672 		fill(obp, 0L, bs);
673 
674 	while ((cnt = readvol(obp, bs)) > 0) {
675 		if (rflags & NULLOUT) {
676 			if (progress && !debug) {
677 				(void) putc('.', stderr);
678 				(void) fflush(stderr);
679 			}
680 			continue;
681 		}
682 		if (cnt < bs && (rflags & FILL)) {
683 			fill(obp, cnt, bs);
684 			cnt = bs;
685 		}
686 		for (obcnt = 0; obcnt < cnt; )
687 			obcnt += writevol(obp + obcnt, (long) (cnt - obcnt));
688 	}
689 }
690 
691 /*
692  * Copy reblocked
693  *
694  * Input buffer size != output buffer size or any other condition
695  * that forces us to use not the simple method.
696  */
697 LOCAL void
copy_reblocked()698 copy_reblocked()
699 {
700 	register long	obcnt = 0;
701 	register long	cnt;
702 	register char	*obp;
703 
704 	if (debug)
705 		error("Copy reblocked ...\n");
706 
707 	obp = memalloc((long) (obs + ibs));
708 
709 	while ((cnt = readvol(obp + obcnt, ibs)) > 0) {
710 		obcnt += cnt;
711 		cnt = 0;
712 		for (cnt = 0; obcnt - cnt >= obs; )
713 			cnt += writevol(obp + cnt, obs);
714 		if (cnt != 0) {
715 			if (obcnt > cnt) {
716 				if (debug)
717 					error("Moving down %ld bytes.\n",
718 								obcnt - cnt);
719 				(void) movebytes(obp + cnt, obp, obcnt - cnt);
720 			}
721 			obcnt -= cnt;
722 		}
723 	}
724 	if (obcnt > 0) {
725 		if (debug)
726 			error("Writing tail of %ld bytes\n", obcnt);
727 		if (flags & FILL) {
728 			fill(obp, obcnt, obs);
729 			obcnt = obs;
730 		}
731 		cnt = 0;
732 		while (obcnt - cnt > 0)
733 			cnt += writevol(obp + cnt, (long) (obcnt - cnt));
734 	}
735 }
736 
737 /*
738  * Read one input block from the input volume.
739  * Switch to the next input volume if needed.
740  * Do conversions.
741  */
742 LOCAL long
readvol(buf,len)743 readvol(buf, len)
744 	char	*buf;
745 	long	len;
746 {
747 	Llong	left;
748 	long	cnt;
749 	register int	rflags;
750 
751 	rflags = flags;
752 
753 	if (count != 0 && irec >= count)
754 		return (0);
755 
756 	if (rflags & NULLIN) {
757 		irec++;
758 		return (len);
759 	}
760 
761 	if (ivsize == 0) {
762 		cnt = readbuf(buf, len);
763 	} else for (;;) {
764 		if ((left = ivsize - ivpos) > 0) {
765 			if ((cnt = readbuf(buf, (long) min(len, left))) > 0)
766 				break;
767 		}
768 		if (!next_in())
769 			return (0);
770 	}
771 	ivpos += cnt;
772 	if (cnt == ibs)
773 		irec++;
774 	else
775 		iparts += cnt;
776 	if (rflags & NULLOUT)
777 		return (cnt);
778 	if (rflags & SWAB)
779 		swabb(buf, cnt);
780 	if (rflags & ASCII)
781 		conv(buf, cnt, asctab);
782 	if (rflags & LCASE)
783 		lcase(buf, cnt);
784 	if (rflags & UCASE)
785 		ucase(buf, cnt);
786 	if (rflags & BLOCK)
787 		cnt = block(buf, cnt);
788 	if (rflags & UNBLOCK)
789 		cnt = unblock(buf, cnt);
790 	if (rflags & EBCDIC)
791 		conv(buf, cnt, ebctab);
792 	if (rflags & IBM)
793 		conv(buf, cnt, ibmtab);
794 	return (cnt);
795 }
796 
797 /*
798  * Write one block to the output volume.
799  * Switch to the next output volume if needed.
800  */
801 LOCAL long
writevol(buf,len)802 writevol(buf, len)
803 	char	*buf;
804 	long	len;
805 {
806 	long cnt;
807 
808 	if (ovsize != 0) {
809 		if (ovpos >= ovsize)
810 			if (!next_out())
811 				term(EX_BAD);
812 		len = min(len, ovsize - ovpos);
813 	}
814 	cnt = writebuf(buf, len);
815 	ovpos += cnt;
816 	if (cnt == obs)
817 		orec++;
818 	else
819 		oparts += cnt;
820 	return (cnt);
821 }
822 
823 /*
824  * Switch to next input volume.
825  */
826 LOCAL BOOL
next_in()827 next_in()
828 {
829 	return (next(infile, "input", ifd, ivpos = ivseek, ivolnum++));
830 }
831 
832 /*
833  * Switch to next ouput volume.
834  */
835 LOCAL BOOL
next_out()836 next_out()
837 {
838 	return (next(outfile, "output", ofd, ovpos = ovseek, ovolnum++));
839 }
840 
841 /*
842  * Switch to next I/O volume.
843  */
844 LOCAL BOOL
next(fname,inout,fd,pos,volnum)845 next(fname, inout, fd, pos, volnum)
846 	char	*fname;
847 	char	*inout;
848 	int	fd;
849 	long	pos;
850 	int	volnum;
851 {
852 	if (progress || debug) {
853 		(void) putc('\n', stderr);
854 		(void) fflush(stderr);
855 	}
856 	errmsgno(EX_BAD, "Done with %s volume # %d.\n", inout, volnum);
857 	if (!cont(inout, ++volnum))
858 		return (FALSE);
859 	error("Insert %s volume # %d in '%s' and then hit <cr>: ",
860 						inout, volnum, fname);
861 	(void) fflush(stderr);
862 	while (getc(tty) != '\n')
863 		if (feof(tty))
864 			return (FALSE);
865 	error("Working on %s volume # %d of '%s'.\n", inout, volnum, fname);
866 	if (fd == ifd)
867 		(void) riseek(pos);
868 	else
869 		(void) roseek(pos);
870 	return (TRUE);
871 }
872 
873 LOCAL BOOL
cont(inout,num)874 cont(inout, num)
875 	char	*inout;
876 	int	num;
877 {
878 		char	answer [16];
879 	register char	*ap;
880 
881 	for (;;) {
882 		error("Do you want to continue with %s volume # %d (y/n): ",
883 						inout, num);
884 		(void) fflush(stderr);
885 		ap = answer;
886 		if (fgetline(tty, ap, 16) == EOF)
887 			return (FALSE);
888 		while (*ap == ' ' || *ap == '\t')
889 			ap++;
890 		makelower(ap);
891 		if (streql(ap, "y") || streql(ap, "yes"))
892 			return (TRUE);
893 		if (streql(ap, "n") || streql(ap, "no"))
894 			return (FALSE);
895 	}
896 }
897 
898 LOCAL void
makelower(s)899 makelower(s)
900 	register char	*s;
901 {
902 	while (*s) {
903 		if (*s >= 'A' && *s <= 'Z')
904 			*s += 'a' - 'A';
905 		else if (*s == ' ' || *s == '\t') {
906 			*s = '\0';
907 			return;
908 		}
909 		s++;
910 	}
911 }
912 
913 /*
914  * Read one input block.
915  * Call readblocks if an error occured and -noerror has been specified.
916  */
917 LOCAL long
readbuf(buf,len)918 readbuf(buf, len)
919 	char	*buf;
920 	long	len;
921 {
922 	long	cnt;
923 	int	err = 0;
924 
925 	lastreaderrs = (Llong)0;
926 	if (debug) {
927 		error("readbuf  (%d, %p, %ld) ", ifd, (void *)buf, len);
928 		(void) fflush(stderr);
929 	}
930 	if (noerror && noseek)
931 		fill(buf, 0L, len);
932 	cnt = rread(buf, len);
933 	if (debug) {
934 		if (cnt < 0)
935 			err = geterrno();
936 		error("= %ld\n", cnt);
937 	}
938 	if (cnt < 0) {
939 		if (!debug)
940 			err = geterrno();
941 		if (progress && !debug)
942 			(void) putc('\n', stderr);
943 		errmsgno(err, "Error reading '%s'.\n", infile);
944 #ifdef	ECONNRESET
945 		if (noerror && err != EPIPE && err != ECONNRESET) {
946 #else
947 		if (noerror && err != EPIPE) {
948 #endif
949 			seterrno(err);
950 			cnt = readblocks(buf, len);
951 		} else {
952 			term(err);
953 		}
954 	}
955 	if (cnt == 0)
956 		if (count != 0 && ivsize == 0) {
957 			if (progress || debug)
958 				(void) putc('\n', stderr);
959 			errmsgno(EX_BAD, "END OF FILE\n");
960 		}
961 
962 	if ((flags & (NULLOUT|MD5SUM)) == (NULLOUT|MD5SUM))
963 		mdupdate(buf, cnt);
964 	return (cnt);
965 }
966 
967 /*
968  * Write one output block.
969  * Call writeblocks if an error occured and -noerror has been specified.
970  */
971 LOCAL long
writebuf(buf,len)972 writebuf(buf, len)
973 	char	*buf;
974 	long	len;
975 {
976 	long	cnt;
977 	int	err = 0;
978 
979 	if (debug)
980 		error("writebuf (%d, %p, %ld)\n", ofd, (void *)buf, len);
981 	if ((lastreaderrs > (Llong)0) && noerrwrite) {
982 		if (debug)
983 			error("seek(%d, %lld)\n", ofd, (Llong)(ovpos + len));
984 		if (roseek(ovpos + len) == (off_t)-1) {
985 			err = geterrno();
986 			if (progress && !debug)
987 				(void) putc('\n', stderr);
988 			errmsgno((int) err, "Error seeking '%s'.\n", outfile);
989 		}
990 		cnt = len;
991 	} else if ((cnt = rwrite(buf, len)) <= 0) {
992 		if (debug)
993 			error("rwrite() -> cnt %ld\n", cnt);
994 		if (cnt == 0)		/* EOF */
995 			err = ENDOFFILE;
996 		else if (cnt < 0)
997 			err = geterrno();
998 		if (progress && !debug)
999 			(void) putc('\n', stderr);
1000 		errmsgno((int) err, "Error writing '%s'.\n", outfile);
1001 		if (noerror &&
1002 #ifdef	ECONNRESET
1003 		    err != ENDOFFILE && err != EPIPE && err != ECONNRESET) {
1004 #else
1005 		    err != ENDOFFILE && err != EPIPE) {
1006 #endif
1007 			seterrno(err);
1008 			cnt = writeblocks(buf, len);
1009 		} else {
1010 			term((int) err);
1011 		}
1012 	}
1013 	if (progress && !debug) {
1014 		(void) putc('.', stderr);
1015 		(void) fflush(stderr);
1016 	}
1017 	if ((flags & (NULLOUT|MD5SUM)) == MD5SUM)
1018 		mdupdate(buf, cnt);
1019 	return (cnt);
1020 }
1021 
1022 /*
1023  * Input error recovery
1024  */
1025 LOCAL long
readblocks(buf,len)1026 readblocks(buf, len)
1027 	register char	*buf;
1028 	register long	len;
1029 {
1030 	register long	cnt;
1031 	register long	aktlen;
1032 	register int	trys;
1033 	register off_t	pos = ivpos;
1034 	register long	total = 0;
1035 		int	err = 0;
1036 
1037 	if (noseek) {
1038 		errmsgno(EX_BAD, "Can't read %ld Bytes at %lld\n",
1039 							len, (Llong)pos);
1040 		readerrs++;
1041 		return (len);
1042 	} else {
1043 		errmsgno(EX_BAD,
1044 			"Retrying to read %ld Bytes at %lld (Block %lld)\n",
1045 			len, (Llong)pos, (Llong)pos/(Llong)sdd_bsize);
1046 	}
1047 	while (len > 0) {
1048 		aktlen = min(sdd_bsize, len);
1049 		trys = 0;
1050 		do {
1051 			if (trys && !(trys & 15)) {
1052 				if (debug) {
1053 					(void) putc('+', stderr);
1054 					(void) fflush(stderr);
1055 				}
1056 				(void) riseek((off_t)(ifsize() - sdd_bsize));
1057 				(void) rread(buf, aktlen);
1058 
1059 			} else if (trys > 0 && (trys == 2 || ! (trys & 7))) {
1060 				if (debug) {
1061 					(void) putc('-', stderr);
1062 					(void) fflush(stderr);
1063 				}
1064 				(void) riseek((off_t)0);
1065 				(void) rread(buf, aktlen);
1066 			}
1067 			if (debug) {
1068 				(void) putc(',', stderr);
1069 				(void) fflush(stderr);
1070 			}
1071 			fill(buf, 0L, aktlen);
1072 			(void) riseek(pos);
1073 			cnt = rread(buf, aktlen);
1074 			if (cnt < 0) {
1075 				err = geterrno();
1076 #ifdef	ECONNRESET
1077 				if (err == EPIPE || err == ECONNRESET)
1078 #else
1079 				if (err == EPIPE)
1080 #endif
1081 					break;
1082 				err = 0;
1083 			}
1084 		} while (cnt < 0 && trys++ < try);
1085 
1086 		if (cnt < 0) {
1087 			if (progress || debug) {
1088 				(void) putc('\n', stderr);
1089 				(void) fflush(stderr);
1090 			}
1091 			errmsgno(EX_BAD, "Block %lld not read correctly.\n",
1092 						(Llong)pos/(Llong)sdd_bsize);
1093 			if (err != 0)
1094 				term((int) err);
1095 			cnt = aktlen;
1096 			readerrs++;
1097 			lastreaderrs++;
1098 
1099 		} else if (cnt == 0)	/* EOF */
1100 			break;
1101 		buf += cnt;
1102 		len -= cnt;
1103 		pos += cnt;
1104 		total += cnt;
1105 	}
1106 	(void) riseek(pos);
1107 	return (total);
1108 }
1109 
1110 /*
1111  * Output error recovery
1112  */
1113 LOCAL long
writeblocks(buf,len)1114 writeblocks(buf, len)
1115 	register char	*buf;
1116 	register long	len;
1117 {
1118 	register long	cnt;
1119 	register long	aktlen;
1120 	register int	trys;
1121 	register off_t	pos = ovpos;
1122 	register long	total = 0;
1123 /*		char	rdbuf[sdd_bsize];*/
1124 		int	err = 0;
1125 
1126 	if (noseek) {
1127 		errmsgno(EX_BAD, "Can't write %ld Bytes at %lld\n",
1128 							len, (Llong)pos);
1129 		writeerrs++;
1130 		return (len);
1131 	} else {
1132 		errmsgno(EX_BAD,
1133 			"Retrying to write %ld Bytes at %lld (Block %lld)\n",
1134 			len, (Llong)pos, (Llong)pos/(Llong)sdd_bsize);
1135 	}
1136 	while (len > 0) {
1137 		aktlen = min(sdd_bsize, len);
1138 		trys = 0;
1139 		do {
1140 			if (trys && !(trys & 15)) {
1141 				if (debug) {
1142 					(void) putc('>', stderr);
1143 					(void) fflush(stderr);
1144 				}
1145 				(void) roseek((off_t)(ifsize() - sdd_bsize));
1146 /* XXX we would need to read the output file here - open with "r" ??? */
1147 /*				(void) rread(rdbuf, aktlen);*/
1148 
1149 			} else if (trys > 0 && (trys == 2 || ! (trys & 7))) {
1150 				if (debug) {
1151 					(void) putc('<', stderr);
1152 					(void) fflush(stderr);
1153 				}
1154 				(void) roseek((off_t)0);
1155 /* XXX we would need to read the output file here - open with "r" ??? */
1156 /*				(void) rread(rdbuf, aktlen);*/
1157 			}
1158 			if (debug) {
1159 				(void) putc(';', stderr);
1160 				(void) fflush(stderr);
1161 			}
1162 			(void) roseek(pos);
1163 			cnt = rwrite(buf, aktlen);
1164 			if (cnt < 0) {
1165 				err = geterrno();
1166 #ifdef	ECONNRESET
1167 				if (err == EPIPE || err == ECONNRESET)
1168 #else
1169 				if (err == EPIPE)
1170 #endif
1171 					break;
1172 				err = 0;
1173 			}
1174 		} while (cnt < 0 && trys++ < try);
1175 		if (cnt < 0) {
1176 			if (progress || debug) {
1177 				(void) putc('\n', stderr);
1178 				(void) fflush(stderr);
1179 			}
1180 			errmsgno(EX_BAD, "Block %lld not written correctly.\n",
1181 						(Llong)pos/(Llong)sdd_bsize);
1182 			if (err != 0)
1183 				term((int) err);
1184 			cnt = aktlen;
1185 			writeerrs++;
1186 
1187 		} else if (cnt == 0)	/* EOF */
1188 			break;
1189 		buf += cnt;
1190 		len -= cnt;
1191 		pos += cnt;
1192 		total += cnt;
1193 	}
1194 	(void) roseek(pos);
1195 	return (total);
1196 }
1197 
1198 LOCAL void
fill(bp,start,end)1199 fill(bp, start, end)
1200 	char	*bp;
1201 	long	start;
1202 	long	end;
1203 {
1204 #ifdef	OLD
1205 	register char *p = &bp[start];
1206 	register char *ep = &bp[end];
1207 
1208 	while (p < ep)
1209 		*p++ = '\0';
1210 #else
1211 	fillbytes(&bp[start], end-start, '\0');
1212 #endif
1213 }
1214 
1215 #define	DO8(a)  a; a; a; a; a; a; a; a;
1216 
1217 LOCAL void
swabb(bp,cnt)1218 swabb(bp, cnt)
1219 	register char	*bp;
1220 	register long	cnt;
1221 {
1222 	register char	c;
1223 
1224 	cnt /= 2;	/* even count only */
1225 	while ((cnt -= 8) >= 0) {
1226 		DO8(
1227 			c = *bp++;
1228 			bp[-1] = *bp;
1229 			*bp++ = c;
1230 		);
1231 	}
1232 	cnt += 8;
1233 	while (--cnt >= 0) {
1234 		c = *bp++;
1235 		bp[-1] = *bp;
1236 		*bp++ = c;
1237 	}
1238 }
1239 
1240 LOCAL void
lcase(bp,cnt)1241 lcase(bp, cnt)
1242 	register char	*bp;
1243 	register long	cnt;
1244 {
1245 	while (--cnt >= 0) {
1246 		if (*bp >= 'A' && *bp <= 'Z')
1247 			*bp += 'a' - 'A';
1248 		bp++;
1249 	}
1250 }
1251 
1252 LOCAL void
ucase(bp,cnt)1253 ucase(bp, cnt)
1254 	register char	*bp;
1255 	register long	cnt;
1256 {
1257 	while (--cnt >= 0) {
1258 		if (*bp >= 'a' && *bp <= 'z')
1259 			*bp -= 'a' - 'A';
1260 		bp++;
1261 	}
1262 }
1263 
1264 LOCAL long
block(bp,cnt)1265 block(bp, cnt)
1266 	register char	*bp;
1267 	register long	cnt;
1268 {
1269 	register long	ocnt;
1270 
1271 	ocnt = cnt;
1272 	while (--cnt >= 0) {
1273 		bp++;
1274 	}
1275 	return (ocnt);
1276 }
1277 
1278 LOCAL long
unblock(bp,cnt)1279 unblock(bp, cnt)
1280 	register char	*bp;
1281 	register long	cnt;
1282 {
1283 	register long	ocnt;
1284 
1285 	ocnt = cnt;
1286 	while (--cnt >= 0) {
1287 		bp++;
1288 	}
1289 	return (ocnt);
1290 }
1291 
1292 LOCAL void
conv(bp,cnt,tab)1293 conv(bp, cnt, tab)
1294 	register char	*bp;
1295 	register long	cnt;
1296 	register unsigned char	*tab;
1297 {
1298 	register char	c;
1299 
1300 	while ((cnt -= 8) >= 0) {
1301 		DO8(
1302 			c = (char)tab[(unsigned char) *bp];
1303 			*bp++ = c;
1304 		);
1305 	}
1306 	cnt += 8;
1307 	while (--cnt >= 0) {
1308 		c = (char)tab[(unsigned char) *bp];
1309 		*bp++ = c;
1310 	}
1311 
1312 	/* Reihenfolge der Auswertung ist nicht sichergestellt !!! bei: */
1313 	/* XXX		*bp++ = tab[(unsigned char) *bp];*/
1314 }
1315 
1316 LOCAL void
term(ret)1317 term(ret)
1318 	int	ret;
1319 {
1320 	if (rmtout) {
1321 #ifdef	USE_REMOTE
1322 		/*
1323 		 * Cannot happen in non remote versions.
1324 		 */
1325 		if (rmtclose(rmtofd) < 0)
1326 			ret = geterrno();
1327 #endif
1328 	} else {
1329 #ifdef	HAVE_FSYNC
1330 		int	cnt = 0;
1331 
1332 		do {
1333 			if (fsync(ofd) != 0)
1334 				ret = geterrno();
1335 
1336 			if (ret == EINVAL)
1337 				ret = 0;
1338 		} while (ret == EINTR && ++cnt < 10);
1339 #endif
1340 		if (close(ofd) != 0 && ret == 0)
1341 			ret = geterrno();
1342 	}
1343 	prstats();
1344 	exit(ret);
1345 }
1346 
1347 LOCAL void
getstarttime()1348 getstarttime()
1349 {
1350 #ifdef	timerclear
1351 	if (showtime && gettimeofday(&starttime, 0L) < 0)
1352 		comerr("Cannot get starttime\n");
1353 #endif
1354 }
1355 
1356 LOCAL void
prstats()1357 prstats()
1358 {
1359 	Llong	savirec = (Llong)0;
1360 	Llong	ibytes;
1361 	Llong	obytes;
1362 	Llong	ikbytes;
1363 	Llong	okbytes;
1364 	int	iper;
1365 	int	oper;
1366 #ifdef	timerclear
1367 	long	sec;
1368 	long	usec;
1369 	long	tmsec;
1370 #endif
1371 
1372 #ifdef	timerclear
1373 	if (showtime && gettimeofday(&stoptime, 0L) < 0)
1374 			comerr("Cannot get stoptime\n");
1375 #endif
1376 	if (flags & NULLIN) {
1377 		savirec = irec;
1378 		irec = (Llong)0;
1379 	}
1380 	ibytes = irec * (Llong)ibs + iparts;
1381 	obytes = orec * (Llong)obs + oparts;
1382 	ikbytes = ibytes >> 10;
1383 	okbytes = obytes >> 10;
1384 	iper = ((ibytes&1023)<<10)/10485;
1385 	oper = ((obytes&1023)<<10)/10485;
1386 
1387 	if (progress || debug) (void) putc('\n', stderr);
1388 	if (readerrs)
1389 		errmsgno(EX_BAD, "%lld %s(s) not read correctly.\n",
1390 					readerrs, noseek?"Record":"Block");
1391 	if (writeerrs)
1392 		errmsgno(EX_BAD, "%lld %s(s) not written correctly.\n",
1393 					writeerrs, noseek?"Record":"Block");
1394 
1395 	errmsgno(EX_BAD,
1396 	"Read  %lld records + %lld bytes (total of %lld bytes = %lld.%02dk).\n",
1397 	irec, iparts, ibytes, ikbytes, iper);
1398 	errmsgno(EX_BAD,
1399 	"Wrote %lld records + %lld bytes (total of %lld bytes = %lld.%02dk).\n",
1400 	orec, oparts, obytes, okbytes, oper);
1401 
1402 	if (flags & NULLIN) {
1403 		irec = savirec;
1404 		ibytes = obytes;
1405 		ikbytes = okbytes;
1406 	}
1407 #ifdef	timerclear
1408 	if (showtime) {
1409 		long	kbs;
1410 
1411 		sec = stoptime.tv_sec - starttime.tv_sec;
1412 		usec = stoptime.tv_usec - starttime.tv_usec;
1413 		tmsec = sec*1000 + usec/1000;
1414 		if (usec < 0) {
1415 			sec--;
1416 			usec += 1000000;
1417 		}
1418 		if (tmsec == 0)
1419 			tmsec++;
1420 
1421 		kbs = ikbytes*(Llong)1000/tmsec;
1422 		errmsgno(EX_BAD, "Total time %ld.%03ldsec (%ld kBytes/sec)\n",
1423 				sec, usec/1000, kbs);
1424 	}
1425 #endif
1426 	if (flags & MD5SUM)
1427 		mdfinal();
1428 }
1429 
1430 LOCAL	char	opts[]	= "\
1431 if*,of*,ibs&,obs&,bs&,cbs&,secsize&,\
1432 count&,ivsize&,ovsize&,iseek&,oseek&,seek&,\
1433 iskip&,oskip&,skip&,ivseek&,ovseek&,\
1434 notrunc,pg,noerror,noerrwrite,noseek,try#,\
1435 fill,swab,block,unblock,lcase,ucase,ascii,ebcdic,ibm,\
1436 md5,\
1437 inull,onull,help,version,debug,time,t";
1438 
1439 LOCAL void
getopts(ac,av)1440 getopts(ac, av)
1441 	int	ac;
1442 	char	*av[];
1443 {
1444 	int	cac;
1445 	char	* const *cav;
1446 	BOOL	help	= FALSE;
1447 	BOOL	prvers	= FALSE;
1448 	BOOL	fillflg	= FALSE;
1449 	BOOL	swabflg	= FALSE;
1450 	BOOL	blkflg	= FALSE;
1451 	BOOL	ublkflg	= FALSE;
1452 	BOOL	lcflg	= FALSE;
1453 	BOOL	ucflg	= FALSE;
1454 	BOOL	ascflg	= FALSE;
1455 	BOOL	ebcflg	= FALSE;
1456 	BOOL	ibmflg	= FALSE;
1457 	BOOL	md5flg	= FALSE;
1458 	BOOL	nullin	= FALSE;
1459 	BOOL	nullout	= FALSE;
1460 	int	trys	= -1;
1461 	Llong	lliseek	 = (Llong)0;
1462 	Llong	lloseek	 = (Llong)0;
1463 	Llong	llaseek	 = (Llong)0;
1464 	Llong	llivseek = (Llong)0;
1465 	Llong	llovseek = (Llong)0;
1466 
1467 	cac = ac - 1;
1468 	cav = av + 1;
1469 	if (getallargs(&cac, &cav, opts,
1470 				&infile, &outfile,
1471 				getnum, &ibs, getnum, &obs, getnum, &bs,
1472 				getnum,	&cbs,
1473 				getnum,	&sdd_bsize,
1474 				getllnum, &count,
1475 				getllnum, &ivsize, getllnum, &ovsize,
1476 				getllnum, &lliseek,  getllnum, &lloseek,
1477 				getllnum, &llaseek,
1478 				getllnum, &iskip,  getllnum, &oskip,
1479 				getllnum, &skip,
1480 				getllnum, &llivseek, getllnum, &llovseek,
1481 #ifndef	lint			/* lint kann leider nur 52 args !!! */
1482 				&notrunc,
1483 				&progress,
1484 				&noerror,
1485 				&noerrwrite,
1486 				&noseek,
1487 				&trys,
1488 				&fillflg,
1489 				&swabflg,
1490 				&blkflg, &ublkflg,
1491 				&lcflg, &ucflg,
1492 				&ascflg, &ebcflg, &ibmflg,
1493 				&md5flg,
1494 				&nullin,
1495 				&nullout,
1496 #endif
1497 				&help, &prvers,
1498 				&debug, &showtime, &showtime) < 0) {
1499 		errmsgno(EX_BAD, "Bad Option: '%s'\n", cav[0]);
1500 		usage(EX_BAD);
1501 	}
1502 	if (help)
1503 		usage(0);
1504 	if (prvers) {
1505 		gtprintf("sdd %s %s (%s-%s-%s)\n\n", "1.72", "2021/08/20",
1506 					HOST_CPU, HOST_VENDOR, HOST_OS);
1507 		gtprintf("Copyright (C) 1984-2021 %s\n", _("J�rg Schilling"));
1508 		gtprintf("This is free software; see the source for copying ");
1509 		gtprintf("conditions.  There is NO\n");
1510 		gtprintf("warranty; not even for MERCHANTABILITY or ");
1511 		gtprintf("FITNESS FOR A PARTICULAR PURPOSE.\n");
1512 		exit(0);
1513 	}
1514 	cac = ac - 1;
1515 	cav = av + 1;
1516 	if (getfiles(&cac, &cav, opts) != 0) {
1517 		errmsgno(EX_BAD, "Bad Argument: '%s'\n", cav[0]);
1518 		usage(EX_BAD);
1519 	}
1520 
1521 	iseek	= (off_t)lliseek;
1522 	oseek	= (off_t)lloseek;
1523 	seek	= (off_t)llaseek;
1524 	ivseek	= (off_t)llivseek;
1525 	ovseek	= (off_t)llovseek;
1526 
1527 	if (iseek != lliseek || oseek != lloseek || seek != llaseek ||
1528 		ivseek != llivseek || ovseek != llovseek) {
1529 
1530 		errmsgno(EX_BAD,
1531 		"Value of *seek= is too large for data type 'off_t'.\n");
1532 		usage(EX_BAD);
1533 	}
1534 
1535 	if (trys >= 0) {
1536 		if (!noerror) {
1537 			errmsgno(EX_BAD, "'try' only with '-noerror'.\n");
1538 			usage(EX_BAD);
1539 		}
1540 		if (noseek) {
1541 			errmsgno(EX_BAD, "Can't try with -noseek.\n");
1542 			usage(EX_BAD);
1543 		}
1544 		try = trys;
1545 	}
1546 	if ((iseek || oseek || seek) && (iskip || oskip || skip)) {
1547 		errmsgno(EX_BAD, "Can't seek and skip.\n");
1548 		usage(EX_BAD);
1549 	}
1550 	if ((iseek || oseek || seek) && noseek) {
1551 		errmsgno(EX_BAD, "Can't seek and noseek.\n");
1552 		usage(EX_BAD);
1553 	}
1554 	if (noseek && noerrwrite) {
1555 		errmsgno(EX_BAD, "Can't noseek and noerrwrite.\n");
1556 		usage(EX_BAD);
1557 	}
1558 	if (bs == 0)
1559 		bs = sdd_bsize;
1560 	if (ibs == 0)
1561 		ibs = bs;
1562 	if (obs == 0)
1563 		obs = bs;
1564 	/*
1565 	 * It makes no sense to check for EISPIPE with lseek() and to
1566 	 * disable seeking, since we currently do not distinct between
1567 	 * noiseek and nooseek.
1568 	 */
1569 	if (noerror && !noseek) {
1570 		if ((ibs == obs) &&
1571 		    (bs % sdd_bsize)) {
1572 			errmsgno(EX_BAD,
1573 			    "Buffer size must be a multiple of %ld.\n",
1574 			    sdd_bsize);
1575 			usage(EX_BAD);
1576 		}
1577 		if (ibs % sdd_bsize) {
1578 			errmsgno(EX_BAD,
1579 			    "Input buffer size must be a multiple of %ld.\n",
1580 			    sdd_bsize);
1581 			usage(EX_BAD);
1582 		}
1583 		if (obs % sdd_bsize) {
1584 			errmsgno(EX_BAD,
1585 			    "Output buffer size must be a multiple of %ld.\n",
1586 			    sdd_bsize);
1587 			usage(EX_BAD);
1588 		}
1589 	}
1590 	if (iskip == 0)
1591 		iskip = skip;
1592 	if (oskip == 0)
1593 		oskip = skip;
1594 	if (iseek == 0)
1595 		iseek = seek;
1596 	if (oseek == 0)
1597 		oseek = seek;
1598 	if (iskip || oskip) {
1599 		errmsgno(EX_BAD, "skip not implemented.\n");
1600 		usage(EX_BAD);
1601 	}
1602 	if (fillflg)
1603 		flags |= FILL;
1604 	if (swabflg)
1605 		flags |= SWAB;
1606 	if (blkflg)
1607 		flags |= BLOCK;
1608 	if (ublkflg)
1609 		flags |= UNBLOCK;
1610 	if ((flags & (BLOCK|UNBLOCK)) && cbs == 0) {
1611 		errmsgno(EX_BAD, "Must specify cbs if block or unblock.\n");
1612 		usage(EX_BAD);
1613 	}
1614 	if (blkflg || ublkflg) {
1615 		errmsgno(EX_BAD, "block/unblock not implemented.\n");
1616 		usage(EX_BAD);
1617 	}
1618 	if (lcflg && ucflg) {
1619 		errmsgno(EX_BAD, "Can't lcase and ucase.\n");
1620 		usage(EX_BAD);
1621 	}
1622 	if (lcflg)
1623 		flags |= LCASE;
1624 	if (ucflg)
1625 		flags |= UCASE;
1626 	if (ascflg)
1627 		flags |= ASCII;
1628 	if (ebcflg && ibmflg) {
1629 		errmsgno(EX_BAD, "Can't ebcdic and ibm.\n");
1630 		usage(EX_BAD);
1631 	}
1632 	if (ebcflg)
1633 		flags |= EBCDIC;
1634 	if (ibmflg)
1635 		flags |= IBM;
1636 	if (md5flg)
1637 		flags |= MD5SUM;
1638 	if (nullin && nullout) {
1639 		errmsgno(EX_BAD, "Can't inull and onull.\n");
1640 		usage(EX_BAD);
1641 	}
1642 	if (nullin) {
1643 		flags &= ~(BLOCK|UNBLOCK);
1644 		flags |= NULLIN;
1645 		ibs = bs = obs;
1646 	}
1647 	if (nullout) {
1648 		flags &= ~(BLOCK|UNBLOCK);
1649 		flags |= NULLOUT;
1650 		obs = bs = ibs;
1651 	}
1652 }
1653 
1654 LOCAL void
usage(ex)1655 usage(ex)
1656 	int ex;
1657 {
1658 	error("\
1659 Usage:	sdd [option=value] [-flag]\n\
1660 Options:\n\
1661 ");
1662 	error("\
1663 	if=name		  Read  input from name instead of stdin\n\
1664 	of=name		  Write output to name instead of stdout\n\
1665 	-inull		  Do not read input from file (use null char's)\n\
1666 	-onull		  Do not write output to any file\n\
1667 	ibs=#,obs=#,bs=#  Set input/outbut buffersize or both to #\n\
1668 	cbs=#		  Set conversion buffersize to #\n\
1669 	secsize=#	  Set basic buffersize for -noerror to # (default %ld)\n\
1670 	ivsize=#,ovsize=# Set input/output volume size to #\n\
1671 	count=#		  Transfer at most # input records\n\
1672 	iseek=#,iskip=#	  Seek/skip # bytes on input before starting\n\
1673 	oseek=#,oskip=#	  Seek/skip # bytes on output before starting\n\
1674 	seek=#,skip=#	  Seek/skip # bytes on input/output before starting\n\
1675 	ivseek=#,ovseek=# Seek # bytes on input/output volumes before starting\n\
1676 ",
1677 	sdd_bsize);
1678 	error("\
1679 	-notrunc	  Do not trunctate existing output file\n\
1680 	-pg		  Print a dot on each write to indicate progress\n\
1681 	-noerror	  Do not stop on error\n\
1682 	-noerrwrite	  Do not write blocks not read correctly\n\
1683 	-noseek		  Don't seek\n\
1684 	try=#		  Set error retrycount to # if -noerror (default 2)\n\
1685 	-debug		  Print debugging messages\n\
1686 	-fill		  Fill each record with zeros up to obs\n\
1687 	-swab,-block,-unblock,-lcase,-ucase,-ascii,-ebcdic,-ibm\n\
1688 	-md5		  Compute the md5 sum for the data\n\
1689 ");
1690 	error("\t-help\t\t  print this online help\n");
1691 	error("\t-version\t  print version number\n");
1692 	exit(ex);
1693 }
1694 
1695 LOCAL int
openremote(filename,iosize)1696 openremote(filename, iosize)
1697 	char	*filename;
1698 	long	iosize;
1699 {
1700 	int	remfd	= -1;
1701 	char	*remfn;
1702 	char	host[128];
1703 
1704 #ifdef	USE_REMOTE
1705 	if ((remfn = rmtfilename(filename)) != NULL) {
1706 		rmthostname(host, sizeof (host), filename);
1707 
1708 		if (debug)
1709 			errmsgno(EX_BAD, "Remote: %s Host: %s file: %s\n",
1710 							filename, host, remfn);
1711 
1712 		remfd = iosize;
1713 		if (remfd != iosize) {
1714 			comerrno(EX_BAD,
1715 				"Buffer size %ld too large for remote operation.\n",
1716 				iosize);
1717 		}
1718 		if ((remfd = rmtgetconn(host, (int)iosize, 0)) < 0)
1719 			comerrno(EX_BAD, "Cannot get connection to '%s'.\n",
1720 				/* errno not valid !! */		host);
1721 	}
1722 #else
1723 	comerrno(EX_BAD, "Remote tape support not present.\n");
1724 #endif
1725 	return (remfd);
1726 }
1727 
1728 LOCAL int
ropenfile(rfd,name,mode)1729 ropenfile(rfd, name, mode)
1730 	int	rfd;
1731 	char	*name;
1732 	int	mode;
1733 {
1734 #ifdef	USE_REMOTE
1735 	int	fd;
1736 
1737 	if ((fd = rmtopen(rfd, name, mode)) < 0)
1738 		comerr("Can't open '%s'.\n", name);
1739 	return (fd);
1740 #else
1741 	comerrno(EX_BAD, "Remote tape support not present.\n");
1742 	/* NOTREACHED */
1743 	return (-1);
1744 #endif
1745 }
1746 
1747 LOCAL ssize_t
rread(buf,cnt)1748 rread(buf, cnt)
1749 	void	*buf;
1750 	size_t	cnt;
1751 {
1752 #ifdef	USE_REMOTE
1753 	if (rmtifd >= 0) {
1754 		int	icnt = cnt;
1755 
1756 		/*
1757 		 * This check is needed as long as librmt uses int in rmtread()
1758 		 */
1759 		if (icnt != cnt) {
1760 			seterrno(EINVAL);
1761 			return (-1);
1762 		}
1763 		return (rmtread(rmtifd, buf, cnt));
1764 	}
1765 #endif
1766 	return (_niread(ifd, buf, cnt));
1767 }
1768 
1769 LOCAL ssize_t
rwrite(buf,cnt)1770 rwrite(buf, cnt)
1771 	void	*buf;
1772 	size_t	cnt;
1773 {
1774 #ifdef	USE_REMOTE
1775 	if (rmtofd >= 0) {
1776 		int	icnt = cnt;
1777 
1778 		/*
1779 		 * This check is needed as long as librmt uses int in rmtwrite()
1780 		 */
1781 		if (icnt != cnt) {
1782 			seterrno(EINVAL);
1783 			return (-1);
1784 		}
1785 		return (rmtwrite(rmtofd, buf, cnt));
1786 	}
1787 #endif
1788 	return (_niwrite(ofd, buf, cnt));
1789 }
1790 
1791 LOCAL off_t
riseek(pos)1792 riseek(pos)
1793 	off_t	pos;
1794 {
1795 #ifdef	USE_REMOTE
1796 	if (rmtifd >= 0)
1797 		return (rmtseek(rmtifd, pos, SEEK_SET));
1798 #endif
1799 	return (lseek(ifd, pos, SEEK_SET));
1800 }
1801 
1802 LOCAL off_t
roseek(pos)1803 roseek(pos)
1804 	off_t	pos;
1805 {
1806 #ifdef	USE_REMOTE
1807 	if (rmtofd >= 0)
1808 		return (rmtseek(rmtofd, pos, SEEK_SET));
1809 #endif
1810 	return (lseek(ofd, pos, SEEK_SET));
1811 }
1812 
1813 LOCAL off_t
ifsize()1814 ifsize()
1815 {
1816 #ifdef	USE_REMOTE
1817 	off_t	opos;
1818 	off_t	pos;
1819 
1820 	if (rmtifd >= 0) {
1821 		opos = rmtseek(rmtifd, (off_t)0, SEEK_CUR);
1822 		pos = rmtseek(rmtifd, (off_t)0, SEEK_END);
1823 		(void) rmtseek(rmtifd, opos, SEEK_SET);
1824 		return (pos);
1825 	}
1826 #endif
1827 	return (filesize(fin));
1828 }
1829 
1830 
1831 MD5_CTX	MD5_context;
1832 
1833 LOCAL void
mdinit()1834 mdinit()
1835 {
1836 	MD5Init(&MD5_context);
1837 }
1838 
1839 LOCAL void
mdupdate(a,s)1840 mdupdate(a, s)
1841 	void	*a;
1842 	size_t	s;
1843 {
1844 	MD5Update(&MD5_context, a, s);
1845 }
1846 
1847 LOCAL void
mdfinal()1848 mdfinal()
1849 {
1850 	MD5_CTX	ctx;
1851 	UInt8_t result[MD5_DIGEST_LENGTH];
1852 
1853 	ctx = MD5_context;
1854 
1855 	MD5Final(result, &ctx);
1856 
1857 	errmsgno(EX_BAD,
1858 	"md5 %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
1859 			result[0],
1860 			result[1],
1861 			result[2],
1862 			result[3],
1863 			result[4],
1864 			result[5],
1865 			result[6],
1866 			result[7],
1867 			result[8],
1868 			result[9],
1869 			result[10],
1870 			result[11],
1871 			result[12],
1872 			result[13],
1873 			result[14],
1874 			result[15]);
1875 }
1876