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