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