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