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