about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2019-02-13 12:20:23 -0800
committerJosh Stone <jistone@redhat.com>2019-02-13 12:20:23 -0800
commita301655c8aed20e5cea9a062663820fc29c5e80c (patch)
tree9497fbbd2baab5c9ff60c8338d3a8b14bbe65fb7
parent0f949c2fcc696d0260a99196d5e5400c59a26a54 (diff)
downloadrust-a301655c8aed20e5cea9a062663820fc29c5e80c.tar.gz
rust-a301655c8aed20e5cea9a062663820fc29c5e80c.zip
Use posix_spawn_file_actions_addchdir_np when possible
This is a non-POSIX extension implemented in Solaris and in glibc 2.29.
With this we can still use `posix_spawn()` when `Command::current_dir()`
has been set, otherwise we fallback to `fork(); chdir(); exec()`.
-rw-r--r--src/libstd/sys/unix/process/process_unix.rs24
1 files changed, 22 insertions, 2 deletions
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
index 12d3e9b13b1..6fbbbb349b1 100644
--- a/src/libstd/sys/unix/process/process_unix.rs
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -281,8 +281,7 @@ impl Command {
         use mem;
         use sys;
 
-        if self.get_cwd().is_some() ||
-            self.get_gid().is_some() ||
+        if self.get_gid().is_some() ||
             self.get_uid().is_some() ||
             self.env_saw_path() ||
             self.get_closures().len() != 0 {
@@ -301,6 +300,24 @@ impl Command {
             }
         }
 
+        // Solaris and glibc 2.29+ can set a new working directory, and maybe
+        // others will gain this non-POSIX function too. We'll check for this
+        // weak symbol as soon as it's needed, so we can return early otherwise
+        // to do a manual chdir before exec.
+        weak! {
+            fn posix_spawn_file_actions_addchdir_np(
+                *mut libc::posix_spawn_file_actions_t,
+                *const libc::c_char
+            ) -> libc::c_int
+        }
+        let addchdir = match self.get_cwd() {
+            Some(cwd) => match posix_spawn_file_actions_addchdir_np.get() {
+                Some(f) => Some((f, cwd)),
+                None => return Ok(None),
+            },
+            None => None,
+        };
+
         let mut p = Process { pid: 0, status: None };
 
         struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t);
@@ -345,6 +362,9 @@ impl Command {
                                                            fd,
                                                            libc::STDERR_FILENO))?;
             }
+            if let Some((f, cwd)) = addchdir {
+                cvt(f(&mut file_actions.0, cwd.as_ptr()))?;
+            }
 
             let mut set: libc::sigset_t = mem::uninitialized();
             cvt(libc::sigemptyset(&mut set))?;