summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2001-12-11 11:40:50 +0000
committerJim Meyering <jim@meyering.net>2001-12-11 11:40:50 +0000
commit24d1484e1c6a598e17a6069f3a0c5d882abd9535 (patch)
tree0b179a2bbb0d8682c7cb3261935103effa8c126f /src
parentefc6e85c74c7085eeb482d225d4074191a2b37d0 (diff)
downloadcoreutils-24d1484e1c6a598e17a6069f3a0c5d882abd9535.tar.xz
(buggy_lseek_support): Remove function.
(skip_via_lseek) [__linux__]: New function. (skip): Use skip_via_lseek, not buggy_lseek_support.
Diffstat (limited to 'src')
-rw-r--r--src/dd.c68
1 files changed, 47 insertions, 21 deletions
diff --git a/src/dd.c b/src/dd.c
index f138f0f75..ca01b8237 100644
--- a/src/dd.c
+++ b/src/dd.c
@@ -734,28 +734,57 @@ swab_buffer (char *buf, size_t *nread)
return ++bufstart;
}
-/* Return nonzero iff the file referenced by FDESC is of a type for
- which lseek's return value is known to be invalid on some systems.
- Otherwise, return zero.
- For example, return nonzero if FDESC references a Linux tape device
- because that lseek returns an offset implying it succeeds, even though
- the function fails to perform the requested operation. In that case,
- lseek should return a negative number and set errno. The offending
- behavior has been confirmed with an Exabyte SCSI tape drive accessed
- via /dev/nst0 on both Linux-2.2.17 and Linux-2.4.16. */
+/* This is a wrapper for lseek. It detects and warns about a kernel
+ bug that makes lseek a no-op for tape devices, even though the kernel
+ lseek return value suggests that the function succeeded.
+
+ The parameters are the same as those of the lseek function, but
+ with the addition of FILENAME, the name of the file associated with
+ descriptor FDESC. The file name is used solely in the warning that's
+ printed when the bug is detected. Return the same value that lseek
+ would have returned, but when the lseek bug is detected, return -1
+ to indicate that lseek failed.
+
+ The offending behavior has been confirmed with an Exabyte SCSI tape
+ drive accessed via /dev/nst0 on both Linux-2.2.17 and Linux-2.4.16. */
#ifdef __linux__
-static int
-buggy_lseek_support (int fdesc)
+
+# include <sys/mtio.h>
+
+# define MT_SAME_POSITION(P, Q) \
+ ((P).mt_resid == (Q).mt_resid \
+ && (P).mt_fileno == (Q).mt_fileno \
+ && (P).mt_blkno == (Q).mt_blkno)
+
+static off_t
+skip_via_lseek (char const *filename, int fdesc, off_t offset, int whence)
{
- struct stat stats;
+ struct mtget s1;
+ struct mtget s2;
+ off_t new_position;
+ int got_original_tape_position;
+
+ got_original_tape_position = (ioctl (fdesc, MTIOCGET, &s1) == 0);
+ /* known bad device type */
+ /* && s.mt_type == MT_ISSCSI2 */
+
+ new_position = lseek (fdesc, offset, whence);
+ if (0 <= new_position
+ && got_original_tape_position
+ && ioctl (fdesc, MTIOCGET, &s2) == 0
+ && MT_SAME_POSITION (s1, s2))
+ {
+ error (0, 0, _("warning: working around lseek kernel bug for file (%s)\n\
+ of mt_type=0x%0lx -- see <sys/mtio.h> for the list of types"),
+ filename, s2.mt_type);
+ new_position = -1;
+ }
- return (fstat (fdesc, &stats) == 0
- && (S_ISCHR (stats.st_mode))
- && major (stats.st_rdev) == 9);
+ return new_position;
}
#else
-# define buggy_lseek_support(Fd) 0
+# define skip_via_lseek(Filename, Fd, Offset, Whence) lseek (Fd, Offset, Whence)
#endif
/* Throw away RECORDS blocks of BLOCKSIZE bytes on file descriptor FDESC,
@@ -769,13 +798,10 @@ skip (int fdesc, char *file, uintmax_t records, size_t blocksize, char *buf)
off_t offset = records * blocksize;
/* Try lseek and if an error indicates it was an inappropriate
- operation, fall back on using read. Some broken versions of
- lseek may return zero, so count that as an error too as a valid
- zero return is not possible here. */
+ operation, fall back on using read. */
if (offset / blocksize != records
- || buggy_lseek_support (fdesc)
- || lseek (fdesc, offset, SEEK_CUR) <= 0)
+ || skip_via_lseek (file, fdesc, offset, SEEK_CUR) < 0)
{
while (records--)
{