This commit is contained in:
Ayush 2025-04-13 13:29:02 +02:00 committed by GitHub
commit ea97747953
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -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::NOT_READY
}
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;