summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <qris@users.noreply.github.com>2018-03-13 21:12:54 +0000
committerGitHub <noreply@github.com>2018-03-13 21:12:54 +0000
commit16a11e868c6280a64ec3f26f7537161dfa748d61 (patch)
tree28b9f1ac7afb1f062035ca4c6021325e4e0050c3
parentf2223e6a6db1d8b282ab23a80fb34d7a89bb3a20 (diff)
parent82445a8e54abbcb37e41db532130dcb82088ac5d (diff)
Merge pull request #26 from boxbackup/fix_raidfile_i386
Fix raidfile tests on 32-bit Linux. A recent fix for Solaris (commit 81e9aa6545f7f19124c9f5e88982b867d8732965) broke support for 32-bit Linux (which wasn't spotted at the time, because we didn't have any 32-bit builders). Try a different approach: detect explicitly whether the `lseek` syscall takes a 64-bit integer offset, regardless of the size of `off_t` in user space. CMake: Add support for M4 CXX flag detection in CMakeLists. Reimplement autoconf tests for 64-bit lseek. Fix error in t-gdb when no debugger is detected. Thanks to Reinhard Tartler (our Debian package maintainer) for pointing out the error, and James O'Gorman for setting up i386 builders to ensure that it's fixed and cannot recur.
-rw-r--r--configure.ac1
-rw-r--r--infrastructure/cmake/CMakeLists.txt114
-rw-r--r--infrastructure/m4/ax_check_syscall_lseek.m4111
-rw-r--r--infrastructure/m4/boxbackup_tests.m438
-rwxr-xr-xinfrastructure/makebuildenv.pl.in2
-rw-r--r--lib/intercept/intercept.cpp18
-rw-r--r--test/raidfile/testraidfile.cpp9
7 files changed, 231 insertions, 62 deletions
diff --git a/configure.ac b/configure.ac
index f9f481d5..58a04406 100644
--- a/configure.ac
+++ b/configure.ac
@@ -139,6 +139,7 @@ Large files: $box_cv_have_large_file_support
Berkeley DB: $ax_path_bdb_ok
Readline: $have_libreadline
Extended attributes: $ac_cv_header_sys_xattr_h
+Debugger: ${with_debugger:-neither GDB nor LLDB detected!}
EOC
cat > config.env <<EOC
diff --git a/infrastructure/cmake/CMakeLists.txt b/infrastructure/cmake/CMakeLists.txt
index 65f59eb8..e6f46148 100644
--- a/infrastructure/cmake/CMakeLists.txt
+++ b/infrastructure/cmake/CMakeLists.txt
@@ -363,6 +363,7 @@ target_compile_definitions(lib_common PUBLIC $<$<CONFIG:Release>:BOX_RELEASE_BUI
include(CheckCXXCompilerFlag)
include(CheckCXXSourceCompiles)
+include(CheckCXXSourceRuns)
include(CheckFunctionExists)
include(CheckIncludeFiles)
include(CheckLibraryExists)
@@ -477,7 +478,7 @@ move_file_if_exists(
"${boxconfig_cmake_h_dir}/BoxConfig.cmake.h.bak")
foreach(m4_filename boxbackup_tests.m4 ax_check_mount_point.m4 ax_func_syscall.m4)
- file(STRINGS "${base_dir}/infrastructure/m4/${m4_filename}" m4_functions REGEX "^ *AC[_A-Z]+\\(.*\\)$")
+ file(STRINGS "${base_dir}/infrastructure/m4/${m4_filename}" m4_functions REGEX "^ *(AC|AX|BOX)_[A-Z_]+\\(.*\\)$")
foreach(m4_function ${m4_functions})
if(DEBUG)
message(STATUS "Processing m4_function: ${m4_function}")
@@ -559,6 +560,22 @@ foreach(m4_filename boxbackup_tests.m4 ax_check_mount_point.m4 ax_func_syscall.m
}
]=] "HAVE_${platform_var_name}")
file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_${platform_var_name}\n")
+ elseif(m4_function MATCHES "^ *BOX_CHECK_CXX_FLAG\\((-[A-Za-z_,=-]+)\\)")
+ if(DEBUG)
+ message(STATUS "Processing BOX_CHECK_CXX_FLAG: ${CMAKE_MATCH_1}")
+ endif()
+
+ if(NOT CMAKE_MATCH_1 STREQUAL "-Wall")
+ set(flag "${CMAKE_MATCH_1}")
+ string(TOLOWER "have_flag_${flag}" have_flag_var_name)
+ string(REGEX REPLACE "[^a-z_]" "_" have_flag_var_name ${have_flag_var_name})
+ string(REGEX REPLACE "__+" "_" have_flag_var_name ${have_flag_var_name})
+
+ CHECK_CXX_COMPILER_FLAG(${flag} ${have_flag_var_name})
+ if(${have_flag_var_name})
+ add_definitions("${flag}")
+ endif()
+ endif()
endif()
endforeach()
@@ -610,6 +627,7 @@ CHECK_CXX_SOURCE_COMPILES([=[
}
]=] "HAVE_STRUCT_STATFS_F_MNTONNAME")
file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_STRUCT_STATFS_F_MNTONNAME\n")
+
CHECK_CXX_SOURCE_COMPILES([=[
#include "BoxConfig.cmake.h"
#ifdef HAVE_SYS_PARAM_H
@@ -623,6 +641,7 @@ CHECK_CXX_SOURCE_COMPILES([=[
}
]=] "HAVE_STRUCT_STATVFS_F_MNTONNAME")
file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_STRUCT_STATVFS_F_MNTONNAME\n")
+
if(HAVE_STRUCT_STATFS_F_MNTONNAME OR
HAVE_STRUCT_STATVFS_F_MNTONNAME OR
HAVE_STRUCT_MNTENT_MNT_DIR OR
@@ -649,6 +668,34 @@ file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_RANDOM_DEVICE\n")
# Build an intermediate version of BoxConfig.cmake.h for use in the following tests:
configure_file("${boxconfig_h_file}" "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h")
+# Emulate ax_func_syscall.m4: Autoconf's AC_CHECK_FUNC (which we emulate above,
+# using check_function_exists) defines the function when testing for its
+# presence, so HAVE___SYSCALL will be true even if __syscall has no definition
+# in the system libraries, and this is precisely the case that we want to test
+# for, so now we test whether a test program compiles with no explicit
+# definition (only the system headers) and if that fails, we set
+# HAVE___SYSCALL_NEED_DEFN to 1.
+
+CHECK_CXX_SOURCE_COMPILES(
+ [=[
+ #include "BoxConfig.cmake.h"
+
+ #ifdef HAVE_SYS_SYSCALL_H
+ # include <sys/syscall.h>
+ #endif
+
+ int main()
+ {
+ __syscall(SYS_exit, 0);
+ return 0;
+ }
+ ]=] HAVE___SYSCALL_NO_DEFN)
+set(HAVE___SYSCALL_NEED_DEFN !HAVE___SYSCALL_NO_DEFN)
+file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE___SYSCALL_NEED_DEFN\n")
+
+# Build an intermediate version of BoxConfig.cmake.h for use in the following tests:
+configure_file("${boxconfig_h_file}" "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h")
+
foreach(struct_member_name "struct ucred.uid" "struct ucred.cr_uid")
string(REGEX MATCH "(.*)\\.(.*)" dummy_var ${struct_member_name})
set(struct_name "${CMAKE_MATCH_1}")
@@ -684,6 +731,71 @@ foreach(struct_member_name "struct ucred.uid" "struct ucred.cr_uid")
]=] "HAVE_${platform_var_name}")
file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_${platform_var_name}\n")
endforeach()
+
+function(AX_TRY_RUN_FD code var)
+ CHECK_CXX_SOURCE_RUNS([=[
+ #include "BoxConfig.cmake.h"
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <sys/syscall.h>
+ #include <sys/types.h>
+
+ #ifdef HAVE___SYSCALL_NEED_DEFN
+ extern "C" off_t __syscall(quad_t number, ...);
+ #endif
+
+ #ifdef HAVE___SYSCALL // always use it if we have it
+ # undef syscall
+ # define syscall __syscall
+ #endif
+
+ int main()
+ {
+ int fd = creat("lseektest", 0600);
+ int res = 1;
+ if(fd>=0)
+ {
+ ${code}
+ close(fd);
+ }
+ unlink("lseektest");
+ return res;
+ }
+ ]=] ${var})
+ file(APPEND "${boxconfig_h_file}" "#cmakedefine ${var}\n")
+endfunction()
+
+AX_TRY_RUN_FD(
+ [=[
+ // This test tries first to seek to position 0, with NO "dummy
+ // argument". If lseek does actually require a dummy argument,
+ // then it will eat SEEK_SET for the offset and try to use 99
+ // as whence, which is invalid, so res will be 0, the program
+ // will return 0 and we will define HAVE_LSEEK_DUMMY_PARAM
+ // (whew! that took 1 hour to figure out) The "dummy argument"
+ // probably means that it takes a 64-bit offset.
+ res = (syscall(SYS_lseek, fd, (int32_t)10, SEEK_SET, 99) == 10) ? 2 : 0;
+ ]=] HAVE_LSEEK_DUMMY_PARAM)
+
+AX_TRY_RUN_FD(
+ [=[
+ // Try to seek to a position that requires a 64-bit
+ // representation, and check the return value, which is the
+ // current position.
+ if(syscall(SYS_lseek, fd, (int64_t)5, SEEK_SET) != 5)
+ {
+ res = 2;
+ }
+ else if(syscall(SYS_lseek, fd, (int64_t)10, SEEK_CUR) != 15)
+ {
+ res = 3;
+ }
+ else
+ {
+ res = 0;
+ }
+ ]=] HAVE_LSEEK_64_BIT)
+
set(CMAKE_REQUIRED_INCLUDES "")
# Build the final version of BoxConfig.cmake.h, as a temporary file.
diff --git a/infrastructure/m4/ax_check_syscall_lseek.m4 b/infrastructure/m4/ax_check_syscall_lseek.m4
index 9fd04c81..4fec851a 100644
--- a/infrastructure/m4/ax_check_syscall_lseek.m4
+++ b/infrastructure/m4/ax_check_syscall_lseek.m4
@@ -11,12 +11,14 @@ dnl @category C
dnl @author Martin Ebourne
dnl @version 2005/07/03
dnl @license AllPermissive
+dnl
-AC_DEFUN([AX_CHECK_SYSCALL_LSEEK], [
- AC_REQUIRE([AX_FUNC_SYSCALL])dnl
- if test "x$ac_cv_header_sys_syscall_h" = "xyes"; then
- AC_CACHE_CHECK([[whether syscall lseek requires dummy parameter]], [box_cv_have_lseek_dummy_param],
- [AC_TRY_RUN(
+AC_DEFUN(
+ [AX_TRY_RUN_FD],
+ [
+ AC_REQUIRE([AX_FUNC_SYSCALL])dnl
+ if test "x$ac_cv_header_sys_syscall_h" = "xyes"; then
+ AC_TRY_RUN(
[
$ac_includes_default
#include <fcntl.h>
@@ -30,40 +32,83 @@ AC_DEFUN([AX_CHECK_SYSCALL_LSEEK], [
#endif
int main()
{
- int fh = creat("lseektest", 0600);
- int res = 0;
- if(fh>=0)
+ int fd = creat("lseektest", 0600);
+ int res = 1;
+ if(fd>=0)
{
+ $1
+ close(fd);
+ }
+ unlink("lseektest");
+ return abs(res);
+ }
+ ],
+ [$2],
+ [$3],
+ [$3 # assume not for cross-compiling]
+ )
+ fi
+ ])dnl
+
+AC_DEFUN([AX_CHECK_SYSCALL_LSEEK_DUMMY_PARAM], [
+ AC_CACHE_CHECK(
+ [[whether syscall lseek requires dummy parameter]],
+ [box_cv_have_lseek_dummy_param],
+ [AX_TRY_RUN_FD(
+ [
// This test tries first to seek to position 0, with NO
// "dummy argument". If lseek does actually require a dummy
// argument, then it will eat SEEK_SET for the offset and
// try to use 99 as whence, which is invalid, so res will be
- // -1, the program will return zero and
- // have_lseek_dummy_param=yes
+ // 1, the program will return 1 and we will define
+ // HAVE_LSEEK_DUMMY_PARAM
// (whew! that took 1 hour to figure out)
// The "dummy argument" probably means that it takes a 64-bit
- // offset, so this was probably a bug anyway, and now that
- // we cast the offset to off_t, it should never be needed
- // (if my reasoning is correct).
- res = syscall(SYS_lseek, fh, (off_t)0, SEEK_SET, 99);
- close(fh);
- }
- unlink("lseektest");
- return res!=-1;
- }
- ],
- [box_cv_have_lseek_dummy_param=yes],
- [box_cv_have_lseek_dummy_param=no],
- [box_cv_have_lseek_dummy_param=no # assume not for cross-compiling]
- )])
- if test "x$box_cv_have_lseek_dummy_param" = "xyes"; then
- AC_DEFINE([HAVE_LSEEK_DUMMY_PARAM], 1,
- [Define to 1 if syscall lseek requires a dummy middle parameter])
- fi
+ // offset.
+ res = (syscall(SYS_lseek, fd, (int32_t)10, SEEK_SET, 99) == 10) ? 0 : 1;
+ ],
+ dnl if the test program succeeds (res == 0):
+ [box_cv_have_lseek_dummy_param=no],
+ dnl if the test program fails (res != 0):
+ [box_cv_have_lseek_dummy_param=yes],
+ )]
+ )
+ if test "x$box_cv_have_lseek_dummy_param" != "xno"; then
+ AC_DEFINE([HAVE_LSEEK_DUMMY_PARAM], 1,
+ [Define to 1 if syscall lseek requires a dummy middle parameter])
fi
- if test "x$box_cv_have_lseek_dummy_param" = "xno"
- then
- m4_ifvaln([$1],[$1],[:])dnl
- m4_ifvaln([$2],[else $2])dnl
+])
+
+# Please note: this does not appear to work! Do not rely on it without further testing:
+AC_DEFUN([AX_CHECK_SYSCALL_LSEEK_64_BIT], [
+ AC_CACHE_CHECK(
+ [[whether syscall lseek takes a 64-bit offset parameter]],
+ [box_cv_have_lseek_64_bit],
+ [AX_TRY_RUN_FD(
+ [
+ // Try to seek to a position that requires a 64-bit representation, and check the return
+ // value, which is the current position.
+ if(syscall(SYS_lseek, fd, (int64_t)5, SEEK_SET) != 5)
+ {
+ res = 2;
+ }
+ else if(syscall(SYS_lseek, fd, (int64_t)10, SEEK_CUR) != 15)
+ {
+ res = 3;
+ }
+ else
+ {
+ res = 0;
+ }
+ ],
+ dnl if the test program succeeds (res == 0):
+ [box_cv_have_lseek_64_bit=yes],
+ dnl if the test program fails (res != 0):
+ [box_cv_have_lseek_64_bit=no]
+ )]
+ )
+ if test "x$box_cv_have_lseek_64_bit" != "xno"; then
+ AC_DEFINE([HAVE_LSEEK_64_BIT], 1,
+ [Define to 1 if syscall lseek takes a 64-bit offset])
fi
- ])dnl
+])
diff --git a/infrastructure/m4/boxbackup_tests.m4 b/infrastructure/m4/boxbackup_tests.m4
index 59467e66..86aa560a 100644
--- a/infrastructure/m4/boxbackup_tests.m4
+++ b/infrastructure/m4/boxbackup_tests.m4
@@ -10,27 +10,28 @@ solaris*)
;;
esac
+# If the compiler supports it, force errors on unknown flags, so that detection works:
+AX_CHECK_COMPILE_FLAG(-Werror=unknown-warning-option,
+ [cxxflags_force_error="-Werror=unknown-warning-option"])
+
+# Reduce compiler flag checking to a one-liner, needed for CMake to parse them
+AC_DEFUN([BOX_CHECK_CXX_FLAG],
+ AX_CHECK_COMPILE_FLAG($1,
+ [cxxflags_strict="$cxxflags_strict $1"],,
+ $cxxflags_force_error)
+)
+
# Enable some compiler flags if the compiler supports them. This gives better warnings
# and detects some problems early.
-AX_CHECK_COMPILE_FLAG(-Wall, [cxxflags_strict="$cxxflags_strict -Wall"])
-# -Wundef would be a good idea, but Boost is full of undefined variable use, so we need
-# to disable it for now so that we can concentrate on real errors:
-dnl AX_CHECK_COMPILE_FLAG(-Wundef, [cxxflags_strict="$cxxflags_strict -Wundef"])
-AX_CHECK_COMPILE_FLAG(-Werror=return-type,
- [cxxflags_strict="$cxxflags_strict -Werror=return-type"])
-AX_CHECK_COMPILE_FLAG(-Werror=delete-non-virtual-dtor,
- [cxxflags_strict="$cxxflags_strict -Werror=delete-non-virtual-dtor"])
-AX_CHECK_COMPILE_FLAG(-Werror=undefined-bool-conversion,
- [cxxflags_strict="$cxxflags_strict -Werror=undefined-bool-conversion"])
-# We should really enable -Werror=sometimes-uninitialized, but QDBM violates it:
-dnl AX_CHECK_COMPILE_FLAG(-Werror=sometimes-uninitialized,
-dnl [cxxflags_strict="$cxxflags_strict -Werror=sometimes-uninitialized"])
+BOX_CHECK_CXX_FLAG(-Wall)
+BOX_CHECK_CXX_FLAG(-Werror=return-type)
+BOX_CHECK_CXX_FLAG(-Werror=delete-non-virtual-dtor)
+BOX_CHECK_CXX_FLAG(-Werror=undefined-bool-conversion)
# This error is detected by MSVC, but not usually by GCC/Clang:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58114
-AX_CHECK_COMPILE_FLAG(-Werror=delete-incomplete,
- [cxxflags_strict="$cxxflags_strict -Werror=delete-incomplete"])
-AX_CHECK_COMPILE_FLAG(-Wno-deprecated-declarations,
- [cxxflags_strict="$cxxflags_strict -Wno-deprecated-declarations"])
+BOX_CHECK_CXX_FLAG(-Werror=delete-incomplete)
+BOX_CHECK_CXX_FLAG(-Wno-deprecated-declarations)
+
AC_SUBST([CXXFLAGS_STRICT], [$cxxflags_strict])
if test "x$GXX" = "xyes"; then
@@ -310,7 +311,8 @@ if test "$netbsd_hack" != "netbsd"; then
fi
AX_FUNC_SYSCALL
-AX_CHECK_SYSCALL_LSEEK
+AX_CHECK_SYSCALL_LSEEK_DUMMY_PARAM
+AX_CHECK_SYSCALL_LSEEK_64_BIT
AC_CHECK_FUNCS([listxattr llistxattr getxattr lgetxattr setxattr lsetxattr])
AC_CHECK_DECLS([XATTR_NOFOLLOW],,, [[#include <sys/xattr.h>]])
diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in
index d5ac9f2f..48958ba1 100755
--- a/infrastructure/makebuildenv.pl.in
+++ b/infrastructure/makebuildenv.pl.in
@@ -628,7 +628,7 @@ __E
{
writetestfile("$mod/t-gdb",
"echo 'No debugger was detected by configure script'\n".
- "exit 2");
+ "exit 2", $mod);
}
}
diff --git a/lib/intercept/intercept.cpp b/lib/intercept/intercept.cpp
index 72bd8d4e..f46e6982 100644
--- a/lib/intercept/intercept.cpp
+++ b/lib/intercept/intercept.cpp
@@ -390,23 +390,23 @@ lseek(int fildes, off_t offset, int whence)
{
// random magic for lseek syscall, see /usr/src/lib/libc/sys/lseek.c
CHECK_FOR_FAKE_ERROR_COND(fildes, 0, SYS_lseek, -1);
+
#ifdef PLATFORM_NO_SYSCALL
int r = TEST_lseek(fildes, offset, whence);
+#elif defined HAVE_LSEEK_DUMMY_PARAM
+ off_t r = syscall(SYS_lseek, fildes, 0 /* extra 0 required here! */, (int32_t)offset,
+ whence);
+#elif defined HAVE_LSEEK_64_BIT
+ off_t r = syscall(SYS_lseek, fildes, (int64_t)offset, whence);
#else
- #ifdef HAVE_LSEEK_DUMMY_PARAM
- off_t r = syscall(SYS_lseek, fildes, 0 /* extra 0 required here! */, offset, whence);
- #elif defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 32
- // Don't bother trying to call SYS__llseek on 32 bit since it is
- // fiddly and not needed for the tests
- off_t r = syscall(SYS_lseek, fildes, (uint32_t)offset, whence);
- #else
- off_t r = syscall(SYS_lseek, fildes, offset, whence);
- #endif
+ off_t r = syscall(SYS_lseek, fildes, (int32_t)offset, whence);
#endif
+
if(r != -1)
{
intercept_filepos = r;
}
+
return r;
}
diff --git a/test/raidfile/testraidfile.cpp b/test/raidfile/testraidfile.cpp
index d771f23d..2314d376 100644
--- a/test/raidfile/testraidfile.cpp
+++ b/test/raidfile/testraidfile.cpp
@@ -653,12 +653,21 @@ int test(int argc, const char *argv[])
IOStream &write1stream = write1; // use the stream interface where possible
write1.Open();
write1stream.Write(data, sizeof(data));
+ TEST_EQUAL(sizeof(data), write1stream.GetPosition());
write1stream.Seek(1024, IOStream::SeekType_Absolute);
+ TEST_EQUAL(1024, write1stream.GetPosition());
write1stream.Write(data2, sizeof(data2));
+ TEST_EQUAL(1024 + sizeof(data2), write1stream.GetPosition());
write1stream.Seek(1024, IOStream::SeekType_Relative);
+ TEST_EQUAL(2048 + sizeof(data2), write1stream.GetPosition());
write1stream.Write(data2, sizeof(data2));
+ TEST_EQUAL(2048 + sizeof(data2) * 2, write1stream.GetPosition());
write1stream.Seek(0, IOStream::SeekType_End);
+ TEST_EQUAL(sizeof(data), write1stream.GetPosition());
write1stream.Write(data, sizeof(data));
+ TEST_EQUAL(sizeof(data) * 2, write1stream.GetPosition());
+ write1stream.Seek(-1, IOStream::SeekType_Relative);
+ TEST_EQUAL(sizeof(data) * 2 - 1, write1stream.GetPosition());
// Before it's deleted, check to see the contents are as expected
int f;