150568Sbostic /*- 250568Sbostic * Copyright (c) 1991 The Regents of the University of California. 350568Sbostic * 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*50778Sbostic static char sccsid[] = "@(#)position.c 5.3 (Berkeley) 08/05/91"; 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> 2050568Sbostic #include <errno.h> 2150568Sbostic #include <unistd.h> 2250568Sbostic #include <string.h> 2350568Sbostic #include "dd.h" 2450568Sbostic #include "extern.h" 2550568Sbostic 2650568Sbostic /* 2750568Sbostic * Position input/output data streams before starting the copy. Device type 2850568Sbostic * dependent. Seekable devices use lseek, and the rest position by reading. 2950568Sbostic * Seeking past the end of file can cause null blocks to be written to the 3050568Sbostic * output. 3150568Sbostic */ 3250568Sbostic void 3350568Sbostic pos_in() 3450568Sbostic { 3550568Sbostic register int bcnt, cnt, nr, warned; 3650568Sbostic 3750568Sbostic /* If not a character, pipe or tape device, try to seek on it. */ 3850568Sbostic if (!(in.flags & (ISCHR|ISPIPE|ISTAPE))) { 3950568Sbostic if (lseek(in.fd, (off_t)(in.offset * in.dbsz), SEEK_CUR) == -1) 4050568Sbostic err("%s: %s", in.name, strerror(errno)); 4150568Sbostic return; 4250568Sbostic } 4350568Sbostic 4450568Sbostic /* 4550568Sbostic * Read the data. If a pipe, read until satisfy the number of bytes 4650568Sbostic * being skipped. No differentiation for reading complete and partial 4750568Sbostic * blocks for other devices. 4850568Sbostic */ 4950568Sbostic for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { 50*50778Sbostic if ((nr = read(in.fd, in.db, bcnt)) > 0) { 5150568Sbostic if (in.flags & ISPIPE) { 5250568Sbostic if (!(bcnt -= nr)) { 5350568Sbostic bcnt = in.dbsz; 5450568Sbostic --cnt; 5550568Sbostic } 5650568Sbostic } else 5750568Sbostic --cnt; 58*50778Sbostic continue; 59*50778Sbostic } 6050568Sbostic 6150568Sbostic if (nr == 0) { 6250568Sbostic if (files_cnt > 1) { 6350568Sbostic --files_cnt; 6450568Sbostic continue; 6550568Sbostic } 6650568Sbostic err("skip reached end of input"); 6750568Sbostic } 6850568Sbostic 6950568Sbostic /* 7050568Sbostic * Input error -- either EOF with no more files, or I/O error. 7150568Sbostic * If noerror not set die. POSIX requires that the warning 7250568Sbostic * message be followed by an I/O display. 7350568Sbostic */ 7450568Sbostic if (ddflags & C_NOERROR) { 7550568Sbostic if (!warned) { 7650568Sbostic warn("%s: %s", in.name, strerror(errno)); 7750568Sbostic warned = 1; 7850568Sbostic summary(0); 7950568Sbostic } 8050568Sbostic continue; 8150568Sbostic } 8250568Sbostic err("%s: %s", in.name, strerror(errno)); 8350568Sbostic } 8450568Sbostic } 8550568Sbostic 8650568Sbostic void 8750568Sbostic pos_out() 8850568Sbostic { 8950568Sbostic register int cnt, n; 9050568Sbostic struct mtop t_op; 9150568Sbostic 9250568Sbostic /* 9350568Sbostic * If not a tape, try seeking on the file. Seeking on a pipe is 9450568Sbostic * going to fail, but don't protect the user -- they shouldn't 9550568Sbostic * have specified the seek operand. 9650568Sbostic */ 9750568Sbostic if (!(out.flags & ISTAPE)) { 9850568Sbostic if (lseek(out.fd, 9950568Sbostic (off_t)out.offset * out.dbsz, SEEK_SET) == -1) 10050568Sbostic err("%s: %s", out.name, strerror(errno)); 10150568Sbostic return; 10250568Sbostic } 10350568Sbostic 10450568Sbostic /* If no read access, try using mtio. */ 10550568Sbostic if (out.flags & NOREAD) { 10650568Sbostic t_op.mt_op = MTFSR; 10750568Sbostic t_op.mt_count = out.offset; 10850568Sbostic 10950568Sbostic if (ioctl(out.fd, MTIOCTOP, &t_op) < 0) 11050568Sbostic err("%s: %s", out.name, strerror(errno)); 11150568Sbostic return; 11250568Sbostic } 11350568Sbostic 11450568Sbostic /* Read it. */ 11550568Sbostic for (cnt = 0; cnt < out.offset; ++cnt) { 11650568Sbostic if ((n = read(out.fd, out.db, out.dbsz)) > 0) 11750568Sbostic continue; 11850568Sbostic 11950568Sbostic if (n < 0) 12050568Sbostic err("%s: %s", out.name, strerror(errno)); 12150568Sbostic 12250568Sbostic /* 12350568Sbostic * If reach EOF, fill with NUL characters; first, back up over 12450568Sbostic * the EOF mark. Note, cnt has not yet been incremented, so 12550568Sbostic * the EOF read does not count as a seek'd block. 12650568Sbostic */ 12750568Sbostic t_op.mt_op = MTBSR; 12850568Sbostic t_op.mt_count = 1; 12950568Sbostic if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) 13050568Sbostic err("%s: %s", out.name, strerror(errno)); 13150568Sbostic 13250568Sbostic while (cnt++ < out.offset) 13350568Sbostic if ((n = write(out.fd, out.db, out.dbsz)) != out.dbsz) 13450568Sbostic err("%s: %s", out.name, strerror(errno)); 13550568Sbostic break; 13650568Sbostic } 13750568Sbostic } 138