150568Sbostic /*- 260660Sbostic * Copyright (c) 1991, 1993 360660Sbostic * The Regents of the University of California. All rights reserved. 450568Sbostic * 550568Sbostic * This code is derived from software contributed to Berkeley by 650588Sbostic * Keith Muller of the University of California, San Diego and Lance 750588Sbostic * Visser of Convex Computer Corporation. 850568Sbostic * 950568Sbostic * %sccs.include.redist.c% 1050568Sbostic */ 1150568Sbostic 1250568Sbostic #ifndef lint 13*66617Spendry static char sccsid[] = "@(#)position.c 8.2 (Berkeley) 04/02/94"; 1450568Sbostic #endif /* not lint */ 1550568Sbostic 1650568Sbostic #include <sys/types.h> 1750568Sbostic #include <sys/stat.h> 1850568Sbostic #include <sys/ioctl.h> 1950568Sbostic #include <sys/mtio.h> 20*66617Spendry 21*66617Spendry #include <err.h> 2250568Sbostic #include <errno.h> 23*66617Spendry #include <string.h> 2450568Sbostic #include <unistd.h> 25*66617Spendry 2650568Sbostic #include "dd.h" 2750568Sbostic #include "extern.h" 2850568Sbostic 2950568Sbostic /* 3050568Sbostic * Position input/output data streams before starting the copy. Device type 3150568Sbostic * dependent. Seekable devices use lseek, and the rest position by reading. 3250568Sbostic * Seeking past the end of file can cause null blocks to be written to the 3350568Sbostic * output. 3450568Sbostic */ 3550568Sbostic void 3650568Sbostic pos_in() 3750568Sbostic { 38*66617Spendry int bcnt, cnt, nr, warned; 3950568Sbostic 4050568Sbostic /* If not a character, pipe or tape device, try to seek on it. */ 4150568Sbostic if (!(in.flags & (ISCHR|ISPIPE|ISTAPE))) { 4250568Sbostic if (lseek(in.fd, (off_t)(in.offset * in.dbsz), SEEK_CUR) == -1) 43*66617Spendry err(1, "%s", in.name); 4450568Sbostic return; 4550568Sbostic } 4650568Sbostic 4750568Sbostic /* 4850568Sbostic * Read the data. If a pipe, read until satisfy the number of bytes 4950568Sbostic * being skipped. No differentiation for reading complete and partial 5050568Sbostic * blocks for other devices. 5150568Sbostic */ 5250568Sbostic for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { 5350778Sbostic if ((nr = read(in.fd, in.db, bcnt)) > 0) { 5450568Sbostic if (in.flags & ISPIPE) { 5550568Sbostic if (!(bcnt -= nr)) { 5650568Sbostic bcnt = in.dbsz; 5750568Sbostic --cnt; 5850568Sbostic } 5950568Sbostic } else 6050568Sbostic --cnt; 6150778Sbostic continue; 6250778Sbostic } 6350568Sbostic 6450568Sbostic if (nr == 0) { 6550568Sbostic if (files_cnt > 1) { 6650568Sbostic --files_cnt; 6750568Sbostic continue; 6850568Sbostic } 69*66617Spendry errx(1, "skip reached end of input"); 7050568Sbostic } 7150568Sbostic 7250568Sbostic /* 7350568Sbostic * Input error -- either EOF with no more files, or I/O error. 7450568Sbostic * If noerror not set die. POSIX requires that the warning 7550568Sbostic * message be followed by an I/O display. 7650568Sbostic */ 7750568Sbostic if (ddflags & C_NOERROR) { 7850568Sbostic if (!warned) { 79*66617Spendry warn("%s", in.name); 8050568Sbostic warned = 1; 81*66617Spendry summary(); 8250568Sbostic } 8350568Sbostic continue; 8450568Sbostic } 85*66617Spendry err(1, "%s", in.name); 8650568Sbostic } 8750568Sbostic } 8850568Sbostic 8950568Sbostic void 9050568Sbostic pos_out() 9150568Sbostic { 9250568Sbostic struct mtop t_op; 93*66617Spendry int cnt, n; 9450568Sbostic 9550568Sbostic /* 9650568Sbostic * If not a tape, try seeking on the file. Seeking on a pipe is 9750568Sbostic * going to fail, but don't protect the user -- they shouldn't 9850568Sbostic * have specified the seek operand. 9950568Sbostic */ 10050568Sbostic if (!(out.flags & ISTAPE)) { 10150568Sbostic if (lseek(out.fd, 10250568Sbostic (off_t)out.offset * out.dbsz, SEEK_SET) == -1) 103*66617Spendry err(1, "%s", out.name); 10450568Sbostic return; 10550568Sbostic } 10650568Sbostic 10750568Sbostic /* If no read access, try using mtio. */ 10850568Sbostic if (out.flags & NOREAD) { 10950568Sbostic t_op.mt_op = MTFSR; 11050568Sbostic t_op.mt_count = out.offset; 11150568Sbostic 11250568Sbostic if (ioctl(out.fd, MTIOCTOP, &t_op) < 0) 113*66617Spendry err(1, "%s", out.name); 11450568Sbostic return; 11550568Sbostic } 11650568Sbostic 11750568Sbostic /* Read it. */ 11850568Sbostic for (cnt = 0; cnt < out.offset; ++cnt) { 11950568Sbostic if ((n = read(out.fd, out.db, out.dbsz)) > 0) 12050568Sbostic continue; 12150568Sbostic 12250568Sbostic if (n < 0) 123*66617Spendry err(1, "%s", out.name); 12450568Sbostic 12550568Sbostic /* 12650568Sbostic * If reach EOF, fill with NUL characters; first, back up over 12750568Sbostic * the EOF mark. Note, cnt has not yet been incremented, so 12850568Sbostic * the EOF read does not count as a seek'd block. 12950568Sbostic */ 13050568Sbostic t_op.mt_op = MTBSR; 13150568Sbostic t_op.mt_count = 1; 13250568Sbostic if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) 133*66617Spendry err(1, "%s", out.name); 13450568Sbostic 13550568Sbostic while (cnt++ < out.offset) 13650568Sbostic if ((n = write(out.fd, out.db, out.dbsz)) != out.dbsz) 137*66617Spendry err(1, "%s", out.name); 13850568Sbostic break; 13950568Sbostic } 14050568Sbostic } 141