Skip to content

Commit 2efb6a9

Browse files
cli: allow downloading legacy servers for older glibc versions (microsoft#204194)
* cli: allow downloading legacy servers for older glibc versions Refs microsoft#206790 * chore: update asset name --------- Co-authored-by: deepak1556 <[email protected]>
1 parent 3d84abb commit 2efb6a9

File tree

3 files changed

+82
-47
lines changed

3 files changed

+82
-47
lines changed

cli/src/update_service.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,11 @@ pub enum Platform {
209209
LinuxAlpineX64,
210210
LinuxAlpineARM64,
211211
LinuxX64,
212+
LinuxX64Legacy,
212213
LinuxARM64,
214+
LinuxARM64Legacy,
213215
LinuxARM32,
216+
LinuxARM32Legacy,
214217
DarwinX64,
215218
DarwinARM64,
216219
WindowsX64,
@@ -237,8 +240,11 @@ impl Platform {
237240
Platform::LinuxAlpineARM64 => "server-alpine-arm64",
238241
Platform::LinuxAlpineX64 => "server-linux-alpine",
239242
Platform::LinuxX64 => "server-linux-x64",
243+
Platform::LinuxX64Legacy => "server-linux-legacy-x64",
240244
Platform::LinuxARM64 => "server-linux-arm64",
245+
Platform::LinuxARM64Legacy => "server-linux-legacy-arm64",
241246
Platform::LinuxARM32 => "server-linux-armhf",
247+
Platform::LinuxARM32Legacy => "server-linux-legacy-armhf",
242248
Platform::DarwinX64 => "server-darwin",
243249
Platform::DarwinARM64 => "server-darwin-arm64",
244250
Platform::WindowsX64 => "server-win32-x64",
@@ -253,8 +259,11 @@ impl Platform {
253259
Platform::LinuxAlpineARM64 => "cli-alpine-arm64",
254260
Platform::LinuxAlpineX64 => "cli-alpine-x64",
255261
Platform::LinuxX64 => "cli-linux-x64",
262+
Platform::LinuxX64Legacy => "cli-linux-x64",
256263
Platform::LinuxARM64 => "cli-linux-arm64",
264+
Platform::LinuxARM64Legacy => "cli-linux-arm64",
257265
Platform::LinuxARM32 => "cli-linux-armhf",
266+
Platform::LinuxARM32Legacy => "cli-linux-armhf",
258267
Platform::DarwinX64 => "cli-darwin-x64",
259268
Platform::DarwinARM64 => "cli-darwin-arm64",
260269
Platform::WindowsARM64 => "cli-win32-arm64",
@@ -309,8 +318,11 @@ impl fmt::Display for Platform {
309318
Platform::LinuxAlpineARM64 => "LinuxAlpineARM64",
310319
Platform::LinuxAlpineX64 => "LinuxAlpineX64",
311320
Platform::LinuxX64 => "LinuxX64",
321+
Platform::LinuxX64Legacy => "LinuxX64Legacy",
312322
Platform::LinuxARM64 => "LinuxARM64",
323+
Platform::LinuxARM64Legacy => "LinuxARM64Legacy",
313324
Platform::LinuxARM32 => "LinuxARM32",
325+
Platform::LinuxARM32Legacy => "LinuxARM32Legacy",
314326
Platform::DarwinX64 => "DarwinX64",
315327
Platform::DarwinARM64 => "DarwinARM64",
316328
Platform::WindowsX64 => "WindowsX64",

cli/src/util/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ pub enum CodeError {
471471

472472
#[error("platform not currently supported: {0}")]
473473
UnsupportedPlatform(String),
474-
#[error("This machine does not meet {name}'s prerequisites, expected either...: {bullets}")]
474+
#[error("This machine does not meet {name}'s prerequisites, expected either...\n{bullets}")]
475475
PrerequisitesFailed { name: &'static str, bullets: String },
476476
#[error("failed to spawn process: {0:?}")]
477477
ProcessSpawnFailed(std::io::Error),

cli/src/util/prereqs.rs

Lines changed: 69 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*--------------------------------------------------------------------------------------------*/
55
use std::cmp::Ordering;
66

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

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

69-
if (gnu_a.is_ok() && gnu_b.is_ok()) || is_nixos {
70-
return Ok(if cfg!(target_arch = "x86_64") {
71-
Platform::LinuxX64
72-
} else if cfg!(target_arch = "arm") {
73-
Platform::LinuxARM32
74-
} else {
75-
Platform::LinuxARM64
76-
});
77-
}
70+
match (&gnu_a, &gnu_b, is_nixos) {
71+
(Ok(false), Ok(false), _) | (_, _, true) => {
72+
return Ok(if cfg!(target_arch = "x86_64") {
73+
Platform::LinuxX64
74+
} else if cfg!(target_arch = "arm") {
75+
Platform::LinuxARM32
76+
} else {
77+
Platform::LinuxARM64
78+
});
79+
}
80+
(Ok(_), Ok(_), _) => {
81+
return Ok(if cfg!(target_arch = "x86_64") {
82+
Platform::LinuxX64Legacy
83+
} else if cfg!(target_arch = "arm") {
84+
Platform::LinuxARM32Legacy
85+
} else {
86+
Platform::LinuxARM64Legacy
87+
});
88+
}
89+
_ => {}
90+
};
7891

7992
if or_musl.is_ok() {
8093
return Ok(if cfg!(target_arch = "x86_64") {
@@ -126,8 +139,9 @@ async fn check_musl_interpreter() -> Result<(), String> {
126139
Ok(())
127140
}
128141

129-
#[allow(dead_code)]
130-
async fn check_glibc_version() -> Result<(), String> {
142+
/// Checks the glibc version, returns "true" if the legacy server is required.
143+
#[cfg(target_os = "linux")]
144+
async fn check_glibc_version() -> Result<bool, String> {
131145
#[cfg(target_env = "gnu")]
132146
let version = {
133147
let v = unsafe { libc::gnu_get_libc_version() };
@@ -137,15 +151,17 @@ async fn check_glibc_version() -> Result<(), String> {
137151
};
138152
#[cfg(not(target_env = "gnu"))]
139153
let version = {
140-
capture_command("ldd", ["--version"])
154+
super::command::capture_command("ldd", ["--version"])
141155
.await
142156
.ok()
143157
.and_then(|o| extract_ldd_version(&o.stdout))
144158
};
145159

146160
if let Some(v) = version {
147161
return if v >= *MIN_LDD_VERSION {
148-
Ok(())
162+
Ok(false)
163+
} else if v >= *MIN_LEGACY_LDD_VERSION {
164+
Ok(true)
149165
} else {
150166
Err(format!(
151167
"find GLIBC >= {} (but found {} instead) for GNU environments",
@@ -154,7 +170,7 @@ async fn check_glibc_version() -> Result<(), String> {
154170
};
155171
}
156172

157-
Ok(())
173+
Ok(false)
158174
}
159175

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

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

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

214-
#[allow(dead_code)]
215-
fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<(), String> {
216-
let all_versions: Vec<SimpleSemver> = LIBSTD_CXX_VERSION_RE
231+
#[cfg(target_os = "linux")]
232+
fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<bool, String> {
233+
let max_version = LIBSTD_CXX_VERSION_RE
217234
.captures_iter(&contents)
218235
.map(|m| SimpleSemver {
219236
major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())),
220237
minor: m.get(2).map_or(0, |s| u32_from_bytes(s.as_bytes())),
221238
patch: m.get(3).map_or(0, |s| u32_from_bytes(s.as_bytes())),
222239
})
223-
.collect();
240+
.max();
224241

225-
if !all_versions.iter().any(|v| &*MIN_CXX_VERSION >= v) {
226-
return Err(format!(
227-
"find GLIBCXX >= {} (but found {} instead) for GNU environments",
228-
*MIN_CXX_VERSION,
229-
all_versions
230-
.iter()
231-
.map(String::from)
232-
.collect::<Vec<String>>()
233-
.join(", ")
234-
));
242+
if let Some(max_version) = &max_version {
243+
if max_version >= &*MIN_CXX_VERSION {
244+
return Ok(false);
245+
}
246+
247+
if max_version >= &*MIN_LEGACY_CXX_VERSION {
248+
return Ok(true);
249+
}
235250
}
236251

237-
Ok(())
252+
Err(format!(
253+
"find GLIBCXX >= {} (but found {} instead) for GNU environments",
254+
*MIN_CXX_VERSION,
255+
max_version
256+
.as_ref()
257+
.map(String::from)
258+
.unwrap_or("none".to_string())
259+
))
238260
}
239261

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

280+
#[allow(dead_code)]
258281
fn extract_libstd_from_ldconfig(output: &[u8]) -> Option<String> {
259282
String::from_utf8_lossy(output)
260283
.lines()
@@ -326,12 +349,12 @@ mod tests {
326349
#[test]
327350
fn test_extract_libstd_from_ldconfig() {
328351
let actual = "
329-
libstoken.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstoken.so.1
330-
libstemmer.so.0d (libc6,x86-64) => /lib/x86_64-linux-gnu/libstemmer.so.0d
331-
libstdc++.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstdc++.so.6
332-
libstartup-notification-1.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstartup-notification-1.so.0
333-
libssl3.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libssl3.so
334-
".to_owned().into_bytes();
352+
libstoken.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstoken.so.1
353+
libstemmer.so.0d (libc6,x86-64) => /lib/x86_64-linux-gnu/libstemmer.so.0d
354+
libstdc++.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstdc++.so.6
355+
libstartup-notification-1.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstartup-notification-1.so.0
356+
libssl3.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libssl3.so
357+
".to_owned().into_bytes();
335358

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

0 commit comments

Comments
 (0)