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