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