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