dd.c revision 46073
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993, 1994 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Keith Muller of the University of California, San Diego and Lance 71556Srgrimes * Visser of Convex Computer Corporation. 81556Srgrimes * 91556Srgrimes * Redistribution and use in source and binary forms, with or without 101556Srgrimes * modification, are permitted provided that the following conditions 111556Srgrimes * are met: 121556Srgrimes * 1. Redistributions of source code must retain the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer. 141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer in the 161556Srgrimes * documentation and/or other materials provided with the distribution. 171556Srgrimes * 3. All advertising materials mentioning features or use of this software 181556Srgrimes * must display the following acknowledgement: 191556Srgrimes * This product includes software developed by the University of 201556Srgrimes * California, Berkeley and its contributors. 211556Srgrimes * 4. Neither the name of the University nor the names of its contributors 221556Srgrimes * may be used to endorse or promote products derived from this software 231556Srgrimes * without specific prior written permission. 241556Srgrimes * 251556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351556Srgrimes * SUCH DAMAGE. 361556Srgrimes */ 371556Srgrimes 381556Srgrimes#ifndef lint 3920420Sstevestatic char const copyright[] = 401556Srgrimes"@(#) Copyright (c) 1991, 1993, 1994\n\ 411556Srgrimes The Regents of the University of California. All rights reserved.\n"; 421556Srgrimes#endif /* not lint */ 431556Srgrimes 441556Srgrimes#ifndef lint 4535773Scharnier#if 0 4636007Scharnierstatic char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; 4735773Scharnier#endif 4835773Scharnierstatic const char rcsid[] = 4946073Simp "$Id: dd.c,v 1.15 1998/05/13 07:33:47 charnier Exp $"; 501556Srgrimes#endif /* not lint */ 511556Srgrimes 521556Srgrimes#include <sys/param.h> 531556Srgrimes#include <sys/stat.h> 541556Srgrimes#include <sys/mtio.h> 551556Srgrimes 561556Srgrimes#include <ctype.h> 571556Srgrimes#include <err.h> 581556Srgrimes#include <errno.h> 591556Srgrimes#include <fcntl.h> 6019720Sphk#include <locale.h> 611556Srgrimes#include <stdio.h> 621556Srgrimes#include <stdlib.h> 631556Srgrimes#include <string.h> 641556Srgrimes#include <unistd.h> 651556Srgrimes 661556Srgrimes#include "dd.h" 671556Srgrimes#include "extern.h" 681556Srgrimes 691556Srgrimesstatic void dd_close __P((void)); 701556Srgrimesstatic void dd_in __P((void)); 711556Srgrimesstatic void getfdtype __P((IO *)); 721556Srgrimesstatic void setup __P((void)); 731556Srgrimes 741556SrgrimesIO in, out; /* input/output state */ 751556SrgrimesSTAT st; /* statistics */ 761556Srgrimesvoid (*cfunc) __P((void)); /* conversion function */ 771556Srgrimesu_long cpy_cnt; /* # of blocks to copy */ 7830312Sjoergu_long pending = 0; /* pending seek if sparse */ 791556Srgrimesu_int ddflags; /* conversion options */ 801556Srgrimesu_int cbsz; /* conversion block size */ 811556Srgrimesu_int files_cnt = 1; /* # of files to copy */ 821556Srgrimesu_char *ctab; /* conversion table */ 831556Srgrimes 841556Srgrimesint 851556Srgrimesmain(argc, argv) 861556Srgrimes int argc; 871556Srgrimes char *argv[]; 881556Srgrimes{ 8919720Sphk (void)setlocale(LC_CTYPE, ""); 901556Srgrimes jcl(argv); 911556Srgrimes setup(); 921556Srgrimes 931556Srgrimes (void)signal(SIGINFO, summaryx); 941556Srgrimes (void)signal(SIGINT, terminate); 951556Srgrimes 961556Srgrimes atexit(summary); 971556Srgrimes 981556Srgrimes while (files_cnt--) 991556Srgrimes dd_in(); 1001556Srgrimes 1011556Srgrimes dd_close(); 1021556Srgrimes exit(0); 1031556Srgrimes} 1041556Srgrimes 1051556Srgrimesstatic void 1061556Srgrimessetup() 1071556Srgrimes{ 1081556Srgrimes u_int cnt; 10919720Sphk struct timeval tv; 1101556Srgrimes 1111556Srgrimes if (in.name == NULL) { 1121556Srgrimes in.name = "stdin"; 1131556Srgrimes in.fd = STDIN_FILENO; 1141556Srgrimes } else { 1151556Srgrimes in.fd = open(in.name, O_RDONLY, 0); 1161556Srgrimes if (in.fd < 0) 1171556Srgrimes err(1, "%s", in.name); 1181556Srgrimes } 1191556Srgrimes 1201556Srgrimes getfdtype(&in); 1211556Srgrimes 1221556Srgrimes if (files_cnt > 1 && !(in.flags & ISTAPE)) 1231556Srgrimes errx(1, "files is not supported for non-tape devices"); 1241556Srgrimes 1251556Srgrimes if (out.name == NULL) { 1261556Srgrimes /* No way to check for read access here. */ 1271556Srgrimes out.fd = STDOUT_FILENO; 1281556Srgrimes out.name = "stdout"; 1291556Srgrimes } else { 1301556Srgrimes#define OFLAGS \ 1311556Srgrimes (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) 1321556Srgrimes out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE); 1331556Srgrimes /* 1341556Srgrimes * May not have read access, so try again with write only. 1351556Srgrimes * Without read we may have a problem if output also does 1361556Srgrimes * not support seeks. 1371556Srgrimes */ 1381556Srgrimes if (out.fd < 0) { 1391556Srgrimes out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE); 1401556Srgrimes out.flags |= NOREAD; 1411556Srgrimes } 1421556Srgrimes if (out.fd < 0) 1431556Srgrimes err(1, "%s", out.name); 1441556Srgrimes } 1451556Srgrimes 1461556Srgrimes getfdtype(&out); 1471556Srgrimes 1481556Srgrimes /* 1491556Srgrimes * Allocate space for the input and output buffers. If not doing 1501556Srgrimes * record oriented I/O, only need a single buffer. 1511556Srgrimes */ 1521556Srgrimes if (!(ddflags & (C_BLOCK|C_UNBLOCK))) { 1531556Srgrimes if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) 1541556Srgrimes err(1, NULL); 1551556Srgrimes out.db = in.db; 1561556Srgrimes } else if ((in.db = 1571556Srgrimes malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL || 1581556Srgrimes (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) 1591556Srgrimes err(1, NULL); 1601556Srgrimes in.dbp = in.db; 1611556Srgrimes out.dbp = out.db; 1621556Srgrimes 1631556Srgrimes /* Position the input/output streams. */ 1641556Srgrimes if (in.offset) 1651556Srgrimes pos_in(); 1661556Srgrimes if (out.offset) 1671556Srgrimes pos_out(); 1681556Srgrimes 1691556Srgrimes /* 1701556Srgrimes * Truncate the output file; ignore errors because it fails on some 1711556Srgrimes * kinds of output files, tapes, for example. 1721556Srgrimes */ 17320420Ssteve if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK)) 1741556Srgrimes (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz); 1751556Srgrimes 1761556Srgrimes /* 1771556Srgrimes * If converting case at the same time as another conversion, build a 1781556Srgrimes * table that does both at once. If just converting case, use the 1791556Srgrimes * built-in tables. 1801556Srgrimes */ 18146073Simp if (ddflags & (C_LCASE|C_UCASE)) { 18246073Simp if (ddflags & C_ASCII) { 1831556Srgrimes if (ddflags & C_LCASE) { 1845702Sache for (cnt = 0; cnt <= 0377; ++cnt) 1851556Srgrimes if (isupper(ctab[cnt])) 1861556Srgrimes ctab[cnt] = tolower(ctab[cnt]); 1871556Srgrimes } else { 1885702Sache for (cnt = 0; cnt <= 0377; ++cnt) 1891556Srgrimes if (islower(ctab[cnt])) 1901556Srgrimes ctab[cnt] = toupper(ctab[cnt]); 1911556Srgrimes } 19246073Simp } else if (ddflags & C_EBCDIC) { 1931556Srgrimes if (ddflags & C_LCASE) { 1945702Sache for (cnt = 0; cnt <= 0377; ++cnt) 1951556Srgrimes if (isupper(cnt)) 1961556Srgrimes ctab[cnt] = ctab[tolower(cnt)]; 1971556Srgrimes } else { 1985702Sache for (cnt = 0; cnt <= 0377; ++cnt) 1991556Srgrimes if (islower(cnt)) 2001556Srgrimes ctab[cnt] = ctab[toupper(cnt)]; 2011556Srgrimes } 20246073Simp } else { 2031556Srgrimes ctab = ddflags & C_LCASE ? u2l : l2u; 2045701Sache if (ddflags & C_LCASE) { 2055702Sache for (cnt = 0; cnt <= 0377; ++cnt) 2065701Sache if (isupper(cnt)) 2075701Sache ctab[cnt] = tolower(cnt); 2085702Sache else 2095702Sache ctab[cnt] = cnt; 2105701Sache } else { 2115702Sache for (cnt = 0; cnt <= 0377; ++cnt) 2125701Sache if (islower(cnt)) 2135701Sache ctab[cnt] = toupper(cnt); 2145702Sache else 2155702Sache ctab[cnt] = cnt; 2165701Sache } 2175701Sache } 21846073Simp } 21919720Sphk (void)gettimeofday(&tv, (struct timezone *)NULL); 22019720Sphk st.start = tv.tv_sec + tv.tv_usec * 1e-6; 2211556Srgrimes} 2221556Srgrimes 2231556Srgrimesstatic void 2241556Srgrimesgetfdtype(io) 2251556Srgrimes IO *io; 2261556Srgrimes{ 2271556Srgrimes struct mtget mt; 2281556Srgrimes struct stat sb; 2291556Srgrimes 2301556Srgrimes if (fstat(io->fd, &sb)) 2311556Srgrimes err(1, "%s", io->name); 2321556Srgrimes if (S_ISCHR(sb.st_mode)) 2331556Srgrimes io->flags |= ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; 2341556Srgrimes else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) 2351556Srgrimes io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */ 2361556Srgrimes} 2371556Srgrimes 2381556Srgrimesstatic void 2391556Srgrimesdd_in() 2401556Srgrimes{ 24128430Sjlemon int n; 2421556Srgrimes 24328430Sjlemon for (;;) { 2441556Srgrimes if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt) 2451556Srgrimes return; 2461556Srgrimes 2471556Srgrimes /* 24828430Sjlemon * Zero the buffer first if sync; If doing block operations 2491556Srgrimes * use spaces. 2501556Srgrimes */ 25128430Sjlemon if (ddflags & C_SYNC) 25228430Sjlemon if (ddflags & (C_BLOCK|C_UNBLOCK)) 2531556Srgrimes memset(in.dbp, ' ', in.dbsz); 2541556Srgrimes else 2551556Srgrimes memset(in.dbp, 0, in.dbsz); 2561556Srgrimes 2571556Srgrimes n = read(in.fd, in.dbp, in.dbsz); 2581556Srgrimes if (n == 0) { 2591556Srgrimes in.dbrcnt = 0; 2601556Srgrimes return; 2611556Srgrimes } 2621556Srgrimes 2631556Srgrimes /* Read error. */ 2641556Srgrimes if (n < 0) { 2651556Srgrimes /* 2661556Srgrimes * If noerror not specified, die. POSIX requires that 2671556Srgrimes * the warning message be followed by an I/O display. 2681556Srgrimes */ 26928430Sjlemon if (!(ddflags & C_NOERROR)) 2701556Srgrimes err(1, "%s", in.name); 2711556Srgrimes warn("%s", in.name); 2721556Srgrimes summary(); 2731556Srgrimes 2741556Srgrimes /* 2751556Srgrimes * If it's not a tape drive or a pipe, seek past the 2761556Srgrimes * error. If your OS doesn't do the right thing for 2771556Srgrimes * raw disks this section should be modified to re-read 2781556Srgrimes * in sector size chunks. 2791556Srgrimes */ 2801556Srgrimes if (!(in.flags & (ISPIPE|ISTAPE)) && 2811556Srgrimes lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) 2821556Srgrimes warn("%s", in.name); 2831556Srgrimes 2841556Srgrimes /* If sync not specified, omit block and continue. */ 2851556Srgrimes if (!(ddflags & C_SYNC)) 2861556Srgrimes continue; 2871556Srgrimes 2881556Srgrimes /* Read errors count as full blocks. */ 2891556Srgrimes in.dbcnt += in.dbrcnt = in.dbsz; 2901556Srgrimes ++st.in_full; 2911556Srgrimes 2921556Srgrimes /* Handle full input blocks. */ 2931556Srgrimes } else if (n == in.dbsz) { 2941556Srgrimes in.dbcnt += in.dbrcnt = n; 2951556Srgrimes ++st.in_full; 2961556Srgrimes 2971556Srgrimes /* Handle partial input blocks. */ 2981556Srgrimes } else { 2991556Srgrimes /* If sync, use the entire block. */ 3001556Srgrimes if (ddflags & C_SYNC) 3011556Srgrimes in.dbcnt += in.dbrcnt = in.dbsz; 3021556Srgrimes else 3031556Srgrimes in.dbcnt += in.dbrcnt = n; 3041556Srgrimes ++st.in_part; 3051556Srgrimes } 3061556Srgrimes 3071556Srgrimes /* 3081556Srgrimes * POSIX states that if bs is set and no other conversions 3091556Srgrimes * than noerror, notrunc or sync are specified, the block 3101556Srgrimes * is output without buffering as it is read. 3111556Srgrimes */ 3121556Srgrimes if (ddflags & C_BS) { 3131556Srgrimes out.dbcnt = in.dbcnt; 3141556Srgrimes dd_out(1); 3151556Srgrimes in.dbcnt = 0; 3161556Srgrimes continue; 3171556Srgrimes } 3181556Srgrimes 3191556Srgrimes if (ddflags & C_SWAB) { 32032324Sjoerg if ((n = in.dbrcnt) & 1) { 3211556Srgrimes ++st.swab; 3221556Srgrimes --n; 3231556Srgrimes } 3241556Srgrimes swab(in.dbp, in.dbp, n); 3251556Srgrimes } 3261556Srgrimes 3271556Srgrimes in.dbp += in.dbrcnt; 3281556Srgrimes (*cfunc)(); 3291556Srgrimes } 3301556Srgrimes} 3311556Srgrimes 3321556Srgrimes/* 3331556Srgrimes * Cleanup any remaining I/O and flush output. If necesssary, output file 3341556Srgrimes * is truncated. 3351556Srgrimes */ 3361556Srgrimesstatic void 3371556Srgrimesdd_close() 3381556Srgrimes{ 3391556Srgrimes if (cfunc == def) 3401556Srgrimes def_close(); 3411556Srgrimes else if (cfunc == block) 3421556Srgrimes block_close(); 3431556Srgrimes else if (cfunc == unblock) 3441556Srgrimes unblock_close(); 34528430Sjlemon if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { 34628430Sjlemon if (ddflags & (C_BLOCK|C_UNBLOCK)) 34728430Sjlemon memset(out.dbp, ' ', out.dbsz - out.dbcnt); 34828430Sjlemon else 34928430Sjlemon memset(out.dbp, 0, out.dbsz - out.dbcnt); 3501556Srgrimes out.dbcnt = out.dbsz; 3511556Srgrimes } 35230312Sjoerg if (out.dbcnt || pending) 3531556Srgrimes dd_out(1); 3541556Srgrimes} 3551556Srgrimes 3561556Srgrimesvoid 3571556Srgrimesdd_out(force) 3581556Srgrimes int force; 3591556Srgrimes{ 3601556Srgrimes static int warned; 36130312Sjoerg int cnt, n, nw, i, sparse; 3621556Srgrimes u_char *outp; 3631556Srgrimes 3641556Srgrimes /* 3651556Srgrimes * Write one or more blocks out. The common case is writing a full 3661556Srgrimes * output block in a single write; increment the full block stats. 3671556Srgrimes * Otherwise, we're into partial block writes. If a partial write, 3681556Srgrimes * and it's a character device, just warn. If a tape device, quit. 3691556Srgrimes * 3701556Srgrimes * The partial writes represent two cases. 1: Where the input block 3711556Srgrimes * was less than expected so the output block was less than expected. 3721556Srgrimes * 2: Where the input block was the right size but we were forced to 3731556Srgrimes * write the block in multiple chunks. The original versions of dd(1) 3741556Srgrimes * never wrote a block in more than a single write, so the latter case 3751556Srgrimes * never happened. 3761556Srgrimes * 3771556Srgrimes * One special case is if we're forced to do the write -- in that case 3781556Srgrimes * we play games with the buffer size, and it's usually a partial write. 3791556Srgrimes */ 3801556Srgrimes outp = out.db; 3811556Srgrimes for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { 3821556Srgrimes for (cnt = n;; cnt -= nw) { 38330312Sjoerg sparse = 0; 38430312Sjoerg if (ddflags & C_SPARSE) { 38530312Sjoerg sparse = 1; /* Is buffer sparse? */ 38630312Sjoerg for (i = 0; i < cnt; i++) 38730312Sjoerg if (outp[i] != 0) { 38830312Sjoerg sparse = 0; 38930312Sjoerg break; 39030312Sjoerg } 39130312Sjoerg } 39230312Sjoerg if (sparse && !force) { 39330312Sjoerg pending += cnt; 39430312Sjoerg nw = cnt; 39530312Sjoerg } else { 39630312Sjoerg if (pending != 0) { 39730312Sjoerg if (force) 39830312Sjoerg pending--; 39930312Sjoerg if (lseek (out.fd, pending, SEEK_CUR) == -1) 40030312Sjoerg err(2, "%s: seek error creating sparse file", 40130312Sjoerg out.name); 40230312Sjoerg if (force) 40330312Sjoerg write(out.fd, outp, 1); 40430312Sjoerg pending = 0; 40530312Sjoerg } 40630312Sjoerg if (cnt) 40730312Sjoerg nw = write(out.fd, outp, cnt); 40830312Sjoerg else 40930312Sjoerg return; 41030312Sjoerg } 41130312Sjoerg 4121556Srgrimes if (nw <= 0) { 4131556Srgrimes if (nw == 0) 4141556Srgrimes errx(1, "%s: end of device", out.name); 4151556Srgrimes if (errno != EINTR) 4161556Srgrimes err(1, "%s", out.name); 4171556Srgrimes nw = 0; 4181556Srgrimes } 4191556Srgrimes outp += nw; 4201556Srgrimes st.bytes += nw; 4211556Srgrimes if (nw == n) { 4221556Srgrimes if (n != out.dbsz) 4231556Srgrimes ++st.out_part; 4241556Srgrimes else 4251556Srgrimes ++st.out_full; 4261556Srgrimes break; 4271556Srgrimes } 4281556Srgrimes ++st.out_part; 4291556Srgrimes if (nw == cnt) 4301556Srgrimes break; 4311556Srgrimes if (out.flags & ISCHR && !warned) { 4321556Srgrimes warned = 1; 4331556Srgrimes warnx("%s: short write on character device", 4341556Srgrimes out.name); 4351556Srgrimes } 4361556Srgrimes if (out.flags & ISTAPE) 4371556Srgrimes errx(1, "%s: short write on tape device", out.name); 4381556Srgrimes } 4391556Srgrimes if ((out.dbcnt -= n) < out.dbsz) 4401556Srgrimes break; 4411556Srgrimes } 4421556Srgrimes 4431556Srgrimes /* Reassemble the output block. */ 4441556Srgrimes if (out.dbcnt) 4451556Srgrimes memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); 4461556Srgrimes out.dbp = out.db + out.dbcnt; 4471556Srgrimes} 448