Jan-Simon broke out pw_util includes into pw_util.h
[unix-history] / usr / src / bin / dd / position.c
CommitLineData
5e002034 1/*-
ba5e8546
KB
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5e002034
KB
4 *
5 * This code is derived from software contributed to Berkeley by
a08a4cd0
KB
6 * Keith Muller of the University of California, San Diego and Lance
7 * Visser of Convex Computer Corporation.
5e002034
KB
8 *
9 * %sccs.include.redist.c%
10 */
11
12#ifndef lint
ba5e8546 13static char sccsid[] = "@(#)position.c 8.1 (Berkeley) %G%";
5e002034
KB
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <sys/ioctl.h>
19#include <sys/mtio.h>
20#include <errno.h>
21#include <unistd.h>
22#include <string.h>
23#include "dd.h"
24#include "extern.h"
25
26/*
27 * Position input/output data streams before starting the copy. Device type
28 * dependent. Seekable devices use lseek, and the rest position by reading.
29 * Seeking past the end of file can cause null blocks to be written to the
30 * output.
31 */
32void
33pos_in()
34{
35 register int bcnt, cnt, nr, warned;
36
37 /* If not a character, pipe or tape device, try to seek on it. */
38 if (!(in.flags & (ISCHR|ISPIPE|ISTAPE))) {
39 if (lseek(in.fd, (off_t)(in.offset * in.dbsz), SEEK_CUR) == -1)
40 err("%s: %s", in.name, strerror(errno));
41 return;
42 }
43
44 /*
45 * Read the data. If a pipe, read until satisfy the number of bytes
46 * being skipped. No differentiation for reading complete and partial
47 * blocks for other devices.
48 */
49 for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
5928f285 50 if ((nr = read(in.fd, in.db, bcnt)) > 0) {
5e002034
KB
51 if (in.flags & ISPIPE) {
52 if (!(bcnt -= nr)) {
53 bcnt = in.dbsz;
54 --cnt;
55 }
5e002034
KB
56 } else
57 --cnt;
5928f285
KB
58 continue;
59 }
5e002034
KB
60
61 if (nr == 0) {
62 if (files_cnt > 1) {
63 --files_cnt;
64 continue;
65 }
66 err("skip reached end of input");
67 }
68
69 /*
70 * Input error -- either EOF with no more files, or I/O error.
71 * If noerror not set die. POSIX requires that the warning
72 * message be followed by an I/O display.
73 */
74 if (ddflags & C_NOERROR) {
75 if (!warned) {
76 warn("%s: %s", in.name, strerror(errno));
77 warned = 1;
78 summary(0);
79 }
80 continue;
81 }
82 err("%s: %s", in.name, strerror(errno));
83 }
84}
85
86void
87pos_out()
88{
89 register int cnt, n;
90 struct mtop t_op;
91
92 /*
93 * If not a tape, try seeking on the file. Seeking on a pipe is
94 * going to fail, but don't protect the user -- they shouldn't
95 * have specified the seek operand.
96 */
97 if (!(out.flags & ISTAPE)) {
98 if (lseek(out.fd,
99 (off_t)out.offset * out.dbsz, SEEK_SET) == -1)
100 err("%s: %s", out.name, strerror(errno));
101 return;
102 }
103
104 /* If no read access, try using mtio. */
105 if (out.flags & NOREAD) {
106 t_op.mt_op = MTFSR;
107 t_op.mt_count = out.offset;
108
109 if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)
110 err("%s: %s", out.name, strerror(errno));
111 return;
112 }
113
114 /* Read it. */
115 for (cnt = 0; cnt < out.offset; ++cnt) {
116 if ((n = read(out.fd, out.db, out.dbsz)) > 0)
117 continue;
118
119 if (n < 0)
120 err("%s: %s", out.name, strerror(errno));
121
122 /*
123 * If reach EOF, fill with NUL characters; first, back up over
124 * the EOF mark. Note, cnt has not yet been incremented, so
125 * the EOF read does not count as a seek'd block.
126 */
127 t_op.mt_op = MTBSR;
128 t_op.mt_count = 1;
129 if (ioctl(out.fd, MTIOCTOP, &t_op) == -1)
130 err("%s: %s", out.name, strerror(errno));
131
132 while (cnt++ < out.offset)
133 if ((n = write(out.fd, out.db, out.dbsz)) != out.dbsz)
134 err("%s: %s", out.name, strerror(errno));
135 break;
136 }
137}