diff --git a/cli/src/update_service.rs b/cli/src/update_service.rs index d218e4a1333..4bec13d6e86 100644 --- a/cli/src/update_service.rs +++ b/cli/src/update_service.rs @@ -209,8 +209,11 @@ pub enum Platform { LinuxAlpineX64, LinuxAlpineARM64, LinuxX64, + LinuxX64Legacy, LinuxARM64, + LinuxARM64Legacy, LinuxARM32, + LinuxARM32Legacy, DarwinX64, DarwinARM64, WindowsX64, @@ -237,8 +240,11 @@ impl Platform { Platform::LinuxAlpineARM64 => "server-alpine-arm64", Platform::LinuxAlpineX64 => "server-linux-alpine", Platform::LinuxX64 => "server-linux-x64", + Platform::LinuxX64Legacy => "server-linux-legacy-x64", Platform::LinuxARM64 => "server-linux-arm64", + Platform::LinuxARM64Legacy => "server-linux-legacy-arm64", Platform::LinuxARM32 => "server-linux-armhf", + Platform::LinuxARM32Legacy => "server-linux-legacy-armhf", Platform::DarwinX64 => "server-darwin", Platform::DarwinARM64 => "server-darwin-arm64", Platform::WindowsX64 => "server-win32-x64", @@ -253,8 +259,11 @@ impl Platform { Platform::LinuxAlpineARM64 => "cli-alpine-arm64", Platform::LinuxAlpineX64 => "cli-alpine-x64", Platform::LinuxX64 => "cli-linux-x64", + Platform::LinuxX64Legacy => "cli-linux-x64", Platform::LinuxARM64 => "cli-linux-arm64", + Platform::LinuxARM64Legacy => "cli-linux-arm64", Platform::LinuxARM32 => "cli-linux-armhf", + Platform::LinuxARM32Legacy => "cli-linux-armhf", Platform::DarwinX64 => "cli-darwin-x64", Platform::DarwinARM64 => "cli-darwin-arm64", Platform::WindowsARM64 => "cli-win32-arm64", @@ -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", diff --git a/cli/src/util/errors.rs b/cli/src/util/errors.rs index 0659a0d1781..fc706199aab 100644 --- a/cli/src/util/errors.rs +++ b/cli/src/util/errors.rs @@ -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), diff --git a/cli/src/util/prereqs.rs b/cli/src/util/prereqs.rs index b22fd469fac..20a5bc94b37 100644 --- a/cli/src/util/prereqs.rs +++ b/cli/src/util/prereqs.rs @@ -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; @@ -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"; @@ -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") { @@ -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 { #[cfg(target_env = "gnu")] let version = { let v = unsafe { libc::gnu_get_libc_version() }; @@ -137,7 +151,7 @@ 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)) @@ -145,7 +159,9 @@ async fn check_glibc_version() -> Result<(), String> { 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", @@ -154,7 +170,7 @@ async fn check_glibc_version() -> Result<(), String> { }; } - Ok(()) + Ok(false) } /// Check for nixos to avoid mandating glibc versions. See: @@ -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 { let mut libstdc_path: Option = None; #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] @@ -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)); @@ -211,30 +228,35 @@ async fn check_glibcxx_version() -> Result<(), String> { } } -#[allow(dead_code)] -fn check_for_sufficient_glibcxx_versions(contents: Vec) -> Result<(), String> { - let all_versions: Vec = LIBSTD_CXX_VERSION_RE +#[cfg(target_os = "linux")] +fn check_for_sufficient_glibcxx_versions(contents: Vec) -> Result { + 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::>() - .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)] @@ -255,6 +277,7 @@ fn extract_generic_version(output: &str) -> Option { }) } +#[allow(dead_code)] fn extract_libstd_from_ldconfig(output: &[u8]) -> Option { String::from_utf8_lossy(output) .lines() @@ -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), @@ -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();