position.c revision 250469
117683Spst/*-
217683Spst * Copyright (c) 1991, 1993, 1994
317683Spst *	The Regents of the University of California.  All rights reserved.
417683Spst *
517683Spst * This code is derived from software contributed to Berkeley by
617683Spst * Keith Muller of the University of California, San Diego and Lance
717683Spst * Visser of Convex Computer Corporation.
817683Spst *
917683Spst * Redistribution and use in source and binary forms, with or without
1017683Spst * modification, are permitted provided that the following conditions
1117683Spst * are met:
1217683Spst * 1. Redistributions of source code must retain the above copyright
1317683Spst *    notice, this list of conditions and the following disclaimer.
1417683Spst * 2. Redistributions in binary form must reproduce the above copyright
1517683Spst *    notice, this list of conditions and the following disclaimer in the
1617683Spst *    documentation and/or other materials provided with the distribution.
1717683Spst * 4. Neither the name of the University nor the names of its contributors
1817683Spst *    may be used to endorse or promote products derived from this software
1917683Spst *    without specific prior written permission.
2026175Sfenner *
2126175Sfenner * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2226175Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2317683Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2426175Sfenner * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2575107Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2675107Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2775107Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2875107Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2917683Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3017683Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3117683Spst * SUCH DAMAGE.
3217683Spst */
3317683Spst
3417683Spst#ifndef lint
3517683Spst#if 0
3617683Spststatic char sccsid[] = "@(#)position.c	8.3 (Berkeley) 4/2/94";
3717683Spst#endif
3817683Spst#endif /* not lint */
3917683Spst#include <sys/cdefs.h>
4017683Spst__FBSDID("$FreeBSD: head/bin/dd/position.c 250469 2013-05-10 18:43:36Z eadler $");
4117683Spst
4217683Spst#include <sys/types.h>
4317683Spst#include <sys/mtio.h>
4417683Spst
4517683Spst#include <err.h>
4617683Spst#include <errno.h>
4717683Spst#include <inttypes.h>
4817683Spst#include <signal.h>
4917683Spst#include <unistd.h>
5017683Spst
5117683Spst#include "dd.h"
5217683Spst#include "extern.h"
5317683Spst
5417683Spst/*
5517683Spst * Position input/output data streams before starting the copy.  Device type
5617683Spst * dependent.  Seekable devices use lseek, and the rest position by reading.
5717683Spst * Seeking past the end of file can cause null blocks to be written to the
5817683Spst * output.
59127664Sbms */
60190225Srpaulovoid
61127664Sbmspos_in(void)
62127664Sbms{
63127664Sbms	off_t cnt;
64127664Sbms	int warned;
65127664Sbms	ssize_t nr;
6617683Spst	size_t bcnt;
6717683Spst
6817683Spst	/* If known to be seekable, try to seek on it. */
6917683Spst	if (in.flags & ISSEEK) {
7017683Spst		errno = 0;
7117683Spst		if (lseek(in.fd, in.offset * in.dbsz, SEEK_CUR) == -1 &&
72276768Sdelphij		    errno != 0)
73276768Sdelphij			err(1, "%s", in.name);
74276768Sdelphij		return;
75276768Sdelphij	}
76276768Sdelphij
77276768Sdelphij	/* Don't try to read a really weird amount (like negative). */
78276768Sdelphij	if (in.offset < 0)
79276768Sdelphij		errx(1, "%s: illegal offset", "iseek/skip");
80276768Sdelphij
81276768Sdelphij	/*
82276768Sdelphij	 * Read the data.  If a pipe, read until satisfy the number of bytes
83276768Sdelphij	 * being skipped.  No differentiation for reading complete and partial
84276768Sdelphij	 * blocks for other devices.
85276768Sdelphij	 */
86276768Sdelphij	for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
87276768Sdelphij		if ((nr = read(in.fd, in.db, bcnt)) > 0) {
88276768Sdelphij			if (in.flags & ISPIPE) {
89276768Sdelphij				if (!(bcnt -= nr)) {
90127664Sbms					bcnt = in.dbsz;
91127664Sbms					--cnt;
9217683Spst				}
9317683Spst			} else
9417683Spst				--cnt;
9517683Spst			if (need_summary)
9617683Spst				summary();
9717683Spst			continue;
9817683Spst		}
9917683Spst
100127664Sbms		if (nr == 0) {
101127664Sbms			if (files_cnt > 1) {
10217683Spst				--files_cnt;
103276768Sdelphij				continue;
10417683Spst			}
10517683Spst			errx(1, "skip reached end of input");
10617683Spst		}
10717683Spst
10817683Spst		/*
10917683Spst		 * Input error -- either EOF with no more files, or I/O error.
11017683Spst		 * If noerror not set die.  POSIX requires that the warning
11117683Spst		 * message be followed by an I/O display.
11217683Spst		 */
11317683Spst		if (ddflags & C_NOERROR) {
11417683Spst			if (!warned) {
11517683Spst				warn("%s", in.name);
11617683Spst				warned = 1;
11717683Spst				summary();
11817683Spst			}
11917683Spst			continue;
12017683Spst		}
12117683Spst		err(1, "%s", in.name);
12217683Spst	}
12317683Spst}
12417683Spst
12517683Spstvoid
12617683Spstpos_out(void)
12717683Spst{
12817683Spst	struct mtop t_op;
12917683Spst	off_t cnt;
13075107Sfenner	ssize_t n;
13117683Spst
13217683Spst	/*
13317683Spst	 * If not a tape, try seeking on the file.  Seeking on a pipe is
13417683Spst	 * going to fail, but don't protect the user -- they shouldn't
13517683Spst	 * have specified the seek operand.
13617683Spst	 */
13717683Spst	if (out.flags & (ISSEEK | ISPIPE)) {
13817683Spst		errno = 0;
13917683Spst		if (lseek(out.fd, out.offset * out.dbsz, SEEK_CUR) == -1 &&
14017683Spst		    errno != 0)
141147894Ssam			err(1, "%s", out.name);
14217683Spst		return;
143127664Sbms	}
144127664Sbms
145127664Sbms	/* Don't try to read a really weird amount (like negative). */
146127664Sbms	if (out.offset < 0)
147127664Sbms		errx(1, "%s: illegal offset", "oseek/seek");
148127664Sbms
149127664Sbms	/* If no read access, try using mtio. */
150127664Sbms	if (out.flags & NOREAD) {
151127664Sbms		t_op.mt_op = MTFSR;
152127664Sbms		t_op.mt_count = out.offset;
153127664Sbms
154127664Sbms		if (ioctl(out.fd, MTIOCTOP, &t_op) == -1)
155127664Sbms			err(1, "%s", out.name);
156127664Sbms		return;
157127664Sbms	}
158127664Sbms
159127664Sbms	/* Read it. */
160127664Sbms	for (cnt = 0; cnt < out.offset; ++cnt) {
161127664Sbms		if ((n = read(out.fd, out.db, out.dbsz)) > 0)
16217683Spst			continue;
16375107Sfenner
16475107Sfenner		if (n == -1)
16517683Spst			err(1, "%s", out.name);
16617683Spst
16717683Spst		/*
16817683Spst		 * If reach EOF, fill with NUL characters; first, back up over
16917683Spst		 * the EOF mark.  Note, cnt has not yet been incremented, so
17017683Spst		 * the EOF read does not count as a seek'd block.
17117683Spst		 */
17217683Spst		t_op.mt_op = MTBSR;
17317683Spst		t_op.mt_count = 1;
17417683Spst		if (ioctl(out.fd, MTIOCTOP, &t_op) == -1)
17575107Sfenner			err(1, "%s", out.name);
17675107Sfenner
17717683Spst		while (cnt++ < out.offset) {
17817683Spst			n = write(out.fd, out.db, out.dbsz);
17917683Spst			if (n == -1)
18017683Spst				err(1, "%s", out.name);
18117683Spst			if ((size_t)n != out.dbsz)
18217683Spst				errx(1, "%s: write failure", out.name);
18317683Spst		}
18417683Spst		break;
18517683Spst	}
18617683Spst}
18717683Spst