1 /*
2  * dd - convert and copy
3  *
4  * Gunnar Ritter, Freiburg i. Br., Germany, January 2003.
5  */
6 /*
7  * Copyright (c) 2003 Gunnar Ritter
8  *
9  * This software is provided 'as-is', without any express or implied
10  * warranty. In no event will the authors be held liable for any damages
11  * arising from the use of this software.
12  *
13  * Permission is granted to anyone to use this software for any purpose,
14  * including commercial applications, and to alter it and redistribute
15  * it freely, subject to the following restrictions:
16  *
17  * 1. The origin of this software must not be misrepresented; you must not
18  *    claim that you wrote the original software. If you use this software
19  *    in a product, an acknowledgment in the product documentation would be
20  *    appreciated but is not required.
21  *
22  * 2. Altered source versions must be plainly marked as such, and must not be
23  *    misrepresented as being the original software.
24  *
25  * 3. This notice may not be removed or altered from any source distribution.
26  */
27 
28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
29 #define	USED	__attribute__ ((used))
30 #elif defined __GNUC__
31 #define	USED	__attribute__ ((unused))
32 #else
33 #define	USED
34 #endif
35 static const char sccsid[] USED = "@(#)dd.sl	1.30 (gritter) 1/22/06";
36 
37 #include	<sys/types.h>
38 #include	<sys/stat.h>
39 #include	<fcntl.h>
40 #include	<unistd.h>
41 #include	<stdio.h>
42 #include	<string.h>
43 #include	<stdlib.h>
44 #include	<errno.h>
45 #include	<libgen.h>
46 #include	<ctype.h>
47 #include	<locale.h>
48 #include	<signal.h>
49 #include	"sigset.h"
50 #include	<wchar.h>
51 #include	<wctype.h>
52 #include	<limits.h>
53 
54 #include	<sys/ioctl.h>
55 
56 #if defined (__linux__) || defined (__sun) || defined (__FreeBSD__) || \
57 	defined (__hpux) || defined (_AIX) || defined (__NetBSD__) || \
58 	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
59 #include	<sys/mtio.h>
60 #else	/* SVR4.2MP */
61 #include	<sys/scsi.h>
62 #include	<sys/st01.h>
63 #endif	/* SVR4.2MP */
64 
65 #include	"atoll.h"
66 #include	"memalign.h"
67 #include	"mbtowi.h"
68 
69 /*
70  * For 'conv=ascii'.
71  */
72 static const unsigned char	c_ascii[] = {
73 0000,0001,0002,0003,0234,0011,0206,0177,0227,0215,0216,0013,0014,0015,0016,0017,
74 0020,0021,0022,0023,0235,0205,0010,0207,0030,0031,0222,0217,0034,0035,0036,0037,
75 0200,0201,0202,0203,0204,0012,0027,0033,0210,0211,0212,0213,0214,0005,0006,0007,
76 0220,0221,0026,0223,0224,0225,0226,0004,0230,0231,0232,0233,0024,0025,0236,0032,
77 0040,0240,0241,0242,0243,0244,0245,0246,0247,0250,0325,0056,0074,0050,0053,0174,
78 0046,0251,0252,0253,0254,0255,0256,0257,0260,0261,0041,0044,0052,0051,0073,0176,
79 0055,0057,0262,0263,0264,0265,0266,0267,0270,0271,0313,0054,0045,0137,0076,0077,
80 0272,0273,0274,0275,0276,0277,0300,0301,0302,0140,0072,0043,0100,0047,0075,0042,
81 0303,0141,0142,0143,0144,0145,0146,0147,0150,0151,0304,0305,0306,0307,0310,0311,
82 0312,0152,0153,0154,0155,0156,0157,0160,0161,0162,0136,0314,0315,0316,0317,0320,
83 0321,0345,0163,0164,0165,0166,0167,0170,0171,0172,0322,0323,0324,0133,0326,0327,
84 0330,0331,0332,0333,0334,0335,0336,0337,0340,0341,0342,0343,0344,0135,0346,0347,
85 0173,0101,0102,0103,0104,0105,0106,0107,0110,0111,0350,0351,0352,0353,0354,0355,
86 0175,0112,0113,0114,0115,0116,0117,0120,0121,0122,0356,0357,0360,0361,0362,0363,
87 0134,0237,0123,0124,0125,0126,0127,0130,0131,0132,0364,0365,0366,0367,0370,0371,
88 0060,0061,0062,0063,0064,0065,0066,0067,0070,0071,0372,0373,0374,0375,0376,0377
89 };
90 
91 /*
92  * For 'conv=ibm'.
93  */
94 static const unsigned char	c_ibm[] = {
95 0000,0001,0002,0003,0067,0055,0056,0057,0026,0005,0045,0013,0014,0015,0016,0017,
96 0020,0021,0022,0023,0074,0075,0062,0046,0030,0031,0077,0047,0034,0035,0036,0037,
97 0100,0132,0177,0173,0133,0154,0120,0175,0115,0135,0134,0116,0153,0140,0113,0141,
98 0360,0361,0362,0363,0364,0365,0366,0367,0370,0371,0172,0136,0114,0176,0156,0157,
99 0174,0301,0302,0303,0304,0305,0306,0307,0310,0311,0321,0322,0323,0324,0325,0326,
100 0327,0330,0331,0342,0343,0344,0345,0346,0347,0350,0351,0255,0340,0275,0137,0155,
101 0171,0201,0202,0203,0204,0205,0206,0207,0210,0211,0221,0222,0223,0224,0225,0226,
102 0227,0230,0231,0242,0243,0244,0245,0246,0247,0250,0251,0300,0117,0320,0241,0007,
103 0040,0041,0042,0043,0044,0025,0006,0027,0050,0051,0052,0053,0054,0011,0012,0033,
104 0060,0061,0032,0063,0064,0065,0066,0010,0070,0071,0072,0073,0004,0024,0076,0341,
105 0101,0102,0103,0104,0105,0106,0107,0110,0111,0121,0122,0123,0124,0125,0126,0127,
106 0130,0131,0142,0143,0144,0145,0146,0147,0150,0151,0160,0161,0162,0163,0164,0165,
107 0166,0167,0170,0200,0212,0213,0214,0215,0216,0217,0220,0232,0233,0234,0235,0236,
108 0237,0240,0252,0253,0254,0255,0256,0257,0260,0261,0262,0263,0264,0265,0266,0267,
109 0270,0271,0272,0273,0274,0275,0276,0277,0312,0313,0314,0315,0316,0317,0332,0333,
110 0334,0335,0336,0337,0352,0353,0354,0355,0356,0357,0372,0373,0374,0375,0376,0377
111 };
112 
113 /*
114  * For 'conv=ebcdic'.
115  */
116 static const unsigned char	c_ebcdic[] = {
117 0000,0001,0002,0003,0067,0055,0056,0057,0026,0005,0045,0013,0014,0015,0016,0017,
118 0020,0021,0022,0023,0074,0075,0062,0046,0030,0031,0077,0047,0034,0035,0036,0037,
119 0100,0132,0177,0173,0133,0154,0120,0175,0115,0135,0134,0116,0153,0140,0113,0141,
120 0360,0361,0362,0363,0364,0365,0366,0367,0370,0371,0172,0136,0114,0176,0156,0157,
121 0174,0301,0302,0303,0304,0305,0306,0307,0310,0311,0321,0322,0323,0324,0325,0326,
122 0327,0330,0331,0342,0343,0344,0345,0346,0347,0350,0351,0255,0340,0275,0232,0155,
123 0171,0201,0202,0203,0204,0205,0206,0207,0210,0211,0221,0222,0223,0224,0225,0226,
124 0227,0230,0231,0242,0243,0244,0245,0246,0247,0250,0251,0300,0117,0320,0137,0007,
125 0040,0041,0042,0043,0044,0025,0006,0027,0050,0051,0052,0053,0054,0011,0012,0033,
126 0060,0061,0032,0063,0064,0065,0066,0010,0070,0071,0072,0073,0004,0024,0076,0341,
127 0101,0102,0103,0104,0105,0106,0107,0110,0111,0121,0122,0123,0124,0125,0126,0127,
128 0130,0131,0142,0143,0144,0145,0146,0147,0150,0151,0160,0161,0162,0163,0164,0165,
129 0166,0167,0170,0200,0212,0213,0214,0215,0216,0217,0220,0152,0233,0234,0235,0236,
130 0237,0240,0252,0253,0254,0112,0256,0257,0260,0261,0262,0263,0264,0265,0266,0267,
131 0270,0271,0272,0273,0274,0241,0276,0277,0312,0313,0314,0315,0316,0317,0332,0333,
132 0334,0335,0336,0337,0352,0353,0354,0355,0356,0357,0372,0373,0374,0375,0376,0377
133 };
134 
135 static char		*progname;	/* argv[0] to main() */
136 
137 typedef	long long	d_type;
138 
139 static char		*iblok;		/* input buffer */
140 static char		*oblok;		/* output buffer */
141 static char		*cblok;		/* conversion buffer */
142 
143 static char		mblok[MB_LEN_MAX+1];	/* tow{upper|lower} buffer */
144 static char		*mbp;		/* points to remaining chars in mblok */
145 static int		mbrest;		/* number of remaining chars in mblok */
146 
147 static const char	*iffile;	/* input file name */
148 static int		iffd;		/* input file descriptor */
149 static const char	*offile;	/* output file name */
150 static int		offd;		/* output file descriptor */
151 static struct stat	istat;		/* stat of input */
152 static struct stat	ostat;		/* stat of output */
153 static d_type		ibs = 512;	/* input block size */
154 static d_type		obs = 512;	/* output block size */
155 static d_type		bs;		/* size for both buffers */
156 static d_type		oflow;		/* remaining bytes in output buffer */
157 static d_type		cbs;		/* conversion block size */
158 static d_type		cflow;		/* remaining bytes in conv. buffer */
159 static int		ctrunc;		/* truncate current data (conv=block) */
160 static d_type		skip;		/* skip these blocks on input */
161 static d_type		count = -1;	/* no more than count blocks of input */
162 static int		files = 1;	/* read EOF this many times */
163 static d_type		iseek;		/* seek these blocks on input */
164 static d_type		oseek;		/* seek these blocks on output */
165 static int		mb_cur_max;	/* MB_CUR_MAX acceleration */
166 
167 static d_type		iwhole;		/* statistics */
168 static d_type		ipartial;
169 static d_type		owhole;
170 static d_type		opartial;
171 static d_type		truncated;
172 
173 static enum charconv {
174 	CHAR_NONE	= 0,
175 	CHAR_ASCII	= 1,
176 	CHAR_EBCDIC	= 2,
177 	CHAR_IBM	= 3
178 } chars = CHAR_NONE;
179 
180 static enum conversion {
181 	CONV_NONE	= 0,
182 	CONV_BLOCK	= 01,
183 	CONV_UNBLOCK	= 02,
184 	CONV_LCASE	= 04,
185 	CONV_UCASE	= 010,
186 	CONV_SWAB	= 020,
187 	CONV_NOERROR	= 040,
188 	CONV_NOTRUNC	= 0100,
189 	CONV_IDIRECT	= 0200,
190 	CONV_ODIRECT	= 0400,
191 	CONV_DIRECT	= 0600,
192 	CONV_SYNC	= 01000
193 } convs = CONV_NONE;
194 
195 static struct {
196 	const char	*c_name;
197 	enum conversion	c_conv;
198 	enum charconv	c_char;
199 } convtab[] = {
200 	{ "ascii",	CONV_UNBLOCK,	CHAR_ASCII	},
201 	{ "ebcdic",	CONV_BLOCK,	CHAR_EBCDIC	},
202 	{ "ibm",	CONV_BLOCK,	CHAR_IBM	},
203 	{ "block",	CONV_BLOCK,	CHAR_NONE	},
204 	{ "unblock",	CONV_UNBLOCK,	CHAR_NONE	},
205 	{ "lcase",	CONV_LCASE,	CHAR_NONE	},
206 	{ "ucase",	CONV_UCASE,	CHAR_NONE	},
207 	{ "swab",	CONV_SWAB,	CHAR_NONE	},
208 	{ "noerror",	CONV_NOERROR,	CHAR_NONE	},
209 	{ "notrunc",	CONV_NOTRUNC,	CHAR_NONE	},
210 #ifdef	O_DIRECT
211 	{ "idirect",	CONV_IDIRECT,	CHAR_NONE	},
212 	{ "odirect",	CONV_ODIRECT,	CHAR_NONE	},
213 #endif	/* O_DIRECT */
214 	{ "sync",	CONV_SYNC,	CHAR_NONE	},
215 	{ NULL,		CONV_NONE,	CHAR_NONE	}
216 };
217 
218 static void *
bmalloc(size_t nbytes)219 bmalloc(size_t nbytes)
220 {
221 	static long	pagesize;
222 	void	*vp;
223 
224 	if (pagesize == 0)
225 		if ((pagesize = sysconf(_SC_PAGESIZE)) < 0)
226 			pagesize = 4096;
227 	if ((vp = memalign(pagesize, nbytes)) == NULL) {
228 		fprintf(stderr, "%s: not enough memory\n", progname);
229 		fprintf(stderr, "Please use a smaller buffer size\n");
230 		exit(077);
231 	}
232 	return vp;
233 }
234 
235 /************************** ARGUMENT SCANNING ***************************/
236 static void
badarg(const char * arg)237 badarg(const char *arg)
238 {
239 	fprintf(stderr, "%s: bad arg: \"%s\"\n", progname, arg);
240 	exit(2);
241 }
242 
243 static void
badnumeric(const char * arg)244 badnumeric(const char *arg)
245 {
246 	fprintf(stderr, "%s: bad numeric arg: \"%s\"\n", progname, arg);
247 	exit(2);
248 }
249 
250 static void
nozeroblok(void)251 nozeroblok(void)
252 {
253 	fprintf(stderr, "%s: buffer sizes cannot be zero\n", progname);
254 	exit(2);
255 }
256 
257 /*
258  * Get the value of a numeric argument.
259  */
260 static d_type
expr(const char * ap)261 expr(const char *ap)
262 {
263 	d_type	val;
264 	char	*x;
265 	int	c;
266 
267 	if (*ap == '-' || *ap == '+')
268 		badnumeric(ap);
269 	val = strtoull(ap, &x, 10);
270 	while ((c = *x++) != '\0') {
271 		switch (c) {
272 		case 'k':
273 			val *= 1024;
274 			break;
275 		case 'b':
276 			val *= 512;
277 			break;
278 		case 'w':
279 			val *= 2;
280 			break;
281 		case 'x':
282 		case '*':
283 			return val * expr(x);
284 		default:
285 			badnumeric(ap);
286 		}
287 	}
288 	return val;
289 }
290 
291 static void
setin(const char * ap)292 setin(const char *ap)
293 {
294 	iffile = ap;
295 }
296 
297 static void
setof(const char * ap)298 setof(const char *ap)
299 {
300 	offile = ap;
301 }
302 
303 static void
setibs(const char * ap)304 setibs(const char *ap)
305 {
306 	ibs = expr(ap);
307 	if (ibs == 0)
308 		nozeroblok();
309 }
310 
311 static void
setobs(const char * ap)312 setobs(const char *ap)
313 {
314 	obs = expr(ap);
315 	if (obs == 0)
316 		nozeroblok();
317 }
318 
319 static void
setbs(const char * ap)320 setbs(const char *ap)
321 {
322 	bs = expr(ap);
323 }
324 
325 static void
setcbs(const char * ap)326 setcbs(const char *ap)
327 {
328 	cbs = expr(ap);
329 }
330 
331 static void
setskip(const char * ap)332 setskip(const char *ap)
333 {
334 	skip = expr(ap);
335 }
336 
337 static void
setcount(const char * ap)338 setcount(const char *ap)
339 {
340 	count = expr(ap);
341 }
342 
343 static void
setconv(const char * ap)344 setconv(const char *ap)
345 {
346 	const char	*cp, *cq;
347 	int	i;
348 
349 	for (;;) {
350 		while (*ap == ',')
351 			ap++;
352 		if (*ap == '\0')
353 			break;
354 		for (i = 0; convtab[i].c_name; i++) {
355 			for (cp = convtab[i].c_name, cq = ap;
356 					*cp && (*cp == *cq);
357 					cp++, cq++);
358 			if (*cp == '\0' && (*cq == ',' || *cq == '\0')) {
359 				convs |= convtab[i].c_conv;
360 				if (convtab[i].c_char != CHAR_NONE)
361 					chars = convtab[i].c_char;
362 				ap = cq;
363 				goto next;
364 			}
365 		}
366 		badarg(ap);
367 	next:;
368 	}
369 }
370 
371 static void
setfiles(const char * ap)372 setfiles(const char *ap)
373 {
374 	files = expr(ap);
375 }
376 
377 static void
setiseek(const char * ap)378 setiseek(const char *ap)
379 {
380 	iseek = expr(ap);
381 }
382 
383 static void
setoseek(const char * ap)384 setoseek(const char *ap)
385 {
386 	oseek = expr(ap);
387 }
388 
389 static struct {
390 	const char	*a_name;
391 	void		(*a_func)(const char *);
392 } argtab[] = {
393 	{ "if=",	setin		},
394 	{ "of=",	setof		},
395 	{ "ibs=",	setibs		},
396 	{ "obs=",	setobs		},
397 	{ "bs=",	setbs		},
398 	{ "cbs=",	setcbs		},
399 	{ "skip=",	setskip		},
400 	{ "seek=",	setoseek	},
401 	{ "count=",	setcount	},
402 	{ "conv=",	setconv		},
403 	{ "files=",	setfiles	},
404 	{ "iseek=",	setiseek	},
405 	{ "oseek=",	setoseek	},
406 	{ NULL,		NULL		}
407 };
408 
409 static const char *
thisarg(const char * sp,const char * ap)410 thisarg(const char *sp, const char *ap)
411 {
412 	do {
413 		if (*sp != *ap)
414 			return NULL;
415 		if (*sp == '=')
416 			return &sp[1];
417 	} while (*sp++ && *ap++);
418 	return NULL;
419 }
420 
421 /******************************* EXECUTION ********************************/
422 static void
stats(void)423 stats(void)
424 {
425 	fprintf(stderr, "%llu+%llu records in\n",
426 			(unsigned long long)iwhole,
427 			(unsigned long long)ipartial);
428 	fprintf(stderr, "%llu+%llu records out\n",
429 			(unsigned long long)owhole,
430 			(unsigned long long)opartial);
431 	if (truncated) {
432 		fprintf(stderr, "%llu truncated record%s\n",
433 				(unsigned long long)truncated,
434 				truncated > 1 ? "s" : "");
435 	}
436 }
437 
438 static void	charconv(char *data, size_t size);
439 static void	bflush(void);
440 static void	cflush(void);
441 static void	uflush(void);
442 
443 static void
quit(int status)444 quit(int status)
445 {
446 	if (mbp)
447 		charconv(NULL, 0);
448 	cflush();
449 	uflush();
450 	bflush();
451 	stats();
452 	exit(status);
453 }
454 
455 static void
onint(int sig)456 onint(int sig)
457 {
458 	stats();
459 	exit(sig | 0200);
460 }
461 
462 static int
ontape(void)463 ontape(void)
464 {
465 	static int	yes = -1;
466 
467 	if (yes == -1) {
468 #if defined (__linux__) || defined (__FreeBSD__) || defined (__hpux) || \
469 	defined (_AIX) || defined (__NetBSD__) || defined (__OpenBSD__) || \
470 	defined (__DragonFly__) || defined (__APPLE__)
471 		struct mtget	mg;
472 		yes = (istat.st_mode&S_IFMT) == S_IFCHR &&
473 			ioctl(iffd, MTIOCGET, &mg) == 0;
474 #elif defined (__sun)
475 		struct mtdrivetype_request	mr;
476 		struct mtdrivetype	md;
477 		mr.size = sizeof md;
478 		mr.mtdtp = &md;
479 		yes = (istat.st_mode&S_IFMT) == S_IFCHR &&
480 			ioctl(iffd, MTIOCGETDRIVETYPE, &mr) == 0;
481 #else	/* SVR4.2MP */
482 		struct blklen	bl;
483 		yes = (istat.st_mode&S_IFMT) == S_IFCHR &&
484 			ioctl(iffd, T_RDBLKLEN, &bl) == 0;
485 #endif	/* SVR4.2MP */
486 	}
487 	return yes;
488 }
489 
490 static void
seekconv(d_type count)491 seekconv(d_type count)
492 {
493 	ssize_t	sz;
494 	off_t	offs;
495 
496 	if (lseek(offd, 0, SEEK_CUR) != (off_t)-1) {
497 		do {
498 			if ((offs = lseek(offd, obs, SEEK_CUR)) == (off_t)-1) {
499 			err:	fprintf(stderr, "%s: output seek error: %s\n",
500 						progname, strerror(errno));
501 				exit(3);
502 			}
503 		} while (--count);
504 		if ((convs & CONV_NOTRUNC) == 0 &&
505 				(ostat.st_mode&S_IFMT) == S_IFREG)
506 			ftruncate(offd, offs);
507 		return;
508 	}
509 	while (count) {
510 		if ((sz = read(offd, oblok, obs)) == 0)
511 			break;
512 		if (sz < 0)
513 			goto err;
514 		count--;
515 	}
516 	if (count) {
517 		memset(oblok, 0, obs);
518 		do {
519 			if ((sz = write(offd, oblok, obs)) < 0)
520 				goto err;
521 		} while (--count);
522 	}
523 }
524 
525 static void
skipconv(int canseek,d_type count)526 skipconv(int canseek, d_type count)
527 {
528 	ssize_t	rd = 0;
529 
530 	if (canseek && lseek(iffd, 0, SEEK_CUR) == (off_t)-1)
531 		canseek = 0;
532 	while (count--) {
533 		if (canseek) {
534 			if (lseek(iffd, ibs, SEEK_CUR) != (off_t)-1)
535 				rd = ibs;
536 			else if (errno == EINVAL)
537 				rd = 0;
538 			else {
539 				fprintf(stderr, "%s: input seek error: %s\n",
540 					progname, strerror(errno));
541 				exit(3);
542 			}
543 		} else {
544 			if ((rd = read(iffd, iblok, ibs)) < 0) {
545 				fprintf(stderr,
546 					"%s: read error during skip: %s\n",
547 					progname, strerror(errno));
548 				exit(3);
549 			}
550 		}
551 		if (rd == 0 && files-- <= 1) {
552 			fprintf(stderr, "%s: cannot skip past end-of-file\n",
553 					progname);
554 			exit(3);
555 		}
556 	}
557 }
558 
559 static void
prepare(void)560 prepare(void)
561 {
562 	int	flags;
563 
564 	if (bs)
565 		ibs = obs = bs;
566 	iblok = bmalloc(ibs);
567 	if (!(bs && chars == CHAR_NONE &&
568 			(convs|CONV_SYNC|CONV_NOERROR|CONV_NOTRUNC|CONV_DIRECT)
569 			== (CONV_SYNC|CONV_NOERROR|CONV_NOTRUNC|CONV_DIRECT)))
570 		oblok = bmalloc(obs);
571 	if (cbs > 0) {
572 		if ((convs & (CONV_BLOCK|CONV_UNBLOCK)) == 0) {
573 			fprintf(stderr,
574 		"%s: cbs must be zero if no block conversion requested\n",
575 				progname);
576 			exit(2);
577 		}
578 		cblok = bmalloc(cbs + 1);
579 	} else
580 		convs &= ~(CONV_BLOCK|CONV_UNBLOCK);
581 	if ((iffd = iffile ? open(iffile, O_RDONLY) : dup(0)) < 0) {
582 		fprintf(stderr, "%s: cannot open %s: %s\n", progname,
583 				iffile ? iffile : "", strerror(errno));
584 		exit(1);
585 	}
586 	fstat(iffd, &istat);
587 #ifdef	O_DIRECT
588 	if (convs & CONV_IDIRECT) {
589 		int	flags;
590 		flags = fcntl(iffd, F_GETFL);
591 		fcntl(iffd, F_SETFL, flags | O_DIRECT);
592 	}
593 #endif	/* O_DIRECT */
594 	if (skip)
595 		skipconv(0, skip);
596 	else if (iseek)
597 		skipconv(1, iseek);
598 	flags = O_RDWR | O_CREAT;
599 	if ((convs & CONV_NOTRUNC) == 0 && oseek == 0)
600 		flags |= O_TRUNC;
601 	if ((offd = offile ? open(offile, flags, 0666) : dup(1)) < 0) {
602 		fprintf(stderr, "%s: cannot %s %s: %s\n",
603 				progname,
604 				flags & O_TRUNC ? "create" : "open",
605 				offile ? offile : "", strerror(errno));
606 		exit(1);
607 	}
608 	fstat(offd, &ostat);
609 #ifdef	O_DIRECT
610 	if (convs & CONV_ODIRECT) {
611 		int	flags;
612 		flags = fcntl(offd, F_GETFL);
613 		fcntl(offd, F_SETFL, flags | O_DIRECT);
614 	}
615 #endif	/* O_DIRECT */
616 	if (oseek)
617 		seekconv(oseek);
618 }
619 
620 static void
swabconv(char * data,size_t size)621 swabconv(char *data, size_t size)
622 {
623 	char	c;
624 
625 	while (size > 1) {
626 		c = data[0];
627 		data[0] = data[1];
628 		data[1] = c;
629 		size -= 2;
630 		data += 2;
631 	}
632 }
633 
634 static void
ascconv(char * data,size_t size)635 ascconv(char *data, size_t size)
636 {
637 	while (size--) {
638 		*data = c_ascii[*data & 0377];
639 		data++;
640 	}
641 }
642 
643 static ssize_t
swrite(const char * data,size_t size)644 swrite(const char *data, size_t size)
645 {
646 	ssize_t	wt;
647 
648 	for (;;) {
649 		if ((wt = write(offd, data, size)) <= 0) {
650 			if (errno == EINTR)
651 				continue;
652 			fprintf(stderr, "%s: write error: %s\n",
653 					progname, strerror(errno));
654 			oflow = 0;
655 			offd = -1;
656 			quit(1);
657 		}
658 		break;
659 	}
660 	return wt;
661 }
662 
663 /*
664  * Write without output buffering (if bs= was specified).
665  */
666 static void
dwrite(const char * data,size_t size)667 dwrite(const char *data, size_t size)
668 {
669 	ssize_t	wrt;
670 
671 	do {
672 		wrt = swrite(data, size);
673 		if (wrt == obs)
674 			owhole++;
675 		else
676 			opartial++;
677 		data += wrt;
678 		size -= wrt;
679 	} while (size > 0);
680 }
681 
682 /*
683  * Write to output buffer. On short write, remaining data is kept within
684  * the buffer and written next time again. Might a warning be useful in
685  * this case?
686  */
687 static void
bwrite(const char * data,size_t size)688 bwrite(const char *data, size_t size)
689 {
690 	ssize_t	wrt;
691 	size_t	di;
692 
693 	while (oflow + size > obs) {
694 		di = obs - oflow;
695 		size -= di;
696 		if (oflow) {
697 			memcpy(&oblok[oflow], data, di);
698 			wrt = swrite(oblok, obs);
699 		} else
700 			wrt = swrite(data, obs);
701 		if (wrt != obs) {
702 			memcpy(oblok, &(oflow ? oblok : data)[wrt], obs - wrt);
703 			opartial++;
704 		} else
705 			owhole++;
706 		oflow = obs - wrt;
707 		data += di;
708 	}
709 	if (size == obs) {
710 		if ((wrt = swrite(data, obs)) == obs)
711 			owhole++;
712 		else
713 			opartial++;
714 		size -= wrt;
715 		data += wrt;
716 	}
717 	if (size) {
718 		memcpy(&oblok[oflow], data, size);
719 		oflow += size;
720 	}
721 }
722 
723 static void
bflush(void)724 bflush(void)
725 {
726 	ssize_t	wrt;
727 
728 	if (offd >= 0) {
729 		while (oflow) {
730 			if ((wrt = swrite(oblok, oflow)) != oflow)
731 				memcpy(oblok, &oblok[wrt], obs - wrt);
732 			oflow -= wrt;
733 			opartial++;
734 		}
735 		if (close(offd) < 0) {
736 			fprintf(stderr, "%s: write error: %s\n",
737 					progname, strerror(errno));
738 			offd = -1;
739 			quit(1);
740 		}
741 		offd = -1;
742 	}
743 }
744 
745 /*
746  * Handle conversions to EBCDIC.
747  */
748 static void
ewrite(char * data,size_t size)749 ewrite(char *data, size_t size)
750 {
751 	char	*dt = data;
752 	size_t	sz = size;
753 	if (chars == CHAR_EBCDIC) {
754 		while (sz--) {
755 			*dt = c_ebcdic[*dt & 0377];
756 			dt++;
757 		}
758 	} else if (chars == CHAR_IBM) {
759 		while (sz--) {
760 			*dt = c_ibm[*dt & 0377];
761 			dt++;
762 		}
763 	}
764 	bwrite(data, size);
765 }
766 
767 /*
768  * Handle 'conv=block'.
769  */
770 static void
cflush(void)771 cflush(void)
772 {
773 	if (convs & CONV_BLOCK && cflow) {
774 		while (cflow < cbs)
775 			cblok[cflow++] = ' ';
776 		ewrite(cblok, cbs);
777 		cflow = 0;
778 	}
779 }
780 
781 static void
cwrite(const char * data,size_t size)782 cwrite(const char *data, size_t size)
783 {
784 	while (size) {
785 		if (ctrunc == 0) {
786 			cblok[cflow] = *data++;
787 			if (cblok[cflow] == '\n') {
788 				if (cflow == 0)
789 					cblok[cflow++] = ' ';
790 				cflush();
791 			} else if (++cflow == cbs) {
792 				cflush();
793 				ctrunc = 1;
794 			}
795 		} else {
796 			if (*data++ == '\n')
797 				ctrunc = 0;
798 			else if (ctrunc == 1) {
799 				truncated++;
800 				ctrunc = 2;
801 			}
802 		}
803 		size--;
804 	}
805 }
806 
807 /*
808  * Handle 'conv=unblock'.
809  */
810 static void
uflush(void)811 uflush(void)
812 {
813 	char	*cp;
814 
815 	if (cflow) {
816 		for (cp = &cblok[cflow-1]; cp >= cblok && *cp == ' '; cp--);
817 		cp[1] = '\n';
818 		bwrite(cblok, cp - cblok + 2);
819 		cflow = 0;
820 	}
821 }
822 
823 static void
uwrite(const char * data,size_t size)824 uwrite(const char *data, size_t size)
825 {
826 	while (size) {
827 		while (cflow < cbs) {
828 			cblok[cflow++] = *data++;
829 			if (--size == 0)
830 				return;
831 		}
832 		uflush();
833 	}
834 }
835 
836 static void
blokconv(char * data,size_t size)837 blokconv(char *data, size_t size)
838 {
839 	switch (chars) {
840 	case CHAR_EBCDIC:
841 	case CHAR_IBM:
842 		if ((convs & (CONV_BLOCK|CONV_UNBLOCK)) == 0) {
843 			ewrite(data, size);
844 			break;
845 		}
846 		/*FALLTHRU*/
847 	default:
848 		if (convs & CONV_BLOCK)
849 			cwrite(data, size);
850 		else if (convs & CONV_UNBLOCK)
851 			uwrite(data, size);
852 		else
853 			bwrite(data, size);
854 		break;
855 	}
856 }
857 
858 static void
charconv(char * data,size_t size)859 charconv(char *data, size_t size)
860 {
861 	if (convs & (CONV_LCASE|CONV_UCASE)) {
862 		if (mb_cur_max > 1) {
863 			/*
864 			 * Multibyte case conversion is somewhat ugly
865 			 * with dd as there is no guarantee that a
866 			 * character fits in an input block. We need
867 			 * another intermediate therefore to store
868 			 * incomplete multibyte sequences.
869 			 */
870 			int	i, n, len;
871 			wint_t	wc;
872 			int	flush = size == 0;
873 
874 			while (size > 0 || (flush && mbrest)) {
875 				i = 0;
876 				if (mbrest && mbp && mbp > mblok) {
877 					do
878 						mblok[i] = mbp[i];
879 					while (i++, --mbrest);
880 				} else if (mbp == mblok) {
881 					i = mbrest;
882 					mbrest = 0;
883 				}
884 				if (i == 0 && size) {
885 					mblok[i++] = *data++;
886 					size--;
887 				}
888 				if (mblok[0] & 0200) {
889 					while (i < mb_cur_max && size) {
890 						mblok[i++] = *data++;
891 						size--;
892 					}
893 					if (!flush && i < mb_cur_max) {
894 						mbp = mblok;
895 						mbrest = i;
896 						return;
897 					}
898 					if ((n = mbtowi(&wc, mblok, i)) < 0) {
899 						len = 1;
900 						wc = WEOF;
901 					} else if (n == 0)
902 						len = 1;
903 					else
904 						len = n;
905 				} else {
906 					wc = mblok[0];
907 					len = n = 1;
908 				}
909 				if (i > 0) {
910 					mbrest = i - len;
911 					mbp = &mblok[len];
912 				} else {
913 					mbrest = 0;
914 					mbp = NULL;
915 				}
916 				if (wc != WEOF) {
917 					char	new[MB_LEN_MAX + 1];
918 
919 					if (convs & CONV_LCASE)
920 						wc = wc & ~(wchar_t)0177 ?
921 							towlower(wc) :
922 							tolower(wc);
923 					if (convs & CONV_UCASE)
924 						wc = wc & ~(wchar_t)0177 ?
925 							towupper(wc) :
926 							toupper(wc);
927 					if ((n = wctomb(new, wc)) > 0)
928 						blokconv(new, n);
929 					else
930 						goto inv;
931 				} else
932 				inv:	blokconv(mblok, len);
933 			}
934 			return;
935 		} else {
936 			char	*dp = data;
937 			size_t	sz = size;
938 
939 			while (sz--) {
940 				if (convs & CONV_LCASE)
941 					*dp = tolower(*dp & 0377);
942 				if (convs & CONV_UCASE)
943 					*dp = toupper(*dp & 0377);
944 				dp++;
945 			}
946 		}
947 	}
948 	blokconv(data, size);
949 }
950 
951 static void
dd(void)952 dd(void)
953 {
954 	ssize_t	rd;
955 
956 	while (count == -1 || count > 0) {
957 		if ((rd = read(iffd, iblok, ibs)) < ibs) {
958 			if (rd < 0) {
959 				fprintf(stderr, "%s: read error: %s\n",
960 						progname, strerror(errno));
961 				if (convs & CONV_NOERROR) {
962 					stats();
963 					if (!ontape())
964 						lseek(iffd, ibs, SEEK_CUR);
965 					if (convs & CONV_SYNC)
966 						rd = 0;
967 					else
968 						continue;
969 				} else
970 					quit(1);
971 			} else if (rd == 0) {
972 				if (files-- <= 1)
973 					break;
974 				continue;
975 			} else if (rd > 0)
976 				ipartial++;
977 			if (convs & CONV_SYNC) {
978 				int	c;
979 
980 				c = convs&(CONV_BLOCK|CONV_UNBLOCK) ? ' ' : 0;
981 				memset(&iblok[rd], c, ibs - rd);
982 				rd = ibs;
983 			}
984 		} else
985 			iwhole++;
986 		if (count > 0)
987 			count--;
988 		if (bs && chars == CHAR_NONE &&
989 			(convs|CONV_SYNC|CONV_NOERROR|CONV_NOTRUNC|CONV_DIRECT)
990 			== (CONV_SYNC|CONV_NOERROR|CONV_NOTRUNC|CONV_DIRECT))
991 			dwrite(iblok, rd);
992 		else {
993 			if (convs & CONV_SWAB)
994 				swabconv(iblok, rd);
995 			if (chars == CHAR_ASCII)
996 				ascconv(iblok, rd);
997 			charconv(iblok, rd);
998 		}
999 	}
1000 }
1001 
1002 int
main(int argc,char ** argv)1003 main(int argc, char **argv)
1004 {
1005 	const char	*cp;
1006 	int	o, i;
1007 
1008 	progname = basename(argv[0]);
1009 	setlocale(LC_CTYPE, "");
1010 	mb_cur_max = MB_CUR_MAX;
1011 	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-' &&
1012 			argv[1][2] == '\0')
1013 		o = 2;
1014 	else
1015 		o = 1;
1016 	while (o < argc) {
1017 		for (i = 0; argtab[i].a_name; i++) {
1018 			if ((cp = thisarg(argv[o], argtab[i].a_name)) != 0) {
1019 				argtab[i].a_func(cp);
1020 				break;
1021 			}
1022 		}
1023 		if (argtab[i].a_name == NULL)
1024 			badarg(argv[o]);
1025 		o++;
1026 	}
1027 	if ((sigset(SIGINT, SIG_IGN)) != SIG_IGN)
1028 		sigset(SIGINT, onint);
1029 	prepare();
1030 	dd();
1031 	quit(0);
1032 	/*NOTREACHED*/
1033 	return 0;
1034 }
1035