xref: /original-bsd/bin/dd/dd.c (revision cd89438c)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)dd.c	5.3 (Berkeley) 04/04/91";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <sys/ioctl.h>
20 #include <sys/mtio.h>
21 #include <sys/stat.h>
22 #include <signal.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #define	BIG	2147483647
30 #define	LCASE	01
31 #define	UCASE	02
32 #define	SWAB	04
33 #define NERR	010
34 #define SYNC	020
35 int	cflag;
36 int	fflag;
37 int	skip;
38 int	seekn;
39 int	count;
40 int	files	= 1;
41 char	*string;
42 char	*ifile;
43 char	*ofile;
44 char	*ibuf;
45 char	*obuf;
46 char	*sbrk();
47 int	ibs	= 512;
48 int	obs	= 512;
49 int	bs;
50 int	cbs;
51 int	ibc;
52 int	obc;
53 int	cbc;
54 int	nifr;
55 int	nipr;
56 int	nofr;
57 int	nopr;
58 int	ntrunc;
59 int	ibf;
60 int	obf;
61 char	*op;
62 int	nspace;
63 char	etoa[] = {
64 	0000,0001,0002,0003,0234,0011,0206,0177,
65 	0227,0215,0216,0013,0014,0015,0016,0017,
66 	0020,0021,0022,0023,0235,0205,0010,0207,
67 	0030,0031,0222,0217,0034,0035,0036,0037,
68 	0200,0201,0202,0203,0204,0012,0027,0033,
69 	0210,0211,0212,0213,0214,0005,0006,0007,
70 	0220,0221,0026,0223,0224,0225,0226,0004,
71 	0230,0231,0232,0233,0024,0025,0236,0032,
72 	0040,0240,0241,0242,0243,0244,0245,0246,
73 	0247,0250,0133,0056,0074,0050,0053,0041,
74 	0046,0251,0252,0253,0254,0255,0256,0257,
75 	0260,0261,0135,0044,0052,0051,0073,0136,
76 	0055,0057,0262,0263,0264,0265,0266,0267,
77 	0270,0271,0174,0054,0045,0137,0076,0077,
78 	0272,0273,0274,0275,0276,0277,0300,0301,
79 	0302,0140,0072,0043,0100,0047,0075,0042,
80 	0303,0141,0142,0143,0144,0145,0146,0147,
81 	0150,0151,0304,0305,0306,0307,0310,0311,
82 	0312,0152,0153,0154,0155,0156,0157,0160,
83 	0161,0162,0313,0314,0315,0316,0317,0320,
84 	0321,0176,0163,0164,0165,0166,0167,0170,
85 	0171,0172,0322,0323,0324,0325,0326,0327,
86 	0330,0331,0332,0333,0334,0335,0336,0337,
87 	0340,0341,0342,0343,0344,0345,0346,0347,
88 	0173,0101,0102,0103,0104,0105,0106,0107,
89 	0110,0111,0350,0351,0352,0353,0354,0355,
90 	0175,0112,0113,0114,0115,0116,0117,0120,
91 	0121,0122,0356,0357,0360,0361,0362,0363,
92 	0134,0237,0123,0124,0125,0126,0127,0130,
93 	0131,0132,0364,0365,0366,0367,0370,0371,
94 	0060,0061,0062,0063,0064,0065,0066,0067,
95 	0070,0071,0372,0373,0374,0375,0376,0377,
96 };
97 char	atoe[] = {
98 	0000,0001,0002,0003,0067,0055,0056,0057,
99 	0026,0005,0045,0013,0014,0015,0016,0017,
100 	0020,0021,0022,0023,0074,0075,0062,0046,
101 	0030,0031,0077,0047,0034,0035,0036,0037,
102 	0100,0117,0177,0173,0133,0154,0120,0175,
103 	0115,0135,0134,0116,0153,0140,0113,0141,
104 	0360,0361,0362,0363,0364,0365,0366,0367,
105 	0370,0371,0172,0136,0114,0176,0156,0157,
106 	0174,0301,0302,0303,0304,0305,0306,0307,
107 	0310,0311,0321,0322,0323,0324,0325,0326,
108 	0327,0330,0331,0342,0343,0344,0345,0346,
109 	0347,0350,0351,0112,0340,0132,0137,0155,
110 	0171,0201,0202,0203,0204,0205,0206,0207,
111 	0210,0211,0221,0222,0223,0224,0225,0226,
112 	0227,0230,0231,0242,0243,0244,0245,0246,
113 	0247,0250,0251,0300,0152,0320,0241,0007,
114 	0040,0041,0042,0043,0044,0025,0006,0027,
115 	0050,0051,0052,0053,0054,0011,0012,0033,
116 	0060,0061,0032,0063,0064,0065,0066,0010,
117 	0070,0071,0072,0073,0004,0024,0076,0341,
118 	0101,0102,0103,0104,0105,0106,0107,0110,
119 	0111,0121,0122,0123,0124,0125,0126,0127,
120 	0130,0131,0142,0143,0144,0145,0146,0147,
121 	0150,0151,0160,0161,0162,0163,0164,0165,
122 	0166,0167,0170,0200,0212,0213,0214,0215,
123 	0216,0217,0220,0232,0233,0234,0235,0236,
124 	0237,0240,0252,0253,0254,0255,0256,0257,
125 	0260,0261,0262,0263,0264,0265,0266,0267,
126 	0270,0271,0272,0273,0274,0275,0276,0277,
127 	0312,0313,0314,0315,0316,0317,0332,0333,
128 	0334,0335,0336,0337,0352,0353,0354,0355,
129 	0356,0357,0372,0373,0374,0375,0376,0377,
130 };
131 char	atoibm[] =
132 {
133 	0000,0001,0002,0003,0067,0055,0056,0057,
134 	0026,0005,0045,0013,0014,0015,0016,0017,
135 	0020,0021,0022,0023,0074,0075,0062,0046,
136 	0030,0031,0077,0047,0034,0035,0036,0037,
137 	0100,0132,0177,0173,0133,0154,0120,0175,
138 	0115,0135,0134,0116,0153,0140,0113,0141,
139 	0360,0361,0362,0363,0364,0365,0366,0367,
140 	0370,0371,0172,0136,0114,0176,0156,0157,
141 	0174,0301,0302,0303,0304,0305,0306,0307,
142 	0310,0311,0321,0322,0323,0324,0325,0326,
143 	0327,0330,0331,0342,0343,0344,0345,0346,
144 	0347,0350,0351,0255,0340,0275,0137,0155,
145 	0171,0201,0202,0203,0204,0205,0206,0207,
146 	0210,0211,0221,0222,0223,0224,0225,0226,
147 	0227,0230,0231,0242,0243,0244,0245,0246,
148 	0247,0250,0251,0300,0117,0320,0241,0007,
149 	0040,0041,0042,0043,0044,0025,0006,0027,
150 	0050,0051,0052,0053,0054,0011,0012,0033,
151 	0060,0061,0032,0063,0064,0065,0066,0010,
152 	0070,0071,0072,0073,0004,0024,0076,0341,
153 	0101,0102,0103,0104,0105,0106,0107,0110,
154 	0111,0121,0122,0123,0124,0125,0126,0127,
155 	0130,0131,0142,0143,0144,0145,0146,0147,
156 	0150,0151,0160,0161,0162,0163,0164,0165,
157 	0166,0167,0170,0200,0212,0213,0214,0215,
158 	0216,0217,0220,0232,0233,0234,0235,0236,
159 	0237,0240,0252,0253,0254,0255,0256,0257,
160 	0260,0261,0262,0263,0264,0265,0266,0267,
161 	0270,0271,0272,0273,0274,0275,0276,0277,
162 	0312,0313,0314,0315,0316,0317,0332,0333,
163 	0334,0335,0336,0337,0352,0353,0354,0355,
164 	0356,0357,0372,0373,0374,0375,0376,0377,
165 };
166 
167 enum ftype { unknown, reg, chr, tape, ispipe } iftype;
168 enum ftype checktype();
169 
170 void stats(), term();
171 
172 main(argc, argv)
173 int	argc;
174 char	**argv;
175 {
176 	int (*conv)();
177 	register char *ip;
178 	register c;
179 	int ebcdic(), ibm(), ascii(), null(), cnull(), block(), unblock();
180 	int a;
181 
182 	conv = null;
183 	for(c=1; c<argc; c++) {
184 		string = argv[c];
185 		if(match("ibs=")) {
186 			ibs = number(BIG);
187 			continue;
188 		}
189 		if(match("obs=")) {
190 			obs = number(BIG);
191 			continue;
192 		}
193 		if(match("cbs=")) {
194 			cbs = number(BIG);
195 			continue;
196 		}
197 		if (match("bs=")) {
198 			bs = number(BIG);
199 			continue;
200 		}
201 		if(match("if=")) {
202 			ifile = string;
203 			continue;
204 		}
205 		if(match("of=")) {
206 			ofile = string;
207 			continue;
208 		}
209 		if(match("skip=")) {
210 			skip = number(BIG);
211 			continue;
212 		}
213 		if(match("seek=")) {
214 			seekn = number(BIG);
215 			continue;
216 		}
217 		if(match("count=")) {
218 			count = number(BIG);
219 			continue;
220 		}
221 		if(match("files=")) {
222 			files = number(BIG);
223 			continue;
224 		}
225 		if(match("conv=")) {
226 		cloop:
227 			if(match(","))
228 				goto cloop;
229 			if(*string == '\0')
230 				continue;
231 			if(match("ebcdic")) {
232 				conv = ebcdic;
233 				goto cloop;
234 			}
235 			if(match("ibm")) {
236 				conv = ibm;
237 				goto cloop;
238 			}
239 			if(match("ascii")) {
240 				conv = ascii;
241 				goto cloop;
242 			}
243 			if(match("block")) {
244 				conv = block;
245 				goto cloop;
246 			}
247 			if(match("unblock")) {
248 				conv = unblock;
249 				goto cloop;
250 			}
251 			if(match("lcase")) {
252 				cflag |= LCASE;
253 				goto cloop;
254 			}
255 			if(match("ucase")) {
256 				cflag |= UCASE;
257 				goto cloop;
258 			}
259 			if(match("swab")) {
260 				cflag |= SWAB;
261 				goto cloop;
262 			}
263 			if(match("noerror")) {
264 				cflag |= NERR;
265 				goto cloop;
266 			}
267 			if(match("sync")) {
268 				cflag |= SYNC;
269 				goto cloop;
270 			}
271 		}
272 		fprintf(stderr,"bad arg: %s\n", string);
273 		exit(1);
274 	}
275 	if(conv == null && cflag&(LCASE|UCASE))
276 		conv = cnull;
277 	if (ifile)
278 		ibf = open(ifile, 0);
279 	else
280 		ibf = dup(0);
281 	if(ibf < 0) {
282 		perror(ifile);
283 		exit(1);
284 	}
285 	iftype = checktype(ibf);
286 	obf = ofile ? open(ofile, O_WRONLY|O_CREAT, 0666) : dup(1);
287 	if(obf < 0) {
288 		fprintf(stderr,"cannot create: %s\n", ofile);
289 		exit(1);
290 	}
291 	if (bs) {
292 		ibs = obs = bs;
293 		if (conv == null && (cflag &~ (SYNC|NERR)) == 0)
294 			fflag++;
295 	}
296 	if(ibs == 0 || obs == 0) {
297 		fprintf(stderr,"counts: cannot be zero\n");
298 		exit(1);
299 	}
300 	ibuf = sbrk(ibs);
301 	if (fflag)
302 		obuf = ibuf;
303 	else
304 		obuf = sbrk(obs);
305 	sbrk(64);	/* For good measure */
306 	if(ibuf == (char *)-1 || obuf == (char *)-1) {
307 		fprintf(stderr, "not enough memory\n");
308 		exit(1);
309 	}
310 	ibc = 0;
311 	obc = 0;
312 	cbc = 0;
313 	op = obuf;
314 
315 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
316 		signal(SIGINT, term);
317 	signal(SIGINFO, stats);
318 	if (skip)
319 	    switch (iftype) {
320 		case tape: {
321 			struct mtop op;
322 
323 			op.mt_op = MTFSR;
324 			op.mt_count = skip;
325 			if (ioctl(ibf, MTIOCTOP, (char *)&op) < 0)
326 				perror("dd: skip: tape forward-space-record");
327 			}
328 			break;
329 		case reg:
330 			lseek(ibf, skip*ibs, SEEK_CUR);
331 			break;
332 		default:
333 			while (skip--)
334 				read(ibf, ibuf, ibs);
335 			break;
336 	}
337 	if (seekn)
338 	    switch (checktype(obf)) {
339 		case reg:
340 			lseek(obf, (long)obs*seekn, SEEK_CUR);
341 			break;
342 		case ispipe:
343 			fprintf(stderr, "dd: can't seek on pipe\n");
344 			break;
345 		default:
346 			while (seekn--)
347 				lseek(obf, (long)obs, SEEK_CUR);
348 			break;
349 	}
350 
351 loop:
352 	if(ibc-- == 0) {
353 		ibc = 0;
354 		if(count==0 || nifr+nipr!=count) {
355 			if (cflag&NERR)
356 				bzero((char *)ibuf, ibs);
357 			ibc = read(ibf, ibuf, ibs);
358 		}
359 		if(ibc == -1) {
360 			perror("read");
361 			if((cflag&NERR) == 0) {
362 				flsh();
363 				term();
364 			}
365 			/* guess actual read size; default still -1 */
366 			for(c=0; c<ibs; c++)
367 				if(ibuf[c] != 0)
368 					ibc = c + 1;
369 			stats();
370 			advance(ibf, iftype, ibs);
371 		}
372 		if(ibc == 0 && --files<=0) {
373 			flsh();
374 			term();
375 		}
376 		if(ibc != ibs) {
377 			if (ibc == -1)
378 				ibc = 0;
379 			nipr++;
380 			if (cflag&SYNC) {
381 				bzero(ibuf + ibc, ibs - ibc);
382 				ibc = ibs;
383 			}
384 		} else
385 			nifr++;
386 		ip = ibuf;
387 		c = ibc >> 1;
388 		if(cflag&SWAB && c)
389 		do {
390 			a = *ip++;
391 			ip[-1] = *ip;
392 			*ip++ = a;
393 		} while(--c);
394 		ip = ibuf;
395 		if (fflag) {
396 			obc = ibc;
397 			flsh();
398 			ibc = 0;
399 		}
400 		goto loop;
401 	}
402 	c = 0;
403 	c |= *ip++;
404 	c &= 0377;
405 	(*conv)(c);
406 	goto loop;
407 }
408 
409 flsh()
410 {
411 	register c;
412 
413 	if(obc) {
414 		if(obc == obs)
415 			nofr++; else
416 			nopr++;
417 		c = write(obf, obuf, obc);
418 		if(c != obc) {
419 			perror("write");
420 			term();
421 		}
422 		obc = 0;
423 	}
424 }
425 
426 match(s)
427 char *s;
428 {
429 	register char *cs;
430 
431 	cs = string;
432 	while(*cs++ == *s)
433 		if(*s++ == '\0')
434 			goto true;
435 	if(*s != '\0')
436 		return(0);
437 
438 true:
439 	cs--;
440 	string = cs;
441 	return(1);
442 }
443 
444 number(big)
445 {
446 	register char *cs;
447 	long n;
448 
449 	cs = string;
450 	n = 0;
451 	while(*cs >= '0' && *cs <= '9')
452 		n = n*10 + *cs++ - '0';
453 	for(;;)
454 	switch(*cs++) {
455 
456 	case 'k':
457 		n *= 1024;
458 		continue;
459 
460 	case 'w':
461 		n *= sizeof(int);
462 		continue;
463 
464 	case 'b':
465 		n *= 512;
466 		continue;
467 
468 	case '*':
469 	case 'x':
470 		string = cs;
471 		n *= number(BIG);
472 
473 	case '\0':
474 		if (n>=big || n<0) {
475 			fprintf(stderr, "dd: argument %ld out of range\n", n);
476 			exit(1);
477 		}
478 		return(n);
479 	}
480 	/* never gets here */
481 }
482 
483 cnull(cc)
484 {
485 	register c;
486 
487 	c = cc;
488 	if(cflag&UCASE && c>='a' && c<='z')
489 		c += 'A'-'a';
490 	if(cflag&LCASE && c>='A' && c<='Z')
491 		c += 'a'-'A';
492 	null(c);
493 }
494 
495 null(c)
496 {
497 
498 	*op = c;
499 	op++;
500 	if(++obc >= obs) {
501 		flsh();
502 		op = obuf;
503 	}
504 }
505 
506 ascii(cc)
507 {
508 	register c;
509 
510 	c = etoa[cc] & 0377;
511 	if(cbs == 0) {
512 		cnull(c);
513 		return;
514 	}
515 	if(c == ' ') {
516 		nspace++;
517 		goto out;
518 	}
519 	while(nspace > 0) {
520 		null(' ');
521 		nspace--;
522 	}
523 	cnull(c);
524 
525 out:
526 	if(++cbc >= cbs) {
527 		null('\n');
528 		cbc = 0;
529 		nspace = 0;
530 	}
531 }
532 
533 unblock(cc)
534 {
535 	register c;
536 
537 	c = cc & 0377;
538 	if(cbs == 0) {
539 		cnull(c);
540 		return;
541 	}
542 	if(c == ' ') {
543 		nspace++;
544 		goto out;
545 	}
546 	while(nspace > 0) {
547 		null(' ');
548 		nspace--;
549 	}
550 	cnull(c);
551 
552 out:
553 	if(++cbc >= cbs) {
554 		null('\n');
555 		cbc = 0;
556 		nspace = 0;
557 	}
558 }
559 
560 ebcdic(cc)
561 {
562 	register c;
563 
564 	c = cc;
565 	if(cflag&UCASE && c>='a' && c<='z')
566 		c += 'A'-'a';
567 	if(cflag&LCASE && c>='A' && c<='Z')
568 		c += 'a'-'A';
569 	c = atoe[c] & 0377;
570 	if(cbs == 0) {
571 		null(c);
572 		return;
573 	}
574 	if(cc == '\n') {
575 		while(cbc < cbs) {
576 			null(atoe[' ']);
577 			cbc++;
578 		}
579 		cbc = 0;
580 		return;
581 	}
582 	if(cbc == cbs)
583 		ntrunc++;
584 	cbc++;
585 	if(cbc <= cbs)
586 		null(c);
587 }
588 
589 ibm(cc)
590 {
591 	register c;
592 
593 	c = cc;
594 	if(cflag&UCASE && c>='a' && c<='z')
595 		c += 'A'-'a';
596 	if(cflag&LCASE && c>='A' && c<='Z')
597 		c += 'a'-'A';
598 	c = atoibm[c] & 0377;
599 	if(cbs == 0) {
600 		null(c);
601 		return;
602 	}
603 	if(cc == '\n') {
604 		while(cbc < cbs) {
605 			null(atoibm[' ']);
606 			cbc++;
607 		}
608 		cbc = 0;
609 		return;
610 	}
611 	if(cbc == cbs)
612 		ntrunc++;
613 	cbc++;
614 	if(cbc <= cbs)
615 		null(c);
616 }
617 
618 block(cc)
619 {
620 	register c;
621 
622 	c = cc;
623 	if(cflag&UCASE && c>='a' && c<='z')
624 		c += 'A'-'a';
625 	if(cflag&LCASE && c>='A' && c<='Z')
626 		c += 'a'-'A';
627 	c &= 0377;
628 	if(cbs == 0) {
629 		null(c);
630 		return;
631 	}
632 	if(cc == '\n') {
633 		while(cbc < cbs) {
634 			null(' ');
635 			cbc++;
636 		}
637 		cbc = 0;
638 		return;
639 	}
640 	if(cbc == cbs)
641 		ntrunc++;
642 	cbc++;
643 	if(cbc <= cbs)
644 		null(c);
645 }
646 
647 void
648 term()
649 {
650 
651 	stats();
652 	exit(0);
653 }
654 
655 void
656 stats()
657 {
658 
659 	fprintf(stderr,"%u+%u records in\n", nifr, nipr);
660 	fprintf(stderr,"%u+%u records out\n", nofr, nopr);
661 	if(ntrunc)
662 		fprintf(stderr,"%u truncated records\n", ntrunc);
663 }
664 
665 enum ftype
666 checktype(fd)
667 	int fd;
668 {
669 	struct stat st;
670 	struct mtget mt;
671 
672 	if (fstat(fd, &st) == -1)
673 		return (unknown);
674 	if (S_ISFIFO(st.st_mode))
675 		return (ispipe);
676 	if (S_ISCHR(st.st_mode)) {
677 		if (ioctl(fd, MTIOCGET, (char *)&mt) != -1)
678 			return (tape);
679 		return (chr);
680 	}
681 	return (reg);	/* or dir, symlink, blk, or ??? */
682 }
683 
684 advance(fd, fdtype, count)
685 {
686 
687 	switch (fdtype) {
688 	case reg:
689 	case chr:
690 		lseek(fd, count, SEEK_CUR);
691 		break;
692 	case ispipe:
693 	case tape:
694 		break;
695 	default:
696 		fprintf(stderr, "dd: unknown input type, can't resynchronize\n");
697 		exit(99);
698 	}
699 }
700 
701