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/process.rs34
-rw-r--r--library/std/src/sys/pal/unix/mod.rs1
-rw-r--r--library/std/src/sys/pal/unix/thread.rs17
-rw-r--r--library/std/src/sys/process/uefi.rs119
-rw-r--r--library/std/src/sys/stdio/uefi.rs8
5 files changed, 166 insertions, 13 deletions
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index da518011a0e..76ce7bce81b 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1286,6 +1286,40 @@ pub struct Output {
     pub stderr: Vec<u8>,
 }
 
+impl Output {
+    /// Returns an error if a nonzero exit status was received.
+    ///
+    /// If the [`Command`] exited successfully,
+    /// `self` is returned.
+    ///
+    /// This is equivalent to calling [`exit_ok`](ExitStatus::exit_ok)
+    /// on [`Output.status`](Output::status).
+    ///
+    /// Note that this will throw away the [`Output::stderr`] field in the error case.
+    /// If the child process outputs useful informantion to stderr, you can:
+    /// * Use `cmd.stderr(Stdio::inherit())` to forward the
+    ///   stderr child process to the parent's stderr,
+    ///   usually printing it to console where the user can see it.
+    ///   This is usually correct for command-line applications.
+    /// * Capture `stderr` using a custom error type.
+    ///   This is usually correct for libraries.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(exit_status_error)]
+    /// # #[cfg(unix)] {
+    /// use std::process::Command;
+    /// assert!(Command::new("false").output().unwrap().exit_ok().is_err());
+    /// # }
+    /// ```
+    #[unstable(feature = "exit_status_error", issue = "84908")]
+    pub fn exit_ok(self) -> Result<Self, ExitStatusError> {
+        self.status.exit_ok()?;
+        Ok(self)
+    }
+}
+
 // If either stderr or stdout are valid utf8 strings it prints the valid
 // strings, otherwise it prints the byte sequence instead
 #[stable(feature = "process_output_debug", since = "1.7.0")]
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index f8733eb6119..3a790d9c868 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -274,6 +274,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         libc::ETXTBSY => ExecutableFileBusy,
         libc::EXDEV => CrossesDevices,
         libc::EINPROGRESS => InProgress,
+        libc::EOPNOTSUPP => Unsupported,
 
         libc::EACCES | libc::EPERM => PermissionDenied,
 
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 9078dd1c231..4f1517b7ef4 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -8,14 +8,19 @@ use crate::sys::weak::weak;
 use crate::sys::{os, stack_overflow};
 use crate::time::Duration;
 use crate::{cmp, io, ptr};
-#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
+#[cfg(not(any(
+    target_os = "l4re",
+    target_os = "vxworks",
+    target_os = "espidf",
+    target_os = "nuttx"
+)))]
 pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
 #[cfg(target_os = "l4re")]
 pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
 #[cfg(target_os = "vxworks")]
 pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
-#[cfg(target_os = "espidf")]
-pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF menuconfig system should be used
+#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used
 
 #[cfg(target_os = "fuchsia")]
 mod zircon {
@@ -52,10 +57,10 @@ impl Thread {
         let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
         assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
 
-        #[cfg(target_os = "espidf")]
+        #[cfg(any(target_os = "espidf", target_os = "nuttx"))]
         if stack > 0 {
             // Only set the stack if a non-zero value is passed
-            // 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used
+            // 0 is used as an indication that the default stack size configured in the ESP-IDF/NuttX menuconfig system should be used
             assert_eq!(
                 libc::pthread_attr_setstacksize(
                     attr.as_mut_ptr(),
@@ -65,7 +70,7 @@ impl Thread {
             );
         }
 
-        #[cfg(not(target_os = "espidf"))]
+        #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
         {
             let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr()));
 
diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs
index b46418ae9bb..5f922292d05 100644
--- a/library/std/src/sys/process/uefi.rs
+++ b/library/std/src/sys/process/uefi.rs
@@ -1,4 +1,4 @@
-use r_efi::protocols::simple_text_output;
+use r_efi::protocols::{simple_text_input, simple_text_output};
 
 use crate::collections::BTreeMap;
 pub use crate::ffi::OsString as EnvKey;
@@ -23,6 +23,7 @@ pub struct Command {
     args: Vec<OsString>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
+    stdin: Option<Stdio>,
     env: CommandEnv,
 }
 
@@ -48,6 +49,7 @@ impl Command {
             args: Vec::new(),
             stdout: None,
             stderr: None,
+            stdin: None,
             env: Default::default(),
         }
     }
@@ -64,8 +66,8 @@ impl Command {
         panic!("unsupported")
     }
 
-    pub fn stdin(&mut self, _stdin: Stdio) {
-        panic!("unsupported")
+    pub fn stdin(&mut self, stdin: Stdio) {
+        self.stdin = Some(stdin);
     }
 
     pub fn stdout(&mut self, stdout: Stdio) {
@@ -122,6 +124,22 @@ impl Command {
         }
     }
 
+    fn create_stdin(
+        s: Stdio,
+    ) -> io::Result<Option<helpers::OwnedProtocol<uefi_command_internal::InputProtocol>>> {
+        match s {
+            Stdio::Null => unsafe {
+                helpers::OwnedProtocol::create(
+                    uefi_command_internal::InputProtocol::null(),
+                    simple_text_input::PROTOCOL_GUID,
+                )
+            }
+            .map(Some),
+            Stdio::Inherit => Ok(None),
+            Stdio::MakePipe => unsupported(),
+        }
+    }
+
     pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
         let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
 
@@ -149,6 +167,15 @@ impl Command {
             cmd.stderr_inherit()
         };
 
+        // Setup Stdin
+        let stdin = self.stdin.unwrap_or(Stdio::Null);
+        let stdin = Self::create_stdin(stdin)?;
+        if let Some(con) = stdin {
+            cmd.stdin_init(con)
+        } else {
+            cmd.stdin_inherit()
+        };
+
         let env = env_changes(&self.env);
 
         // Set any new vars
@@ -334,7 +361,7 @@ impl<'a> fmt::Debug for CommandArgs<'a> {
 
 #[allow(dead_code)]
 mod uefi_command_internal {
-    use r_efi::protocols::{loaded_image, simple_text_output};
+    use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output};
 
     use crate::ffi::{OsStr, OsString};
     use crate::io::{self, const_error};
@@ -350,6 +377,7 @@ mod uefi_command_internal {
         handle: NonNull<crate::ffi::c_void>,
         stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
         stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
+        stdin: Option<helpers::OwnedProtocol<InputProtocol>>,
         st: OwnedTable<r_efi::efi::SystemTable>,
         args: Option<(*mut u16, usize)>,
     }
@@ -384,7 +412,14 @@ mod uefi_command_internal {
                     helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
                 let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });
 
-                Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None })
+                Ok(Self {
+                    handle: child_handle,
+                    stdout: None,
+                    stderr: None,
+                    stdin: None,
+                    st,
+                    args: None,
+                })
             }
         }
 
