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 * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 34114433Sobrien#if 0 351556Srgrimes#ifndef lint 3620420Sstevestatic char const copyright[] = 371556Srgrimes"@(#) Copyright (c) 1991, 1993, 1994\n\ 381556Srgrimes The Regents of the University of California. All rights reserved.\n"; 391556Srgrimes#endif /* not lint */ 401556Srgrimes 411556Srgrimes#ifndef lint 4236007Scharnierstatic char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; 43114433Sobrien#endif /* not lint */ 4435773Scharnier#endif 4599109Sobrien#include <sys/cdefs.h> 4699109Sobrien__FBSDID("$FreeBSD$"); 471556Srgrimes 481556Srgrimes#include <sys/param.h> 491556Srgrimes#include <sys/stat.h> 5050460Sgreen#include <sys/conf.h> 5160859Sobrien#include <sys/disklabel.h> 5250460Sgreen#include <sys/filio.h> 5391807Smarkm#include <sys/time.h> 541556Srgrimes 55266488Sthomas#include <assert.h> 561556Srgrimes#include <ctype.h> 571556Srgrimes#include <err.h> 581556Srgrimes#include <errno.h> 591556Srgrimes#include <fcntl.h> 60111629Smarkm#include <inttypes.h> 6119720Sphk#include <locale.h> 621556Srgrimes#include <stdio.h> 631556Srgrimes#include <stdlib.h> 641556Srgrimes#include <string.h> 651556Srgrimes#include <unistd.h> 661556Srgrimes 671556Srgrimes#include "dd.h" 681556Srgrimes#include "extern.h" 691556Srgrimes 7090108Simpstatic void dd_close(void); 7190108Simpstatic void dd_in(void); 7290108Simpstatic void getfdtype(IO *); 7390108Simpstatic void setup(void); 741556Srgrimes 751556SrgrimesIO in, out; /* input/output state */ 761556SrgrimesSTAT st; /* statistics */ 7790108Simpvoid (*cfunc)(void); /* conversion function */ 78111629Smarkmuintmax_t cpy_cnt; /* # of blocks to copy */ 7991079Smarkmstatic off_t pending = 0; /* pending seek if sparse */ 80266488Sthomasstatic off_t last_sp = 0; /* size of last added sparse block */ 81111629Smarkmu_int ddflags = 0; /* conversion options */ 8251208Sgreensize_t cbsz; /* conversion block size */ 83111629Smarkmuintmax_t files_cnt = 1; /* # of files to copy */ 8451249Sgreenconst u_char *ctab; /* conversion table */ 85133762Srwatsonchar fill_char; /* Character to fill with if defined */ 86250469Seadlervolatile sig_atomic_t need_summary; 871556Srgrimes 881556Srgrimesint 8990108Simpmain(int argc __unused, char *argv[]) 901556Srgrimes{ 9119720Sphk (void)setlocale(LC_CTYPE, ""); 921556Srgrimes jcl(argv); 931556Srgrimes setup(); 941556Srgrimes 95250469Seadler (void)signal(SIGINFO, siginfo_handler); 961556Srgrimes (void)signal(SIGINT, terminate); 971556Srgrimes 981556Srgrimes atexit(summary); 991556Srgrimes 1001556Srgrimes while (files_cnt--) 1011556Srgrimes dd_in(); 1021556Srgrimes 1031556Srgrimes dd_close(); 104249063Sbrooks /* 105249063Sbrooks * Some devices such as cfi(4) may perform significant amounts 106249063Sbrooks * of work when a write descriptor is closed. Close the out 107249063Sbrooks * descriptor explicitly so that the summary handler (called 108249063Sbrooks * from an atexit() hook) includes this work. 109249063Sbrooks */ 110249063Sbrooks close(out.fd); 1111556Srgrimes exit(0); 1121556Srgrimes} 1131556Srgrimes 114126667Sphkstatic int 115126667Sphkparity(u_char c) 116126667Sphk{ 117126667Sphk int i; 118126667Sphk 119126667Sphk i = c ^ (c >> 1) ^ (c >> 2) ^ (c >> 3) ^ 120126667Sphk (c >> 4) ^ (c >> 5) ^ (c >> 6) ^ (c >> 7); 121126667Sphk return (i & 1); 122126667Sphk} 123126667Sphk 1241556Srgrimesstatic void 12590108Simpsetup(void) 1261556Srgrimes{ 1271556Srgrimes u_int cnt; 12819720Sphk struct timeval tv; 1291556Srgrimes 1301556Srgrimes if (in.name == NULL) { 1311556Srgrimes in.name = "stdin"; 1321556Srgrimes in.fd = STDIN_FILENO; 1331556Srgrimes } else { 13448051Sgreen in.fd = open(in.name, O_RDONLY, 0); 13548026Sgreen if (in.fd == -1) 1361556Srgrimes err(1, "%s", in.name); 1371556Srgrimes } 1381556Srgrimes 1391556Srgrimes getfdtype(&in); 1401556Srgrimes 1411556Srgrimes if (files_cnt > 1 && !(in.flags & ISTAPE)) 1421556Srgrimes errx(1, "files is not supported for non-tape devices"); 1431556Srgrimes 1441556Srgrimes if (out.name == NULL) { 1451556Srgrimes /* No way to check for read access here. */ 1461556Srgrimes out.fd = STDOUT_FILENO; 1471556Srgrimes out.name = "stdout"; 1481556Srgrimes } else { 1491556Srgrimes#define OFLAGS \ 1501556Srgrimes (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) 1511556Srgrimes out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE); 1521556Srgrimes /* 1531556Srgrimes * May not have read access, so try again with write only. 1541556Srgrimes * Without read we may have a problem if output also does 1551556Srgrimes * not support seeks. 1561556Srgrimes */ 15748026Sgreen if (out.fd == -1) { 1581556Srgrimes out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE); 1591556Srgrimes out.flags |= NOREAD; 1601556Srgrimes } 16148026Sgreen if (out.fd == -1) 1621556Srgrimes err(1, "%s", out.name); 1631556Srgrimes } 1641556Srgrimes 1651556Srgrimes getfdtype(&out); 1661556Srgrimes 1671556Srgrimes /* 1681556Srgrimes * Allocate space for the input and output buffers. If not doing 1691556Srgrimes * record oriented I/O, only need a single buffer. 1701556Srgrimes */ 17151249Sgreen if (!(ddflags & (C_BLOCK | C_UNBLOCK))) { 1721556Srgrimes if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) 17351208Sgreen err(1, "input buffer"); 1741556Srgrimes out.db = in.db; 17551208Sgreen } else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL || 17651208Sgreen (out.db = malloc(out.dbsz + cbsz)) == NULL) 17751208Sgreen err(1, "output buffer"); 178266488Sthomas 179266488Sthomas /* dbp is the first free position in each buffer. */ 1801556Srgrimes in.dbp = in.db; 1811556Srgrimes out.dbp = out.db; 1821556Srgrimes 1831556Srgrimes /* Position the input/output streams. */ 1841556Srgrimes if (in.offset) 1851556Srgrimes pos_in(); 1861556Srgrimes if (out.offset) 1871556Srgrimes pos_out(); 1881556Srgrimes 1891556Srgrimes /* 19063688Sgreen * Truncate the output file. If it fails on a type of output file 19163688Sgreen * that it should _not_ fail on, error out. 1921556Srgrimes */ 19362311Sgreen if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) && 19462311Sgreen out.flags & ISTRUNC) 19562311Sgreen if (ftruncate(out.fd, out.offset * out.dbsz) == -1) 19662311Sgreen err(1, "truncating %s", out.name); 1971556Srgrimes 198126667Sphk if (ddflags & (C_LCASE | C_UCASE | C_ASCII | C_EBCDIC | C_PARITY)) { 199126667Sphk if (ctab != NULL) { 200126667Sphk for (cnt = 0; cnt <= 0377; ++cnt) 201126667Sphk casetab[cnt] = ctab[cnt]; 20246073Simp } else { 203126667Sphk for (cnt = 0; cnt <= 0377; ++cnt) 204126667Sphk casetab[cnt] = cnt; 2055701Sache } 206126667Sphk if ((ddflags & C_PARITY) && !(ddflags & C_ASCII)) { 207126667Sphk /* 208126667Sphk * If the input is not EBCDIC, and we do parity 209126667Sphk * processing, strip input parity. 210126667Sphk */ 211126667Sphk for (cnt = 200; cnt <= 0377; ++cnt) 212126667Sphk casetab[cnt] = casetab[cnt & 0x7f]; 213126667Sphk } 214126667Sphk if (ddflags & C_LCASE) { 215126667Sphk for (cnt = 0; cnt <= 0377; ++cnt) 216126667Sphk casetab[cnt] = tolower(casetab[cnt]); 217126667Sphk } else if (ddflags & C_UCASE) { 218126667Sphk for (cnt = 0; cnt <= 0377; ++cnt) 219126667Sphk casetab[cnt] = toupper(casetab[cnt]); 220126667Sphk } 221126667Sphk if ((ddflags & C_PARITY)) { 222126667Sphk /* 223126667Sphk * This should strictly speaking be a no-op, but I 224126667Sphk * wonder what funny LANG settings could get us. 225126667Sphk */ 226126667Sphk for (cnt = 0; cnt <= 0377; ++cnt) 227126667Sphk casetab[cnt] = casetab[cnt] & 0x7f; 228126667Sphk } 229126667Sphk if ((ddflags & C_PARSET)) { 230126667Sphk for (cnt = 0; cnt <= 0377; ++cnt) 231126667Sphk casetab[cnt] = casetab[cnt] | 0x80; 232126667Sphk } 233126667Sphk if ((ddflags & C_PAREVEN)) { 234126667Sphk for (cnt = 0; cnt <= 0377; ++cnt) 235126667Sphk if (parity(casetab[cnt])) 236126667Sphk casetab[cnt] = casetab[cnt] | 0x80; 237126667Sphk } 238126667Sphk if ((ddflags & C_PARODD)) { 239126667Sphk for (cnt = 0; cnt <= 0377; ++cnt) 240126667Sphk if (!parity(casetab[cnt])) 241126667Sphk casetab[cnt] = casetab[cnt] | 0x80; 242126667Sphk } 243126667Sphk 24451208Sgreen ctab = casetab; 24546073Simp } 24651208Sgreen 247239991Sed (void)gettimeofday(&tv, NULL); 248239991Sed st.start = tv.tv_sec + tv.tv_usec * 1e-6; 2491556Srgrimes} 2501556Srgrimes 2511556Srgrimesstatic void 25290108Simpgetfdtype(IO *io) 2531556Srgrimes{ 2541556Srgrimes struct stat sb; 25550460Sgreen int type; 2561556Srgrimes 25751208Sgreen if (fstat(io->fd, &sb) == -1) 2581556Srgrimes err(1, "%s", io->name); 25962311Sgreen if (S_ISREG(sb.st_mode)) 26062311Sgreen io->flags |= ISTRUNC; 26150460Sgreen if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) { 26250487Sgreen if (ioctl(io->fd, FIODTYPE, &type) == -1) { 26351913Sgreen err(1, "%s", io->name); 26450487Sgreen } else { 26550487Sgreen if (type & D_TAPE) 26650487Sgreen io->flags |= ISTAPE; 267109873Sphk else if (type & (D_DISK | D_MEM)) 26851212Sgreen io->flags |= ISSEEK; 26950487Sgreen if (S_ISCHR(sb.st_mode) && (type & D_TAPE) == 0) 27050487Sgreen io->flags |= ISCHR; 27150487Sgreen } 27251335Sgreen return; 27351335Sgreen } 27451335Sgreen errno = 0; 27551335Sgreen if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) 27651335Sgreen io->flags |= ISPIPE; 27751335Sgreen else 27851249Sgreen io->flags |= ISSEEK; 2791556Srgrimes} 2801556Srgrimes 2811556Srgrimesstatic void 28290108Simpdd_in(void) 2831556Srgrimes{ 28448026Sgreen ssize_t n; 2851556Srgrimes 28628430Sjlemon for (;;) { 28751335Sgreen switch (cpy_cnt) { 28851335Sgreen case -1: /* count=0 was specified */ 2891556Srgrimes return; 29051335Sgreen case 0: 29151335Sgreen break; 29251335Sgreen default: 293111629Smarkm if (st.in_full + st.in_part >= (uintmax_t)cpy_cnt) 29451335Sgreen return; 29551335Sgreen break; 29651335Sgreen } 2971556Srgrimes 2981556Srgrimes /* 29951208Sgreen * Zero the buffer first if sync; if doing block operations, 3001556Srgrimes * use spaces. 3011556Srgrimes */ 30248026Sgreen if (ddflags & C_SYNC) { 303133762Srwatson if (ddflags & C_FILL) 304133762Srwatson memset(in.dbp, fill_char, in.dbsz); 305133762Srwatson else if (ddflags & (C_BLOCK | C_UNBLOCK)) 3061556Srgrimes memset(in.dbp, ' ', in.dbsz); 3071556Srgrimes else 3081556Srgrimes memset(in.dbp, 0, in.dbsz); 30948026Sgreen } 3101556Srgrimes 3111556Srgrimes n = read(in.fd, in.dbp, in.dbsz); 3121556Srgrimes if (n == 0) { 3131556Srgrimes in.dbrcnt = 0; 3141556Srgrimes return; 3151556Srgrimes } 3161556Srgrimes 3171556Srgrimes /* Read error. */ 31848026Sgreen if (n == -1) { 3191556Srgrimes /* 3201556Srgrimes * If noerror not specified, die. POSIX requires that 3211556Srgrimes * the warning message be followed by an I/O display. 3221556Srgrimes */ 32328430Sjlemon if (!(ddflags & C_NOERROR)) 3241556Srgrimes err(1, "%s", in.name); 3251556Srgrimes warn("%s", in.name); 3261556Srgrimes summary(); 3271556Srgrimes 3281556Srgrimes /* 32951249Sgreen * If it's a seekable file descriptor, seek past the 3301556Srgrimes * error. If your OS doesn't do the right thing for 3311556Srgrimes * raw disks this section should be modified to re-read 3321556Srgrimes * in sector size chunks. 3331556Srgrimes */ 33451249Sgreen if (in.flags & ISSEEK && 3351556Srgrimes lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) 3361556Srgrimes warn("%s", in.name); 3371556Srgrimes 3381556Srgrimes /* If sync not specified, omit block and continue. */ 3391556Srgrimes if (!(ddflags & C_SYNC)) 3401556Srgrimes continue; 3411556Srgrimes 3421556Srgrimes /* Read errors count as full blocks. */ 3431556Srgrimes in.dbcnt += in.dbrcnt = in.dbsz; 3441556Srgrimes ++st.in_full; 3451556Srgrimes 3461556Srgrimes /* Handle full input blocks. */ 34762311Sgreen } else if ((size_t)n == in.dbsz) { 3481556Srgrimes in.dbcnt += in.dbrcnt = n; 3491556Srgrimes ++st.in_full; 3501556Srgrimes 3511556Srgrimes /* Handle partial input blocks. */ 3521556Srgrimes } else { 3531556Srgrimes /* If sync, use the entire block. */ 3541556Srgrimes if (ddflags & C_SYNC) 3551556Srgrimes in.dbcnt += in.dbrcnt = in.dbsz; 3561556Srgrimes else 3571556Srgrimes in.dbcnt += in.dbrcnt = n; 3581556Srgrimes ++st.in_part; 3591556Srgrimes } 3601556Srgrimes 3611556Srgrimes /* 3621556Srgrimes * POSIX states that if bs is set and no other conversions 3631556Srgrimes * than noerror, notrunc or sync are specified, the block 3641556Srgrimes * is output without buffering as it is read. 3651556Srgrimes */ 366249811Skib if ((ddflags & ~(C_NOERROR | C_NOTRUNC | C_SYNC)) == C_BS) { 3671556Srgrimes out.dbcnt = in.dbcnt; 3681556Srgrimes dd_out(1); 3691556Srgrimes in.dbcnt = 0; 3701556Srgrimes continue; 3711556Srgrimes } 3721556Srgrimes 3731556Srgrimes if (ddflags & C_SWAB) { 37432324Sjoerg if ((n = in.dbrcnt) & 1) { 3751556Srgrimes ++st.swab; 3761556Srgrimes --n; 3771556Srgrimes } 37862311Sgreen swab(in.dbp, in.dbp, (size_t)n); 3791556Srgrimes } 3801556Srgrimes 3811556Srgrimes in.dbp += in.dbrcnt; 3821556Srgrimes (*cfunc)(); 383250469Seadler if (need_summary) { 384250469Seadler summary(); 385250469Seadler } 3861556Srgrimes } 3871556Srgrimes} 3881556Srgrimes 3891556Srgrimes/* 39051249Sgreen * Clean up any remaining I/O and flush output. If necessary, the output file 3911556Srgrimes * is truncated. 3921556Srgrimes */ 3931556Srgrimesstatic void 39490108Simpdd_close(void) 3951556Srgrimes{ 3961556Srgrimes if (cfunc == def) 3971556Srgrimes def_close(); 3981556Srgrimes else if (cfunc == block) 3991556Srgrimes block_close(); 4001556Srgrimes else if (cfunc == unblock) 4011556Srgrimes unblock_close(); 40228430Sjlemon if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { 403133762Srwatson if (ddflags & C_FILL) 404133762Srwatson memset(out.dbp, fill_char, out.dbsz - out.dbcnt); 405133762Srwatson else if (ddflags & (C_BLOCK | C_UNBLOCK)) 40628430Sjlemon memset(out.dbp, ' ', out.dbsz - out.dbcnt); 40728430Sjlemon else 40828430Sjlemon memset(out.dbp, 0, out.dbsz - out.dbcnt); 4091556Srgrimes out.dbcnt = out.dbsz; 4101556Srgrimes } 41130312Sjoerg if (out.dbcnt || pending) 4121556Srgrimes dd_out(1); 4131556Srgrimes} 4141556Srgrimes 4151556Srgrimesvoid 41690108Simpdd_out(int force) 4171556Srgrimes{ 41851208Sgreen u_char *outp; 41951208Sgreen size_t cnt, i, n; 42051208Sgreen ssize_t nw; 4211556Srgrimes static int warned; 42251208Sgreen int sparse; 4231556Srgrimes 4241556Srgrimes /* 4251556Srgrimes * Write one or more blocks out. The common case is writing a full 4261556Srgrimes * output block in a single write; increment the full block stats. 4271556Srgrimes * Otherwise, we're into partial block writes. If a partial write, 4281556Srgrimes * and it's a character device, just warn. If a tape device, quit. 4291556Srgrimes * 4301556Srgrimes * The partial writes represent two cases. 1: Where the input block 4311556Srgrimes * was less than expected so the output block was less than expected. 4321556Srgrimes * 2: Where the input block was the right size but we were forced to 4331556Srgrimes * write the block in multiple chunks. The original versions of dd(1) 4341556Srgrimes * never wrote a block in more than a single write, so the latter case 4351556Srgrimes * never happened. 4361556Srgrimes * 4371556Srgrimes * One special case is if we're forced to do the write -- in that case 4381556Srgrimes * we play games with the buffer size, and it's usually a partial write. 4391556Srgrimes */ 4401556Srgrimes outp = out.db; 441266488Sthomas 442266488Sthomas /* 443266488Sthomas * If force, first try to write all pending data, else try to write 444266488Sthomas * just one block. Subsequently always write data one full block at 445266488Sthomas * a time at most. 446266488Sthomas */ 4471556Srgrimes for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { 448266488Sthomas cnt = n; 449266488Sthomas do { 45030312Sjoerg sparse = 0; 45130312Sjoerg if (ddflags & C_SPARSE) { 45230312Sjoerg sparse = 1; /* Is buffer sparse? */ 45330312Sjoerg for (i = 0; i < cnt; i++) 45430312Sjoerg if (outp[i] != 0) { 45530312Sjoerg sparse = 0; 45630312Sjoerg break; 45730312Sjoerg } 45830312Sjoerg } 45930312Sjoerg if (sparse && !force) { 46030312Sjoerg pending += cnt; 461266488Sthomas last_sp = cnt; 46230312Sjoerg nw = cnt; 46330312Sjoerg } else { 46430312Sjoerg if (pending != 0) { 465266488Sthomas /* If forced to write, and we have no 466266488Sthomas * data left, we need to write the last 467266488Sthomas * sparse block explicitly. 468266488Sthomas */ 469266488Sthomas if (force && cnt == 0) { 470266488Sthomas pending -= last_sp; 471266488Sthomas assert(outp == out.db); 472266488Sthomas memset(outp, 0, cnt); 473266488Sthomas } 47448051Sgreen if (lseek(out.fd, pending, SEEK_CUR) == 47548051Sgreen -1) 47648051Sgreen err(2, "%s: seek error creating sparse file", 47748051Sgreen out.name); 478266488Sthomas pending = last_sp = 0; 47930312Sjoerg } 48030312Sjoerg if (cnt) 48130312Sjoerg nw = write(out.fd, outp, cnt); 48230312Sjoerg else 48330312Sjoerg return; 48430312Sjoerg } 48530312Sjoerg 4861556Srgrimes if (nw <= 0) { 4871556Srgrimes if (nw == 0) 4881556Srgrimes errx(1, "%s: end of device", out.name); 4891556Srgrimes if (errno != EINTR) 4901556Srgrimes err(1, "%s", out.name); 4911556Srgrimes nw = 0; 4921556Srgrimes } 493266488Sthomas 4941556Srgrimes outp += nw; 4951556Srgrimes st.bytes += nw; 496266488Sthomas 497266488Sthomas if ((size_t)nw == n && n == out.dbsz) 498266488Sthomas ++st.out_full; 499266488Sthomas else 500266488Sthomas ++st.out_part; 501266488Sthomas 502266488Sthomas if ((size_t) nw != cnt) { 503266488Sthomas if (out.flags & ISTAPE) 504266488Sthomas errx(1, "%s: short write on tape device", 505266488Sthomas out.name); 506266488Sthomas if (out.flags & ISCHR && !warned) { 507266488Sthomas warned = 1; 508266488Sthomas warnx("%s: short write on character device", 509266488Sthomas out.name); 510266488Sthomas } 5111556Srgrimes } 512266488Sthomas 513266488Sthomas cnt -= nw; 514266488Sthomas } while (cnt != 0); 515266488Sthomas 5161556Srgrimes if ((out.dbcnt -= n) < out.dbsz) 5171556Srgrimes break; 5181556Srgrimes } 5191556Srgrimes 5201556Srgrimes /* Reassemble the output block. */ 5211556Srgrimes if (out.dbcnt) 52251208Sgreen (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); 5231556Srgrimes out.dbp = out.db + out.dbcnt; 5241556Srgrimes} 525