Skip to content

Commit d7a7b0a

Browse files
committed
uefi: process: Add args support
- Wrap all args with quotes. - Escape ^ and " inside quotes using ^. Signed-off-by: Ayush Singh <[email protected]>
1 parent 24ed1c1 commit d7a7b0a

File tree

1 file changed

+56
-12
lines changed

1 file changed

+56
-12
lines changed

std/src/sys/pal/uefi/process.rs

+56-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::{fmt, io};
1818
#[derive(Debug)]
1919
pub struct Command {
2020
prog: OsString,
21+
args: Vec<OsString>,
2122
stdout: Option<Stdio>,
2223
stderr: Option<Stdio>,
2324
}
@@ -39,12 +40,11 @@ pub enum Stdio {
3940

4041
impl Command {
4142
pub fn new(program: &OsStr) -> Command {
42-
Command { prog: program.to_os_string(), stdout: None, stderr: None }
43+
Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None }
4344
}
4445

45-
// FIXME: Implement arguments as reverse of parsing algorithm
46-
pub fn arg(&mut self, _arg: &OsStr) {
47-
panic!("unsupported")
46+
pub fn arg(&mut self, arg: &OsStr) {
47+
self.args.push(arg.to_os_string());
4848
}
4949

5050
pub fn env_mut(&mut self) -> &mut CommandEnv {
@@ -72,7 +72,7 @@ impl Command {
7272
}
7373

7474
pub fn get_args(&self) -> CommandArgs<'_> {
75-
panic!("unsupported")
75+
CommandArgs { iter: self.args.iter() }
7676
}
7777

7878
pub fn get_envs(&self) -> CommandEnvs<'_> {
@@ -116,6 +116,12 @@ impl Command {
116116
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
117117
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
118118

119+
// UEFI adds the bin name by default
120+
if !self.args.is_empty() {
121+
let args = uefi_command_internal::create_args(&self.prog, &self.args);
122+
cmd.set_args(args);
123+
}
124+
119125
// Setup Stdout
120126
let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
121127
let stdout = Self::create_pipe(stdout)?;
@@ -315,7 +321,7 @@ mod uefi_command_internal {
315321
stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
316322
stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
317323
st: OwnedTable<r_efi::efi::SystemTable>,
318-
args: Option<Vec<u16>>,
324+
args: Option<(*mut u16, usize)>,
319325
}
320326

321327
impl Image {
@@ -449,20 +455,20 @@ mod uefi_command_internal {
449455
}
450456
}
451457

452-
pub fn set_args(&mut self, args: &OsStr) {
458+
pub fn set_args(&mut self, args: Box<[u16]>) {
453459
let loaded_image: NonNull<loaded_image::Protocol> =
454460
helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
455461

456-
let mut args = args.encode_wide().collect::<Vec<u16>>();
457-
let args_size = (crate::mem::size_of::<u16>() * args.len()) as u32;
462+
let len = args.len();
463+
let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap();
464+
let ptr = Box::into_raw(args).as_mut_ptr();
458465

459466
unsafe {
460-
(*loaded_image.as_ptr()).load_options =
461-
args.as_mut_ptr() as *mut crate::ffi::c_void;
467+
(*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void;
462468
(*loaded_image.as_ptr()).load_options_size = args_size;
463469
}
464470

465-
self.args = Some(args);
471+
self.args = Some((ptr, len));
466472
}
467473

468474
fn update_st_crc32(&mut self) -> io::Result<()> {
@@ -502,6 +508,10 @@ mod uefi_command_internal {
502508
((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
503509
}
504510
}
511+
512+
if let Some((ptr, len)) = self.args {
513+
let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) };
514+
}
505515
}
506516
}
507517

@@ -681,4 +691,38 @@ mod uefi_command_internal {
681691
}
682692
}
683693
}
694+
695+
pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
696+
const QUOTE: u16 = 0x0022;
697+
const SPACE: u16 = 0x0020;
698+
const CARET: u16 = 0x005e;
699+
const NULL: u16 = 0;
700+
701+
// This is the lower bound on the final length under the assumption that
702+
// the arguments only contain ASCII characters.
703+
let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum());
704+
705+
// Wrap program name in quotes to avoid any problems
706+
res.push(QUOTE);
707+
res.extend(prog.encode_wide());
708+
res.push(QUOTE);
709+
res.push(SPACE);
710+
711+
for arg in args {
712+
// Wrap the argument in quotes to be treat as single arg
713+
res.push(QUOTE);
714+
for c in arg.encode_wide() {
715+
// CARET in quotes is used to escape CARET or QUOTE
716+
if c == QUOTE || c == CARET {
717+
res.push(CARET);
718+
}
719+
res.push(c);
720+
}
721+
res.push(QUOTE);
722+
723+
res.push(SPACE);
724+
}
725+
726+
res.into_boxed_slice()
727+
}
684728
}

0 commit comments

Comments
 (0)