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/ffi/mod.rs2
-rw-r--r--library/std/src/io/pipe.rs38
-rw-r--r--library/std/src/lib.rs4
-rw-r--r--library/std/src/os/net/linux_ext/addr.rs6
-rw-r--r--library/std/src/os/net/linux_ext/socket.rs3
-rw-r--r--library/std/src/os/net/linux_ext/tcp.rs6
-rw-r--r--library/std/src/os/unix/process.rs18
-rw-r--r--library/std/src/process.rs14
-rw-r--r--library/std/src/sys/process/unix/common.rs13
-rw-r--r--library/std/src/sys/process/unix/unix.rs10
-rw-r--r--library/std/src/sys/process/unix/vxworks.rs6
11 files changed, 98 insertions, 22 deletions
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 56791609910..024cb71b915 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -172,7 +172,7 @@ pub use core::ffi::c_void;
               all supported platforms",
     issue = "44930"
 )]
-pub use core::ffi::{VaList, VaListImpl};
+pub use core::ffi::{VaArgSafe, VaList, VaListImpl};
 #[stable(feature = "core_ffi_c", since = "1.64.0")]
 pub use core::ffi::{
     c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs
index 47243806cd2..16727d44541 100644
--- a/library/std/src/io/pipe.rs
+++ b/library/std/src/io/pipe.rs
@@ -38,30 +38,44 @@ use crate::sys_common::{FromInner, IntoInner};
 /// > not rely on a particular capacity: an application should be designed so that a reading process
 /// > consumes data as soon as it is available, so that a writing process does not remain blocked.
 ///
-/// # Examples
+/// # Example
 ///
 /// ```no_run
 /// # #[cfg(miri)] fn main() {}
 /// # #[cfg(not(miri))]
 /// # fn main() -> std::io::Result<()> {
+/// use std::io::{Read, Write, pipe};
 /// use std::process::Command;
-/// use std::io::{pipe, Read, Write};
-/// let (ping_rx, mut ping_tx) = pipe()?;
-/// let (mut pong_rx, pong_tx) = pipe()?;
+/// let (ping_reader, mut ping_writer) = pipe()?;
+/// let (mut pong_reader, pong_writer) = pipe()?;
 ///
-/// // Spawn a process that echoes its input.
-/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
+/// // Spawn a child process that echoes its input.
+/// let mut echo_command = Command::new("cat");
+/// echo_command.stdin(ping_reader);
+/// echo_command.stdout(pong_writer);
+/// let mut echo_child = echo_command.spawn()?;
 ///
-/// ping_tx.write_all(b"hello")?;
-/// // Close to unblock echo_server's reader.
-/// drop(ping_tx);
+/// // Send input to the child process. Note that because we're writing all the input before we
+/// // read any output, this could deadlock if the child's input and output pipe buffers both
+/// // filled up. Those buffers are usually at least a few KB, so "hello" is fine, but for longer
+/// // inputs we'd need to read and write at the same time, e.g. using threads.
+/// ping_writer.write_all(b"hello")?;
+///
+/// // `cat` exits when it reads EOF from stdin, but that can't happen while any ping writer
+/// // remains open. We need to drop our ping writer, or read_to_string will deadlock below.
+/// drop(ping_writer);
+///
+/// // The pong reader can't report EOF while any pong writer remains open. Our Command object is
+/// // holding a pong writer, and again read_to_string will deadlock if we don't drop it.
+/// drop(echo_command);
 ///
 /// let mut buf = String::new();
-/// // Block until echo_server's writer is closed.
-/// pong_rx.read_to_string(&mut buf)?;
+/// // Block until `cat` closes its stdout (a pong writer).
+/// pong_reader.read_to_string(&mut buf)?;
 /// assert_eq!(&buf, "hello");
 ///
-/// echo_server.wait()?;
+/// // At this point we know `cat` has exited, but we still need to wait to clean up the "zombie".
+/// echo_child.wait()?;
 /// # Ok(())
 /// # }
 /// ```
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index ef41b47384d..4d984617739 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -700,8 +700,8 @@ mod panicking;
 #[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)]
 mod backtrace_rs;
 
-#[unstable(feature = "cfg_match", issue = "115585")]
-pub use core::cfg_match;
+#[unstable(feature = "cfg_select", issue = "115585")]
+pub use core::cfg_select;
 #[unstable(
     feature = "concat_bytes",
     issue = "87555",
diff --git a/library/std/src/os/net/linux_ext/addr.rs b/library/std/src/os/net/linux_ext/addr.rs
index aed772056e1..41009c0e284 100644
--- a/library/std/src/os/net/linux_ext/addr.rs
+++ b/library/std/src/os/net/linux_ext/addr.rs
@@ -23,7 +23,10 @@ pub trait SocketAddrExt: Sealed {
     ///
     /// ```no_run
     /// use std::os::unix::net::{UnixListener, SocketAddr};
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::SocketAddrExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::SocketAddrExt;
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let addr = SocketAddr::from_abstract_name(b"hidden")?;
@@ -48,7 +51,10 @@ pub trait SocketAddrExt: Sealed {
     ///
     /// ```no_run
     /// use std::os::unix::net::{UnixListener, SocketAddr};
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::SocketAddrExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::SocketAddrExt;
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let name = b"hidden";
diff --git a/library/std/src/os/net/linux_ext/socket.rs b/library/std/src/os/net/linux_ext/socket.rs
index 4e4168f693c..a15feb6bd9f 100644
--- a/library/std/src/os/net/linux_ext/socket.rs
+++ b/library/std/src/os/net/linux_ext/socket.rs
@@ -27,7 +27,10 @@ pub trait UnixSocketExt: Sealed {
     ///
     /// ```no_run
     /// #![feature(unix_socket_ancillary_data)]
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::UnixSocketExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::UnixSocketExt;
     /// use std::os::unix::net::UnixDatagram;
     ///
     /// fn main() -> std::io::Result<()> {
diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs
index c8d012962d4..95dffb3bc43 100644
--- a/library/std/src/os/net/linux_ext/tcp.rs
+++ b/library/std/src/os/net/linux_ext/tcp.rs
@@ -25,7 +25,10 @@ pub trait TcpStreamExt: Sealed {
     /// ```no_run
     /// #![feature(tcp_quickack)]
     /// use std::net::TcpStream;
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::TcpStreamExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::TcpStreamExt;
     ///
     /// let stream = TcpStream::connect("127.0.0.1:8080")
     ///         .expect("Couldn't connect to the server...");
@@ -43,7 +46,10 @@ pub trait TcpStreamExt: Sealed {
     /// ```no_run
     /// #![feature(tcp_quickack)]
     /// use std::net::TcpStream;
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::TcpStreamExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::TcpStreamExt;
     ///
     /// let stream = TcpStream::connect("127.0.0.1:8080")
     ///         .expect("Couldn't connect to the server...");
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 7c3fa7d6507..57ce3c5a4bf 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -8,6 +8,7 @@ use cfg_if::cfg_if;
 
 use crate::ffi::OsStr;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::path::Path;
 use crate::sealed::Sealed;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 use crate::{io, process, sys};
@@ -197,6 +198,18 @@ pub trait CommandExt: Sealed {
     /// ```
     #[stable(feature = "process_set_process_group", since = "1.64.0")]
     fn process_group(&mut self, pgroup: i32) -> &mut process::Command;
+
+    /// Set the root of the child process. This calls `chroot` in the child process before executing
+    /// the command.
+    ///
+    /// This happens before changing to the directory specified with
+    /// [`process::Command::current_dir`], and that directory will be relative to the new root.
+    ///
+    /// If no directory has been specified with [`process::Command::current_dir`], this will set the
+    /// directory to `/`, to avoid leaving the current directory outside the chroot. (This is an
+    /// intentional difference from the underlying `chroot` system call.)
+    #[unstable(feature = "process_chroot", issue = "141298")]
+    fn chroot<P: AsRef<Path>>(&mut self, dir: P) -> &mut process::Command;
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -242,6 +255,11 @@ impl CommandExt for process::Command {
         self.as_inner_mut().pgroup(pgroup);
         self
     }
+
+    fn chroot<P: AsRef<Path>>(&mut self, dir: P) -> &mut process::Command {
+        self.as_inner_mut().chroot(dir.as_ref());
+        self
+    }
 }
 
 /// Unix-specific extensions to [`process::ExitStatus`] and
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index df6b9a6e563..373584d0117 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1348,7 +1348,7 @@ impl Output {
     ///
     /// ```
     /// #![feature(exit_status_error)]
-    /// # #[cfg(unix)] {
+    /// # #[cfg(all(unix, not(target_os = "android")))] {
     /// use std::process::Command;
     /// assert!(Command::new("false").output().unwrap().exit_ok().is_err());
     /// # }
@@ -1695,7 +1695,7 @@ impl From<io::Stdout> for Stdio {
     /// # Ok(())
     /// # }
     /// #
-    /// # if cfg!(unix) {
+    /// # if cfg!(all(unix, not(target_os = "android"))) {
     /// #     test().unwrap();
     /// # }
     /// ```
@@ -1724,7 +1724,7 @@ impl From<io::Stderr> for Stdio {
     /// # Ok(())
     /// # }
     /// #
-    /// # if cfg!(unix) {
+    /// # if cfg!(all(unix, not(target_os = "android"))) {
     /// #     test().unwrap();
     /// # }
     /// ```
@@ -1907,7 +1907,7 @@ impl crate::sealed::Sealed for ExitStatusError {}
 ///
 /// ```
 /// #![feature(exit_status_error)]
-/// # if cfg!(unix) {
+/// # if cfg!(all(unix, not(target_os = "android"))) {
 /// use std::process::{Command, ExitStatusError};
 ///
 /// fn run(cmd: &str) -> Result<(), ExitStatusError> {
@@ -1950,7 +1950,7 @@ impl ExitStatusError {
     ///
     /// ```
     /// #![feature(exit_status_error)]
-    /// # #[cfg(unix)] {
+    /// # #[cfg(all(unix, not(target_os = "android")))] {
     /// use std::process::Command;
     ///
     /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err();
@@ -1975,7 +1975,7 @@ impl ExitStatusError {
     /// ```
     /// #![feature(exit_status_error)]
     ///
-    /// # if cfg!(unix) {
+    /// # if cfg!(all(unix, not(target_os = "android"))) {
     /// use std::num::NonZero;
     /// use std::process::Command;
     ///
@@ -2532,7 +2532,7 @@ pub fn id() -> u32 {
 #[rustc_on_unimplemented(on(
     cause = "MainFunctionType",
     message = "`main` has invalid return type `{Self}`",
-    label = "`main` can only return types that implement `{Termination}`"
+    label = "`main` can only return types that implement `{This}`"
 ))]
 pub trait Termination {
     /// Is called to get the representation of the value as status code.
diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs
index a9c2510e6d4..e205a839005 100644
--- a/library/std/src/sys/process/unix/common.rs
+++ b/library/std/src/sys/process/unix/common.rs
@@ -88,6 +88,7 @@ pub struct Command {
 
     program_kind: ProgramKind,
     cwd: Option<CString>,
+    chroot: Option<CString>,
     uid: Option<uid_t>,
     gid: Option<gid_t>,
     saw_nul: bool,
@@ -182,6 +183,7 @@ impl Command {
             program_kind,
             env: Default::default(),
             cwd: None,
+            chroot: None,
             uid: None,
             gid: None,
             saw_nul,
@@ -206,6 +208,7 @@ impl Command {
             program_kind,
             env: Default::default(),
             cwd: None,
+            chroot: None,
             uid: None,
             gid: None,
             saw_nul,
@@ -254,6 +257,12 @@ impl Command {
     pub fn pgroup(&mut self, pgroup: pid_t) {
         self.pgroup = Some(pgroup);
     }
+    pub fn chroot(&mut self, dir: &Path) {
+        self.chroot = Some(os2c(dir.as_os_str(), &mut self.saw_nul));
+        if self.cwd.is_none() {
+            self.cwd(&OsStr::new("/"));
+        }
+    }
 
     #[cfg(target_os = "linux")]
     pub fn create_pidfd(&mut self, val: bool) {
@@ -326,6 +335,10 @@ impl Command {
     pub fn get_pgroup(&self) -> Option<pid_t> {
         self.pgroup
     }
+    #[allow(dead_code)]
+    pub fn get_chroot(&self) -> Option<&CStr> {
+        self.chroot.as_deref()
+    }
 
     pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
         &mut self.closures
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index 1b3bd2de265..4f595ac9a1c 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -323,6 +323,15 @@ impl Command {
                 cvt(libc::setuid(u as uid_t))?;
             }
         }
+        if let Some(chroot) = self.get_chroot() {
+            #[cfg(not(target_os = "fuchsia"))]
+            cvt(libc::chroot(chroot.as_ptr()))?;
+            #[cfg(target_os = "fuchsia")]
+            return Err(io::const_error!(
+                io::ErrorKind::Unsupported,
+                "chroot not supported by fuchsia"
+            ));
+        }
         if let Some(cwd) = self.get_cwd() {
             cvt(libc::chdir(cwd.as_ptr()))?;
         }
@@ -447,6 +456,7 @@ impl Command {
             || (self.env_saw_path() && !self.program_is_path())
             || !self.get_closures().is_empty()
             || self.get_groups().is_some()
+            || self.get_chroot().is_some()
         {
             return Ok(None);
         }
diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs
index fab3b36ebf3..f33b4a375da 100644
--- a/library/std/src/sys/process/unix/vxworks.rs
+++ b/library/std/src/sys/process/unix/vxworks.rs
@@ -27,6 +27,12 @@ impl Command {
                 "nul byte found in provided data",
             ));
         }
+        if self.get_chroot().is_some() {
+            return Err(io::const_error!(
+                ErrorKind::Unsupported,
+                "chroot not supported by vxworks",
+            ));
+        }
         let (ours, theirs) = self.setup_io(default, needs_stdin)?;
         let mut p = Process { pid: 0, status: None };