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