diff --git a/.github/workflows/glibc-detectors.yml b/.github/workflows/glibc-detectors.yml new file mode 100644 index 0000000..26fec6e --- /dev/null +++ b/.github/workflows/glibc-detectors.yml @@ -0,0 +1,67 @@ +on: + push: + branches: + - main + pull_request: + paths: + - .github/workflows/glibc-detectors.yml + - linux-glibc-detectors/** + +name: Glibc Detectors + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + RUST_LOG: info + RUST_BACKTRACE: 1 + RUSTFLAGS: "-D warnings" + CARGO_TERM_COLOR: always + +jobs: + build: + name: ${{ matrix.target }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - { name: x86_64, target: x86_64-unknown-linux-gnu } + - { name: i686, target: i686-unknown-linux-gnu } + - { name: aarch64, target: aarch64-unknown-linux-gnu } + - { name: armv7l, target: arm-unknown-linux-gnueabi } + - { name: ppc64, target: powerpc64-unknown-linux-gnu } + - { name: ppc64le, target: powerpc64le-unknown-linux-gnu } +# - { name: s390x, target: s390x-unknown-linux-gnu } + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly-2024-07-14 + targets: ${{ matrix.target }} + components: rust-src + + - uses: taiki-e/install-action@v2 + name: Install cargo-zigbuild + with: + tool: cargo-zigbuild@0.19.1 + + - name: Install Zig + uses: goto-bus-stop/setup-zig@v2 + with: + version: 0.12.0 + + - name: Run build + run: cargo +nightly-2024-07-14 zigbuild --manifest-path linux-glibc-detectors/Cargo.toml -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target ${{ matrix.target }} --release + + - name: Move binary + run: mv linux-glibc-detectors/target/${{ matrix.target }}/release/linux-glibc-detector linux-glibc-detector-${{ matrix.name }} + + - uses: actions/upload-artifact@v4 + with: + name: linux-glibc-detector-${{ matrix.name }} + path: linux-glibc-detector-${{ matrix.name }} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 6c7aa46..5a48ba1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,6 @@ description = "Detects the runtime version of libc on Linux systems" [dependencies] tracing = "0.1.40" tempfile = "3.9.0" + +[dev-dependencies] +tracing-test = "0.2.5" diff --git a/linux-glibc-detectors/.gitignore b/linux-glibc-detectors/.gitignore new file mode 100644 index 0000000..91b8835 --- /dev/null +++ b/linux-glibc-detectors/.gitignore @@ -0,0 +1,3 @@ +/target +/Cargo.lock +.idea/ diff --git a/linux-glibc-detectors/Cargo.lock b/linux-glibc-detectors/Cargo.lock new file mode 100644 index 0000000..9358c35 --- /dev/null +++ b/linux-glibc-detectors/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "linux-glibc-detector" +version = "0.1.0" +dependencies = [ + "libc", +] diff --git a/linux-glibc-detectors/Cargo.toml b/linux-glibc-detectors/Cargo.toml new file mode 100644 index 0000000..eec4460 --- /dev/null +++ b/linux-glibc-detectors/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "linux-glibc-detector" +version = "0.1.0" +edition = "2021" + +[dependencies] +libc = "0.2.155" + +[profile.release] +strip = true +opt-level = "z" +lto = true +codegen-units = 1 +panic = "abort" \ No newline at end of file diff --git a/linux-glibc-detectors/README.md b/linux-glibc-detectors/README.md new file mode 100644 index 0000000..e8c7c79 --- /dev/null +++ b/linux-glibc-detectors/README.md @@ -0,0 +1,20 @@ +# GLibc detector + +This directory contains the source code for a very simple program to detect the glibc version using the `gnu_get_libc_version` function. + +## Building + +To build the program, we need to make sure that we link to an ancient version of glibc to ensure maximum compatiblity. +We can use [cargo zigbuild](https://github.com/rust-cross/cargo-zigbuild) to use `zig` as the linker to allow linking against a specific glibc version without having to muck about with docker images. + +To build to program, run the following commands: + +```sh +ARCH=x86_64-unknown-linux-gnu + +# Make sure you have the appropriate target to build for. +rustup target add $ARCH + +# Build the program using zigbuild +cargo +nightly zigbuild -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target $ARCH --release +``` \ No newline at end of file diff --git a/linux-glibc-detectors/bin/README.md b/linux-glibc-detectors/bin/README.md new file mode 100644 index 0000000..1bf027f --- /dev/null +++ b/linux-glibc-detectors/bin/README.md @@ -0,0 +1 @@ +These files are generated on CI and copied here. Do not edit manually. \ No newline at end of file diff --git a/linux-glibc-detectors/bin/linux-glibc-detector-aarch64 b/linux-glibc-detectors/bin/linux-glibc-detector-aarch64 new file mode 100755 index 0000000..deaf0db Binary files /dev/null and b/linux-glibc-detectors/bin/linux-glibc-detector-aarch64 differ diff --git a/linux-glibc-detectors/bin/linux-glibc-detector-armv7l b/linux-glibc-detectors/bin/linux-glibc-detector-armv7l new file mode 100755 index 0000000..e5ee19d Binary files /dev/null and b/linux-glibc-detectors/bin/linux-glibc-detector-armv7l differ diff --git a/linux-glibc-detectors/bin/linux-glibc-detector-i686 b/linux-glibc-detectors/bin/linux-glibc-detector-i686 new file mode 100755 index 0000000..1aa44df Binary files /dev/null and b/linux-glibc-detectors/bin/linux-glibc-detector-i686 differ diff --git a/linux-glibc-detectors/bin/linux-glibc-detector-ppc64 b/linux-glibc-detectors/bin/linux-glibc-detector-ppc64 new file mode 100755 index 0000000..b660914 Binary files /dev/null and b/linux-glibc-detectors/bin/linux-glibc-detector-ppc64 differ diff --git a/linux-glibc-detectors/bin/linux-glibc-detector-ppc64le b/linux-glibc-detectors/bin/linux-glibc-detector-ppc64le new file mode 100755 index 0000000..38848c8 Binary files /dev/null and b/linux-glibc-detectors/bin/linux-glibc-detector-ppc64le differ diff --git a/linux-glibc-detectors/bin/linux-glibc-detector-x86_64 b/linux-glibc-detectors/bin/linux-glibc-detector-x86_64 new file mode 100755 index 0000000..a0ed95a Binary files /dev/null and b/linux-glibc-detectors/bin/linux-glibc-detector-x86_64 differ diff --git a/linux-glibc-detectors/src/main.rs b/linux-glibc-detectors/src/main.rs new file mode 100644 index 0000000..4fb05f2 --- /dev/null +++ b/linux-glibc-detectors/src/main.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +// Link with libc +#[link(name = "c")] +extern "C" {} + +extern crate libc; + +#[no_mangle] +pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + libc::puts(libc::gnu_get_libc_version()); + } + 0 +} + +#[panic_handler] +fn my_panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/rust-toolchain b/rust-toolchain index 25948c2..79fcd0a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.75.0 +1.77.0 diff --git a/src/lib.rs b/src/lib.rs index 138f57d..d2bf649 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,11 +21,11 @@ fn glibc_detectors() -> Vec<(&'static str, &'static [u8])> { { detectors.push(( "x86_64", - include_bytes!("./linux-glibc-detectors/glibc-detector-x86_64").as_slice(), + include_bytes!("../linux-glibc-detectors/bin/linux-glibc-detector-x86_64").as_slice(), )); detectors.push(( "i686", - include_bytes!("./linux-glibc-detectors/glibc-detector-i686").as_slice(), + include_bytes!("../linux-glibc-detectors/bin/linux-glibc-detector-i686").as_slice(), )); } @@ -33,27 +33,27 @@ fn glibc_detectors() -> Vec<(&'static str, &'static [u8])> { { detectors.push(( "aarch64", - include_bytes!("./linux-glibc-detectors/glibc-detector-aarch64").as_slice(), + include_bytes!("../linux-glibc-detectors/bin/linux-glibc-detector-aarch64").as_slice(), )); detectors.push(( "armv7l", - include_bytes!("./linux-glibc-detectors/glibc-detector-armv7l").as_slice(), + include_bytes!("../linux-glibc-detectors/bin/linux-glibc-detector-armv7l").as_slice(), )); } - #[cfg(target_arch = "powerpc64")] + #[cfg(all(target_arch = "powerpc64", target_endian = "big"))] { detectors.push(( - "ppc64le", - include_bytes!("./linux-glibc-detectors/glibc-detector-ppc64le").as_slice(), + "ppc64", + include_bytes!("../linux-glibc-detectors/bin/linux-glibc-detector-ppc64").as_slice(), )); } - #[cfg(target_arch = "s390x")] + #[cfg(all(target_arch = "powerpc64", target_endian = "little"))] { detectors.push(( - "s390x", - include_bytes!("./linux-glibc-detectors/glibc-detector-s390x").as_slice(), + "ppc64le", + include_bytes!("../linux-glibc-detectors/bin/linux-glibc-detector-ppc64le").as_slice(), )); } @@ -129,7 +129,15 @@ pub fn glibc_version() -> Option<(u32, u32)> { /// Detect the current version of `musl` `libc` by inspecting the `/lib/ld-musl-*.so.1` loaders. pub fn musl_libc_version() -> Option<(u32, u32)> { - for arch in ["x86_64", "aarch64", "i386", "armhf", "powerpc64le", "s390x"] { + for arch in [ + "x86_64", + "aarch64", + "i386", + "armhf", + "arm", + "powerpc64le", + "s390x", + ] { let loader = PathBuf::from(format!("/lib/ld-musl-{arch}.so.1")); if !loader.exists() { continue; @@ -217,6 +225,7 @@ pub fn libc_version() -> Option { #[cfg(test)] mod test { use super::*; + use tracing_test::traced_test; #[test] fn test_glibc_version() { @@ -229,6 +238,7 @@ mod test { } #[test] + #[traced_test] fn test_libc_version() { let version = libc_version(); match version { diff --git a/src/linux-glibc-detectors/README.md b/src/linux-glibc-detectors/README.md deleted file mode 100644 index af2eda2..0000000 --- a/src/linux-glibc-detectors/README.md +++ /dev/null @@ -1,24 +0,0 @@ -This file was taken from https://github.com/njsmith/posy/blob/61ff56c68a6aeff744b274170c32f59ac9ac20e1/src/platform_tags/linux-glibc-detectors/README.md -Licensed under MIT/APACHE-2.0 - -# The problem - -When running on Linux, `posy` needs to know whether glibc is -installed, and which version, for which architectures. This is -difficult because: - -- `posy` itself might be linked as a static musl binary, so it can't - use `dlopen` or call any glibc-specific functions. -- The system might support multiple architectures (e.g. x86-64 and - i386). - -# The solution - -We have a tiny little program `glibc-detector.c`, which links against -glibc, and does nothing except print out the output of `gnu_get_libc_version()` - -We built this program in a Docker container running an old distro, to -make sure it doesn't use any new glibc symbol versions, against a -variety of architectures. Then we save those executables here, so we -don't need access to an old distro at build time – and since by -definition, these executables are unlikely to change! diff --git a/src/linux-glibc-detectors/glibc-detector-aarch64 b/src/linux-glibc-detectors/glibc-detector-aarch64 deleted file mode 100644 index cf9192d..0000000 Binary files a/src/linux-glibc-detectors/glibc-detector-aarch64 and /dev/null differ diff --git a/src/linux-glibc-detectors/glibc-detector-armv7l b/src/linux-glibc-detectors/glibc-detector-armv7l deleted file mode 100644 index 9c51120..0000000 Binary files a/src/linux-glibc-detectors/glibc-detector-armv7l and /dev/null differ diff --git a/src/linux-glibc-detectors/glibc-detector-i686 b/src/linux-glibc-detectors/glibc-detector-i686 deleted file mode 100644 index 024e33a..0000000 Binary files a/src/linux-glibc-detectors/glibc-detector-i686 and /dev/null differ diff --git a/src/linux-glibc-detectors/glibc-detector-ppc64le b/src/linux-glibc-detectors/glibc-detector-ppc64le deleted file mode 100644 index 33bfe50..0000000 Binary files a/src/linux-glibc-detectors/glibc-detector-ppc64le and /dev/null differ diff --git a/src/linux-glibc-detectors/glibc-detector-s390x b/src/linux-glibc-detectors/glibc-detector-s390x deleted file mode 100644 index d2c2a24..0000000 Binary files a/src/linux-glibc-detectors/glibc-detector-s390x and /dev/null differ diff --git a/src/linux-glibc-detectors/glibc-detector-x86_64 b/src/linux-glibc-detectors/glibc-detector-x86_64 deleted file mode 100644 index d478bf0..0000000 Binary files a/src/linux-glibc-detectors/glibc-detector-x86_64 and /dev/null differ diff --git a/src/linux-glibc-detectors/glibc-detector.c b/src/linux-glibc-detectors/glibc-detector.c deleted file mode 100644 index 7060e6a..0000000 --- a/src/linux-glibc-detectors/glibc-detector.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Taken from https://github.com/njsmith/posy/blob/61ff56c68a6aeff744b274170c32f59ac9ac20e1/src/platform_tags/linux-glibc-detectors/glibc-detector.c - * Licensed under MIT/APACHE-2.0 - - * A tiny C program that tries to fetch the version of glibc that it's run - * against. - */ - -#include -#include - -int main(int argc, char** argv) -{ - puts(gnu_get_libc_version()); - return 0; -} diff --git a/src/linux-glibc-detectors/rebuild.py b/src/linux-glibc-detectors/rebuild.py deleted file mode 100644 index 27437d3..0000000 --- a/src/linux-glibc-detectors/rebuild.py +++ /dev/null @@ -1,62 +0,0 @@ -# Taken from https://github.com/njsmith/posy/blob/61ff56c68a6aeff744b274170c32f59ac9ac20e1/src/platform_tags/linux-glibc-detectors/rebuild.py -# Licensed under MIT/APACHE-2.0 - -# Note: on Ubuntu, `apt install qemu-user-static` makes it possible to run this script -# with all arches. -# -# To rebuild specific versions: -# python rebuild.py x86_64 i686 -# -# To rebuild all versions: -# python rebuild.py - -# This image uses glibc 2.28. But, it has lots of arches available, it runs well under -# qemu-user-static for me (as opposed to centos:7, where yum segfaults on arm), and -# based on 'readelf' output + experiments I believe that the particular symbols we're -# using are stable enough that 2.28 should still work fine. And if I'm wrong we can -# always fix it :-) -BASE_IMAGE = "debian:buster-slim" - -# docker platforms from the "OS/ARCH" column at -# https://hub.docker.com/_/debian?tab=tags&page=1&ordering=last_updated&name=buster -PY_ARCH_TO_DOCKER_PLATFORM = { - "x86_64": "linux/amd64", - "i686": "linux/386", - "aarch64": "linux/arm64/v8", - "armv7l": "linux/arm/v7", - "ppc64le": "linux/ppc64le", - "s390x": "linux/s390x", -} - -import sys -import os -import subprocess - -py_arches = sys.argv[1:] -if not py_arches: - py_arches = PY_ARCH_TO_DOCKER_PLATFORM.keys() - -for py_arch in py_arches: - print(f"-- Building for {py_arch} --") - docker_arch = PY_ARCH_TO_DOCKER_PLATFORM[py_arch] - exec_name = f"glibc-detector-{py_arch}" - - subprocess.run( - [ - "docker", "run", "--rm", "-it", - f"--platform={docker_arch}", - "-v", f"{os.getcwd()}:/host", - BASE_IMAGE, - "bash", "-c", - f""" - set -euxo pipefail - cd /host - #yum install -y gcc - apt update && apt install -y gcc - gcc -Os glibc-detector.c -o {exec_name} - strip {exec_name} - ./{exec_name} - """ - ], - check=True - ) diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8afbdf1 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("{:?}", libc_detector::libc_version()); +}