dd.c revision 28430
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. 363044Sdg * 3728430Sjlemon * $Id: dd.c,v 1.10 1997/02/22 14:02:44 peter Exp $ 381556Srgrimes */ 391556Srgrimes 401556Srgrimes#ifndef lint 4120420Sstevestatic char const copyright[] = 421556Srgrimes"@(#) Copyright (c) 1991, 1993, 1994\n\ 431556Srgrimes The Regents of the University of California. All rights reserved.\n"; 441556Srgrimes#endif /* not lint */ 451556Srgrimes 461556Srgrimes#ifndef lint 4720420Sstevestatic char const sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; 481556Srgrimes#endif /* not lint */ 491556Srgrimes 501556Srgrimes#include <sys/param.h> 511556Srgrimes#include <sys/stat.h> 521556Srgrimes#include <sys/ioctl.h> 531556Srgrimes#include <sys/mtio.h> 541556Srgrimes 551556Srgrimes#include <ctype.h> 561556Srgrimes#include <err.h> 571556Srgrimes#include <errno.h> 581556Srgrimes#include <fcntl.h> 5919720Sphk#include <locale.h> 601556Srgrimes#include <signal.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 */ 781556Srgrimesu_int ddflags; /* conversion options */ 791556Srgrimesu_int cbsz; /* conversion block size */ 801556Srgrimesu_int files_cnt = 1; /* # of files to copy */ 811556Srgrimesu_char *ctab; /* conversion table */ 821556Srgrimes 831556Srgrimesint 841556Srgrimesmain(argc, argv) 851556Srgrimes int argc; 861556Srgrimes char *argv[]; 871556Srgrimes{ 8819720Sphk (void)setlocale(LC_CTYPE, ""); 891556Srgrimes jcl(argv); 901556Srgrimes setup(); 911556Srgrimes 921556Srgrimes (void)signal(SIGINFO, summaryx); 931556Srgrimes (void)signal(SIGINT, terminate); 941556Srgrimes 951556Srgrimes atexit(summary); 961556Srgrimes 971556Srgrimes while (files_cnt--) 981556Srgrimes dd_in(); 991556Srgrimes 1001556Srgrimes dd_close(); 1011556Srgrimes exit(0); 1021556Srgrimes} 1031556Srgrimes 1041556Srgrimesstatic void 1051556Srgrimessetup() 1061556Srgrimes{ 1071556Srgrimes u_int cnt; 10819720Sphk struct timeval tv; 1091556Srgrimes 1101556Srgrimes if (in.name == NULL) { 1111556Srgrimes in.name = "stdin"; 1121556Srgrimes in.fd = STDIN_FILENO; 1131556Srgrimes } else { 1141556Srgrimes in.fd = open(in.name, O_RDONLY, 0); 1151556Srgrimes if (in.fd < 0) 1161556Srgrimes err(1, "%s", in.name); 1171556Srgrimes } 1181556Srgrimes 1191556Srgrimes getfdtype(&in); 1201556Srgrimes 1211556Srgrimes if (files_cnt > 1 && !(in.flags & ISTAPE)) 1221556Srgrimes errx(1, "files is not supported for non-tape devices"); 1231556Srgrimes 1241556Srgrimes if (out.name == NULL) { 1251556Srgrimes /* No way to check for read access here. */ 1261556Srgrimes out.fd = STDOUT_FILENO; 1271556Srgrimes out.name = "stdout"; 1281556Srgrimes } else { 1291556Srgrimes#define OFLAGS \ 1301556Srgrimes (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) 1311556Srgrimes out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE); 1321556Srgrimes /* 1331556Srgrimes * May not have read access, so try again with write only. 1341556Srgrimes * Without read we may have a problem if output also does 1351556Srgrimes * not support seeks. 1361556Srgrimes */ 1371556Srgrimes if (out.fd < 0) { 1381556Srgrimes out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE); 1391556Srgrimes out.flags |= NOREAD; 1401556Srgrimes } 1411556Srgrimes if (out.fd < 0) 1421556Srgrimes err(1, "%s", out.name); 1431556Srgrimes } 1441556Srgrimes 1451556Srgrimes getfdtype(&out); 1461556Srgrimes 1471556Srgrimes /* 1481556Srgrimes * Allocate space for the input and output buffers. If not doing 1491556Srgrimes * record oriented I/O, only need a single buffer. 1501556Srgrimes */ 1511556Srgrimes if (!(ddflags & (C_BLOCK|C_UNBLOCK))) { 1521556Srgrimes if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) 1531556Srgrimes err(1, NULL); 1541556Srgrimes out.db = in.db; 1551556Srgrimes } else if ((in.db = 1561556Srgrimes malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL || 1571556Srgrimes (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) 1581556Srgrimes err(1, NULL); 1591556Srgrimes in.dbp = in.db; 1601556Srgrimes out.dbp = out.db; 1611556Srgrimes 1621556Srgrimes /* Position the input/output streams. */ 1631556Srgrimes if (in.offset) 1641556Srgrimes pos_in(); 1651556Srgrimes if (out.offset) 1661556Srgrimes pos_out(); 1671556Srgrimes 1681556Srgrimes /* 1691556Srgrimes * Truncate the output file; ignore errors because it fails on some 1701556Srgrimes * kinds of output files, tapes, for example. 1711556Srgrimes */ 17220420Ssteve if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK)) 1731556Srgrimes (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz); 1741556Srgrimes 1751556Srgrimes /* 1761556Srgrimes * If converting case at the same time as another conversion, build a 1771556Srgrimes * table that does both at once. If just converting case, use the 1781556Srgrimes * built-in tables. 1791556Srgrimes */ 1801556Srgrimes if (ddflags & (C_LCASE|C_UCASE)) 1811556Srgrimes if (ddflags & C_ASCII) 1821556Srgrimes if (ddflags & C_LCASE) { 1835702Sache for (cnt = 0; cnt <= 0377; ++cnt) 1841556Srgrimes if (isupper(ctab[cnt])) 1851556Srgrimes ctab[cnt] = tolower(ctab[cnt]); 1861556Srgrimes } else { 1875702Sache for (cnt = 0; cnt <= 0377; ++cnt) 1881556Srgrimes if (islower(ctab[cnt])) 1891556Srgrimes ctab[cnt] = toupper(ctab[cnt]); 1901556Srgrimes } 1911556Srgrimes else if (ddflags & C_EBCDIC) 1921556Srgrimes if (ddflags & C_LCASE) { 1935702Sache for (cnt = 0; cnt <= 0377; ++cnt) 1941556Srgrimes if (isupper(cnt)) 1951556Srgrimes ctab[cnt] = ctab[tolower(cnt)]; 1961556Srgrimes } else { 1975702Sache for (cnt = 0; cnt <= 0377; ++cnt) 1981556Srgrimes if (islower(cnt)) 1991556Srgrimes ctab[cnt] = ctab[toupper(cnt)]; 2001556Srgrimes } 2015701Sache else { 2021556Srgrimes ctab = ddflags & C_LCASE ? u2l : l2u; 2035701Sache if (ddflags & C_LCASE) { 2045702Sache for (cnt = 0; cnt <= 0377; ++cnt) 2055701Sache if (isupper(cnt)) 2065701Sache ctab[cnt] = tolower(cnt); 2075702Sache else 2085702Sache ctab[cnt] = cnt; 2095701Sache } else { 2105702Sache for (cnt = 0; cnt <= 0377; ++cnt) 2115701Sache if (islower(cnt)) 2125701Sache ctab[cnt] = toupper(cnt); 2135702Sache else 2145702Sache ctab[cnt] = cnt; 2155701Sache } 2165701Sache } 21719720Sphk (void)gettimeofday(&tv, (struct timezone *)NULL); 21819720Sphk st.start = tv.tv_sec + tv.tv_usec * 1e-6; 2191556Srgrimes} 2201556Srgrimes 2211556Srgrimesstatic void 2221556Srgrimesgetfdtype(io) 2231556Srgrimes IO *io; 2241556Srgrimes{ 2251556Srgrimes struct mtget mt; 2261556Srgrimes struct stat sb; 2271556Srgrimes 2281556Srgrimes if (fstat(io->fd, &sb)) 2291556Srgrimes err(1, "%s", io->name); 2301556Srgrimes if (S_ISCHR(sb.st_mode)) 2311556Srgrimes io->flags |= ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; 2321556Srgrimes else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) 2331556Srgrimes io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */ 2341556Srgrimes} 2351556Srgrimes 2361556Srgrimesstatic void 2371556Srgrimesdd_in() 2381556Srgrimes{ 23928430Sjlemon int n; 2401556Srgrimes 24128430Sjlemon for (;;) { 2421556Srgrimes if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt) 2431556Srgrimes return; 2441556Srgrimes 2451556Srgrimes /* 24628430Sjlemon * Zero the buffer first if sync; If doing block operations 2471556Srgrimes * use spaces. 2481556Srgrimes */ 24928430Sjlemon if (ddflags & C_SYNC) 25028430Sjlemon if (ddflags & (C_BLOCK|C_UNBLOCK)) 2511556Srgrimes memset(in.dbp, ' ', in.dbsz); 2521556Srgrimes else 2531556Srgrimes memset(in.dbp, 0, in.dbsz); 2541556Srgrimes 2551556Srgrimes n = read(in.fd, in.dbp, in.dbsz); 2561556Srgrimes if (n == 0) { 2571556Srgrimes in.dbrcnt = 0; 2581556Srgrimes return; 2591556Srgrimes } 2601556Srgrimes 2611556Srgrimes /* Read error. */ 2621556Srgrimes if (n < 0) { 2631556Srgrimes /* 2641556Srgrimes * If noerror not specified, die. POSIX requires that 2651556Srgrimes * the warning message be followed by an I/O display. 2661556Srgrimes */ 26728430Sjlemon if (!(ddflags & C_NOERROR)) 2681556Srgrimes err(1, "%s", in.name); 2691556Srgrimes warn("%s", in.name); 2701556Srgrimes summary(); 2711556Srgrimes 2721556Srgrimes /* 2731556Srgrimes * If it's not a tape drive or a pipe, seek past the 2741556Srgrimes * error. If your OS doesn't do the right thing for 2751556Srgrimes * raw disks this section should be modified to re-read 2761556Srgrimes * in sector size chunks. 2771556Srgrimes */ 2781556Srgrimes if (!(in.flags & (ISPIPE|ISTAPE)) && 2791556Srgrimes lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) 2801556Srgrimes warn("%s", in.name); 2811556Srgrimes 2821556Srgrimes /* If sync not specified, omit block and continue. */ 2831556Srgrimes if (!(ddflags & C_SYNC)) 2841556Srgrimes continue; 2851556Srgrimes 2861556Srgrimes /* Read errors count as full blocks. */ 2871556Srgrimes in.dbcnt += in.dbrcnt = in.dbsz; 2881556Srgrimes ++st.in_full; 2891556Srgrimes 2901556Srgrimes /* Handle full input blocks. */ 2911556Srgrimes } else if (n == in.dbsz) { 2921556Srgrimes in.dbcnt += in.dbrcnt = n; 2931556Srgrimes ++st.in_full; 2941556Srgrimes 2951556Srgrimes /* Handle partial input blocks. */ 2961556Srgrimes } else { 2971556Srgrimes /* If sync, use the entire block. */ 2981556Srgrimes if (ddflags & C_SYNC) 2991556Srgrimes in.dbcnt += in.dbrcnt = in.dbsz; 3001556Srgrimes else 3011556Srgrimes in.dbcnt += in.dbrcnt = n; 3021556Srgrimes ++st.in_part; 3031556Srgrimes } 3041556Srgrimes 3051556Srgrimes /* 3061556Srgrimes * POSIX states that if bs is set and no other conversions 3071556Srgrimes * than noerror, notrunc or sync are specified, the block 3081556Srgrimes * is output without buffering as it is read. 3091556Srgrimes */ 3101556Srgrimes if (ddflags & C_BS) { 3111556Srgrimes out.dbcnt = in.dbcnt; 3121556Srgrimes dd_out(1); 3131556Srgrimes in.dbcnt = 0; 3141556Srgrimes continue; 3151556Srgrimes } 3161556Srgrimes 3171556Srgrimes if (ddflags & C_SWAB) { 3181556Srgrimes if ((n = in.dbcnt) & 1) { 3191556Srgrimes ++st.swab; 3201556Srgrimes --n; 3211556Srgrimes } 3221556Srgrimes swab(in.dbp, in.dbp, n); 3231556Srgrimes } 3241556Srgrimes 3251556Srgrimes in.dbp += in.dbrcnt; 3261556Srgrimes (*cfunc)(); 3271556Srgrimes } 3281556Srgrimes} 3291556Srgrimes 3301556Srgrimes/* 3311556Srgrimes * Cleanup any remaining I/O and flush output. If necesssary, output file 3321556Srgrimes * is truncated. 3331556Srgrimes */ 3341556Srgrimesstatic void 3351556Srgrimesdd_close() 3361556Srgrimes{ 3371556Srgrimes if (cfunc == def) 3381556Srgrimes def_close(); 3391556Srgrimes else if (cfunc == block) 3401556Srgrimes block_close(); 3411556Srgrimes else if (cfunc == unblock) 3421556Srgrimes unblock_close(); 34328430Sjlemon if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { 34428430Sjlemon if (ddflags & (C_BLOCK|C_UNBLOCK)) 34528430Sjlemon memset(out.dbp, ' ', out.dbsz - out.dbcnt); 34628430Sjlemon else 34728430Sjlemon memset(out.dbp, 0, out.dbsz - out.dbcnt); 3481556Srgrimes out.dbcnt = out.dbsz; 3491556Srgrimes } 3501556Srgrimes if (out.dbcnt) 3511556Srgrimes dd_out(1); 3521556Srgrimes} 3531556Srgrimes 3541556Srgrimesvoid 3551556Srgrimesdd_out(force) 3561556Srgrimes int force; 3571556Srgrimes{ 3581556Srgrimes static int warned; 3591556Srgrimes int cnt, n, nw; 3601556Srgrimes u_char *outp; 3611556Srgrimes 3621556Srgrimes /* 3631556Srgrimes * Write one or more blocks out. The common case is writing a full 3641556Srgrimes * output block in a single write; increment the full block stats. 3651556Srgrimes * Otherwise, we're into partial block writes. If a partial write, 3661556Srgrimes * and it's a character device, just warn. If a tape device, quit. 3671556Srgrimes * 3681556Srgrimes * The partial writes represent two cases. 1: Where the input block 3691556Srgrimes * was less than expected so the output block was less than expected. 3701556Srgrimes * 2: Where the input block was the right size but we were forced to 3711556Srgrimes * write the block in multiple chunks. The original versions of dd(1) 3721556Srgrimes * never wrote a block in more than a single write, so the latter case 3731556Srgrimes * never happened. 3741556Srgrimes * 3751556Srgrimes * One special case is if we're forced to do the write -- in that case 3761556Srgrimes * we play games with the buffer size, and it's usually a partial write. 3771556Srgrimes */ 3781556Srgrimes outp = out.db; 3791556Srgrimes for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { 3801556Srgrimes for (cnt = n;; cnt -= nw) { 3811556Srgrimes nw = write(out.fd, outp, cnt); 3821556Srgrimes if (nw <= 0) { 3831556Srgrimes if (nw == 0) 3841556Srgrimes errx(1, "%s: end of device", out.name); 3851556Srgrimes if (errno != EINTR) 3861556Srgrimes err(1, "%s", out.name); 3871556Srgrimes nw = 0; 3881556Srgrimes } 3891556Srgrimes outp += nw; 3901556Srgrimes st.bytes += nw; 3911556Srgrimes if (nw == n) { 3921556Srgrimes if (n != out.dbsz) 3931556Srgrimes ++st.out_part; 3941556Srgrimes else 3951556Srgrimes ++st.out_full; 3961556Srgrimes break; 3971556Srgrimes } 3981556Srgrimes ++st.out_part; 3991556Srgrimes if (nw == cnt) 4001556Srgrimes break; 4011556Srgrimes if (out.flags & ISCHR && !warned) { 4021556Srgrimes warned = 1; 4031556Srgrimes warnx("%s: short write on character device", 4041556Srgrimes out.name); 4051556Srgrimes } 4061556Srgrimes if (out.flags & ISTAPE) 4071556Srgrimes errx(1, "%s: short write on tape device", out.name); 4081556Srgrimes } 4091556Srgrimes if ((out.dbcnt -= n) < out.dbsz) 4101556Srgrimes break; 4111556Srgrimes } 4121556Srgrimes 4131556Srgrimes /* Reassemble the output block. */ 4141556Srgrimes if (out.dbcnt) 4151556Srgrimes memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); 4161556Srgrimes out.dbp = out.db + out.dbcnt; 4171556Srgrimes} 418