mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-09 18:12:07 +00:00
platform-host: check /bin/sh, then /bin/dash and then /bin/ls (#1818)
Previously, we were only checking /bin/sh. While that works in most cases, it seems like there are still scenarios where /bin/sh isn't an executable itself, and is instead just a shell script that calls /bin/dash. (See #1810 for example.) In this PR, we make the `ld` detection a bit more robust by trying multiple paths. As with previous changes, we emit copious logs to help debug this in the future. It's not totally clear how to test this. I'm not sure how to reproduce the environment mentions in #1810 specifically since it seems like an internal variant of WSL Ubuntu. Fixes #1810
This commit is contained in:
parent
fac9d843dc
commit
deef6c102d
1 changed files with 40 additions and 8 deletions
|
@ -186,18 +186,50 @@ fn musl_ld_output_to_version(kind: &str, output: &[u8]) -> Result<Os, PlatformEr
|
|||
Ok(Os::Musllinux { major, minor })
|
||||
}
|
||||
|
||||
/// Find musl libc path from executable's ELF header.
|
||||
/// Find musl ld path from executable's ELF header.
|
||||
fn find_ld_path() -> Result<PathBuf, PlatformError> {
|
||||
let buffer = fs::read("/bin/sh")?;
|
||||
let error_str = "Couldn't parse /bin/sh for detecting the ld version";
|
||||
let elf = Elf::parse(&buffer)
|
||||
.map_err(|err| PlatformError::OsVersionDetectionError(format!("{error_str}: {err}")))?;
|
||||
// At first, we just looked for /bin/ls. But on some Linux distros, /bin/ls
|
||||
// is a shell script that just calls /usr/bin/ls. So we switched to looking
|
||||
// at /bin/sh. But apparently in some environments, /bin/sh is itself just
|
||||
// a shell script that calls /bin/dash. So... We just try a few different
|
||||
// paths. In most cases, /bin/sh should work.
|
||||
//
|
||||
// See: https://github.com/astral-sh/uv/pull/1493
|
||||
// See: https://github.com/astral-sh/uv/issues/1810
|
||||
let attempts = ["/bin/sh", "/bin/dash", "/bin/ls"];
|
||||
for path in attempts {
|
||||
match find_ld_path_at(path) {
|
||||
Ok(ld_path) => return Ok(ld_path),
|
||||
Err(err) => {
|
||||
tracing::trace!("attempt to find `ld` path at {path} failed: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(PlatformError::OsVersionDetectionError(format!(
|
||||
"Couldn't parse ELF interpreter path out of any of the following paths: {joined}",
|
||||
joined = attempts.join(", "),
|
||||
)))
|
||||
}
|
||||
|
||||
/// Attempt to find the path to the `ld` executable by
|
||||
/// ELF parsing the given path. If this fails for any
|
||||
/// reason, then an error is returned.
|
||||
fn find_ld_path_at(path: impl AsRef<Path>) -> Result<PathBuf, PlatformError> {
|
||||
let path = path.as_ref();
|
||||
let buffer = fs::read(path)?;
|
||||
let elf = Elf::parse(&buffer).map_err(|err| {
|
||||
PlatformError::OsVersionDetectionError(format!(
|
||||
"Couldn't parse {path} as an ELF file: {err}",
|
||||
path = path.display()
|
||||
))
|
||||
})?;
|
||||
if let Some(elf_interpreter) = elf.interpreter {
|
||||
Ok(PathBuf::from(elf_interpreter))
|
||||
} else {
|
||||
Err(PlatformError::OsVersionDetectionError(
|
||||
error_str.to_string(),
|
||||
))
|
||||
Err(PlatformError::OsVersionDetectionError(format!(
|
||||
"Couldn't find ELF interpreter path from {path}",
|
||||
path = path.display()
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue