From 518b3f7eeed94027673b55b6f459a22983ac542f Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Wed, 28 Feb 2018 15:33:36 -0800 Subject: [PATCH 01/18] Update libc to bring in posix_spawn bindings for FreeBSD. --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 56444a4545bd7..8bed48a751562 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 56444a4545bd71430d64b86b8a71714cfdbe9f5d +Subproject commit 8bed48a751562c1c396b361bb6940c677268e997 From 11696acd6d070a90e8dd386a3c9ae877740fb0e2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 25 Jan 2018 18:13:45 -0800 Subject: [PATCH 02/18] Support posix_spawn() when possible. --- src/libstd/sys/unix/process/process_unix.rs | 102 ++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 189280a4ba9a8..d66c2375140c0 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -24,6 +24,7 @@ impl Command { -> io::Result<(Process, StdioPipes)> { use sys; + const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; let envp = self.capture_env(); @@ -34,6 +35,11 @@ impl Command { } let (ours, theirs) = self.setup_io(default, needs_stdin)?; + + if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? { + return Ok((ret, ours)) + } + let (input, output) = sys::pipe::anon_pipe()?; let pid = unsafe { @@ -229,6 +235,102 @@ impl Command { libc::execvp(self.get_argv()[0], self.get_argv().as_ptr()); io::Error::last_os_error() } + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] + fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) + -> io::Result> + { + Ok(None) + } + + #[cfg(any(target_os = "linux", target_os = "macos"))] + fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) + -> io::Result> + { + use mem; + use sys; + + if self.get_cwd().is_some() || + self.get_gid().is_some() || + self.get_uid().is_some() || + self.get_closures().len() != 0 { + return Ok(None) + } + + let mut p = Process { pid: 0, status: None }; + + struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t); + + impl Drop for PosixSpawnFileActions { + fn drop(&mut self) { + unsafe { + libc::posix_spawn_file_actions_destroy(&mut self.0); + } + } + } + + struct PosixSpawnattr(libc::posix_spawnattr_t); + + impl Drop for PosixSpawnattr { + fn drop(&mut self) { + unsafe { + libc::posix_spawnattr_destroy(&mut self.0); + } + } + } + + unsafe { + let mut file_actions = PosixSpawnFileActions(mem::zeroed()); + let mut attrs = PosixSpawnattr(mem::zeroed()); + + libc::posix_spawnattr_init(&mut attrs.0); + libc::posix_spawn_file_actions_init(&mut file_actions.0); + + if let Some(fd) = stdio.stdin.fd() { + cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + fd, + libc::STDIN_FILENO))?; + } + if let Some(fd) = stdio.stdout.fd() { + cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + fd, + libc::STDOUT_FILENO))?; + } + if let Some(fd) = stdio.stderr.fd() { + cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + fd, + libc::STDERR_FILENO))?; + } + + let mut set: libc::sigset_t = mem::zeroed(); + cvt(libc::sigemptyset(&mut set))?; + cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0, + &set))?; + cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?; + cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0, + &set))?; + + let flags = libc::POSIX_SPAWN_SETSIGDEF | + libc::POSIX_SPAWN_SETSIGMASK; + cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?; + + let envp = envp.map(|c| c.as_ptr()) + .unwrap_or(sys::os::environ() as *const _); + let ret = libc::posix_spawnp( + &mut p.pid, + self.get_argv()[0], + &file_actions.0, + &attrs.0, + self.get_argv().as_ptr() as *const _, + envp as *const _, + ); + if ret == 0 { + Ok(Some(p)) + } else { + Err(io::Error::last_os_error()) + } + } + } } //////////////////////////////////////////////////////////////////////////////// From f4633865d37dea15a88220e886e77839aa1fd1ba Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 17:33:44 -0800 Subject: [PATCH 03/18] Avoid error for unused variables --- src/libstd/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index d66c2375140c0..05b4b9b085b4b 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -237,7 +237,7 @@ impl Command { } #[cfg(not(any(target_os = "linux", target_os = "macos")))] - fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) + fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>) -> io::Result> { Ok(None) From 94630e4ca509f9b37e4c066eee94f40da12cba51 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 20:23:46 -0800 Subject: [PATCH 04/18] No need to zero when an initializer for the object is already used. --- src/libstd/sys/unix/process/process_unix.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 05b4b9b085b4b..b394d5ff41aa2 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -280,8 +280,8 @@ impl Command { } unsafe { - let mut file_actions = PosixSpawnFileActions(mem::zeroed()); - let mut attrs = PosixSpawnattr(mem::zeroed()); + let mut file_actions = PosixSpawnFileActions(mem::uninitialized()); + let mut attrs = PosixSpawnattr(mem::uninitialized()); libc::posix_spawnattr_init(&mut attrs.0); libc::posix_spawn_file_actions_init(&mut file_actions.0); @@ -302,7 +302,7 @@ impl Command { libc::STDERR_FILENO))?; } - let mut set: libc::sigset_t = mem::zeroed(); + let mut set: libc::sigset_t = mem::uninitialized(); cvt(libc::sigemptyset(&mut set))?; cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0, &set))?; From 8e3fa0d3c450051d6445aa82682416eb307b2d5b Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 23:51:19 -0800 Subject: [PATCH 05/18] Pass proper pointer for envp. --- src/libstd/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index b394d5ff41aa2..9765ff37e9b7d 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -315,7 +315,7 @@ impl Command { cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?; let envp = envp.map(|c| c.as_ptr()) - .unwrap_or(sys::os::environ() as *const _); + .unwrap_or(*sys::os::environ() as *const _); let ret = libc::posix_spawnp( &mut p.pid, self.get_argv()[0], From b3ecf5f57ca9d34d10ffd9d064a027ce3f4888ac Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 23:51:39 -0800 Subject: [PATCH 06/18] Remove excess newline --- src/libstd/sys/unix/process/process_unix.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 9765ff37e9b7d..fa66245abb6d2 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -24,7 +24,6 @@ impl Command { -> io::Result<(Process, StdioPipes)> { use sys; - const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; let envp = self.capture_env(); From 85b82f254e28f5e50b25d8e096af0f01e4441ef7 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Tue, 27 Feb 2018 14:12:52 -0800 Subject: [PATCH 07/18] Support posix_spawn() for FreeBSD. spawn() is expected to return an error if the specified file could not be executed. FreeBSD's posix_spawn() supports returning ENOENT/ENOEXEC if the exec() fails, which not all platforms support. This brings a very significant performance improvement for FreeBSD, involving heavy use of Command in threads, due to fork() invoking jemalloc fork handlers and causing lock contention. FreeBSD's posix_spawn() avoids this problem due to using vfork() internally. --- src/libstd/sys/unix/process/process_unix.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index fa66245abb6d2..c7841a861ceb7 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -235,14 +235,14 @@ impl Command { io::Error::last_os_error() } - #[cfg(not(any(target_os = "linux", target_os = "macos")))] + #[cfg(not(any(target_os = "freebsd")))] fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>) -> io::Result> { Ok(None) } - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "freebsd"))] fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) -> io::Result> { From e6efd0d640742ed4a2fbd32fe79fb743772838cc Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Wed, 28 Feb 2018 19:09:59 -0800 Subject: [PATCH 08/18] Add a specific test for spawn() returning ENOENT --- .../run-pass/process-spawn-nonexistent.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/run-pass/process-spawn-nonexistent.rs diff --git a/src/test/run-pass/process-spawn-nonexistent.rs b/src/test/run-pass/process-spawn-nonexistent.rs new file mode 100644 index 0000000000000..9219cd625f30f --- /dev/null +++ b/src/test/run-pass/process-spawn-nonexistent.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-cloudabi no processes +// ignore-emscripten no processes + +use std::io::ErrorKind; +use std::process::Command; + +fn main() { + assert_eq!(Command::new("nonexistent") + .spawn() + .unwrap_err() + .kind(), + ErrorKind::NotFound); +} From a9ea876960a06f3ae00049515bf9ef706cca806b Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Wed, 28 Feb 2018 22:16:35 -0800 Subject: [PATCH 09/18] posix_spawn() always returns its error rather than setting errno. --- src/libstd/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index c7841a861ceb7..c5dda6273efa3 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -326,7 +326,7 @@ impl Command { if ret == 0 { Ok(Some(p)) } else { - Err(io::Error::last_os_error()) + Err(io::Error::from_raw_os_error(ret)) } } } From 2e2d9260f9425cd700199383096d8201190737de Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Thu, 1 Mar 2018 09:17:49 -0800 Subject: [PATCH 10/18] posix_spawn() on OSX supports returning ENOENT. --- src/libstd/sys/unix/process/process_unix.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index c5dda6273efa3..dcf0278b4aaa7 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -235,14 +235,14 @@ impl Command { io::Error::last_os_error() } - #[cfg(not(any(target_os = "freebsd")))] + #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>) -> io::Result> { Ok(None) } - #[cfg(any(target_os = "freebsd"))] + #[cfg(any(target_os = "macos", target_os = "freebsd"))] fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) -> io::Result> { From ef73b3ae2eac3a03f5b966a4f8b2a568e3619d51 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Thu, 1 Mar 2018 09:18:16 -0800 Subject: [PATCH 11/18] Add comment explaining when posix_spawn() can be supported. --- src/libstd/sys/unix/process/process_unix.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index dcf0278b4aaa7..bd6a8d3f64bee 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -242,6 +242,8 @@ impl Command { Ok(None) } + // Only support platforms for which posix_spawn() can return ENOENT + // directly. #[cfg(any(target_os = "macos", target_os = "freebsd"))] fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) -> io::Result> From 99b50efb6eb048297cda699ad017821822591d7a Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Fri, 2 Mar 2018 08:50:37 -0800 Subject: [PATCH 12/18] Use _ --- src/libstd/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index bd6a8d3f64bee..51ae0aa73159a 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -236,7 +236,7 @@ impl Command { } #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] - fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>) + fn posix_spawn(&mut self, _: &ChildPipes, _: Option<&CStringArray>) -> io::Result> { Ok(None) From 5ba6b3a728fb50cd65237b8eeac2f2df05c3c77f Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Fri, 2 Mar 2018 12:50:07 -0800 Subject: [PATCH 13/18] Move glibc version lookup handling to sys::os and add a simpler glibc_version() --- src/libstd/sys/unix/net.rs | 33 +++++---------------------------- src/libstd/sys/unix/os.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 3f65975e60880..04d9f0b06d344 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -383,12 +383,12 @@ impl IntoInner for Socket { // believe it's thread-safe). #[cfg(target_env = "gnu")] fn on_resolver_failure() { + use sys; + // If the version fails to parse, we treat it the same as "not glibc". - if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) { - if let Some(version) = parse_glibc_version(version_str) { - if version < (2, 26) { - unsafe { libc::res_init() }; - } + if let Some(version) = sys::os::glibc_version() { + if version < (2, 26) { + unsafe { libc::res_init() }; } } } @@ -396,29 +396,6 @@ fn on_resolver_failure() { #[cfg(not(target_env = "gnu"))] fn on_resolver_failure() {} -#[cfg(target_env = "gnu")] -fn glibc_version_cstr() -> Option<&'static CStr> { - weak! { - fn gnu_get_libc_version() -> *const libc::c_char - } - if let Some(f) = gnu_get_libc_version.get() { - unsafe { Some(CStr::from_ptr(f())) } - } else { - None - } -} - -// Returns Some((major, minor)) if the string is a valid "x.y" version, -// ignoring any extra dot-separated parts. Otherwise return None. -#[cfg(target_env = "gnu")] -fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { - let mut parsed_ints = version.split(".").map(str::parse::).fuse(); - match (parsed_ints.next(), parsed_ints.next()) { - (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), - _ => None - } -} - #[cfg(all(test, taget_env = "gnu"))] mod test { use super::*; diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index a46e855b4a6f4..4c86fddee4b45 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -546,3 +546,35 @@ pub fn getpid() -> u32 { pub fn getppid() -> u32 { unsafe { libc::getppid() as u32 } } + +#[cfg(target_env = "gnu")] +pub fn glibc_version() -> Option<(usize, usize)> { + if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) { + parse_glibc_version(version_str) + } else { + None + } +} + +#[cfg(target_env = "gnu")] +fn glibc_version_cstr() -> Option<&'static CStr> { + weak! { + fn gnu_get_libc_version() -> *const libc::c_char + } + if let Some(f) = gnu_get_libc_version.get() { + unsafe { Some(CStr::from_ptr(f())) } + } else { + None + } +} + +// Returns Some((major, minor)) if the string is a valid "x.y" version, +// ignoring any extra dot-separated parts. Otherwise return None. +#[cfg(target_env = "gnu")] +fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { + let mut parsed_ints = version.split(".").map(str::parse::).fuse(); + match (parsed_ints.next(), parsed_ints.next()) { + (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), + _ => None + } +} From d740083fc8981ee933dc48a6b3dcee21b82c993e Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Fri, 2 Mar 2018 13:02:38 -0800 Subject: [PATCH 14/18] Support posix_spawn() for Linux glibc 2.24+. The relevant support was added in https://sourceware.org/bugzilla/show_bug.cgi?id=10354#c12 --- src/libstd/sys/unix/process/process_unix.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 51ae0aa73159a..29e33ee822ee5 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -235,7 +235,8 @@ impl Command { io::Error::last_os_error() } - #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] + #[cfg(not(any(target_os = "macos", target_os = "freebsd", + all(target_os = "linux", target_env = "gnu"))))] fn posix_spawn(&mut self, _: &ChildPipes, _: Option<&CStringArray>) -> io::Result> { @@ -244,7 +245,8 @@ impl Command { // Only support platforms for which posix_spawn() can return ENOENT // directly. - #[cfg(any(target_os = "macos", target_os = "freebsd"))] + #[cfg(any(target_os = "macos", target_os = "freebsd", + all(target_os = "linux", target_env = "gnu")))] fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) -> io::Result> { @@ -258,6 +260,18 @@ impl Command { return Ok(None) } + // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly. + #[cfg(all(target_os = "linux", target_env = "gnu"))] + { + if let Some(version) = sys::os::glibc_version() { + if version < (2, 24) { + return Ok(None) + } + } else { + return Ok(None) + } + } + let mut p = Process { pid: 0, status: None }; struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t); From 57c74c39813c4668d3be5a0c244758f59ab32d9a Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 19 Mar 2018 12:40:42 -0700 Subject: [PATCH 15/18] Update beta to version with fixed FreeBSD support from #49023. Fixes #42681 --- src/stage0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stage0.txt b/src/stage0.txt index b9578386ce5bc..96ec1e6834dff 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-02-20 +date: 2018-03-18 rustc: beta cargo: beta From 6212904dd800864ca20ede8690fc827a1169fa26 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 19 Mar 2018 15:40:09 -0700 Subject: [PATCH 16/18] Don't use posix_spawn() if PATH was modified in the environment. The expected behavior is that the environment's PATH should be used to find the process. posix_spawn() could be used if we iterated PATH to search for the binary to execute. For now just skip posix_spawn() if PATH is modified. --- src/libstd/sys/unix/process/process_common.rs | 3 +++ src/libstd/sys/unix/process/process_unix.rs | 1 + src/libstd/sys_common/process.rs | 12 ++++++++++++ 3 files changed, 16 insertions(+) diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index d0486f06a143a..48255489dd916 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -184,6 +184,9 @@ impl Command { let maybe_env = self.env.capture_if_changed(); maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) } + pub fn env_saw_path(&self) -> bool { + self.env.have_changed_path() + } pub fn setup_io(&self, default: Stdio, needs_stdin: bool) -> io::Result<(StdioPipes, ChildPipes)> { diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 29e33ee822ee5..9d6d607e3f340 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -256,6 +256,7 @@ impl Command { if self.get_cwd().is_some() || self.get_gid().is_some() || self.get_uid().is_some() || + self.env_saw_path() || self.get_closures().len() != 0 { return Ok(None) } diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index fd1a5fdb4109b..775491d762cda 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -47,6 +47,7 @@ impl EnvKey for DefaultEnvKey {} #[derive(Clone, Debug)] pub struct CommandEnv { clear: bool, + saw_path: bool, vars: BTreeMap> } @@ -54,6 +55,7 @@ impl Default for CommandEnv { fn default() -> Self { CommandEnv { clear: false, + saw_path: false, vars: Default::default() } } @@ -108,9 +110,11 @@ impl CommandEnv { // The following functions build up changes pub fn set(&mut self, key: &OsStr, value: &OsStr) { + self.maybe_saw_path(&key); self.vars.insert(key.to_owned().into(), Some(value.to_owned())); } pub fn remove(&mut self, key: &OsStr) { + self.maybe_saw_path(&key); if self.clear { self.vars.remove(key); } else { @@ -121,4 +125,12 @@ impl CommandEnv { self.clear = true; self.vars.clear(); } + pub fn have_changed_path(&self) -> bool { + self.saw_path || self.clear + } + fn maybe_saw_path(&mut self, key: &OsStr) { + if !self.saw_path && key.to_os_string() == OsString::from("PATH") { + self.saw_path = true; + } + } } From 8e0faf79c0859f22d4e11268f272247a6ef73709 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 19 Mar 2018 16:15:26 -0700 Subject: [PATCH 17/18] Simplify PATH key comparison --- src/libstd/sys_common/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index 775491d762cda..d0c5951bd6c0a 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -129,7 +129,7 @@ impl CommandEnv { self.saw_path || self.clear } fn maybe_saw_path(&mut self, key: &OsStr) { - if !self.saw_path && key.to_os_string() == OsString::from("PATH") { + if !self.saw_path && key == "PATH" { self.saw_path = true; } } From 70559c54ce2a493a15f447436e281e16fc55b291 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Thu, 22 Mar 2018 09:49:20 -0700 Subject: [PATCH 18/18] Command::env_saw_path() may be unused on platforms not using posix_spawn() --- src/libstd/sys/unix/process/process_common.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 48255489dd916..b7f30600b8a4c 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -184,6 +184,7 @@ impl Command { let maybe_env = self.env.capture_if_changed(); maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) } + #[allow(dead_code)] pub fn env_saw_path(&self) -> bool { self.env.have_changed_path() }