position.c revision 250469
1238106Sdes/*-
2238106Sdes * Copyright (c) 1991, 1993, 1994
3238106Sdes *	The Regents of the University of California.  All rights reserved.
4238106Sdes *
5238106Sdes * This code is derived from software contributed to Berkeley by
6238106Sdes * Keith Muller of the University of California, San Diego and Lance
7238106Sdes * Visser of Convex Computer Corporation.
8238106Sdes *
9238106Sdes * Redistribution and use in source and binary forms, with or without
10238106Sdes * modification, are permitted provided that the following conditions
11238106Sdes * are met:
12238106Sdes * 1. Redistributions of source code must retain the above copyright
13238106Sdes *    notice, this list of conditions and the following disclaimer.
14238106Sdes * 2. Redistributions in binary form must reproduce the above copyright
15238106Sdes *    notice, this list of conditions and the following disclaimer in the
16238106Sdes *    documentation and/or other materials provided with the distribution.
17238106Sdes * 4. Neither the name of the University nor the names of its contributors
18238106Sdes *    may be used to endorse or promote products derived from this software
19238106Sdes *    without specific prior written permission.
20238106Sdes *
21238106Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22238106Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23238106Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24269257Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25269257Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26269257Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27269257Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28269257Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29269257Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30269257Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31269257Sdes * SUCH DAMAGE.
32269257Sdes */
33269257Sdes
34238106Sdes#ifndef lint
35238106Sdes#if 0
36238106Sdesstatic char sccsid[] = "@(#)position.c	8.3 (Berkeley) 4/2/94";
37238106Sdes#endif
38238106Sdes#endif /* not lint */
39238106Sdes#include <sys/cdefs.h>
40238106Sdes__FBSDID("$FreeBSD: head/bin/dd/position.c 250469 2013-05-10 18:43:36Z eadler $");
41238106Sdes
42238106Sdes#include <sys/types.h>
43238106Sdes#include <sys/mtio.h>
44238106Sdes
45238106Sdes#include <err.h>
46238106Sdes#include <errno.h>
47238106Sdes#include <inttypes.h>
48238106Sdes#include <signal.h>
49238106Sdes#include <unistd.h>
50238106Sdes
51238106Sdes#include "dd.h"
52238106Sdes#include "extern.h"
53238106Sdes
54238106Sdes/*
55238106Sdes * Position input/output data streams before starting the copy.  Device type
56238106Sdes * dependent.  Seekable devices use lseek, and the rest position by reading.
57238106Sdes * Seeking past the end of file can cause null blocks to be written to the
58238106Sdes * output.
59238106Sdes */
60238106Sdesvoid
61238106Sdespos_in(void)
62238106Sdes{
63238106Sdes	off_t cnt;
64238106Sdes	int warned;
65238106Sdes	ssize_t nr;
66238106Sdes	size_t bcnt;
67238106Sdes
68238106Sdes	/* If known to be seekable, try to seek on it. */
69238106Sdes	if (in.flags & ISSEEK) {
70238106Sdes		errno = 0;
71238106Sdes		if (lseek(in.fd, in.offset * in.dbsz, SEEK_CUR) == -1 &&
72238106Sdes		    errno != 0)
73238106Sdes			err(1, "%s", in.name);
74238106Sdes		return;
75238106Sdes	}
76238106Sdes
77238106Sdes	/* Don't try to read a really weird amount (like negative). */
78238106Sdes	if (in.offset < 0)
79238106Sdes		errx(1, "%s: illegal offset", "iseek/skip");
80238106Sdes
81238106Sdes	/*
82238106Sdes	 * Read the data.  If a pipe, read until satisfy the number of bytes
83238106Sdes	 * being skipped.  No differentiation for reading complete and partial
84238106Sdes	 * blocks for other devices.
85238106Sdes	 */
86238106Sdes	for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
87238106Sdes		if ((nr = read(in.fd, in.db, bcnt)) > 0) {
88238106Sdes			if (in.flags & ISPIPE) {
89238106Sdes				if (!(bcnt -= nr)) {
90238106Sdes					bcnt = in.dbsz;
91238106Sdes					--cnt;
92238106Sdes				}
93238106Sdes			} else
94238106Sdes				--cnt;
95238106Sdes			if (need_summary)
96238106Sdes				summary();
97238106Sdes			continue;
98238106Sdes		}
99238106Sdes
100238106Sdes		if (nr == 0) {
101238106Sdes			if (files_cnt > 1) {
102238106Sdes				--files_cnt;
103238106Sdes				continue;
104238106Sdes			}
105238106Sdes			errx(1, "skip reached end of input");
106238106Sdes		}
107238106Sdes
108238106Sdes		/*
109238106Sdes		 * Input error -- either EOF with no more files, or I/O error.
110238106Sdes		 * If noerror not set die.  POSIX requires that the warning
111238106Sdes		 * message be followed by an I/O display.
112238106Sdes		 */
113238106Sdes		if (ddflags & C_NOERROR) {
114238106Sdes			if (!warned) {
115238106Sdes				warn("%s", in.name);
116238106Sdes				warned = 1;
117238106Sdes				summary();
118238106Sdes			}
119238106Sdes			continue;
120238106Sdes		}
121238106Sdes		err(1, "%s", in.name);
122238106Sdes	}
123238106Sdes}
124238106Sdes
125238106Sdesvoid
126238106Sdespos_out(void)
127238106Sdes{
128238106Sdes	struct mtop t_op;
129238106Sdes	off_t cnt;
130238106Sdes	ssize_t n;
131238106Sdes
132238106Sdes	/*
133238106Sdes	 * If not a tape, try seeking on the file.  Seeking on a pipe is
134238106Sdes	 * going to fail, but don't protect the user -- they shouldn't
135238106Sdes	 * have specified the seek operand.
136238106Sdes	 */
137238106Sdes	if (out.flags & (ISSEEK | ISPIPE)) {
138238106Sdes		errno = 0;
139238106Sdes		if (lseek(out.fd, out.offset * out.dbsz, SEEK_CUR) == -1 &&
140238106Sdes		    errno != 0)
141238106Sdes			err(1, "%s", out.name);
142238106Sdes		return;
143238106Sdes	}
144238106Sdes
145238106Sdes	/* Don't try to read a really weird amount (like negative). */
146238106Sdes	if (out.offset < 0)
147238106Sdes		errx(1, "%s: illegal offset", "oseek/seek");
148238106Sdes
149238106Sdes	/* If no read access, try using mtio. */
150238106Sdes	if (out.flags & NOREAD) {
151238106Sdes		t_op.mt_op = MTFSR;
152238106Sdes		t_op.mt_count = out.offset;
153238106Sdes
154238106Sdes		if (ioctl(out.fd, MTIOCTOP, &t_op) == -1)
155238106Sdes			err(1, "%s", out.name);
156238106Sdes		return;
157238106Sdes	}
158238106Sdes
159238106Sdes	/* Read it. */
160238106Sdes	for (cnt = 0; cnt < out.offset; ++cnt) {
161238106Sdes		if ((n = read(out.fd, out.db, out.dbsz)) > 0)
162238106Sdes			continue;
163238106Sdes
164238106Sdes		if (n == -1)
165238106Sdes			err(1, "%s", out.name);
166238106Sdes
167238106Sdes		/*
168238106Sdes		 * If reach EOF, fill with NUL characters; first, back up over
169238106Sdes		 * the EOF mark.  Note, cnt has not yet been incremented, so
170238106Sdes		 * the EOF read does not count as a seek'd block.
171238106Sdes		 */
172238106Sdes		t_op.mt_op = MTBSR;
173238106Sdes		t_op.mt_count = 1;
174238106Sdes		if (ioctl(out.fd, MTIOCTOP, &t_op) == -1)
175238106Sdes			err(1, "%s", out.name);
176238106Sdes
177238106Sdes		while (cnt++ < out.offset) {
178238106Sdes			n = write(out.fd, out.db, out.dbsz);
179238106Sdes			if (n == -1)
180238106Sdes				err(1, "%s", out.name);
181238106Sdes			if ((size_t)n != out.dbsz)
182238106Sdes				errx(1, "%s: write failure", out.name);
183238106Sdes		}
184238106Sdes		break;
185238106Sdes	}
186238106Sdes}
187238106Sdes