From c08932c6e5e1609835219e9f42efe46bb6624a7d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Feb 2018 08:47:40 +0000 Subject: Fix raidfile tests on 32-bit Linux A recent fix for Solaris (commit 81e9aa6545f7f19124c9f5e88982b867d8732965) broke support for 32-bit Linux (which wasn't spotted because we didn't have any 32-bit builders). Try a different approach: detect whether the lseek syscall takes a 64-bit integer offset, and use that if possible. CMake: reimplement autoconf tests for 64-bit lseek (cherry picked from commit 138ea5d174f146f14d91a16bf5d1ce8e479d2024) --- infrastructure/cmake/CMakeLists.txt | 96 ++++++++++++++++++++++++ infrastructure/m4/ax_check_syscall_lseek.m4 | 111 +++++++++++++++++++--------- infrastructure/m4/boxbackup_tests.m4 | 3 +- 3 files changed, 176 insertions(+), 34 deletions(-) (limited to 'infrastructure') diff --git a/infrastructure/cmake/CMakeLists.txt b/infrastructure/cmake/CMakeLists.txt index 65f59eb8..a00e10d7 100644 --- a/infrastructure/cmake/CMakeLists.txt +++ b/infrastructure/cmake/CMakeLists.txt @@ -363,6 +363,7 @@ target_compile_definitions(lib_common PUBLIC $<$:BOX_RELEASE_BUI include(CheckCXXCompilerFlag) include(CheckCXXSourceCompiles) +include(CheckCXXSourceRuns) include(CheckFunctionExists) include(CheckIncludeFiles) include(CheckLibraryExists) @@ -610,6 +611,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 +625,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 +652,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 + #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 +715,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 + #include + #include + #include + + #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 @@ -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..74a870e9 100644 --- a/infrastructure/m4/boxbackup_tests.m4 +++ b/infrastructure/m4/boxbackup_tests.m4 @@ -310,7 +310,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 ]]) -- cgit v1.2.3