1 /*
2 * dd - convert and copy
3 *
4 * Gunnar Ritter, Freiburg i. Br., Germany, January 2003.
5 */
6 /*
7 * Copyright (c) 2003 Gunnar Ritter
8 *
9 * This software is provided 'as-is', without any express or implied
10 * warranty. In no event will the authors be held liable for any damages
11 * arising from the use of this software.
12 *
13 * Permission is granted to anyone to use this software for any purpose,
14 * including commercial applications, and to alter it and redistribute
15 * it freely, subject to the following restrictions:
16 *
17 * 1. The origin of this software must not be misrepresented; you must not
18 * claim that you wrote the original software. If you use this software
19 * in a product, an acknowledgment in the product documentation would be
20 * appreciated but is not required.
21 *
22 * 2. Altered source versions must be plainly marked as such, and must not be
23 * misrepresented as being the original software.
24 *
25 * 3. This notice may not be removed or altered from any source distribution.
26 */
27
28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
29 #define USED __attribute__ ((used))
30 #elif defined __GNUC__
31 #define USED __attribute__ ((unused))
32 #else
33 #define USED
34 #endif
35 static const char sccsid[] USED = "@(#)dd.sl 1.30 (gritter) 1/22/06";
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <errno.h>
45 #include <libgen.h>
46 #include <ctype.h>
47 #include <locale.h>
48 #include <signal.h>
49 #include "sigset.h"
50 #include <wchar.h>
51 #include <wctype.h>
52 #include <limits.h>
53
54 #include <sys/ioctl.h>
55
56 #if defined (__linux__) || defined (__sun) || defined (__FreeBSD__) || \
57 defined (__hpux) || defined (_AIX) || defined (__NetBSD__) || \
58 defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
59 #include <sys/mtio.h>
60 #else /* SVR4.2MP */
61 #include <sys/scsi.h>
62 #include <sys/st01.h>
63 #endif /* SVR4.2MP */
64
65 #include "atoll.h"
66 #include "memalign.h"
67 #include "mbtowi.h"
68
69 /*
70 * For 'conv=ascii'.
71 */
72 static const unsigned char c_ascii[] = {
73 0000,0001,0002,0003,0234,0011,0206,0177,0227,0215,0216,0013,0014,0015,0016,0017,
74 0020,0021,0022,0023,0235,0205,0010,0207,0030,0031,0222,0217,0034,0035,0036,0037,
75 0200,0201,0202,0203,0204,0012,0027,0033,0210,0211,0212,0213,0214,0005,0006,0007,
76 0220,0221,0026,0223,0224,0225,0226,0004,0230,0231,0232,0233,0024,0025,0236,0032,
77 0040,0240,0241,0242,0243,0244,0245,0246,0247,0250,0325,0056,0074,0050,0053,0174,
78 0046,0251,0252,0253,0254,0255,0256,0257,0260,0261,0041,0044,0052,0051,0073,0176,
79 0055,0057,0262,0263,0264,0265,0266,0267,0270,0271,0313,0054,0045,0137,0076,0077,
80 0272,0273,0274,0275,0276,0277,0300,0301,0302,0140,0072,0043,0100,0047,0075,0042,
81 0303,0141,0142,0143,0144,0145,0146,0147,0150,0151,0304,0305,0306,0307,0310,0311,
82 0312,0152,0153,0154,0155,0156,0157,0160,0161,0162,0136,0314,0315,0316,0317,0320,
83 0321,0345,0163,0164,0165,0166,0167,0170,0171,0172,0322,0323,0324,0133,0326,0327,
84 0330,0331,0332,0333,0334,0335,0336,0337,0340,0341,0342,0343,0344,0135,0346,0347,
85 0173,0101,0102,0103,0104,0105,0106,0107,0110,0111,0350,0351,0352,0353,0354,0355,
86 0175,0112,0113,0114,0115,0116,0117,0120,0121,0122,0356,0357,0360,0361,0362,0363,
87 0134,0237,0123,0124,0125,0126,0127,0130,0131,0132,0364,0365,0366,0367,0370,0371,
88 0060,0061,0062,0063,0064,0065,0066,0067,0070,0071,0372,0373,0374,0375,0376,0377
89 };
90
91 /*
92 * For 'conv=ibm'.
93 */
94 static const unsigned char c_ibm[] = {
95 0000,0001,0002,0003,0067,0055,0056,0057,0026,0005,0045,0013,0014,0015,0016,0017,
96 0020,0021,0022,0023,0074,0075,0062,0046,0030,0031,0077,0047,0034,0035,0036,0037,
97 0100,0132,0177,0173,0133,0154,0120,0175,0115,0135,0134,0116,0153,0140,0113,0141,
98 0360,0361,0362,0363,0364,0365,0366,0367,0370,0371,0172,0136,0114,0176,0156,0157,
99 0174,0301,0302,0303,0304,0305,0306,0307,0310,0311,0321,0322,0323,0324,0325,0326,
100 0327,0330,0331,0342,0343,0344,0345,0346,0347,0350,0351,0255,0340,0275,0137,0155,
101 0171,0201,0202,0203,0204,0205,0206,0207,0210,0211,0221,0222,0223,0224,0225,0226,
102 0227,0230,0231,0242,0243,0244,0245,0246,0247,0250,0251,0300,0117,0320,0241,0007,
103 0040,0041,0042,0043,0044,0025,0006,0027,0050,0051,0052,0053,0054,0011,0012,0033,
104 0060,0061,0032,0063,0064,0065,0066,0010,0070,0071,0072,0073,0004,0024,0076,0341,
105 0101,0102,0103,0104,0105,0106,0107,0110,0111,0121,0122,0123,0124,0125,0126,0127,
106 0130,0131,0142,0143,0144,0145,0146,0147,0150,0151,0160,0161,0162,0163,0164,0165,
107 0166,0167,0170,0200,0212,0213,0214,0215,0216,0217,0220,0232,0233,0234,0235,0236,
108 0237,0240,0252,0253,0254,0255,0256,0257,0260,0261,0262,0263,0264,0265,0266,0267,
109 0270,0271,0272,0273,0274,0275,0276,0277,0312,0313,0314,0315,0316,0317,0332,0333,
110 0334,0335,0336,0337,0352,0353,0354,0355,0356,0357,0372,0373,0374,0375,0376,0377
111 };
112
113 /*
114 * For 'conv=ebcdic'.
115 */
116 static const unsigned char c_ebcdic[] = {
117 0000,0001,0002,0003,0067,0055,0056,0057,0026,0005,0045,0013,0014,0015,0016,0017,
118 0020,0021,0022,0023,0074,0075,0062,0046,0030,0031,0077,0047,0034,0035,0036,0037,
119 0100,0132,0177,0173,0133,0154,0120,0175,0115,0135,0134,0116,0153,0140,0113,0141,
120 0360,0361,0362,0363,0364,0365,0366,0367,0370,0371,0172,0136,0114,0176,0156,0157,
121 0174,0301,0302,0303,0304,0305,0306,0307,0310,0311,0321,0322,0323,0324,0325,0326,
122 0327,0330,0331,0342,0343,0344,0345,0346,0347,0350,0351,0255,0340,0275,0232,0155,
123 0171,0201,0202,0203,0204,0205,0206,0207,0210,0211,0221,0222,0223,0224,0225,0226,
124 0227,0230,0231,0242,0243,0244,0245,0246,0247,0250,0251,0300,0117,0320,0137,0007,
125 0040,0041,0042,0043,0044,0025,0006,0027,0050,0051,0052,0053,0054,0011,0012,0033,
126 0060,0061,0032,0063,0064,0065,0066,0010,0070,0071,0072,0073,0004,0024,0076,0341,
127 0101,0102,0103,0104,0105,0106,0107,0110,0111,0121,0122,0123,0124,0125,0126,0127,
128 0130,0131,0142,0143,0144,0145,0146,0147,0150,0151,0160,0161,0162,0163,0164,0165,
129 0166,0167,0170,0200,0212,0213,0214,0215,0216,0217,0220,0152,0233,0234,0235,0236,
130 0237,0240,0252,0253,0254,0112,0256,0257,0260,0261,0262,0263,0264,0265,0266,0267,
131 0270,0271,0272,0273,0274,0241,0276,0277,0312,0313,0314,0315,0316,0317,0332,0333,
132 0334,0335,0336,0337,0352,0353,0354,0355,0356,0357,0372,0373,0374,0375,0376,0377
133 };
134
135 static char *progname; /* argv[0] to main() */
136
137 typedef long long d_type;
138
139 static char *iblok; /* input buffer */
140 static char *oblok; /* output buffer */
141 static char *cblok; /* conversion buffer */
142
143 static char mblok[MB_LEN_MAX+1]; /* tow{upper|lower} buffer */
144 static char *mbp; /* points to remaining chars in mblok */
145 static int mbrest; /* number of remaining chars in mblok */
146
147 static const char *iffile; /* input file name */
148 static int iffd; /* input file descriptor */
149 static const char *offile; /* output file name */
150 static int offd; /* output file descriptor */
151 static struct stat istat; /* stat of input */
152 static struct stat ostat; /* stat of output */
153 static d_type ibs = 512; /* input block size */
154 static d_type obs = 512; /* output block size */
155 static d_type bs; /* size for both buffers */
156 static d_type oflow; /* remaining bytes in output buffer */
157 static d_type cbs; /* conversion block size */
158 static d_type cflow; /* remaining bytes in conv. buffer */
159 static int ctrunc; /* truncate current data (conv=block) */
160 static d_type skip; /* skip these blocks on input */
161 static d_type count = -1; /* no more than count blocks of input */
162 static int files = 1; /* read EOF this many times */
163 static d_type iseek; /* seek these blocks on input */
164 static d_type oseek; /* seek these blocks on output */
165 static int mb_cur_max; /* MB_CUR_MAX acceleration */
166
167 static d_type iwhole; /* statistics */
168 static d_type ipartial;
169 static d_type owhole;
170 static d_type opartial;
171 static d_type truncated;
172
173 static enum charconv {
174 CHAR_NONE = 0,
175 CHAR_ASCII = 1,
176 CHAR_EBCDIC = 2,
177 CHAR_IBM = 3
178 } chars = CHAR_NONE;
179
180 static enum conversion {
181 CONV_NONE = 0,
182 CONV_BLOCK = 01,
183 CONV_UNBLOCK = 02,
184 CONV_LCASE = 04,
185 CONV_UCASE = 010,
186 CONV_SWAB = 020,
187 CONV_NOERROR = 040,
188 CONV_NOTRUNC = 0100,
189 CONV_IDIRECT = 0200,
190 CONV_ODIRECT = 0400,
191 CONV_DIRECT = 0600,
192 CONV_SYNC = 01000
193 } convs = CONV_NONE;
194
195 static struct {
196 const char *c_name;
197 enum conversion c_conv;
198 enum charconv c_char;
199 } convtab[] = {
200 { "ascii", CONV_UNBLOCK, CHAR_ASCII },
201 { "ebcdic", CONV_BLOCK, CHAR_EBCDIC },
202 { "ibm", CONV_BLOCK, CHAR_IBM },
203 { "block", CONV_BLOCK, CHAR_NONE },
204 { "unblock", CONV_UNBLOCK, CHAR_NONE },
205 { "lcase", CONV_LCASE, CHAR_NONE },
206 { "ucase", CONV_UCASE, CHAR_NONE },
207 { "swab", CONV_SWAB, CHAR_NONE },
208 { "noerror", CONV_NOERROR, CHAR_NONE },
209 { "notrunc", CONV_NOTRUNC, CHAR_NONE },
210 #ifdef O_DIRECT
211 { "idirect", CONV_IDIRECT, CHAR_NONE },
212 { "odirect", CONV_ODIRECT, CHAR_NONE },
213 #endif /* O_DIRECT */
214 { "sync", CONV_SYNC, CHAR_NONE },
215 { NULL, CONV_NONE, CHAR_NONE }
216 };
217
218 static void *
bmalloc(size_t nbytes)219 bmalloc(size_t nbytes)
220 {
221 static long pagesize;
222 void *vp;
223
224 if (pagesize == 0)
225 if ((pagesize = sysconf(_SC_PAGESIZE)) < 0)
226 pagesize = 4096;
227 if ((vp = memalign(pagesize, nbytes)) == NULL) {
228 fprintf(stderr, "%s: not enough memory\n", progname);
229 fprintf(stderr, "Please use a smaller buffer size\n");
230 exit(077);
231 }
232 return vp;
233 }
234
235 /************************** ARGUMENT SCANNING ***************************/
236 static void
badarg(const char * arg)237 badarg(const char *arg)
238 {
239 fprintf(stderr, "%s: bad arg: \"%s\"\n", progname, arg);
240 exit(2);
241 }
242
243 static void
badnumeric(const char * arg)244 badnumeric(const char *arg)
245 {
246 fprintf(stderr, "%s: bad numeric arg: \"%s\"\n", progname, arg);
247 exit(2);
248 }
249
250 static void
nozeroblok(void)251 nozeroblok(void)
252 {
253 fprintf(stderr, "%s: buffer sizes cannot be zero\n", progname);
254 exit(2);
255 }
256
257 /*
258 * Get the value of a numeric argument.
259 */
260 static d_type
expr(const char * ap)261 expr(const char *ap)
262 {
263 d_type val;
264 char *x;
265 int c;
266
267 if (*ap == '-' || *ap == '+')
268 badnumeric(ap);
269 val = strtoull(ap, &x, 10);
270 while ((c = *x++) != '\0') {
271 switch (c) {
272 case 'k':
273 val *= 1024;
274 break;
275 case 'b':
276 val *= 512;
277 break;
278 case 'w':
279 val *= 2;
280 break;
281 case 'x':
282 case '*':
283 return val * expr(x);
284 default:
285 badnumeric(ap);
286 }
287 }
288 return val;
289 }
290
291 static void
setin(const char * ap)292 setin(const char *ap)
293 {
294 iffile = ap;
295 }
296
297 static void
setof(const char * ap)298 setof(const char *ap)
299 {
300 offile = ap;
301 }
302
303 static void
setibs(const char * ap)304 setibs(const char *ap)
305 {
306 ibs = expr(ap);
307 if (ibs == 0)
308 nozeroblok();
309 }
310
311 static void
setobs(const char * ap)312 setobs(const char *ap)
313 {
314 obs = expr(ap);
315 if (obs == 0)
316 nozeroblok();
317 }
318
319 static void
setbs(const char * ap)320 setbs(const char *ap)
321 {
322 bs = expr(ap);
323 }
324
325 static void
setcbs(const char * ap)326 setcbs(const char *ap)
327 {
328 cbs = expr(ap);
329 }
330
331 static void
setskip(const char * ap)332 setskip(const char *ap)
333 {
334 skip = expr(ap);
335 }
336
337 static void
setcount(const char * ap)338 setcount(const char *ap)
339 {
340 count = expr(ap);
341 }
342
343 static void
setconv(const char * ap)344 setconv(const char *ap)
345 {
346 const char *cp, *cq;
347 int i;
348
349 for (;;) {
350 while (*ap == ',')
351 ap++;
352 if (*ap == '\0')
353 break;
354 for (i = 0; convtab[i].c_name; i++) {
355 for (cp = convtab[i].c_name, cq = ap;
356 *cp && (*cp == *cq);
357 cp++, cq++);
358 if (*cp == '\0' && (*cq == ',' || *cq == '\0')) {
359 convs |= convtab[i].c_conv;
360 if (convtab[i].c_char != CHAR_NONE)
361 chars = convtab[i].c_char;
362 ap = cq;
363 goto next;
364 }
365 }
366 badarg(ap);
367 next:;
368 }
369 }
370
371 static void
setfiles(const char * ap)372 setfiles(const char *ap)
373 {
374 files = expr(ap);
375 }
376
377 static void
setiseek(const char * ap)378 setiseek(const char *ap)
379 {
380 iseek = expr(ap);
381 }
382
383 static void
setoseek(const char * ap)384 setoseek(const char *ap)
385 {
386 oseek = expr(ap);
387 }
388
389 static struct {
390 const char *a_name;
391 void (*a_func)(const char *);
392 } argtab[] = {
393 { "if=", setin },
394 { "of=", setof },
395 { "ibs=", setibs },
396 { "obs=", setobs },
397 { "bs=", setbs },
398 { "cbs=", setcbs },
399 { "skip=", setskip },
400 { "seek=", setoseek },
401 { "count=", setcount },
402 { "conv=", setconv },
403 { "files=", setfiles },
404 { "iseek=", setiseek },
405 { "oseek=", setoseek },
406 { NULL, NULL }
407 };
408
409 static const char *
thisarg(const char * sp,const char * ap)410 thisarg(const char *sp, const char *ap)
411 {
412 do {
413 if (*sp != *ap)
414 return NULL;
415 if (*sp == '=')
416 return &sp[1];
417 } while (*sp++ && *ap++);
418 return NULL;
419 }
420
421 /******************************* EXECUTION ********************************/
422 static void
stats(void)423 stats(void)
424 {
425 fprintf(stderr, "%llu+%llu records in\n",
426 (unsigned long long)iwhole,
427 (unsigned long long)ipartial);
428 fprintf(stderr, "%llu+%llu records out\n",
429 (unsigned long long)owhole,
430 (unsigned long long)opartial);
431 if (truncated) {
432 fprintf(stderr, "%llu truncated record%s\n",
433 (unsigned long long)truncated,
434 truncated > 1 ? "s" : "");
435 }
436 }
437
438 static void charconv(char *data, size_t size);
439 static void bflush(void);
440 static void cflush(void);
441 static void uflush(void);
442
443 static void
quit(int status)444 quit(int status)
445 {
446 if (mbp)
447 charconv(NULL, 0);
448 cflush();
449 uflush();
450 bflush();
451 stats();
452 exit(status);
453 }
454
455 static void
onint(int sig)456 onint(int sig)
457 {
458 stats();
459 exit(sig | 0200);
460 }
461
462 static int
ontape(void)463 ontape(void)
464 {
465 static int yes = -1;
466
467 if (yes == -1) {
468 #if defined (__linux__) || defined (__FreeBSD__) || defined (__hpux) || \
469 defined (_AIX) || defined (__NetBSD__) || defined (__OpenBSD__) || \
470 defined (__DragonFly__) || defined (__APPLE__)
471 struct mtget mg;
472 yes = (istat.st_mode&S_IFMT) == S_IFCHR &&
473 ioctl(iffd, MTIOCGET, &mg) == 0;
474 #elif defined (__sun)
475 struct mtdrivetype_request mr;
476 struct mtdrivetype md;
477 mr.size = sizeof md;
478 mr.mtdtp = &md;
479 yes = (istat.st_mode&S_IFMT) == S_IFCHR &&
480 ioctl(iffd, MTIOCGETDRIVETYPE, &mr) == 0;
481 #else /* SVR4.2MP */
482 struct blklen bl;
483 yes = (istat.st_mode&S_IFMT) == S_IFCHR &&
484 ioctl(iffd, T_RDBLKLEN, &bl) == 0;
485 #endif /* SVR4.2MP */
486 }
487 return yes;
488 }
489
490 static void
seekconv(d_type count)491 seekconv(d_type count)
492 {
493 ssize_t sz;
494 off_t offs;
495
496 if (lseek(offd, 0, SEEK_CUR) != (off_t)-1) {
497 do {
498 if ((offs = lseek(offd, obs, SEEK_CUR)) == (off_t)-1) {
499 err: fprintf(stderr, "%s: output seek error: %s\n",
500 progname, strerror(errno));
501 exit(3);
502 }
503 } while (--count);
504 if ((convs & CONV_NOTRUNC) == 0 &&
505 (ostat.st_mode&S_IFMT) == S_IFREG)
506 ftruncate(offd, offs);
507 return;
508 }
509 while (count) {
510 if ((sz = read(offd, oblok, obs)) == 0)
511 break;
512 if (sz < 0)
513 goto err;
514 count--;
515 }
516 if (count) {
517 memset(oblok, 0, obs);
518 do {
519 if ((sz = write(offd, oblok, obs)) < 0)
520 goto err;
521 } while (--count);
522 }
523 }
524
525 static void
skipconv(int canseek,d_type count)526 skipconv(int canseek, d_type count)
527 {
528 ssize_t rd = 0;
529
530 if (canseek && lseek(iffd, 0, SEEK_CUR) == (off_t)-1)
531 canseek = 0;
532 while (count--) {
533 if (canseek) {
534 if (lseek(iffd, ibs, SEEK_CUR) != (off_t)-1)
535 rd = ibs;
536 else if (errno == EINVAL)
537 rd = 0;
538 else {
539 fprintf(stderr, "%s: input seek error: %s\n",
540 progname, strerror(errno));
541 exit(3);
542 }
543 } else {
544 if ((rd = read(iffd, iblok, ibs)) < 0) {
545 fprintf(stderr,
546 "%s: read error during skip: %s\n",
547 progname, strerror(errno));
548 exit(3);
549 }
550 }
551 if (rd == 0 && files-- <= 1) {
552 fprintf(stderr, "%s: cannot skip past end-of-file\n",
553 progname);
554 exit(3);
555 }
556 }
557 }
558
559 static void
prepare(void)560 prepare(void)
561 {
562 int flags;
563
564 if (bs)
565 ibs = obs = bs;
566 iblok = bmalloc(ibs);
567 if (!(bs && chars == CHAR_NONE &&
568 (convs|CONV_SYNC|CONV_NOERROR|CONV_NOTRUNC|CONV_DIRECT)
569 == (CONV_SYNC|CONV_NOERROR|CONV_NOTRUNC|CONV_DIRECT)))
570 oblok = bmalloc(obs);
571 if (cbs > 0) {
572 if ((convs & (CONV_BLOCK|CONV_UNBLOCK)) == 0) {
573 fprintf(stderr,
574 "%s: cbs must be zero if no block conversion requested\n",
575 progname);
576 exit(2);
577 }
578 cblok = bmalloc(cbs + 1);
579 } else
580 convs &= ~(CONV_BLOCK|CONV_UNBLOCK);
581 if ((iffd = iffile ? open(iffile, O_RDONLY) : dup(0)) < 0) {
582 fprintf(stderr, "%s: cannot open %s: %s\n", progname,
583 iffile ? iffile : "", strerror(errno));
584 exit(1);
585 }
586 fstat(iffd, &istat);
587 #ifdef O_DIRECT
588 if (convs & CONV_IDIRECT) {
589 int flags;
590 flags = fcntl(iffd, F_GETFL);
591 fcntl(iffd, F_SETFL, flags | O_DIRECT);
592 }
593 #endif /* O_DIRECT */
594 if (skip)
595 skipconv(0, skip);
596 else if (iseek)
597 skipconv(1, iseek);
598 flags = O_RDWR | O_CREAT;
599 if ((convs & CONV_NOTRUNC) == 0 && oseek == 0)
600 flags |= O_TRUNC;
601 if ((offd = offile ? open(offile, flags, 0666) : dup(1)) < 0) {
602 fprintf(stderr, "%s: cannot %s %s: %s\n",
603 progname,
604 flags & O_TRUNC ? "create" : "open",
605 offile ? offile : "", strerror(errno));
606 exit(1);
607 }
608 fstat(offd, &ostat);
609 #ifdef O_DIRECT
610 if (convs & CONV_ODIRECT) {
611 int flags;
612 flags = fcntl(offd, F_GETFL);
613 fcntl(offd, F_SETFL, flags | O_DIRECT);
614 }
615 #endif /* O_DIRECT */
616 if (oseek)
617 seekconv(oseek);
618 }
619
620 static void
swabconv(char * data,size_t size)621 swabconv(char *data, size_t size)
622 {
623 char c;
624
625 while (size > 1) {
626 c = data[0];
627 data[0] = data[1];
628 data[1] = c;
629 size -= 2;
630 data += 2;
631 }
632 }
633
634 static void
ascconv(char * data,size_t size)635 ascconv(char *data, size_t size)
636 {
637 while (size--) {
638 *data = c_ascii[*data & 0377];
639 data++;
640 }
641 }
642
643 static ssize_t
swrite(const char * data,size_t size)644 swrite(const char *data, size_t size)
645 {
646 ssize_t wt;
647
648 for (;;) {
649 if ((wt = write(offd, data, size)) <= 0) {
650 if (errno == EINTR)
651 continue;
652 fprintf(stderr, "%s: write error: %s\n",
653 progname, strerror(errno));
654 oflow = 0;
655 offd = -1;
656 quit(1);
657 }
658 break;
659 }
660 return wt;
661 }
662
663 /*
664 * Write without output buffering (if bs= was specified).
665 */
666 static void
dwrite(const char * data,size_t size)667 dwrite(const char *data, size_t size)
668 {
669 ssize_t wrt;
670
671 do {
672 wrt = swrite(data, size);
673 if (wrt == obs)
674 owhole++;
675 else
676 opartial++;
677 data += wrt;
678 size -= wrt;
679 } while (size > 0);
680 }
681
682 /*
683 * Write to output buffer. On short write, remaining data is kept within
684 * the buffer and written next time again. Might a warning be useful in
685 * this case?
686 */
687 static void
bwrite(const char * data,size_t size)688 bwrite(const char *data, size_t size)
689 {
690 ssize_t wrt;
691 size_t di;
692
693 while (oflow + size > obs) {
694 di = obs - oflow;
695 size -= di;
696 if (oflow) {
697 memcpy(&oblok[oflow], data, di);
698 wrt = swrite(oblok, obs);
699 } else
700 wrt = swrite(data, obs);
701 if (wrt != obs) {
702 memcpy(oblok, &(oflow ? oblok : data)[wrt], obs - wrt);
703 opartial++;
704 } else
705 owhole++;
706 oflow = obs - wrt;
707 data += di;
708 }
709 if (size == obs) {
710 if ((wrt = swrite(data, obs)) == obs)
711 owhole++;
712 else
713 opartial++;
714 size -= wrt;
715 data += wrt;
716 }
717 if (size) {
718 memcpy(&oblok[oflow], data, size);
719 oflow += size;
720 }
721 }
722
723 static void
bflush(void)724 bflush(void)
725 {
726 ssize_t wrt;
727
728 if (offd >= 0) {
729 while (oflow) {
730 if ((wrt = swrite(oblok, oflow)) != oflow)
731 memcpy(oblok, &oblok[wrt], obs - wrt);
732 oflow -= wrt;
733 opartial++;
734 }
735 if (close(offd) < 0) {
736 fprintf(stderr, "%s: write error: %s\n",
737 progname, strerror(errno));
738 offd = -1;
739 quit(1);
740 }
741 offd = -1;
742 }
743 }
744
745 /*
746 * Handle conversions to EBCDIC.
747 */
748 static void
ewrite(char * data,size_t size)749 ewrite(char *data, size_t size)
750 {
751 char *dt = data;
752 size_t sz = size;
753 if (chars == CHAR_EBCDIC) {
754 while (sz--) {
755 *dt = c_ebcdic[*dt & 0377];
756 dt++;
757 }
758 } else if (chars == CHAR_IBM) {
759 while (sz--) {
760 *dt = c_ibm[*dt & 0377];
761 dt++;
762 }
763 }
764 bwrite(data, size);
765 }
766
767 /*
768 * Handle 'conv=block'.
769 */
770 static void
cflush(void)771 cflush(void)
772 {
773 if (convs & CONV_BLOCK && cflow) {
774 while (cflow < cbs)
775 cblok[cflow++] = ' ';
776 ewrite(cblok, cbs);
777 cflow = 0;
778 }
779 }
780
781 static void
cwrite(const char * data,size_t size)782 cwrite(const char *data, size_t size)
783 {
784 while (size) {
785 if (ctrunc == 0) {
786 cblok[cflow] = *data++;
787 if (cblok[cflow] == '\n') {
788 if (cflow == 0)
789 cblok[cflow++] = ' ';
790 cflush();
791 } else if (++cflow == cbs) {
792 cflush();
793 ctrunc = 1;
794 }
795 } else {
796 if (*data++ == '\n')
797 ctrunc = 0;
798 else if (ctrunc == 1) {
799 truncated++;
800 ctrunc = 2;
801 }
802 }
803 size--;
804 }
805 }
806
807 /*
808 * Handle 'conv=unblock'.
809 */
810 static void
uflush(void)811 uflush(void)
812 {
813 char *cp;
814
815 if (cflow) {
816 for (cp = &cblok[cflow-1]; cp >= cblok && *cp == ' '; cp--);
817 cp[1] = '\n';
818 bwrite(cblok, cp - cblok + 2);
819 cflow = 0;
820 }
821 }
822
823 static void
uwrite(const char * data,size_t size)824 uwrite(const char *data, size_t size)
825 {
826 while (size) {
827 while (cflow < cbs) {
828 cblok[cflow++] = *data++;
829 if (--size == 0)
830 return;
831 }
832 uflush();
833 }
834 }
835
836 static void
blokconv(char * data,size_t size)837 blokconv(char *data, size_t size)
838 {
839 switch (chars) {
840 case CHAR_EBCDIC:
841 case CHAR_IBM:
842 if ((convs & (CONV_BLOCK|CONV_UNBLOCK)) == 0) {
843 ewrite(data, size);
844 break;
845 }
846 /*FALLTHRU*/
847 default:
848 if (convs & CONV_BLOCK)
849 cwrite(data, size);
850 else if (convs & CONV_UNBLOCK)
851 uwrite(data, size);
852 else
853 bwrite(data, size);
854 break;
855 }
856 }
857
858 static void
charconv(char * data,size_t size)859 charconv(char *data, size_t size)
860 {
861 if (convs & (CONV_LCASE|CONV_UCASE)) {
862 if (mb_cur_max > 1) {
863 /*
864 * Multibyte case conversion is somewhat ugly
865 * with dd as there is no guarantee that a
866 * character fits in an input block. We need
867 * another intermediate therefore to store
868 * incomplete multibyte sequences.
869 */
870 int i, n, len;
871 wint_t wc;
872 int flush = size == 0;
873
874 while (size > 0 || (flush && mbrest)) {
875 i = 0;
876 if (mbrest && mbp && mbp > mblok) {
877 do
878 mblok[i] = mbp[i];
879 while (i++, --mbrest);
880 } else if (mbp == mblok) {
881 i = mbrest;
882 mbrest = 0;
883 }
884 if (i == 0 && size) {
885 mblok[i++] = *data++;
886 size--;
887 }
888 if (mblok[0] & 0200) {
889 while (i < mb_cur_max && size) {
890 mblok[i++] = *data++;
891 size--;
892 }
893 if (!flush && i < mb_cur_max) {
894 mbp = mblok;
895 mbrest = i;
896 return;
897 }
898 if ((n = mbtowi(&wc, mblok, i)) < 0) {
899 len = 1;
900 wc = WEOF;
901 } else if (n == 0)
902 len = 1;
903 else
904 len = n;
905 } else {
906 wc = mblok[0];
907 len = n = 1;
908 }
909 if (i > 0) {
910 mbrest = i - len;
911 mbp = &mblok[len];
912 } else {
913 mbrest = 0;
914 mbp = NULL;
915 }
916 if (wc != WEOF) {
917 char new[MB_LEN_MAX + 1];
918
919 if (convs & CONV_LCASE)
920 wc = wc & ~(wchar_t)0177 ?
921 towlower(wc) :
922 tolower(wc);
923 if (convs & CONV_UCASE)
924 wc = wc & ~(wchar_t)0177 ?
925 towupper(wc) :
926 toupper(wc);
927 if ((n = wctomb(new, wc)) > 0)
928 blokconv(new, n);
929 else
930 goto inv;
931 } else
932 inv: blokconv(mblok, len);
933 }
934 return;
935 } else {
936 char *dp = data;
937 size_t sz = size;
938
939 while (sz--) {
940 if (convs & CONV_LCASE)
941 *dp = tolower(*dp & 0377);
942 if (convs & CONV_UCASE)
943 *dp = toupper(*dp & 0377);
944 dp++;
945 }
946 }
947 }
948 blokconv(data, size);
949 }
950
951 static void
dd(void)952 dd(void)
953 {
954 ssize_t rd;
955
956 while (count == -1 || count > 0) {
957 if ((rd = read(iffd, iblok, ibs)) < ibs) {
958 if (rd < 0) {
959 fprintf(stderr, "%s: read error: %s\n",
960 progname, strerror(errno));
961 if (convs & CONV_NOERROR) {
962 stats();
963 if (!ontape())
964 lseek(iffd, ibs, SEEK_CUR);
965 if (convs & CONV_SYNC)
966 rd = 0;
967 else
968 continue;
969 } else
970 quit(1);
971 } else if (rd == 0) {
972 if (files-- <= 1)
973 break;
974 continue;
975 } else if (rd > 0)
976 ipartial++;
977 if (convs & CONV_SYNC) {
978 int c;
979
980 c = convs&(CONV_BLOCK|CONV_UNBLOCK) ? ' ' : 0;
981 memset(&iblok[rd], c, ibs - rd);
982 rd = ibs;
983 }
984 } else
985 iwhole++;
986 if (count > 0)
987 count--;
988 if (bs && chars == CHAR_NONE &&
989 (convs|CONV_SYNC|CONV_NOERROR|CONV_NOTRUNC|CONV_DIRECT)
990 == (CONV_SYNC|CONV_NOERROR|CONV_NOTRUNC|CONV_DIRECT))
991 dwrite(iblok, rd);
992 else {
993 if (convs & CONV_SWAB)
994 swabconv(iblok, rd);
995 if (chars == CHAR_ASCII)
996 ascconv(iblok, rd);
997 charconv(iblok, rd);
998 }
999 }
1000 }
1001
1002 int
main(int argc,char ** argv)1003 main(int argc, char **argv)
1004 {
1005 const char *cp;
1006 int o, i;
1007
1008 progname = basename(argv[0]);
1009 setlocale(LC_CTYPE, "");
1010 mb_cur_max = MB_CUR_MAX;
1011 if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-' &&
1012 argv[1][2] == '\0')
1013 o = 2;
1014 else
1015 o = 1;
1016 while (o < argc) {
1017 for (i = 0; argtab[i].a_name; i++) {
1018 if ((cp = thisarg(argv[o], argtab[i].a_name)) != 0) {
1019 argtab[i].a_func(cp);
1020 break;
1021 }
1022 }
1023 if (argtab[i].a_name == NULL)
1024 badarg(argv[o]);
1025 o++;
1026 }
1027 if ((sigset(SIGINT, SIG_IGN)) != SIG_IGN)
1028 sigset(SIGINT, onint);
1029 prepare();
1030 dd();
1031 quit(0);
1032 /*NOTREACHED*/
1033 return 0;
1034 }
1035