@@ -445,6 +480,17 @@ mod uefi_command_internal {
             }
         }
 
+        fn set_stdin(
+            &mut self,
+            handle: r_efi::efi::Handle,
+            protocol: *mut simple_text_input::Protocol,
+        ) {
+            unsafe {
+                (*self.st.as_mut_ptr()).console_in_handle = handle;
+                (*self.st.as_mut_ptr()).con_in = protocol;
+            }
+        }
+
         pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
             self.set_stdout(
                 protocol.handle().as_ptr(),
@@ -471,6 +517,19 @@ mod uefi_command_internal {
             unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
         }
 
+        pub(crate) fn stdin_init(&mut self, protocol: helpers::OwnedProtocol<InputProtocol>) {
+            self.set_stdin(
+                protocol.handle().as_ptr(),
+                protocol.as_ref() as *const InputProtocol as *mut simple_text_input::Protocol,
+            );
+            self.stdin = Some(protocol);
+        }
+
+        pub(crate) fn stdin_inherit(&mut self) {
+            let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
+            unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) }
+        }
+
         pub fn stderr(&self) -> io::Result<Vec<u8>> {
             match &self.stderr {
                 Some(stderr) => stderr.as_ref().utf8(),
@@ -722,6 +781,56 @@ mod uefi_command_internal {
         }
     }
 
+    #[repr(C)]
+    pub(crate) struct InputProtocol {
+        reset: simple_text_input::ProtocolReset,
+        read_key_stroke: simple_text_input::ProtocolReadKeyStroke,
+        wait_for_key: r_efi::efi::Event,
+    }
+
+    impl InputProtocol {
+        pub(crate) fn null() -> Self {
+            let evt = helpers::OwnedEvent::new(
+                r_efi::efi::EVT_NOTIFY_WAIT,
+                r_efi::efi::TPL_CALLBACK,
+                Some(Self::empty_notify),
+                None,
+            )
+            .unwrap();
+
+            Self {
+                reset: Self::null_reset,
+                read_key_stroke: Self::null_read_key,
+                wait_for_key: evt.into_raw(),
+            }
+        }
+
+        extern "efiapi" fn null_reset(
+            _: *mut simple_text_input::Protocol,
+            _: r_efi::efi::Boolean,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::SUCCESS
+        }
+
+        extern "efiapi" fn null_read_key(
+            _: *mut simple_text_input::Protocol,
+            _: *mut simple_text_input::InputKey,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::UNSUPPORTED
+        }
+
+        extern "efiapi" fn empty_notify(_: r_efi::efi::Event, _: *mut crate::ffi::c_void) {}
+    }
+
+    impl Drop for InputProtocol {
+        fn drop(&mut self) {
+            // Close wait_for_key
+            unsafe {
+                let _ = helpers::OwnedEvent::from_raw(self.wait_for_key);
+            }
+        }
+    }
+
     pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
         const QUOTE: u16 = 0x0022;
         const SPACE: u16 = 0x0020;
diff --git a/library/std/src/sys/stdio/uefi.rs b/library/std/src/sys/stdio/uefi.rs
index 257e321dd03..ccd6bf658b0 100644
--- a/library/std/src/sys/stdio/uefi.rs
+++ b/library/std/src/sys/stdio/uefi.rs
@@ -142,8 +142,12 @@ impl io::Write for Stderr {
 // UTF-16 character should occupy 4 bytes at most in UTF-8
 pub const STDIN_BUF_SIZE: usize = 4;
 
-pub fn is_ebadf(_err: &io::Error) -> bool {
-    false
+pub fn is_ebadf(err: &io::Error) -> bool {
+    if let Some(x) = err.raw_os_error() {
+        r_efi::efi::Status::UNSUPPORTED.as_usize() == x
+    } else {
+        false
+    }
 }
 
 pub fn panic_output() -> Option<impl io::Write> {