xref: /plan9-contrib/sys/src/cmd/dd.c (revision 53e3ee71f37751cbb76303e518ab6934fae3f622)
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 'm':
372 		n *= 1024*1024;
373 		continue;
374 
375 	case 'k':
376 		n *= 1024;
377 		continue;
378 
379 	case 'b':
380 		n *= 512;
381 		continue;
382 
383 /*	case '*':*/
384 	case 'x':
385 		string = cs;
386 		n *= number(VBIG);
387 
388 	case '\0':
389 		if(n > big) {
390 			fprint(2, "dd: argument %llud out of range\n", n);
391 			exits("range");
392 		}
393 		return n;
394 	}
395 	/* never gets here */
396 }
397 
398 void
cnull(int cc)399 cnull(int cc)
400 {
401 	int c;
402 
403 	c = cc;
404 	if((cflag&UCASE) && c>='a' && c<='z')
405 		c += 'A'-'a';
406 	if((cflag&LCASE) && c>='A' && c<='Z')
407 		c += 'a'-'A';
408 	null(c);
409 }
410 
411 void
null(int c)412 null(int c)
413 {
414 
415 	*op = c;
416 	op++;
417 	if(++obc >= obs) {
418 		flsh();
419 		op = obuf;
420 	}
421 }
422 
423 void
ascii(int cc)424 ascii(int cc)
425 {
426 	int c;
427 
428 	c = etoa[cc];
429 	if(cbs == 0) {
430 		cnull(c);
431 		return;
432 	}
433 	if(c == ' ') {
434 		nspace++;
435 		goto out;
436 	}
437 	while(nspace > 0) {
438 		null(' ');
439 		nspace--;
440 	}
441 	cnull(c);
442 
443 out:
444 	if(++cbc >= cbs) {
445 		null('\n');
446 		cbc = 0;
447 		nspace = 0;
448 	}
449 }
450 
451 void
unblock(int cc)452 unblock(int cc)
453 {
454 	int c;
455 
456 	c = cc & 0377;
457 	if(cbs == 0) {
458 		cnull(c);
459 		return;
460 	}
461 	if(c == ' ') {
462 		nspace++;
463 		goto out;
464 	}
465 	while(nspace > 0) {
466 		null(' ');
467 		nspace--;
468 	}
469 	cnull(c);
470 
471 out:
472 	if(++cbc >= cbs) {
473 		null('\n');
474 		cbc = 0;
475 		nspace = 0;
476 	}
477 }
478 
479 void
ebcdic(int cc)480 ebcdic(int cc)
481 {
482 	int c;
483 
484 	c = cc;
485 	if(cflag&UCASE && c>='a' && c<='z')
486 		c += 'A'-'a';
487 	if(cflag&LCASE && c>='A' && c<='Z')
488 		c += 'a'-'A';
489 	c = atoe[c];
490 	if(cbs == 0) {
491 		null(c);
492 		return;
493 	}
494 	if(cc == '\n') {
495 		while(cbc < cbs) {
496 			null(atoe[' ']);
497 			cbc++;
498 		}
499 		cbc = 0;
500 		return;
501 	}
502 	if(cbc == cbs)
503 		ntrunc++;
504 	cbc++;
505 	if(cbc <= cbs)
506 		null(c);
507 }
508 
509 void
ibm(int cc)510 ibm(int cc)
511 {
512 	int c;
513 
514 	c = cc;
515 	if(cflag&UCASE && c>='a' && c<='z')
516 		c += 'A'-'a';
517 	if(cflag&LCASE && c>='A' && c<='Z')
518 		c += 'a'-'A';
519 	c = atoibm[c] & 0377;
520 	if(cbs == 0) {
521 		null(c);
522 		return;
523 	}
524 	if(cc == '\n') {
525 		while(cbc < cbs) {
526 			null(atoibm[' ']);
527 			cbc++;
528 		}
529 		cbc = 0;
530 		return;
531 	}
532 	if(cbc == cbs)
533 		ntrunc++;
534 	cbc++;
535 	if(cbc <= cbs)
536 		null(c);
537 }
538 
539 void
block(int cc)540 block(int cc)
541 {
542 	int c;
543 
544 	c = cc;
545 	if(cflag&UCASE && c>='a' && c<='z')
546 		c += 'A'-'a';
547 	if(cflag&LCASE && c>='A' && c<='Z')
548 		c += 'a'-'A';
549 	c &= 0377;
550 	if(cbs == 0) {
551 		null(c);
552 		return;
553 	}
554 	if(cc == '\n') {
555 		while(cbc < cbs) {
556 			null(' ');
557 			cbc++;
558 		}
559 		cbc = 0;
560 		return;
561 	}
562 	if(cbc == cbs)
563 		ntrunc++;
564 	cbc++;
565 	if(cbc <= cbs)
566 		null(c);
567 }
568 
569 void
term(char * status)570 term(char *status)
571 {
572 	stats();
573 	exits(status);
574 }
575 
576 void
stats(void)577 stats(void)
578 {
579 	if(quiet)
580 		return;
581 	fprint(2, "%lud+%lud records in\n", nifr, nipr);
582 	fprint(2, "%lud+%lud records out\n", nofr, nopr);
583 	if(ntrunc)
584 		fprint(2, "%lud truncated records\n", ntrunc);
585 }
586 
587 uchar	etoa[] =
588 {
589 	0000,0001,0002,0003,0234,0011,0206,0177,
590 	0227,0215,0216,0013,0014,0015,0016,0017,
591 	0020,0021,0022,0023,0235,0205,0010,0207,
592 	0030,0031,0222,0217,0034,0035,0036,0037,
593 	0200,0201,0202,0203,0204,0012,0027,0033,
594 	0210,0211,0212,0213,0214,0005,0006,0007,
595 	0220,0221,0026,0223,0224,0225,0226,0004,
596 	0230,0231,0232,0233,0024,0025,0236,0032,
597 	0040,0240,0241,0242,0243,0244,0245,0246,
598 	0247,0250,0133,0056,0074,0050,0053,0041,
599 	0046,0251,0252,0253,0254,0255,0256,0257,
600 	0260,0261,0135,0044,0052,0051,0073,0136,
601 	0055,0057,0262,0263,0264,0265,0266,0267,
602 	0270,0271,0174,0054,0045,0137,0076,0077,
603 	0272,0273,0274,0275,0276,0277,0300,0301,
604 	0302,0140,0072,0043,0100,0047,0075,0042,
605 	0303,0141,0142,0143,0144,0145,0146,0147,
606 	0150,0151,0304,0305,0306,0307,0310,0311,
607 	0312,0152,0153,0154,0155,0156,0157,0160,
608 	0161,0162,0313,0314,0315,0316,0317,0320,
609 	0321,0176,0163,0164,0165,0166,0167,0170,
610 	0171,0172,0322,0323,0324,0325,0326,0327,
611 	0330,0331,0332,0333,0334,0335,0336,0337,
612 	0340,0341,0342,0343,0344,0345,0346,0347,
613 	0173,0101,0102,0103,0104,0105,0106,0107,
614 	0110,0111,0350,0351,0352,0353,0354,0355,
615 	0175,0112,0113,0114,0115,0116,0117,0120,
616 	0121,0122,0356,0357,0360,0361,0362,0363,
617 	0134,0237,0123,0124,0125,0126,0127,0130,
618 	0131,0132,0364,0365,0366,0367,0370,0371,
619 	0060,0061,0062,0063,0064,0065,0066,0067,
620 	0070,0071,0372,0373,0374,0375,0376,0377,
621 };
622 uchar	atoe[] =
623 {
624 	0000,0001,0002,0003,0067,0055,0056,0057,
625 	0026,0005,0045,0013,0014,0015,0016,0017,
626 	0020,0021,0022,0023,0074,0075,0062,0046,
627 	0030,0031,0077,0047,0034,0035,0036,0037,
628 	0100,0117,0177,0173,0133,0154,0120,0175,
629 	0115,0135,0134,0116,0153,0140,0113,0141,
630 	0360,0361,0362,0363,0364,0365,0366,0367,
631 	0370,0371,0172,0136,0114,0176,0156,0157,
632 	0174,0301,0302,0303,0304,0305,0306,0307,
633 	0310,0311,0321,0322,0323,0324,0325,0326,
634 	0327,0330,0331,0342,0343,0344,0345,0346,
635 	0347,0350,0351,0112,0340,0132,0137,0155,
636 	0171,0201,0202,0203,0204,0205,0206,0207,
637 	0210,0211,0221,0222,0223,0224,0225,0226,
638 	0227,0230,0231,0242,0243,0244,0245,0246,
639 	0247,0250,0251,0300,0152,0320,0241,0007,
640 	0040,0041,0042,0043,0044,0025,0006,0027,
641 	0050,0051,0052,0053,0054,0011,0012,0033,
642 	0060,0061,0032,0063,0064,0065,0066,0010,
643 	0070,0071,0072,0073,0004,0024,0076,0341,
644 	0101,0102,0103,0104,0105,0106,0107,0110,
645 	0111,0121,0122,0123,0124,0125,0126,0127,
646 	0130,0131,0142,0143,0144,0145,0146,0147,
647 	0150,0151,0160,0161,0162,0163,0164,0165,
648 	0166,0167,0170,0200,0212,0213,0214,0215,
649 	0216,0217,0220,0232,0233,0234,0235,0236,
650 	0237,0240,0252,0253,0254,0255,0256,0257,
651 	0260,0261,0262,0263,0264,0265,0266,0267,
652 	0270,0271,0272,0273,0274,0275,0276,0277,
653 	0312,0313,0314,0315,0316,0317,0332,0333,
654 	0334,0335,0336,0337,0352,0353,0354,0355,
655 	0356,0357,0372,0373,0374,0375,0376,0377,
656 };
657 uchar	atoibm[] =
658 {
659 	0000,0001,0002,0003,0067,0055,0056,0057,
660 	0026,0005,0045,0013,0014,0015,0016,0017,
661 	0020,0021,0022,0023,0074,0075,0062,0046,
662 	0030,0031,0077,0047,0034,0035,0036,0037,
663 	0100,0132,0177,0173,0133,0154,0120,0175,
664 	0115,0135,0134,0116,0153,0140,0113,0141,
665 	0360,0361,0362,0363,0364,0365,0366,0367,
666 	0370,0371,0172,0136,0114,0176,0156,0157,
667 	0174,0301,0302,0303,0304,0305,0306,0307,
668 	0310,0311,0321,0322,0323,0324,0325,0326,
669 	0327,0330,0331,0342,0343,0344,0345,0346,
670 	0347,0350,0351,0255,0340,0275,0137,0155,
671 	0171,0201,0202,0203,0204,0205,0206,0207,
672 	0210,0211,0221,0222,0223,0224,0225,0226,
673 	0227,0230,0231,0242,0243,0244,0245,0246,
674 	0247,0250,0251,0300,0117,0320,0241,0007,
675 	0040,0041,0042,0043,0044,0025,0006,0027,
676 	0050,0051,0052,0053,0054,0011,0012,0033,
677 	0060,0061,0032,0063,0064,0065,0066,0010,
678 	0070,0071,0072,0073,0004,0024,0076,0341,
679 	0101,0102,0103,0104,0105,0106,0107,0110,
680 	0111,0121,0122,0123,0124,0125,0126,0127,
681 	0130,0131,0142,0143,0144,0145,0146,0147,
682 	0150,0151,0160,0161,0162,0163,0164,0165,
683 	0166,0167,0170,0200,0212,0213,0214,0215,
684 	0216,0217,0220,0232,0233,0234,0235,0236,
685 	0237,0240,0252,0253,0254,0255,0256,0257,
686 	0260,0261,0262,0263,0264,0265,0266,0267,
687 	0270,0271,0272,0273,0274,0275,0276,0277,
688 	0312,0313,0314,0315,0316,0317,0332,0333,
689 	0334,0335,0336,0337,0352,0353,0354,0355,
690 	0356,0357,0372,0373,0374,0375,0376,0377,
691 };
692