about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/sys/unix/process/process_common.rs33
-rw-r--r--library/std/src/sys/unix/process/process_common/tests.rs24
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs4
3 files changed, 60 insertions, 1 deletions
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index 6985f1d7830..2834ee0ace8 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -92,6 +92,7 @@ pub struct Command {
     argv: Argv,
     env: CommandEnv,
 
+    program_kind: ProgramKind,
     cwd: Option<CString>,
     uid: Option<uid_t>,
     gid: Option<gid_t>,
@@ -148,15 +149,40 @@ pub enum Stdio {
     Fd(FileDesc),
 }
 
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum ProgramKind {
+    /// A program that would be looked up on the PATH (e.g. `ls`)
+    PathLookup,
+    /// A relative path (e.g. `my-dir/foo`, `../foo`, `./foo`)
+    Relative,
+    /// An absolute path.
+    Absolute,
+}
+
+impl ProgramKind {
+    fn new(program: &OsStr) -> Self {
+        if program.bytes().starts_with(b"/") {
+            Self::Absolute
+        } else if program.bytes().contains(&b'/') {
+            // If the program has more than one component in it, it is a relative path.
+            Self::Relative
+        } else {
+            Self::PathLookup
+        }
+    }
+}
+
 impl Command {
     #[cfg(not(target_os = "linux"))]
     pub fn new(program: &OsStr) -> Command {
         let mut saw_nul = false;
+        let program_kind = ProgramKind::new(program.as_ref());
         let program = os2c(program, &mut saw_nul);
         Command {
             argv: Argv(vec![program.as_ptr(), ptr::null()]),
             args: vec![program.clone()],
             program,
+            program_kind,
             env: Default::default(),
             cwd: None,
             uid: None,
@@ -174,11 +200,13 @@ impl Command {
     #[cfg(target_os = "linux")]
     pub fn new(program: &OsStr) -> Command {
         let mut saw_nul = false;
+        let program_kind = ProgramKind::new(program.as_ref());
         let program = os2c(program, &mut saw_nul);
         Command {
             argv: Argv(vec![program.as_ptr(), ptr::null()]),
             args: vec![program.clone()],
             program,
+            program_kind,
             env: Default::default(),
             cwd: None,
             uid: None,
@@ -254,6 +282,11 @@ impl Command {
         OsStr::from_bytes(self.program.as_bytes())
     }
 
+    #[allow(dead_code)]
+    pub fn get_program_kind(&self) -> ProgramKind {
+        self.program_kind
+    }
+
     pub fn get_args(&self) -> CommandArgs<'_> {
         let mut iter = self.args.iter();
         iter.next();
diff --git a/library/std/src/sys/unix/process/process_common/tests.rs b/library/std/src/sys/unix/process/process_common/tests.rs
index 1956b3692a7..d176b3401c0 100644
--- a/library/std/src/sys/unix/process/process_common/tests.rs
+++ b/library/std/src/sys/unix/process/process_common/tests.rs
@@ -122,3 +122,27 @@ fn test_process_group_no_posix_spawn() {
         t!(cat.wait());
     }
 }
+
+#[test]
+fn test_program_kind() {
+    let vectors = &[
+        ("foo", ProgramKind::PathLookup),
+        ("foo.out", ProgramKind::PathLookup),
+        ("./foo", ProgramKind::Relative),
+        ("../foo", ProgramKind::Relative),
+        ("dir/foo", ProgramKind::Relative),
+        // Note that paths on Unix can't contain / in them, so this is actually the directory "fo\\"
+        // followed by the file "o".
+        ("fo\\/o", ProgramKind::Relative),
+        ("/foo", ProgramKind::Absolute),
+        ("/dir/../foo", ProgramKind::Absolute),
+    ];
+
+    for (program, expected_kind) in vectors {
+        assert_eq!(
+            ProgramKind::new(program.as_ref()),
+            *expected_kind,
+            "actual != expected program kind for input {program}",
+        );
+    }
+}
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 75bb92437fd..26ae6281771 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -453,7 +453,9 @@ impl Command {
                     // successfully launch the program, but erroneously return
                     // ENOENT when used with posix_spawn_file_actions_addchdir_np
                     // which was introduced in macOS 10.15.
-                    return Ok(None);
+                    if self.get_program_kind() == ProgramKind::Relative {
+                        return Ok(None);
+                    }
                 }
                 match posix_spawn_file_actions_addchdir_np.get() {
                     Some(f) => Some((f, cwd)),