From 9c27e4766dede7a69b65cc412125ac8186d84852 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 8 Jun 2023 14:10:04 +0200 Subject: [PATCH] Decide which FTL architecture to pick by by installed architectures rather than by detected processor (this may be wrong in an emulated Docker environment) Signed-off-by: DL6ER --- automated install/basic-install.sh | 76 +++++++---- test/test_any_automated_install.py | 211 ++++++++++++++++++++--------- 2 files changed, 197 insertions(+), 90 deletions(-) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index d49ae012..b14546d1 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -1806,10 +1806,19 @@ FTLinstall() { } get_binary_name() { - # This gives the machine architecture which may be different from the OS architecture... + # Get the OS architecture (we cannot use uname -m as this may return an incorrect architecture when buildx-compiling with QEMU for arm) local machine machine=$(uname -m) + # Get local GLIBC version (leave at "0.0" if no GLIBC, e.g., on musl) + local l_glibc_version="0.0" + if ldd --version 2>&1 | grep -q "GLIBC"; then + l_glibc_version=$(ldd --version | head -n1 | grep -o '[0-9.]*$') + printf "%b %b Detected GLIBC version %s\\n" "${OVER}" "${TICK}" "${l_glibc_version}" + else + printf "%b %b No GLIBC detected\\n" "${OVER}" "${CROSS}" + fi + local l_binary local str="Detecting processor" @@ -1817,36 +1826,51 @@ get_binary_name() { # If the machine is arm or aarch if [[ "${machine}" == "arm"* || "${machine}" == *"aarch"* ]]; then # ARM + # Get supported processor from other binaries installed on the system + local cpu_arch + cpu_arch=$(readelf -A "$(command -v sh)" | grep Tag_CPU_arch | awk '{ print $2 }') + + # Get the revision from the CPU architecture local rev - rev=$(uname -m | sed "s/[^0-9]//g;") - local lib - lib=$(ldd "$(command -v sh)" | grep -E '^\s*/lib' | awk '{ print $1 }') - if [[ "${lib}" == "/lib/ld-linux-aarch64.so.1" ]]; then - printf "%b %b Detected AArch64 (64 Bit ARM) processor\\n" "${OVER}" "${TICK}" + rev=$(echo "${cpu_arch}" | grep -o '[0-9]*') + if [[ "${machine}" == "aarch64" ]]; then + printf "%b %b Detected AArch64 (64 Bit ARM) architecture\\n" "${OVER}" "${TICK}" # set the binary to be used l_binary="pihole-FTL-arm64" - elif [[ "${lib}" == "/lib/ld-linux-armhf.so.3" ]]; then - # Hard-float available: Use gnueabihf binaries + elif [[ "${cpu_arch}" == "armv6KZ" ]]; then + printf "%b %b Detected ARMv6KZ architecture\\n" "${OVER}" "${TICK}" + # set the binary to be used + l_binary="pihole-FTL-armv6" + else # If ARMv8 or higher is found (e.g., BCM2837 as found in Raspberry Pi Model 3B) if [[ "${rev}" -gt 7 ]]; then - printf "%b %b Detected ARMv8 (or newer) processor\\n" "${OVER}" "${TICK}" - # set the binary to be used - l_binary="pihole-FTL-armv8" - elif [[ "${rev}" -eq 7 ]]; then - # Otherwise, if ARMv7 is found (e.g., BCM2836 as found in Raspberry Pi Model 2) - printf "%b %b Detected ARMv7 processor (with hard-float support)\\n" "${OVER}" "${TICK}" + printf "%b %b Detected ARMv8 (or newer) architecture\\n" "${OVER}" "${TICK}" # set the binary to be used l_binary="pihole-FTL-armv7" - else - # Otherwise, use the ARMv6 binary (e.g., BCM2835 as found in Raspberry Pi Zero and Model 1) - printf "%b %b Detected ARMv6 processor (with hard-float support)\\n" "${OVER}" "${TICK}" + elif [[ "${rev}" -gt 6 ]]; then + # Otherwise, if ARMv7 is found (e.g., BCM2836 as found in Raspberry Pi Model 2) + printf "%b %b Detected ARMv7 architecture\\n" "${OVER}" "${TICK}" # set the binary to be used l_binary="pihole-FTL-armv6" + elif [[ "${rev}" -gt 5 ]]; then + # Check if the system is using GLIBC 2.29 or higher + if [[ -n "${l_glibc_version}" && "$(printf '%s\n' "2.29" "${l_glibc_version}" | sort -V | head -n1)" == "2.29" ]]; then + # If so, use the ARMv6 binary (e.g., BCM2835 as found in Raspberry Pi Zero and Model 1) + printf "%b %b Detected ARMv6 architecture (running GLIBC 2.29 or higher)\\n" "${OVER}" "${TICK}" + # set the binary to be used + l_binary="pihole-FTL-armv5" + else + # Otherwise, use the ARMv5 binary (e.g., BCM2835 as found in Raspberry Pi Zero and Model 1) + printf "%b %b Detected ARMv6 architecture (running GLIBC older than 2.29)\\n" "${OVER}" "${TICK}" + # set the binary to be used + l_binary="pihole-FTL-armv4" + fi + else + # Otherwise, use the ARMv4 binary (e.g., BCM2835 as found in Raspberry Pi Zero and Model 1) + printf "%b %b Detected ARMv4 or ARMv5 architecture\\n" "${OVER}" "${TICK}" + # set the binary to be used + l_binary="pihole-FTL-armv4" fi - else - # No hard-float support found - printf "%b %b%b ARM processor without hard-float support detected%b\\n" "${OVER}" "${COL_LIGHT_RED}" "${CROSS}" "${COL_NC}" - l_binary="" fi elif [[ "${machine}" == "x86_64" ]]; then # This gives the processor of packages dpkg installs (for example, "i386") @@ -1858,25 +1882,25 @@ get_binary_name() { # We only check this for Debian-based systems as this has been an issue # in the past (see https://github.com/pi-hole/pi-hole/pull/2004) if [[ "${dpkgarch}" == "i386" ]]; then - printf "%b %b Detected 32bit (i686) processor\\n" "${OVER}" "${TICK}" + printf "%b %b Detected 32bit (i686) architecture\\n" "${OVER}" "${TICK}" l_binary="pihole-FTL-386" else # 64bit - printf "%b %b Detected x86_64 processor\\n" "${OVER}" "${TICK}" + printf "%b %b Detected x86_64 architecture\\n" "${OVER}" "${TICK}" # set the binary to be used l_binary="pihole-FTL-amd64" fi elif [[ "${machine}" == "riscv64" ]]; then - printf "%b %b Detected riscv64 processor\\n" "${OVER}" "${TICK}" + printf "%b %b Detected riscv64 architecture\\n" "${OVER}" "${TICK}" l_binary="pihole-FTL-riscv64" else # Something else - we try to use 32bit executable and warn the user if [[ ! "${machine}" == "i686" ]]; then printf "%b %b %s...\\n" "${OVER}" "${CROSS}" "${str}" - printf " %b %bNot able to detect processor (unknown: %s), trying x86 (32bit) executable%b\\n" "${INFO}" "${COL_LIGHT_RED}" "${machine}" "${COL_NC}" + printf " %b %bNot able to detect architecture (unknown: %s), trying x86 (32bit) executable%b\\n" "${INFO}" "${COL_LIGHT_RED}" "${machine}" "${COL_NC}" printf " %b Contact Pi-hole Support if you experience issues (e.g: FTL not running)\\n" "${INFO}" else - printf "%b %b Detected 32bit (i686) processor\\n" "${OVER}" "${TICK}" + printf "%b %b Detected 32bit (i686) architecture\\n" "${OVER}" "${TICK}" fi l_binary="pihole-FTL-linux-386" fi diff --git a/test/test_any_automated_install.py b/test/test_any_automated_install.py index 5c902c2b..4431c565 100644 --- a/test/test_any_automated_install.py +++ b/test/test_any_automated_install.py @@ -241,12 +241,36 @@ def test_FTL_detect_aarch64_no_errors(host): """ # mock uname to return aarch64 platform mock_command("uname", {"-m": ("aarch64", "0")}, host) - # mock ldd to respond with aarch64 shared library - mock_command( - "ldd", + detectPlatform = host.run( + """ + source /opt/pihole/basic-install.sh + create_pihole_user + funcOutput=$(get_binary_name) + binary="pihole-FTL${funcOutput##*pihole-FTL}" + theRest="${funcOutput%pihole-FTL*}" + FTLdetect "${binary}" "${theRest}" + """ + ) + expected_stdout = info_box + " FTL Checks..." + assert expected_stdout in detectPlatform.stdout + expected_stdout = tick_box + " Detected AArch64 (64 Bit ARM) architecture" + assert expected_stdout in detectPlatform.stdout + expected_stdout = tick_box + " Downloading and Installing FTL" + assert expected_stdout in detectPlatform.stdout + + +def test_FTL_detect_armv4_no_errors(host): + """ + confirms only armv4 package is downloaded for FTL engine + """ + # mock uname to return armv4 platform + mock_command("uname", {"-m": ("armv4t", "0")}, host) + # mock readelf to respond with armv4 CPU architecture + mock_command_2( + "readelf", { - "/bin/sh": ("/lib/ld-linux-aarch64.so.1", "0"), - "/usr/bin/sh": ("/lib/ld-linux-aarch64.so.1", "0"), + "-A /bin/sh": ("Tag_CPU_arch: armv4t", "0"), + "-A /usr/bin/sh": ("Tag_CPU_arch: armv4t", "0"), }, host, ) @@ -262,77 +286,65 @@ def test_FTL_detect_aarch64_no_errors(host): ) expected_stdout = info_box + " FTL Checks..." assert expected_stdout in detectPlatform.stdout - expected_stdout = tick_box + " Detected AArch64 (64 Bit ARM) processor" + expected_stdout = tick_box + " Detected ARMv4 or ARMv5 architecture" assert expected_stdout in detectPlatform.stdout expected_stdout = tick_box + " Downloading and Installing FTL" assert expected_stdout in detectPlatform.stdout -def test_FTL_detect_armv4t_no_install(host): +def test_FTL_detect_armv5_no_errors(host): """ - confirms armv4t architecture is not supported - """ - # mock uname to return armv4t platform - mock_command("uname", {"-m": ("armv4t", "0")}, host) - # mock ldd to respond with armv4t shared library - mock_command( - "ldd", - { - "/bin/sh": ("/lib/ld-linux.so.3", "0"), - "/usr/bin/sh": ("/lib/ld-linux.so.3", "0"), - }, - host, - ) - detectPlatform = host.run( - """ - source /opt/pihole/basic-install.sh - get_binary_name - """ - ) - expected_stdout = cross_box + (" ARM processor without hard-float support detected") - assert expected_stdout in detectPlatform.stdout - - -def test_FTL_detect_armv5te_no_install(host): - """ - confirms armv5te architecture is not supported + confirms only armv5 package is downloaded for FTL engine """ # mock uname to return armv5te platform mock_command("uname", {"-m": ("armv5te", "0")}, host) - # mock ldd to respond with ld-linux shared library - mock_command( - "ldd", + # mock readelf to respond with armv5 CPU architecture + mock_command_2( + "readelf", { - "/bin/sh": ("/lib/ld-linux.so.3", "0"), - "/usr/bin/sh": ("/lib/ld-linux.so.3", "0"), + "-A /bin/sh": ("Tag_CPU_arch: armv5te", "0"), + "-A /usr/bin/sh": ("Tag_CPU_arch: armv5te", "0"), }, host, ) detectPlatform = host.run( """ source /opt/pihole/basic-install.sh - get_binary_name + create_pihole_user + funcOutput=$(get_binary_name) + binary="pihole-FTL${funcOutput##*pihole-FTL}" + theRest="${funcOutput%pihole-FTL*}" + FTLdetect "${binary}" "${theRest}" """ ) - expected_stdout = cross_box + (" ARM processor without hard-float support detected") + expected_stdout = info_box + " FTL Checks..." + assert expected_stdout in detectPlatform.stdout + expected_stdout = tick_box + " Detected ARMv4 or ARMv5 architecture" + assert expected_stdout in detectPlatform.stdout + expected_stdout = tick_box + " Downloading and Installing FTL" assert expected_stdout in detectPlatform.stdout -def test_FTL_detect_armv6l_no_errors(host): +def test_FTL_detect_armv6_old_no_errors(host): """ - confirms only armv6l package is downloaded for FTL engine + confirms only armv6 package is downloaded for FTL engine """ # mock uname to return armv6l platform mock_command("uname", {"-m": ("armv6l", "0")}, host) - # mock ldd to respond with ld-linux-armhf shared library - mock_command( - "ldd", + # mock readelf to respond with armv6l CPU architecture + mock_command_2( + "readelf", { - "/bin/sh": ("/lib/ld-linux-armhf.so.3", "0"), - "/usr/bin/sh": ("/lib/ld-linux-armhf.so.3", "0"), + "-A /bin/sh": ("Tag_CPU_arch: armv6l", "0"), + "-A /usr/bin/sh": ("Tag_CPU_arch: armv6l", "0"), }, host, ) + # Mock old ldd GLIBC version + mock_command( + "ldd", {"--version": ("ldd (Debian GLIBC 2.13-38+deb7u8) 2.13", "0")}, host + ) + detectPlatform = host.run( """ source /opt/pihole/basic-install.sh @@ -346,25 +358,98 @@ def test_FTL_detect_armv6l_no_errors(host): expected_stdout = info_box + " FTL Checks..." assert expected_stdout in detectPlatform.stdout expected_stdout = tick_box + ( - " Detected ARMv6 processor " "(with hard-float support)" + " Detected ARMv6 architecture (running GLIBC older than 2.29)" ) assert expected_stdout in detectPlatform.stdout expected_stdout = tick_box + " Downloading and Installing FTL" assert expected_stdout in detectPlatform.stdout +def test_FTL_detect_armv6_recent_no_errors(host): + """ + confirms only armv6 package is downloaded for FTL engine + """ + # mock uname to return armv6l platform + mock_command("uname", {"-m": ("armv6l", "0")}, host) + # mock readelf to respond with armv6l CPU architecture + mock_command_2( + "readelf", + { + "-A /bin/sh": ("Tag_CPU_arch: armv6l", "0"), + "-A /usr/bin/sh": ("Tag_CPU_arch: armv6l", "0"), + }, + host, + ) + # Mock old ldd GLIBC version + mock_command( + "ldd", {"--version": ("'ldd (Debian GLIBC 2.35-38+deb7u8) 2.35'", "0")}, host + ) + + detectPlatform = host.run( + """ + source /opt/pihole/basic-install.sh + create_pihole_user + funcOutput=$(get_binary_name) + binary="pihole-FTL${funcOutput##*pihole-FTL}" + theRest="${funcOutput%pihole-FTL*}" + FTLdetect "${binary}" "${theRest}" + """ + ) + expected_stdout = info_box + " FTL Checks..." + assert expected_stdout in detectPlatform.stdout + expected_stdout = tick_box + ( + " Detected ARMv6 architecture (running GLIBC 2.29 or higher)" + ) + assert expected_stdout in detectPlatform.stdout + expected_stdout = tick_box + " Downloading and Installing FTL" + assert expected_stdout in detectPlatform.stdout + + +def test_FTL_detect_armv6KZ_no_errors(host): + """ + confirms only armv6KZ package is downloaded for FTL engine + """ + # mock uname to return armv6KZ platform + mock_command("uname", {"-m": ("armv6KZ", "0")}, host) + # mock readelf to respond with armv6l CPU architecture + mock_command_2( + "readelf", + { + "-A /bin/sh": ("Tag_CPU_arch: armv6KZ", "0"), + "-A /usr/bin/sh": ("Tag_CPU_arch: armv6KZ", "0"), + }, + host, + ) + detectPlatform = host.run( + """ + source /opt/pihole/basic-install.sh + create_pihole_user + funcOutput=$(get_binary_name) + binary="pihole-FTL${funcOutput##*pihole-FTL}" + theRest="${funcOutput%pihole-FTL*}" + FTLdetect "${binary}" "${theRest}" + """ + ) + expected_stdout = info_box + " FTL Checks..." + assert expected_stdout in detectPlatform.stdout + expected_stdout = tick_box + " Detected ARMv6KZ architecture" + assert expected_stdout in detectPlatform.stdout + expected_stdout = tick_box + " Downloading and Installing FTL" + assert expected_stdout in detectPlatform.stdout + + def test_FTL_detect_armv7l_no_errors(host): """ confirms only armv7l package is downloaded for FTL engine """ # mock uname to return armv7l platform mock_command("uname", {"-m": ("armv7l", "0")}, host) - # mock ldd to respond with ld-linux-armhf shared lib rary - mock_command( - "ldd", + # mock readelf to respond with armv7l CPU architecture + mock_command_2( + "readelf", { - "/bin/sh": ("/lib/ld-linux-armhf.so.3", "0"), - "/usr/bin/sh": ("/lib/ld-linux-armhf.so.3", "0"), + "-A /bin/sh": ("Tag_CPU_arch: armv7l", "0"), + "-A /usr/bin/sh": ("Tag_CPU_arch: armv7l", "0"), }, host, ) @@ -380,9 +465,7 @@ def test_FTL_detect_armv7l_no_errors(host): ) expected_stdout = info_box + " FTL Checks..." assert expected_stdout in detectPlatform.stdout - expected_stdout = tick_box + ( - " Detected ARMv7 processor " "(with hard-float support)" - ) + expected_stdout = tick_box + (" Detected ARMv7 architecture") assert expected_stdout in detectPlatform.stdout expected_stdout = tick_box + " Downloading and Installing FTL" assert expected_stdout in detectPlatform.stdout @@ -394,12 +477,12 @@ def test_FTL_detect_armv8a_no_errors(host): """ # mock uname to return armv8a platform mock_command("uname", {"-m": ("armv8a", "0")}, host) - # mock ldd to respond with ld-linux-armhf shared library - mock_command( - "ldd", + # mock readelf to respond with armv8a CPU architecture + mock_command_2( + "readelf", { - "/bin/sh": ("/lib/ld-linux-armhf.so.3", "0"), - "/usr/bin/sh": ("/lib/ld-linux-armhf.so.3", "0"), + "-A /bin/sh": ("Tag_CPU_arch: armv8a", "0"), + "-A /usr/bin/sh": ("Tag_CPU_arch: armv8a", "0"), }, host, ) @@ -415,7 +498,7 @@ def test_FTL_detect_armv8a_no_errors(host): ) expected_stdout = info_box + " FTL Checks..." assert expected_stdout in detectPlatform.stdout - expected_stdout = tick_box + " Detected ARMv8 (or newer) processor" + expected_stdout = tick_box + " Detected ARMv8 (or newer) architecture" assert expected_stdout in detectPlatform.stdout expected_stdout = tick_box + " Downloading and Installing FTL" assert expected_stdout in detectPlatform.stdout @@ -437,7 +520,7 @@ def test_FTL_detect_x86_64_no_errors(host): ) expected_stdout = info_box + " FTL Checks..." assert expected_stdout in detectPlatform.stdout - expected_stdout = tick_box + " Detected x86_64 processor" + expected_stdout = tick_box + " Detected x86_64 architecture" assert expected_stdout in detectPlatform.stdout expected_stdout = tick_box + " Downloading and Installing FTL" assert expected_stdout in detectPlatform.stdout @@ -457,7 +540,7 @@ def test_FTL_detect_unknown_no_errors(host): FTLdetect "${binary}" "${theRest}" """ ) - expected_stdout = "Not able to detect processor (unknown: mips)" + expected_stdout = "Not able to detect architecture (unknown: mips)" assert expected_stdout in detectPlatform.stdout