@@ -18,6 +18,7 @@ use crate::{fmt, io};
18
18
#[derive(Debug)]
19
19
pub struct Command {
20
20
prog: OsString,
21
+ args: Vec<OsString>,
21
22
stdout: Option<Stdio>,
22
23
stderr: Option<Stdio>,
23
24
}
@@ -39,12 +40,11 @@ pub enum Stdio {
39
40
40
41
impl Command {
41
42
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 }
43
44
}
44
45
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());
48
48
}
49
49
50
50
pub fn env_mut(&mut self) -> &mut CommandEnv {
@@ -72,7 +72,7 @@ impl Command {
72
72
}
73
73
74
74
pub fn get_args(&self) -> CommandArgs<'_> {
75
- panic!("unsupported")
75
+ CommandArgs { iter: self.args.iter() }
76
76
}
77
77
78
78
pub fn get_envs(&self) -> CommandEnvs<'_> {
@@ -116,6 +116,12 @@ impl Command {
116
116
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
117
117
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
118
118
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
+
119
125
// Setup Stdout
120
126
let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
121
127
let stdout = Self::create_pipe(stdout)?;
@@ -315,7 +321,7 @@ mod uefi_command_internal {
315
321
stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
316
322
stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
317
323
st: OwnedTable<r_efi::efi::SystemTable>,
318
- args: Option<Vec< u16> >,
324
+ args: Option<(*mut u16, usize) >,
319
325
}
320
326
321
327
impl Image {
@@ -449,20 +455,20 @@ mod uefi_command_internal {
449
455
}
450
456
}
451
457
452
- pub fn set_args(&mut self, args: &OsStr ) {
458
+ pub fn set_args(&mut self, args: Box<[u16]> ) {
453
459
let loaded_image: NonNull<loaded_image::Protocol> =
454
460
helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
455
461
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();
458
465
459
466
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;
462
468
(*loaded_image.as_ptr()).load_options_size = args_size;
463
469
}
464
470
465
- self.args = Some(args );
471
+ self.args = Some((ptr, len) );
466
472
}
467
473
468
474
fn update_st_crc32(&mut self) -> io::Result<()> {
@@ -502,6 +508,10 @@ mod uefi_command_internal {
502
508
((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
503
509
}
504
510
}
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
+ }
505
515
}
506
516
}
507
517
@@ -681,4 +691,38 @@ mod uefi_command_internal {
681
691
}
682
692
}
683
693
}
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
+ }
684
728
}
0 commit comments