]> git.lizzy.rs Git - rust.git/commitdiff
Use posix_spawn_file_actions_addchdir_np when possible
authorJosh Stone <jistone@redhat.com>
Wed, 13 Feb 2019 20:20:23 +0000 (12:20 -0800)
committerJosh Stone <jistone@redhat.com>
Wed, 13 Feb 2019 20:20:23 +0000 (12:20 -0800)
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()`.

src/libstd/sys/unix/process/process_unix.rs

index 12d3e9b13b1156120f73b5f983c330f97c17dd77..6fbbbb349b171a9a86e30ca8118abc18bc425391 100644 (file)
@@ -281,8 +281,7 @@ fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>)
         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 @@ fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>)
             }
         }
 
+        // 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 @@ fn drop(&mut self) {
                                                            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))?;