Skip to content

Commit

Permalink
cli: allow downloading legacy servers for older glibc versions
Browse files Browse the repository at this point in the history
Refs #206790
  • Loading branch information
connor4312 authored and deepak1556 committed Mar 21, 2024
1 parent 09d5f4e commit c6866f6
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 47 deletions.
12 changes: 12 additions & 0 deletions cli/src/update_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,11 @@ pub enum Platform {
LinuxAlpineX64,
LinuxAlpineARM64,
LinuxX64,
LinuxX64Legacy,
LinuxARM64,
LinuxARM64Legacy,
LinuxARM32,
LinuxARM32Legacy,
DarwinX64,
DarwinARM64,
WindowsX64,
Expand All @@ -237,8 +240,11 @@ impl Platform {
Platform::LinuxAlpineARM64 => "server-alpine-arm64",
Platform::LinuxAlpineX64 => "server-linux-alpine",
Platform::LinuxX64 => "server-linux-x64",
Platform::LinuxX64Legacy => "legacy-server-linux-x64",
Platform::LinuxARM64 => "server-linux-arm64",
Platform::LinuxARM64Legacy => "legacy-server-linux-arm64",
Platform::LinuxARM32 => "server-linux-armhf",
Platform::LinuxARM32Legacy => "legacy-server-linux-armhf",
Platform::DarwinX64 => "server-darwin",
Platform::DarwinARM64 => "server-darwin-arm64",
Platform::WindowsX64 => "server-win32-x64",
Expand All @@ -253,8 +259,11 @@ impl Platform {
Platform::LinuxAlpineARM64 => "cli-alpine-arm64",
Platform::LinuxAlpineX64 => "cli-alpine-x64",
Platform::LinuxX64 => "cli-linux-x64",
Platform::LinuxX64Legacy => "cli-legacy-linux-x64",
Platform::LinuxARM64 => "cli-linux-arm64",
Platform::LinuxARM64Legacy => "cli-legacy-linux-arm64",
Platform::LinuxARM32 => "cli-linux-armhf",
Platform::LinuxARM32Legacy => "cli-legacy-linux-armhf",
Platform::DarwinX64 => "cli-darwin-x64",
Platform::DarwinARM64 => "cli-darwin-arm64",
Platform::WindowsARM64 => "cli-win32-arm64",
Expand Down Expand Up @@ -309,8 +318,11 @@ impl fmt::Display for Platform {
Platform::LinuxAlpineARM64 => "LinuxAlpineARM64",
Platform::LinuxAlpineX64 => "LinuxAlpineX64",
Platform::LinuxX64 => "LinuxX64",
Platform::LinuxX64Legacy => "LinuxX64Legacy",
Platform::LinuxARM64 => "LinuxARM64",
Platform::LinuxARM64Legacy => "LinuxARM64Legacy",
Platform::LinuxARM32 => "LinuxARM32",
Platform::LinuxARM32Legacy => "LinuxARM32Legacy",
Platform::DarwinX64 => "DarwinX64",
Platform::DarwinARM64 => "DarwinARM64",
Platform::WindowsX64 => "WindowsX64",
Expand Down
2 changes: 1 addition & 1 deletion cli/src/util/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ pub enum CodeError {

#[error("platform not currently supported: {0}")]
UnsupportedPlatform(String),
#[error("This machine does not meet {name}'s prerequisites, expected either...: {bullets}")]
#[error("This machine does not meet {name}'s prerequisites, expected either...\n{bullets}")]
PrerequisitesFailed { name: &'static str, bullets: String },
#[error("failed to spawn process: {0:?}")]
ProcessSpawnFailed(std::io::Error),
Expand Down
115 changes: 69 additions & 46 deletions cli/src/util/prereqs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
use std::cmp::Ordering;

use super::command::capture_command;
use crate::constants::QUALITYLESS_SERVER_NAME;
use crate::update_service::Platform;
use lazy_static::lazy_static;
Expand All @@ -20,8 +19,10 @@ lazy_static! {
static ref GENERIC_VERSION_RE: Regex = Regex::new(r"^([0-9]+)\.([0-9]+)$").unwrap();
static ref LIBSTD_CXX_VERSION_RE: BinRegex =
BinRegex::new(r"GLIBCXX_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?").unwrap();
static ref MIN_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 19);
static ref MIN_LDD_VERSION: SimpleSemver = SimpleSemver::new(2, 17, 0);
static ref MIN_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 25);
static ref MIN_LEGACY_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 19);
static ref MIN_LDD_VERSION: SimpleSemver = SimpleSemver::new(2, 28, 0);
static ref MIN_LEGACY_LDD_VERSION: SimpleSemver = SimpleSemver::new(2, 17, 0);
}

const NIXOS_TEST_PATH: &str = "/etc/NIXOS";
Expand Down Expand Up @@ -63,18 +64,30 @@ impl PreReqChecker {
} else {
println!("!!! WARNING: Skipping server pre-requisite check !!!");
println!("!!! Server stability is not guaranteed. Proceed at your own risk. !!!");
(Ok(()), Ok(()))
(Ok(false), Ok(false))
};

if (gnu_a.is_ok() && gnu_b.is_ok()) || is_nixos {
return Ok(if cfg!(target_arch = "x86_64") {
Platform::LinuxX64
} else if cfg!(target_arch = "arm") {
Platform::LinuxARM32
} else {
Platform::LinuxARM64
});
}
match (&gnu_a, &gnu_b, is_nixos) {
(Ok(false), Ok(false), _) | (_, _, true) => {
return Ok(if cfg!(target_arch = "x86_64") {
Platform::LinuxX64
} else if cfg!(target_arch = "arm") {
Platform::LinuxARM32
} else {
Platform::LinuxARM64
});
}
(Ok(_), Ok(_), _) => {
return Ok(if cfg!(target_arch = "x86_64") {
Platform::LinuxX64Legacy
} else if cfg!(target_arch = "arm") {
Platform::LinuxARM32Legacy
} else {
Platform::LinuxARM64Legacy
});
}
_ => {}
};

if or_musl.is_ok() {
return Ok(if cfg!(target_arch = "x86_64") {
Expand Down Expand Up @@ -126,8 +139,9 @@ async fn check_musl_interpreter() -> Result<(), String> {
Ok(())
}

#[allow(dead_code)]
async fn check_glibc_version() -> Result<(), String> {
/// Checks the glibc version, returns "true" if the legacy server is required.
#[cfg(target_os = "linux")]
async fn check_glibc_version() -> Result<bool, String> {
#[cfg(target_env = "gnu")]
let version = {
let v = unsafe { libc::gnu_get_libc_version() };
Expand All @@ -137,15 +151,17 @@ async fn check_glibc_version() -> Result<(), String> {
};
#[cfg(not(target_env = "gnu"))]
let version = {
capture_command("ldd", ["--version"])
super::command::capture_command("ldd", ["--version"])
.await
.ok()
.and_then(|o| extract_ldd_version(&o.stdout))
};

if let Some(v) = version {
return if v >= *MIN_LDD_VERSION {
Ok(())
Ok(false)
} else if v >= *MIN_LEGACY_LDD_VERSION {
Ok(true)
} else {
Err(format!(
"find GLIBC >= {} (but found {} instead) for GNU environments",
Expand All @@ -154,7 +170,7 @@ async fn check_glibc_version() -> Result<(), String> {
};
}

Ok(())
Ok(false)
}

/// Check for nixos to avoid mandating glibc versions. See:
Expand All @@ -180,8 +196,9 @@ pub async fn skip_requirements_check() -> bool {
false
}

#[allow(dead_code)]
async fn check_glibcxx_version() -> Result<(), String> {
/// Checks the glibc++ version, returns "true" if the legacy server is required.
#[cfg(target_os = "linux")]
async fn check_glibcxx_version() -> Result<bool, String> {
let mut libstdc_path: Option<String> = None;

#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
Expand All @@ -193,7 +210,7 @@ async fn check_glibcxx_version() -> Result<(), String> {
if fs::metadata(DEFAULT_LIB_PATH).await.is_ok() {
libstdc_path = Some(DEFAULT_LIB_PATH.to_owned());
} else if fs::metadata(LDCONFIG_PATH).await.is_ok() {
libstdc_path = capture_command(LDCONFIG_PATH, ["-p"])
libstdc_path = super::command::capture_command(LDCONFIG_PATH, ["-p"])
.await
.ok()
.and_then(|o| extract_libstd_from_ldconfig(&o.stdout));
Expand All @@ -211,30 +228,35 @@ async fn check_glibcxx_version() -> Result<(), String> {
}
}

#[allow(dead_code)]
fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<(), String> {
let all_versions: Vec<SimpleSemver> = LIBSTD_CXX_VERSION_RE
#[cfg(target_os = "linux")]
fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<bool, String> {
let max_version = LIBSTD_CXX_VERSION_RE
.captures_iter(&contents)
.map(|m| SimpleSemver {
major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())),
minor: m.get(2).map_or(0, |s| u32_from_bytes(s.as_bytes())),
patch: m.get(3).map_or(0, |s| u32_from_bytes(s.as_bytes())),
})
.collect();
.max();

if !all_versions.iter().any(|v| &*MIN_CXX_VERSION >= v) {
return Err(format!(
"find GLIBCXX >= {} (but found {} instead) for GNU environments",
*MIN_CXX_VERSION,
all_versions
.iter()
.map(String::from)
.collect::<Vec<String>>()
.join(", ")
));
if let Some(max_version) = &max_version {
if max_version >= &*MIN_CXX_VERSION {
return Ok(false);
}

if max_version >= &*MIN_LEGACY_CXX_VERSION {
return Ok(true);
}
}

Ok(())
Err(format!(
"find GLIBCXX >= {} (but found {} instead) for GNU environments",
*MIN_CXX_VERSION,
max_version
.as_ref()
.map(String::from)
.unwrap_or("none".to_string())
))
}

#[allow(dead_code)]
Expand All @@ -255,6 +277,7 @@ fn extract_generic_version(output: &str) -> Option<SimpleSemver> {
})
}

#[allow(dead_code)]
fn extract_libstd_from_ldconfig(output: &[u8]) -> Option<String> {
String::from_utf8_lossy(output)
.lines()
Expand Down Expand Up @@ -326,12 +349,12 @@ mod tests {
#[test]
fn test_extract_libstd_from_ldconfig() {
let actual = "
libstoken.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstoken.so.1
libstemmer.so.0d (libc6,x86-64) => /lib/x86_64-linux-gnu/libstemmer.so.0d
libstdc++.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstdc++.so.6
libstartup-notification-1.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstartup-notification-1.so.0
libssl3.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libssl3.so
".to_owned().into_bytes();
libstoken.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstoken.so.1
libstemmer.so.0d (libc6,x86-64) => /lib/x86_64-linux-gnu/libstemmer.so.0d
libstdc++.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstdc++.so.6
libstartup-notification-1.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstartup-notification-1.so.0
libssl3.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libssl3.so
".to_owned().into_bytes();

assert_eq!(
extract_libstd_from_ldconfig(&actual),
Expand All @@ -358,10 +381,10 @@ mod tests {
#[test]
fn check_for_sufficient_glibcxx_versions() {
let actual = "ldd (Ubuntu GLIBC 2.31-0ubuntu9.7) 2.31
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper."
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper."
.to_owned()
.into_bytes();

Expand Down

0 comments on commit c6866f6

Please # to comment.