1 /* $NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt 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\ 39 The Regents of the University of California. All rights reserved."); 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.49 2012/02/21 01:49:01 matt 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/mtio.h> 54 #include <sys/time.h> 55 56 #include <ctype.h> 57 #include <err.h> 58 #include <errno.h> 59 #include <fcntl.h> 60 #include <locale.h> 61 #include <signal.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 67 #include "dd.h" 68 #include "extern.h" 69 70 static void dd_close(void); 71 static void dd_in(void); 72 static void getfdtype(IO *); 73 static void redup_clean_fd(IO *); 74 static void setup(void); 75 76 int main(int, char *[]); 77 78 IO in, out; /* input/output state */ 79 STAT st; /* statistics */ 80 void (*cfunc)(void); /* conversion function */ 81 uint64_t cpy_cnt; /* # of blocks to copy */ 82 static off_t pending = 0; /* pending seek if sparse */ 83 u_int ddflags; /* conversion options */ 84 uint64_t cbsz; /* conversion block size */ 85 u_int files_cnt = 1; /* # of files to copy */ 86 uint64_t progress = 0; /* display sign of life */ 87 const u_char *ctab; /* conversion table */ 88 sigset_t infoset; /* a set blocking SIGINFO */ 89 const char *msgfmt = "posix"; /* default summary() message format */ 90 91 /* 92 * Ops for stdin/stdout and crunch'd dd. These are always host ops. 93 */ 94 static const struct ddfops ddfops_stdfd = { 95 .op_open = open, 96 .op_close = close, 97 .op_fcntl = fcntl, 98 .op_ioctl = ioctl, 99 .op_fstat = fstat, 100 .op_fsync = fsync, 101 .op_ftruncate = ftruncate, 102 .op_lseek = lseek, 103 .op_read = read, 104 .op_write = write, 105 }; 106 extern const struct ddfops ddfops_prog; 107 108 int 109 main(int argc, char *argv[]) 110 { 111 int ch; 112 113 setprogname(argv[0]); 114 (void)setlocale(LC_ALL, ""); 115 116 while ((ch = getopt(argc, argv, "")) != -1) { 117 switch (ch) { 118 default: 119 errx(EXIT_FAILURE, "usage: dd [operand ...]"); 120 /* NOTREACHED */ 121 } 122 } 123 argc -= (optind - 1); 124 argv += (optind - 1); 125 126 jcl(argv); 127 #ifndef CRUNCHOPS 128 if (ddfops_prog.op_init && ddfops_prog.op_init() == -1) 129 err(1, "prog init"); 130 #endif 131 setup(); 132 133 (void)signal(SIGINFO, summaryx); 134 (void)signal(SIGINT, terminate); 135 (void)sigemptyset(&infoset); 136 (void)sigaddset(&infoset, SIGINFO); 137 138 (void)atexit(summary); 139 140 while (files_cnt--) 141 dd_in(); 142 143 dd_close(); 144 exit(0); 145 /* NOTREACHED */ 146 } 147 148 static void 149 setup(void) 150 { 151 #ifdef CRUNCHOPS 152 const struct ddfops *prog_ops = &ddfops_stdfd; 153 #else 154 const struct ddfops *prog_ops = &ddfops_prog; 155 #endif 156 157 if (in.name == NULL) { 158 in.name = "stdin"; 159 in.fd = STDIN_FILENO; 160 in.ops = &ddfops_stdfd; 161 } else { 162 in.ops = prog_ops; 163 in.fd = ddop_open(in, in.name, O_RDONLY, 0); 164 if (in.fd < 0) 165 err(EXIT_FAILURE, "%s", in.name); 166 /* NOTREACHED */ 167 168 /* Ensure in.fd is outside the stdio descriptor range */ 169 redup_clean_fd(&in); 170 } 171 172 getfdtype(&in); 173 174 if (files_cnt > 1 && !(in.flags & ISTAPE)) { 175 errx(EXIT_FAILURE, "files is not supported for non-tape devices"); 176 /* NOTREACHED */ 177 } 178 179 if (out.name == NULL) { 180 /* No way to check for read access here. */ 181 out.fd = STDOUT_FILENO; 182 out.name = "stdout"; 183 out.ops = &ddfops_stdfd; 184 } else { 185 out.ops = prog_ops; 186 #define OFLAGS \ 187 (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) 188 out.fd = ddop_open(out, out.name, O_RDWR | OFLAGS, DEFFILEMODE); 189 /* 190 * May not have read access, so try again with write only. 191 * Without read we may have a problem if output also does 192 * not support seeks. 193 */ 194 if (out.fd < 0) { 195 out.fd = ddop_open(out, out.name, O_WRONLY | OFLAGS, 196 DEFFILEMODE); 197 out.flags |= NOREAD; 198 } 199 if (out.fd < 0) { 200 err(EXIT_FAILURE, "%s", out.name); 201 /* NOTREACHED */ 202 } 203 204 /* Ensure out.fd is outside the stdio descriptor range */ 205 redup_clean_fd(&out); 206 } 207 208 getfdtype(&out); 209 210 /* 211 * Allocate space for the input and output buffers. If not doing 212 * record oriented I/O, only need a single buffer. 213 */ 214 if (!(ddflags & (C_BLOCK|C_UNBLOCK))) { 215 size_t dbsz = out.dbsz; 216 if (!(ddflags & C_BS)) 217 dbsz += in.dbsz - 1; 218 if ((in.db = malloc(dbsz)) == NULL) { 219 err(EXIT_FAILURE, NULL); 220 /* NOTREACHED */ 221 } 222 out.db = in.db; 223 } else if ((in.db = 224 malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL || 225 (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) { 226 err(EXIT_FAILURE, NULL); 227 /* NOTREACHED */ 228 } 229 in.dbp = in.db; 230 out.dbp = out.db; 231 232 /* Position the input/output streams. */ 233 if (in.offset) 234 pos_in(); 235 if (out.offset) 236 pos_out(); 237 238 /* 239 * Truncate the output file; ignore errors because it fails on some 240 * kinds of output files, tapes, for example. 241 */ 242 if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK)) 243 (void)ddop_ftruncate(out, out.fd, (off_t)out.offset * out.dbsz); 244 245 /* 246 * If converting case at the same time as another conversion, build a 247 * table that does both at once. If just converting case, use the 248 * built-in tables. 249 */ 250 if (ddflags & (C_LCASE|C_UCASE)) { 251 #ifdef NO_CONV 252 /* Should not get here, but just in case... */ 253 errx(EXIT_FAILURE, "case conv and -DNO_CONV"); 254 /* NOTREACHED */ 255 #else /* NO_CONV */ 256 u_int cnt; 257 258 if (ddflags & C_ASCII || ddflags & C_EBCDIC) { 259 if (ddflags & C_LCASE) { 260 for (cnt = 0; cnt < 256; ++cnt) 261 casetab[cnt] = tolower(ctab[cnt]); 262 } else { 263 for (cnt = 0; cnt < 256; ++cnt) 264 casetab[cnt] = toupper(ctab[cnt]); 265 } 266 } else { 267 if (ddflags & C_LCASE) { 268 for (cnt = 0; cnt < 256; ++cnt) 269 casetab[cnt] = tolower(cnt); 270 } else { 271 for (cnt = 0; cnt < 256; ++cnt) 272 casetab[cnt] = toupper(cnt); 273 } 274 } 275 276 ctab = casetab; 277 #endif /* NO_CONV */ 278 } 279 280 (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */ 281 } 282 283 static void 284 getfdtype(IO *io) 285 { 286 struct mtget mt; 287 struct stat sb; 288 289 if (io->ops->op_fstat(io->fd, &sb)) { 290 err(EXIT_FAILURE, "%s", io->name); 291 /* NOTREACHED */ 292 } 293 if (S_ISCHR(sb.st_mode)) 294 io->flags |= io->ops->op_ioctl(io->fd, MTIOCGET, &mt) 295 ? ISCHR : ISTAPE; 296 else if (io->ops->op_lseek(io->fd, (off_t)0, SEEK_CUR) == -1 297 && errno == ESPIPE) 298 io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */ 299 } 300 301 /* 302 * Move the parameter file descriptor to a descriptor that is outside the 303 * stdio descriptor range, if necessary. This is required to avoid 304 * accidentally outputting completion or error messages into the 305 * output file that were intended for the tty. 306 */ 307 static void 308 redup_clean_fd(IO *io) 309 { 310 int fd = io->fd; 311 int newfd; 312 313 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && 314 fd != STDERR_FILENO) 315 /* File descriptor is ok, return immediately. */ 316 return; 317 318 /* 319 * 3 is the first descriptor greater than STD*_FILENO. Any 320 * free descriptor valued 3 or above is acceptable... 321 */ 322 newfd = io->ops->op_fcntl(fd, F_DUPFD, 3); 323 if (newfd < 0) { 324 err(EXIT_FAILURE, "dupfd IO"); 325 /* NOTREACHED */ 326 } 327 328 io->ops->op_close(fd); 329 io->fd = newfd; 330 } 331 332 static void 333 dd_in(void) 334 { 335 int flags; 336 int64_t n; 337 338 for (flags = ddflags;;) { 339 if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt) 340 return; 341 342 /* 343 * Clear the buffer first if doing "sync" on input. 344 * If doing block operations use spaces. This will 345 * affect not only the C_NOERROR case, but also the 346 * last partial input block which should be padded 347 * with zero and not garbage. 348 */ 349 if (flags & C_SYNC) { 350 if (flags & (C_BLOCK|C_UNBLOCK)) 351 (void)memset(in.dbp, ' ', in.dbsz); 352 else 353 (void)memset(in.dbp, 0, in.dbsz); 354 } 355 356 n = ddop_read(in, in.fd, in.dbp, in.dbsz); 357 if (n == 0) { 358 in.dbrcnt = 0; 359 return; 360 } 361 362 /* Read error. */ 363 if (n < 0) { 364 365 /* 366 * If noerror not specified, die. POSIX requires that 367 * the warning message be followed by an I/O display. 368 */ 369 if (!(flags & C_NOERROR)) { 370 err(EXIT_FAILURE, "%s", in.name); 371 /* NOTREACHED */ 372 } 373 warn("%s", in.name); 374 summary(); 375 376 /* 377 * If it's not a tape drive or a pipe, seek past the 378 * error. If your OS doesn't do the right thing for 379 * raw disks this section should be modified to re-read 380 * in sector size chunks. 381 */ 382 if (!(in.flags & (ISPIPE|ISTAPE)) && 383 ddop_lseek(in, in.fd, (off_t)in.dbsz, SEEK_CUR)) 384 warn("%s", in.name); 385 386 /* If sync not specified, omit block and continue. */ 387 if (!(ddflags & C_SYNC)) 388 continue; 389 390 /* Read errors count as full blocks. */ 391 in.dbcnt += in.dbrcnt = in.dbsz; 392 ++st.in_full; 393 394 /* Handle full input blocks. */ 395 } else if ((uint64_t)n == in.dbsz) { 396 in.dbcnt += in.dbrcnt = n; 397 ++st.in_full; 398 399 /* Handle partial input blocks. */ 400 } else { 401 /* If sync, use the entire block. */ 402 if (ddflags & C_SYNC) 403 in.dbcnt += in.dbrcnt = in.dbsz; 404 else 405 in.dbcnt += in.dbrcnt = n; 406 ++st.in_part; 407 } 408 409 /* 410 * POSIX states that if bs is set and no other conversions 411 * than noerror, notrunc or sync are specified, the block 412 * is output without buffering as it is read. 413 */ 414 if (ddflags & C_BS) { 415 out.dbcnt = in.dbcnt; 416 dd_out(1); 417 in.dbcnt = 0; 418 continue; 419 } 420 421 if (ddflags & C_SWAB) { 422 if ((n = in.dbrcnt) & 1) { 423 ++st.swab; 424 --n; 425 } 426 swab(in.dbp, in.dbp, n); 427 } 428 429 in.dbp += in.dbrcnt; 430 (*cfunc)(); 431 } 432 } 433 434 /* 435 * Cleanup any remaining I/O and flush output. If necessary, output file 436 * is truncated. 437 */ 438 static void 439 dd_close(void) 440 { 441 442 if (cfunc == def) 443 def_close(); 444 else if (cfunc == block) 445 block_close(); 446 else if (cfunc == unblock) 447 unblock_close(); 448 if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) { 449 (void)memset(out.dbp, 0, out.dbsz - out.dbcnt); 450 out.dbcnt = out.dbsz; 451 } 452 /* If there are pending sparse blocks, make sure 453 * to write out the final block un-sparse 454 */ 455 if ((out.dbcnt == 0) && pending) { 456 memset(out.db, 0, out.dbsz); 457 out.dbcnt = out.dbsz; 458 out.dbp = out.db + out.dbcnt; 459 pending -= out.dbsz; 460 } 461 if (out.dbcnt) 462 dd_out(1); 463 464 /* 465 * Reporting nfs write error may be deferred until next 466 * write(2) or close(2) system call. So, we need to do an 467 * extra check. If an output is stdout, the file structure 468 * may be shared with other processes and close(2) just 469 * decreases the reference count. 470 */ 471 if (out.fd == STDOUT_FILENO && ddop_fsync(out, out.fd) == -1 472 && errno != EINVAL) { 473 err(EXIT_FAILURE, "fsync stdout"); 474 /* NOTREACHED */ 475 } 476 if (ddop_close(out, out.fd) == -1) { 477 err(EXIT_FAILURE, "close"); 478 /* NOTREACHED */ 479 } 480 } 481 482 void 483 dd_out(int force) 484 { 485 static int warned; 486 int64_t cnt, n, nw; 487 u_char *outp; 488 489 /* 490 * Write one or more blocks out. The common case is writing a full 491 * output block in a single write; increment the full block stats. 492 * Otherwise, we're into partial block writes. If a partial write, 493 * and it's a character device, just warn. If a tape device, quit. 494 * 495 * The partial writes represent two cases. 1: Where the input block 496 * was less than expected so the output block was less than expected. 497 * 2: Where the input block was the right size but we were forced to 498 * write the block in multiple chunks. The original versions of dd(1) 499 * never wrote a block in more than a single write, so the latter case 500 * never happened. 501 * 502 * One special case is if we're forced to do the write -- in that case 503 * we play games with the buffer size, and it's usually a partial write. 504 */ 505 outp = out.db; 506 for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { 507 for (cnt = n;; cnt -= nw) { 508 509 if (!force && ddflags & C_SPARSE) { 510 int sparse, i; 511 sparse = 1; /* Is buffer sparse? */ 512 for (i = 0; i < cnt; i++) 513 if (outp[i] != 0) { 514 sparse = 0; 515 break; 516 } 517 if (sparse) { 518 pending += cnt; 519 outp += cnt; 520 nw = 0; 521 break; 522 } 523 } 524 if (pending != 0) { 525 if (ddop_lseek(out, 526 out.fd, pending, SEEK_CUR) == -1) 527 err(EXIT_FAILURE, "%s: seek error creating sparse file", 528 out.name); 529 } 530 nw = bwrite(&out, outp, cnt); 531 if (nw <= 0) { 532 if (nw == 0) 533 errx(EXIT_FAILURE, 534 "%s: end of device", out.name); 535 /* NOTREACHED */ 536 if (errno != EINTR) 537 err(EXIT_FAILURE, "%s", out.name); 538 /* NOTREACHED */ 539 nw = 0; 540 } 541 if (pending) { 542 st.bytes += pending; 543 st.sparse += pending/out.dbsz; 544 st.out_full += pending/out.dbsz; 545 pending = 0; 546 } 547 outp += nw; 548 st.bytes += nw; 549 if (nw == n) { 550 if ((uint64_t)n != out.dbsz) 551 ++st.out_part; 552 else 553 ++st.out_full; 554 break; 555 } 556 ++st.out_part; 557 if (nw == cnt) 558 break; 559 if (out.flags & ISCHR && !warned) { 560 warned = 1; 561 warnx("%s: short write on character device", out.name); 562 } 563 if (out.flags & ISTAPE) 564 errx(EXIT_FAILURE, 565 "%s: short write on tape device", out.name); 566 /* NOTREACHED */ 567 568 } 569 if ((out.dbcnt -= n) < out.dbsz) 570 break; 571 } 572 573 /* Reassemble the output block. */ 574 if (out.dbcnt) 575 (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); 576 out.dbp = out.db + out.dbcnt; 577 578 if (progress && (st.out_full + st.out_part) % progress == 0) 579 (void)write(STDERR_FILENO, ".", 1); 580 } 581 582 /* 583 * A protected against SIGINFO write 584 */ 585 ssize_t 586 bwrite(IO *io, const void *buf, size_t len) 587 { 588 sigset_t oset; 589 ssize_t rv; 590 int oerrno; 591 592 (void)sigprocmask(SIG_BLOCK, &infoset, &oset); 593 rv = io->ops->op_write(io->fd, buf, len); 594 oerrno = errno; 595 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 596 errno = oerrno; 597 return (rv); 598 } 599