1 /* $NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Keith Muller of the University of California, San Diego and Lance 9 * Visser of Convex Computer Corporation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; 45 #else 46 __RCSID("$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $"); 47 #endif 48 #endif /* not lint */ 49 50 #include <sys/param.h> 51 #include <sys/stat.h> 52 #include <sys/ioctl.h> 53 #include <sys/time.h> 54 55 #include <ctype.h> 56 #include <err.h> 57 #include <errno.h> 58 #include <fcntl.h> 59 #include <signal.h> 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <unistd.h> 64 65 #include "dd.h" 66 67 #define NO_CONV 68 69 //#include "extern.h" 70 void block(void); 71 void block_close(void); 72 void dd_out(int); 73 void def(void); 74 void def_close(void); 75 void jcl(char **); 76 void pos_in(void); 77 void pos_out(void); 78 void summary(void); 79 void summaryx(int); 80 void terminate(int); 81 void unblock(void); 82 void unblock_close(void); 83 ssize_t bwrite(int, const void *, size_t); 84 85 extern IO in, out; 86 extern STAT st; 87 extern void (*cfunc)(void); 88 extern uint64_t cpy_cnt; 89 extern uint64_t cbsz; 90 extern u_int ddflags; 91 extern u_int files_cnt; 92 extern int progress; 93 extern const u_char *ctab; 94 extern const u_char a2e_32V[], a2e_POSIX[]; 95 extern const u_char e2a_32V[], e2a_POSIX[]; 96 extern const u_char a2ibm_32V[], a2ibm_POSIX[]; 97 extern u_char casetab[]; 98 99 100 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 101 102 static void dd_close(void); 103 static void dd_in(void); 104 static void getfdtype(IO *); 105 static int redup_clean_fd(int); 106 static void setup(void); 107 108 109 IO in, out; /* input/output state */ 110 STAT st; /* statistics */ 111 void (*cfunc)(void); /* conversion function */ 112 uint64_t cpy_cnt; /* # of blocks to copy */ 113 static off_t pending = 0; /* pending seek if sparse */ 114 u_int ddflags; /* conversion options */ 115 uint64_t cbsz; /* conversion block size */ 116 u_int files_cnt = 1; /* # of files to copy */ 117 int progress = 0; /* display sign of life */ 118 const u_char *ctab; /* conversion table */ 119 sigset_t infoset; /* a set blocking SIGINFO */ 120 121 int 122 dd_main(int argc, char *argv[]) 123 { 124 int ch; 125 126 while ((ch = getopt(argc, argv, "")) != -1) { 127 switch (ch) { 128 default: 129 fprintf(stderr, "usage: dd [operand ...]\n"); 130 exit(1); 131 /* NOTREACHED */ 132 } 133 } 134 argc -= (optind - 1); 135 argv += (optind - 1); 136 137 jcl(argv); 138 setup(); 139 140 // (void)signal(SIGINFO, summaryx); 141 (void)signal(SIGINT, terminate); 142 (void)sigemptyset(&infoset); 143 // (void)sigaddset(&infoset, SIGINFO); 144 145 (void)atexit(summary); 146 147 while (files_cnt--) 148 dd_in(); 149 150 dd_close(); 151 exit(0); 152 /* NOTREACHED */ 153 } 154 155 static void 156 setup(void) 157 { 158 159 if (in.name == NULL) { 160 in.name = "stdin"; 161 in.fd = STDIN_FILENO; 162 } else { 163 in.fd = open(in.name, O_RDONLY, 0); 164 if (in.fd < 0) { 165 fprintf(stderr, "%s: cannot open for read: %s\n", 166 in.name, strerror(errno)); 167 exit(1); 168 /* NOTREACHED */ 169 } 170 171 /* Ensure in.fd is outside the stdio descriptor range */ 172 in.fd = redup_clean_fd(in.fd); 173 } 174 175 getfdtype(&in); 176 177 if (files_cnt > 1 && !(in.flags & ISTAPE)) { 178 fprintf(stderr, 179 "files is not supported for non-tape devices\n"); 180 exit(1); 181 /* NOTREACHED */ 182 } 183 184 if (out.name == NULL) { 185 /* No way to check for read access here. */ 186 out.fd = STDOUT_FILENO; 187 out.name = "stdout"; 188 } else { 189 #define OFLAGS \ 190 (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) 191 out.fd = open(out.name, O_RDWR | OFLAGS /*, DEFFILEMODE */); 192 /* 193 * May not have read access, so try again with write only. 194 * Without read we may have a problem if output also does 195 * not support seeks. 196 */ 197 if (out.fd < 0) { 198 out.fd = open(out.name, O_WRONLY | OFLAGS /*, DEFFILEMODE */); 199 out.flags |= NOREAD; 200 } 201 if (out.fd < 0) { 202 fprintf(stderr, "%s: cannot open for write: %s\n", 203 out.name, strerror(errno)); 204 exit(1); 205 /* NOTREACHED */ 206 } 207 208 /* Ensure out.fd is outside the stdio descriptor range */ 209 out.fd = redup_clean_fd(out.fd); 210 } 211 212 getfdtype(&out); 213 214 /* 215 * Allocate space for the input and output buffers. If not doing 216 * record oriented I/O, only need a single buffer. 217 */ 218 if (!(ddflags & (C_BLOCK|C_UNBLOCK))) { 219 if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) { 220 exit(1); 221 /* NOTREACHED */ 222 } 223 out.db = in.db; 224 } else if ((in.db = 225 malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL || 226 (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) { 227 exit(1); 228 /* NOTREACHED */ 229 } 230 in.dbp = in.db; 231 out.dbp = out.db; 232 233 /* Position the input/output streams. */ 234 if (in.offset) 235 pos_in(); 236 if (out.offset) 237 pos_out(); 238 239 /* 240 * Truncate the output file; ignore errors because it fails on some 241 * kinds of output files, tapes, for example. 242 */ 243 if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK)) 244 (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz); 245 246 /* 247 * If converting case at the same time as another conversion, build a 248 * table that does both at once. If just converting case, use the 249 * built-in tables. 250 */ 251 if (ddflags & (C_LCASE|C_UCASE)) { 252 #ifdef NO_CONV 253 /* Should not get here, but just in case... */ 254 fprintf(stderr, "case conv and -DNO_CONV\n"); 255 exit(1); 256 /* NOTREACHED */ 257 #else /* NO_CONV */ 258 u_int cnt; 259 260 if (ddflags & C_ASCII || ddflags & C_EBCDIC) { 261 if (ddflags & C_LCASE) { 262 for (cnt = 0; cnt < 0377; ++cnt) 263 casetab[cnt] = tolower(ctab[cnt]); 264 } else { 265 for (cnt = 0; cnt < 0377; ++cnt) 266 casetab[cnt] = toupper(ctab[cnt]); 267 } 268 } else { 269 if (ddflags & C_LCASE) { 270 for (cnt = 0; cnt < 0377; ++cnt) 271 casetab[cnt] = tolower(cnt); 272 } else { 273 for (cnt = 0; cnt < 0377; ++cnt) 274 casetab[cnt] = toupper(cnt); 275 } 276 } 277 278 ctab = casetab; 279 #endif /* NO_CONV */ 280 } 281 282 (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */ 283 } 284 285 static void 286 getfdtype(IO *io) 287 { 288 // struct mtget mt; 289 struct stat sb; 290 291 if (fstat(io->fd, &sb)) { 292 fprintf(stderr, "%s: cannot fstat: %s\n", 293 io->name, strerror(errno)); 294 exit(1); 295 /* NOTREACHED */ 296 } 297 if (S_ISCHR(sb.st_mode)) 298 io->flags |= /*ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; */ ISCHR; 299 else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) 300 io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */ 301 } 302 303 /* 304 * Move the parameter file descriptor to a descriptor that is outside the 305 * stdio descriptor range, if necessary. This is required to avoid 306 * accidentally outputting completion or error messages into the 307 * output file that were intended for the tty. 308 */ 309 static int 310 redup_clean_fd(int fd) 311 { 312 int newfd; 313 314 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && 315 fd != STDERR_FILENO) 316 /* File descriptor is ok, return immediately. */ 317 return fd; 318 319 /* 320 * 3 is the first descriptor greater than STD*_FILENO. Any 321 * free descriptor valued 3 or above is acceptable... 322 */ 323 newfd = fcntl(fd, F_DUPFD, 3); 324 if (newfd < 0) { 325 fprintf(stderr, "dupfd IO: %s\n", strerror(errno)); 326 exit(1); 327 /* NOTREACHED */ 328 } 329 330 close(fd); 331 332 return newfd; 333 } 334 335 static void 336 dd_in(void) 337 { 338 int flags; 339 int64_t n; 340 341 for (flags = ddflags;;) { 342 if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt) 343 return; 344 345 /* 346 * Clear the buffer first if doing "sync" on input. 347 * If doing block operations use spaces. This will 348 * affect not only the C_NOERROR case, but also the 349 * last partial input block which should be padded 350 * with zero and not garbage. 351 */ 352 if (flags & C_SYNC) { 353 if (flags & (C_BLOCK|C_UNBLOCK)) 354 (void)memset(in.dbp, ' ', in.dbsz); 355 else 356 (void)memset(in.dbp, 0, in.dbsz); 357 } 358 359 n = read(in.fd, in.dbp, in.dbsz); 360 if (n == 0) { 361 in.dbrcnt = 0; 362 return; 363 } 364 365 /* Read error. */ 366 if (n < 0) { 367 368 /* 369 * If noerror not specified, die. POSIX requires that 370 * the warning message be followed by an I/O display. 371 */ 372 fprintf(stderr, "%s: read error: %s\n", 373 in.name, strerror(errno)); 374 if (!(flags & C_NOERROR)) { 375 exit(1); 376 /* NOTREACHED */ 377 } 378 summary(); 379 380 /* 381 * If it's not a tape drive or a pipe, seek past the 382 * error. If your OS doesn't do the right thing for 383 * raw disks this section should be modified to re-read 384 * in sector size chunks. 385 */ 386 if (!(in.flags & (ISPIPE|ISTAPE)) && 387 lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) 388 fprintf(stderr, "%s: seek error: %s\n", 389 in.name, strerror(errno)); 390 391 /* If sync not specified, omit block and continue. */ 392 if (!(ddflags & C_SYNC)) 393 continue; 394 395 /* Read errors count as full blocks. */ 396 in.dbcnt += in.dbrcnt = in.dbsz; 397 ++st.in_full; 398 399 /* Handle full input blocks. */ 400 } else if (n == in.dbsz) { 401 in.dbcnt += in.dbrcnt = n; 402 ++st.in_full; 403 404 /* Handle partial input blocks. */ 405 } else { 406 /* If sync, use the entire block. */ 407 if (ddflags & C_SYNC) 408 in.dbcnt += in.dbrcnt = in.dbsz; 409 else 410 in.dbcnt += in.dbrcnt = n; 411 ++st.in_part; 412 } 413 414 /* 415 * POSIX states that if bs is set and no other conversions 416 * than noerror, notrunc or sync are specified, the block 417 * is output without buffering as it is read. 418 */ 419 if (ddflags & C_BS) { 420 out.dbcnt = in.dbcnt; 421 dd_out(1); 422 in.dbcnt = 0; 423 continue; 424 } 425 426 /* if (ddflags & C_SWAB) { 427 if ((n = in.dbrcnt) & 1) { 428 ++st.swab; 429 --n; 430 } 431 swab(in.dbp, in.dbp, n); 432 } 433 */ 434 in.dbp += in.dbrcnt; 435 (*cfunc)(); 436 } 437 } 438 439 /* 440 * Cleanup any remaining I/O and flush output. If necesssary, output file 441 * is truncated. 442 */ 443 static void 444 dd_close(void) 445 { 446 447 if (cfunc == def) 448 def_close(); 449 else if (cfunc == block) 450 block_close(); 451 else if (cfunc == unblock) 452 unblock_close(); 453 if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) { 454 (void)memset(out.dbp, 0, out.dbsz - out.dbcnt); 455 out.dbcnt = out.dbsz; 456 } 457 /* If there are pending sparse blocks, make sure 458 * to write out the final block un-sparse 459 */ 460 if ((out.dbcnt == 0) && pending) { 461 memset(out.db, 0, out.dbsz); 462 out.dbcnt = out.dbsz; 463 out.dbp = out.db + out.dbcnt; 464 pending -= out.dbsz; 465 } 466 if (out.dbcnt) 467 dd_out(1); 468 469 /* 470 * Reporting nfs write error may be defered until next 471 * write(2) or close(2) system call. So, we need to do an 472 * extra check. If an output is stdout, the file structure 473 * may be shared among with other processes and close(2) just 474 * decreases the reference count. 475 */ 476 if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) { 477 fprintf(stderr, "fsync stdout: %s\n", strerror(errno)); 478 exit(1); 479 /* NOTREACHED */ 480 } 481 if (close(out.fd) == -1) { 482 fprintf(stderr, "close: %s\n", strerror(errno)); 483 exit(1); 484 /* NOTREACHED */ 485 } 486 } 487 488 void 489 dd_out(int force) 490 { 491 static int warned; 492 int64_t cnt, n, nw; 493 u_char *outp; 494 495 /* 496 * Write one or more blocks out. The common case is writing a full 497 * output block in a single write; increment the full block stats. 498 * Otherwise, we're into partial block writes. If a partial write, 499 * and it's a character device, just warn. If a tape device, quit. 500 * 501 * The partial writes represent two cases. 1: Where the input block 502 * was less than expected so the output block was less than expected. 503 * 2: Where the input block was the right size but we were forced to 504 * write the block in multiple chunks. The original versions of dd(1) 505 * never wrote a block in more than a single write, so the latter case 506 * never happened. 507 * 508 * One special case is if we're forced to do the write -- in that case 509 * we play games with the buffer size, and it's usually a partial write. 510 */ 511 outp = out.db; 512 for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { 513 for (cnt = n;; cnt -= nw) { 514 515 if (!force && ddflags & C_SPARSE) { 516 int sparse, i; 517 sparse = 1; /* Is buffer sparse? */ 518 for (i = 0; i < cnt; i++) 519 if (outp[i] != 0) { 520 sparse = 0; 521 break; 522 } 523 if (sparse) { 524 pending += cnt; 525 outp += cnt; 526 nw = 0; 527 break; 528 } 529 } 530 if (pending != 0) { 531 if (lseek(out.fd, pending, SEEK_CUR) == 532 -1) { 533 fprintf(stderr, 534 "%s: seek error creating " 535 "sparse file: %s\n", 536 out.name, strerror(errno)); 537 exit(1); 538 } 539 } 540 nw = bwrite(out.fd, outp, cnt); 541 if (nw <= 0) { 542 if (nw == 0) { 543 fprintf(stderr, "%s: end of device\n", 544 out.name); 545 exit(1); 546 /* NOTREACHED */ 547 } 548 if (errno != EINTR) { 549 fprintf(stderr, "%s: write error: %s\n", 550 out.name, strerror(errno)); 551 /* NOTREACHED */ 552 exit(1); 553 } 554 nw = 0; 555 } 556 if (pending) { 557 st.bytes += pending; 558 st.sparse += pending/out.dbsz; 559 st.out_full += pending/out.dbsz; 560 pending = 0; 561 } 562 outp += nw; 563 st.bytes += nw; 564 if (nw == n) { 565 if (n != out.dbsz) 566 ++st.out_part; 567 else 568 ++st.out_full; 569 break; 570 } 571 ++st.out_part; 572 if (nw == cnt) 573 break; 574 if (out.flags & ISCHR && !warned) { 575 warned = 1; 576 fprintf(stderr, "%s: short write on character " 577 "device\n", out.name); 578 } 579 if (out.flags & ISTAPE) { 580 fprintf(stderr, 581 "%s: short write on tape device", 582 out.name); 583 exit(1); 584 /* NOTREACHED */ 585 } 586 } 587 if ((out.dbcnt -= n) < out.dbsz) 588 break; 589 } 590 591 /* Reassemble the output block. */ 592 if (out.dbcnt) 593 (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); 594 out.dbp = out.db + out.dbcnt; 595 596 if (progress) 597 (void)write(STDERR_FILENO, ".", 1); 598 } 599 600 /* 601 * A protected against SIGINFO write 602 */ 603 ssize_t 604 bwrite(int fd, const void *buf, size_t len) 605 { 606 sigset_t oset; 607 ssize_t rv; 608 int oerrno; 609 610 (void)sigprocmask(SIG_BLOCK, &infoset, &oset); 611 rv = write(fd, buf, len); 612 oerrno = errno; 613 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 614 errno = oerrno; 615 return (rv); 616 } 617 618 /* 619 * Position input/output data streams before starting the copy. Device type 620 * dependent. Seekable devices use lseek, and the rest position by reading. 621 * Seeking past the end of file can cause null blocks to be written to the 622 * output. 623 */ 624 void 625 pos_in(void) 626 { 627 int bcnt, cnt, nr, warned; 628 629 /* If not a pipe or tape device, try to seek on it. */ 630 if (!(in.flags & (ISPIPE|ISTAPE))) { 631 if (lseek(in.fd, 632 (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) { 633 fprintf(stderr, "%s: seek error: %s", 634 in.name, strerror(errno)); 635 exit(1); 636 /* NOTREACHED */ 637 } 638 return; 639 /* NOTREACHED */ 640 } 641 642 /* 643 * Read the data. If a pipe, read until satisfy the number of bytes 644 * being skipped. No differentiation for reading complete and partial 645 * blocks for other devices. 646 */ 647 for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { 648 if ((nr = read(in.fd, in.db, bcnt)) > 0) { 649 if (in.flags & ISPIPE) { 650 if (!(bcnt -= nr)) { 651 bcnt = in.dbsz; 652 --cnt; 653 } 654 } else 655 --cnt; 656 continue; 657 } 658 659 if (nr == 0) { 660 if (files_cnt > 1) { 661 --files_cnt; 662 continue; 663 } 664 fprintf(stderr, "skip reached end of input\n"); 665 exit(1); 666 /* NOTREACHED */ 667 } 668 669 /* 670 * Input error -- either EOF with no more files, or I/O error. 671 * If noerror not set die. POSIX requires that the warning 672 * message be followed by an I/O display. 673 */ 674 if (ddflags & C_NOERROR) { 675 if (!warned) { 676 677 fprintf(stderr, "%s: error occurred\n", 678 in.name); 679 warned = 1; 680 summary(); 681 } 682 continue; 683 } 684 fprintf(stderr, "%s: read error: %s", in.name, strerror(errno)); 685 exit(1); 686 /* NOTREACHED */ 687 } 688 } 689 690 void 691 pos_out(void) 692 { 693 // struct mtop t_op; 694 int cnt, n; 695 696 /* 697 * If not a tape, try seeking on the file. Seeking on a pipe is 698 * going to fail, but don't protect the user -- they shouldn't 699 * have specified the seek operand. 700 */ 701 if (!(out.flags & ISTAPE)) { 702 if (lseek(out.fd, 703 (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1) { 704 fprintf(stderr, "%s: seek error: %s\n", 705 out.name, strerror(errno)); 706 exit(1); 707 /* NOTREACHED */ 708 } 709 return; 710 } 711 712 /* If no read access, try using mtio. */ 713 if (out.flags & NOREAD) { 714 /* t_op.mt_op = MTFSR; 715 t_op.mt_count = out.offset; 716 717 if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/ 718 fprintf(stderr, "%s: cannot read", out.name); 719 exit(1); 720 /* NOTREACHED */ 721 return; 722 } 723 724 /* Read it. */ 725 for (cnt = 0; cnt < out.offset; ++cnt) { 726 if ((n = read(out.fd, out.db, out.dbsz)) > 0) 727 continue; 728 729 if (n < 0) { 730 fprintf(stderr, "%s: cannot position by reading: %s\n", 731 out.name, strerror(errno)); 732 exit(1); 733 /* NOTREACHED */ 734 } 735 736 /* 737 * If reach EOF, fill with NUL characters; first, back up over 738 * the EOF mark. Note, cnt has not yet been incremented, so 739 * the EOF read does not count as a seek'd block. 740 */ 741 /* t_op.mt_op = MTBSR; 742 t_op.mt_count = 1; 743 if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ { 744 fprintf(stderr, "%s: cannot position\n", out.name); 745 exit(1); 746 /* NOTREACHED */ 747 } 748 749 while (cnt++ < out.offset) 750 if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) { 751 fprintf(stderr, "%s: cannot position " 752 "by writing: %s\n", 753 out.name, strerror(errno)); 754 exit(1); 755 /* NOTREACHED */ 756 } 757 break; 758 } 759 } 760 761 /* 762 * def -- 763 * Copy input to output. Input is buffered until reaches obs, and then 764 * output until less than obs remains. Only a single buffer is used. 765 * Worst case buffer calculation is (ibs + obs - 1). 766 */ 767 void 768 def(void) 769 { 770 uint64_t cnt; 771 u_char *inp; 772 const u_char *t; 773 774 if ((t = ctab) != NULL) 775 for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) 776 *inp = t[*inp]; 777 778 /* Make the output buffer look right. */ 779 out.dbp = in.dbp; 780 out.dbcnt = in.dbcnt; 781 782 if (in.dbcnt >= out.dbsz) { 783 /* If the output buffer is full, write it. */ 784 dd_out(0); 785 786 /* 787 * Ddout copies the leftover output to the beginning of 788 * the buffer and resets the output buffer. Reset the 789 * input buffer to match it. 790 */ 791 in.dbp = out.dbp; 792 in.dbcnt = out.dbcnt; 793 } 794 } 795 796 void 797 def_close(void) 798 { 799 800 /* Just update the count, everything is already in the buffer. */ 801 if (in.dbcnt) 802 out.dbcnt = in.dbcnt; 803 } 804 805 #ifdef NO_CONV 806 /* Build a smaller version (i.e. for a miniroot) */ 807 /* These can not be called, but just in case... */ 808 static const char no_block[] = "unblock and -DNO_CONV?\n"; 809 void block(void) { fprintf(stderr, "%s", no_block + 2); exit(1); } 810 void block_close(void) { fprintf(stderr, "%s", no_block + 2); exit(1); } 811 void unblock(void) { fprintf(stderr, "%s", no_block); exit(1); } 812 void unblock_close(void) { fprintf(stderr, "%s", no_block); exit(1); } 813 #else /* NO_CONV */ 814 815 /* 816 * Copy variable length newline terminated records with a max size cbsz 817 * bytes to output. Records less than cbs are padded with spaces. 818 * 819 * max in buffer: MAX(ibs, cbsz) 820 * max out buffer: obs + cbsz 821 */ 822 void 823 block(void) 824 { 825 static int intrunc; 826 int ch = 0; /* pacify gcc */ 827 uint64_t cnt, maxlen; 828 u_char *inp, *outp; 829 const u_char *t; 830 831 /* 832 * Record truncation can cross block boundaries. If currently in a 833 * truncation state, keep tossing characters until reach a newline. 834 * Start at the beginning of the buffer, as the input buffer is always 835 * left empty. 836 */ 837 if (intrunc) { 838 for (inp = in.db, cnt = in.dbrcnt; 839 cnt && *inp++ != '\n'; --cnt); 840 if (!cnt) { 841 in.dbcnt = 0; 842 in.dbp = in.db; 843 return; 844 } 845 intrunc = 0; 846 /* Adjust the input buffer numbers. */ 847 in.dbcnt = cnt - 1; 848 in.dbp = inp + cnt - 1; 849 } 850 851 /* 852 * Copy records (max cbsz size chunks) into the output buffer. The 853 * translation is done as we copy into the output buffer. 854 */ 855 for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { 856 maxlen = MIN(cbsz, in.dbcnt); 857 if ((t = ctab) != NULL) 858 for (cnt = 0; 859 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) 860 *outp++ = t[ch]; 861 else 862 for (cnt = 0; 863 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) 864 *outp++ = ch; 865 /* 866 * Check for short record without a newline. Reassemble the 867 * input block. 868 */ 869 if (ch != '\n' && in.dbcnt < cbsz) { 870 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 871 break; 872 } 873 874 /* Adjust the input buffer numbers. */ 875 in.dbcnt -= cnt; 876 if (ch == '\n') 877 --in.dbcnt; 878 879 /* Pad short records with spaces. */ 880 if (cnt < cbsz) 881 (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); 882 else { 883 /* 884 * If the next character wouldn't have ended the 885 * block, it's a truncation. 886 */ 887 if (!in.dbcnt || *inp != '\n') 888 ++st.trunc; 889 890 /* Toss characters to a newline. */ 891 for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt); 892 if (!in.dbcnt) 893 intrunc = 1; 894 else 895 --in.dbcnt; 896 } 897 898 /* Adjust output buffer numbers. */ 899 out.dbp += cbsz; 900 if ((out.dbcnt += cbsz) >= out.dbsz) 901 dd_out(0); 902 outp = out.dbp; 903 } 904 in.dbp = in.db + in.dbcnt; 905 } 906 907 void 908 block_close(void) 909 { 910 911 /* 912 * Copy any remaining data into the output buffer and pad to a record. 913 * Don't worry about truncation or translation, the input buffer is 914 * always empty when truncating, and no characters have been added for 915 * translation. The bottom line is that anything left in the input 916 * buffer is a truncated record. Anything left in the output buffer 917 * just wasn't big enough. 918 */ 919 if (in.dbcnt) { 920 ++st.trunc; 921 (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt); 922 (void)memset(out.dbp + in.dbcnt, 923 ctab ? ctab[' '] : ' ', cbsz - in.dbcnt); 924 out.dbcnt += cbsz; 925 } 926 } 927 928 /* 929 * Convert fixed length (cbsz) records to variable length. Deletes any 930 * trailing blanks and appends a newline. 931 * 932 * max in buffer: MAX(ibs, cbsz) + cbsz 933 * max out buffer: obs + cbsz 934 */ 935 void 936 unblock(void) 937 { 938 uint64_t cnt; 939 u_char *inp; 940 const u_char *t; 941 942 /* Translation and case conversion. */ 943 if ((t = ctab) != NULL) 944 for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--) 945 *inp = t[*inp]; 946 /* 947 * Copy records (max cbsz size chunks) into the output buffer. The 948 * translation has to already be done or we might not recognize the 949 * spaces. 950 */ 951 for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) { 952 for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t); 953 if (t >= inp) { 954 cnt = t - inp + 1; 955 (void)memmove(out.dbp, inp, cnt); 956 out.dbp += cnt; 957 out.dbcnt += cnt; 958 } 959 ++out.dbcnt; 960 *out.dbp++ = '\n'; 961 if (out.dbcnt >= out.dbsz) 962 dd_out(0); 963 } 964 if (in.dbcnt) 965 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 966 in.dbp = in.db + in.dbcnt; 967 } 968 969 void 970 unblock_close(void) 971 { 972 uint64_t cnt; 973 u_char *t; 974 975 if (in.dbcnt) { 976 warnx("%s: short input record", in.name); 977 for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t); 978 if (t >= in.db) { 979 cnt = t - in.db + 1; 980 (void)memmove(out.dbp, in.db, cnt); 981 out.dbp += cnt; 982 out.dbcnt += cnt; 983 } 984 ++out.dbcnt; 985 *out.dbp++ = '\n'; 986 } 987 } 988 989 #endif /* NO_CONV */ 990 991 #define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000) 992 993 void 994 summary(void) 995 { 996 char buf[100]; 997 int64_t mS; 998 struct timeval tv; 999 1000 if (progress) 1001 (void)write(STDERR_FILENO, "\n", 1); 1002 1003 (void)gettimeofday(&tv, NULL); 1004 mS = tv2mS(tv) - tv2mS(st.start); 1005 if (mS == 0) 1006 mS = 1; 1007 /* Use snprintf(3) so that we don't reenter stdio(3). */ 1008 (void)snprintf(buf, sizeof(buf), 1009 "%llu+%llu records in\n%llu+%llu records out\n", 1010 (unsigned long long)st.in_full, (unsigned long long)st.in_part, 1011 (unsigned long long)st.out_full, (unsigned long long)st.out_part); 1012 (void)write(STDERR_FILENO, buf, strlen(buf)); 1013 if (st.swab) { 1014 (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n", 1015 (unsigned long long)st.swab, 1016 (st.swab == 1) ? "block" : "blocks"); 1017 (void)write(STDERR_FILENO, buf, strlen(buf)); 1018 } 1019 if (st.trunc) { 1020 (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n", 1021 (unsigned long long)st.trunc, 1022 (st.trunc == 1) ? "block" : "blocks"); 1023 (void)write(STDERR_FILENO, buf, strlen(buf)); 1024 } 1025 if (st.sparse) { 1026 (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n", 1027 (unsigned long long)st.sparse, 1028 (st.sparse == 1) ? "block" : "blocks"); 1029 (void)write(STDERR_FILENO, buf, strlen(buf)); 1030 } 1031 (void)snprintf(buf, sizeof(buf), 1032 "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n", 1033 (unsigned long long) st.bytes, 1034 (long) (mS / 1000), 1035 (int) (mS % 1000), 1036 (unsigned long long) (st.bytes * 1000LL / mS)); 1037 (void)write(STDERR_FILENO, buf, strlen(buf)); 1038 } 1039 1040 void 1041 terminate(int notused) 1042 { 1043 1044 exit(0); 1045 /* NOTREACHED */ 1046 } 1047 1048 static int c_arg(const void *, const void *); 1049 #ifndef NO_CONV 1050 static int c_conv(const void *, const void *); 1051 #endif 1052 static void f_bs(char *); 1053 static void f_cbs(char *); 1054 static void f_conv(char *); 1055 static void f_count(char *); 1056 static void f_files(char *); 1057 static void f_ibs(char *); 1058 static void f_if(char *); 1059 static void f_obs(char *); 1060 static void f_of(char *); 1061 static void f_seek(char *); 1062 static void f_skip(char *); 1063 static void f_progress(char *); 1064 1065 static const struct arg { 1066 const char *name; 1067 void (*f)(char *); 1068 u_int set, noset; 1069 } args[] = { 1070 /* the array needs to be sorted by the first column so 1071 bsearch() can be used to find commands quickly */ 1072 { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, 1073 { "cbs", f_cbs, C_CBS, C_CBS }, 1074 { "conv", f_conv, 0, 0 }, 1075 { "count", f_count, C_COUNT, C_COUNT }, 1076 { "files", f_files, C_FILES, C_FILES }, 1077 { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 1078 { "if", f_if, C_IF, C_IF }, 1079 { "obs", f_obs, C_OBS, C_BS|C_OBS }, 1080 { "of", f_of, C_OF, C_OF }, 1081 { "progress", f_progress, 0, 0 }, 1082 { "seek", f_seek, C_SEEK, C_SEEK }, 1083 { "skip", f_skip, C_SKIP, C_SKIP }, 1084 }; 1085 1086 /* 1087 * args -- parse JCL syntax of dd. 1088 */ 1089 void 1090 jcl(char **argv) 1091 { 1092 struct arg *ap, tmp; 1093 char *oper, *arg; 1094 1095 in.dbsz = out.dbsz = 512; 1096 1097 while ((oper = *++argv) != NULL) { 1098 if ((arg = strchr(oper, '=')) == NULL) { 1099 fprintf(stderr, "unknown operand %s\n", oper); 1100 exit(1); 1101 /* NOTREACHED */ 1102 } 1103 *arg++ = '\0'; 1104 if (!*arg) { 1105 fprintf(stderr, "no value specified for %s\n", oper); 1106 exit(1); 1107 /* NOTREACHED */ 1108 } 1109 tmp.name = oper; 1110 if (!(ap = (struct arg *)bsearch(&tmp, args, 1111 sizeof(args)/sizeof(struct arg), sizeof(struct arg), 1112 c_arg))) { 1113 fprintf(stderr, "unknown operand %s\n", tmp.name); 1114 exit(1); 1115 /* NOTREACHED */ 1116 } 1117 if (ddflags & ap->noset) { 1118 fprintf(stderr, 1119 "%s: illegal argument combination or already set\n", 1120 tmp.name); 1121 exit(1); 1122 /* NOTREACHED */ 1123 } 1124 ddflags |= ap->set; 1125 ap->f(arg); 1126 } 1127 1128 /* Final sanity checks. */ 1129 1130 if (ddflags & C_BS) { 1131 /* 1132 * Bs is turned off by any conversion -- we assume the user 1133 * just wanted to set both the input and output block sizes 1134 * and didn't want the bs semantics, so we don't warn. 1135 */ 1136 if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | 1137 C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) { 1138 ddflags &= ~C_BS; 1139 ddflags |= C_IBS|C_OBS; 1140 } 1141 1142 /* Bs supersedes ibs and obs. */ 1143 if (ddflags & C_BS && ddflags & (C_IBS|C_OBS)) 1144 fprintf(stderr, "bs supersedes ibs and obs\n"); 1145 } 1146 1147 /* 1148 * Ascii/ebcdic and cbs implies block/unblock. 1149 * Block/unblock requires cbs and vice-versa. 1150 */ 1151 if (ddflags & (C_BLOCK|C_UNBLOCK)) { 1152 if (!(ddflags & C_CBS)) { 1153 fprintf(stderr, "record operations require cbs\n"); 1154 exit(1); 1155 /* NOTREACHED */ 1156 } 1157 cfunc = ddflags & C_BLOCK ? block : unblock; 1158 } else if (ddflags & C_CBS) { 1159 if (ddflags & (C_ASCII|C_EBCDIC)) { 1160 if (ddflags & C_ASCII) { 1161 ddflags |= C_UNBLOCK; 1162 cfunc = unblock; 1163 } else { 1164 ddflags |= C_BLOCK; 1165 cfunc = block; 1166 } 1167 } else { 1168 fprintf(stderr, 1169 "cbs meaningless if not doing record operations\n"); 1170 exit(1); 1171 /* NOTREACHED */ 1172 } 1173 } else 1174 cfunc = def; 1175 1176 /* Read, write and seek calls take off_t as arguments. 1177 * 1178 * The following check is not done because an off_t is a quad 1179 * for current NetBSD implementations. 1180 * 1181 * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz) 1182 * errx(1, "seek offsets cannot be larger than %d", INT_MAX); 1183 */ 1184 } 1185 1186 static int 1187 c_arg(const void *a, const void *b) 1188 { 1189 1190 return (strcmp(((const struct arg *)a)->name, 1191 ((const struct arg *)b)->name)); 1192 } 1193 1194 static long long strsuftoll(const char* name, const char* arg, int def, unsigned int max) 1195 { 1196 long long result; 1197 1198 if (sscanf(arg, "%lld", &result) == 0) 1199 result = def; 1200 return result; 1201 } 1202 1203 static void 1204 f_bs(char *arg) 1205 { 1206 1207 in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX); 1208 } 1209 1210 static void 1211 f_cbs(char *arg) 1212 { 1213 1214 cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX); 1215 } 1216 1217 static void 1218 f_count(char *arg) 1219 { 1220 1221 cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX); 1222 if (!cpy_cnt) 1223 terminate(0); 1224 } 1225 1226 static void 1227 f_files(char *arg) 1228 { 1229 1230 files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX); 1231 if (!files_cnt) 1232 terminate(0); 1233 } 1234 1235 static void 1236 f_ibs(char *arg) 1237 { 1238 1239 if (!(ddflags & C_BS)) 1240 in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX); 1241 } 1242 1243 static void 1244 f_if(char *arg) 1245 { 1246 1247 in.name = arg; 1248 } 1249 1250 static void 1251 f_obs(char *arg) 1252 { 1253 1254 if (!(ddflags & C_BS)) 1255 out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX); 1256 } 1257 1258 static void 1259 f_of(char *arg) 1260 { 1261 1262 out.name = arg; 1263 } 1264 1265 static void 1266 f_seek(char *arg) 1267 { 1268 1269 out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX); 1270 } 1271 1272 static void 1273 f_skip(char *arg) 1274 { 1275 1276 in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX); 1277 } 1278 1279 static void 1280 f_progress(char *arg) 1281 { 1282 1283 if (*arg != '0') 1284 progress = 1; 1285 } 1286 1287 #ifdef NO_CONV 1288 /* Build a small version (i.e. for a ramdisk root) */ 1289 static void 1290 f_conv(char *arg) 1291 { 1292 1293 fprintf(stderr, "conv option disabled\n"); 1294 exit(1); 1295 /* NOTREACHED */ 1296 } 1297 #else /* NO_CONV */ 1298 1299 static const struct conv { 1300 const char *name; 1301 u_int set, noset; 1302 const u_char *ctab; 1303 } clist[] = { 1304 { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 1305 { "block", C_BLOCK, C_UNBLOCK, NULL }, 1306 { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 1307 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 1308 { "lcase", C_LCASE, C_UCASE, NULL }, 1309 { "noerror", C_NOERROR, 0, NULL }, 1310 { "notrunc", C_NOTRUNC, 0, NULL }, 1311 { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 1312 { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 1313 { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 1314 { "osync", C_OSYNC, C_BS, NULL }, 1315 { "sparse", C_SPARSE, 0, NULL }, 1316 { "swab", C_SWAB, 0, NULL }, 1317 { "sync", C_SYNC, 0, NULL }, 1318 { "ucase", C_UCASE, C_LCASE, NULL }, 1319 { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 1320 /* If you add items to this table, be sure to add the 1321 * conversions to the C_BS check in the jcl routine above. 1322 */ 1323 }; 1324 1325 static void 1326 f_conv(char *arg) 1327 { 1328 struct conv *cp, tmp; 1329 1330 while (arg != NULL) { 1331 tmp.name = strsep(&arg, ","); 1332 if (!(cp = (struct conv *)bsearch(&tmp, clist, 1333 sizeof(clist)/sizeof(struct conv), sizeof(struct conv), 1334 c_conv))) { 1335 errx(EXIT_FAILURE, "unknown conversion %s", tmp.name); 1336 /* NOTREACHED */ 1337 } 1338 if (ddflags & cp->noset) { 1339 errx(EXIT_FAILURE, "%s: illegal conversion combination", tmp.name); 1340 /* NOTREACHED */ 1341 } 1342 ddflags |= cp->set; 1343 if (cp->ctab) 1344 ctab = cp->ctab; 1345 } 1346 } 1347 1348 static int 1349 c_conv(const void *a, const void *b) 1350 { 1351 1352 return (strcmp(((const struct conv *)a)->name, 1353 ((const struct conv *)b)->name)); 1354 } 1355 1356 #endif /* NO_CONV */ 1357 1358 1359