mirror of
https://github.com/wez/wezterm.git
synced 2024-09-11 14:25:57 +03:00
pty: improve unix path searching
We were unconditionally checking against the cwd for relative paths, which isn't conformant to posix's path search logic. This commit revises the search to only do so if the requested executable starts with either a `.` or `..` path component. In addition, we now also allow for path components in $PATH to specify cwd-relative paths. refs: #4920
This commit is contained in:
parent
17dadbeb1e
commit
c4113906f9
@ -6,6 +6,7 @@ use std::collections::BTreeMap;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::path::{Component, Path};
|
||||
|
||||
/// Used to deal with Windows having case-insensitive environment variables.
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
@ -40,7 +41,6 @@ impl EnvEntry {
|
||||
fn get_shell() -> String {
|
||||
use nix::unistd::{access, AccessFlags};
|
||||
use std::ffi::CStr;
|
||||
use std::path::Path;
|
||||
use std::str;
|
||||
|
||||
let ent = unsafe { libc::getpwuid(libc::getuid()) };
|
||||
@ -413,28 +413,40 @@ impl CommandBuilder {
|
||||
|
||||
fn search_path(&self, exe: &OsStr, cwd: &OsStr) -> anyhow::Result<OsString> {
|
||||
use nix::unistd::{access, AccessFlags};
|
||||
use std::path::Path;
|
||||
|
||||
let exe_path: &Path = exe.as_ref();
|
||||
if exe_path.is_relative() {
|
||||
let cwd: &Path = cwd.as_ref();
|
||||
let abs_path = cwd.join(exe_path);
|
||||
|
||||
let mut errors = vec![];
|
||||
|
||||
if abs_path.is_dir() {
|
||||
errors.push(format!("{} exists but is a directory", abs_path.display()));
|
||||
} else if access(&abs_path, AccessFlags::X_OK).is_ok() {
|
||||
return Ok(abs_path.into_os_string());
|
||||
} else if access(&abs_path, AccessFlags::F_OK).is_ok() {
|
||||
errors.push(format!(
|
||||
"{} exists but is not executable",
|
||||
// If the requested executable is explicitly relative to cwd,
|
||||
// then check only there.
|
||||
if is_cwd_relative_path(exe_path) {
|
||||
let abs_path = cwd.join(exe_path);
|
||||
|
||||
if abs_path.is_dir() {
|
||||
anyhow::bail!(
|
||||
"Unable to spawn {} because it is a directory",
|
||||
abs_path.display()
|
||||
);
|
||||
} else if access(&abs_path, AccessFlags::X_OK).is_ok() {
|
||||
return Ok(abs_path.into_os_string());
|
||||
} else if access(&abs_path, AccessFlags::F_OK).is_ok() {
|
||||
anyhow::bail!(
|
||||
"Unable to spawn {} because it is not executable",
|
||||
abs_path.display()
|
||||
);
|
||||
}
|
||||
|
||||
anyhow::bail!(
|
||||
"Unable to spawn {} because it does not exist",
|
||||
abs_path.display()
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(path) = self.resolve_path() {
|
||||
for path in std::env::split_paths(&path) {
|
||||
let candidate = path.join(&exe);
|
||||
let candidate = cwd.join(&path).join(&exe);
|
||||
|
||||
if candidate.is_dir() {
|
||||
errors.push(format!("{} exists but is a directory", candidate.display()));
|
||||
@ -733,10 +745,27 @@ impl CommandBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the path begins with `./` or `../`
|
||||
fn is_cwd_relative_path<P: AsRef<Path>>(p: P) -> bool {
|
||||
matches!(
|
||||
p.as_ref().components().next(),
|
||||
Some(Component::CurDir | Component::ParentDir)
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cwd_relative() {
|
||||
assert!(is_cwd_relative_path("."));
|
||||
assert!(is_cwd_relative_path("./foo"));
|
||||
assert!(is_cwd_relative_path("../foo"));
|
||||
assert!(!is_cwd_relative_path("foo"));
|
||||
assert!(!is_cwd_relative_path("/foo"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_env() {
|
||||
let mut cmd = CommandBuilder::new("dummy");
|
||||
|
Loading…
Reference in New Issue
Block a user