Skip to content

Commit 1ed804d

Browse files
committed
uefi: process: Add support for command environment variables
Set environment variables before launching the process and restore the prior variables after the program exists. This is the same implementation as the one used by UEFI Shell Execute [0]. [0]: https://github.com/tianocore/edk2/blob/2d2642f4832ebc45cb7d5ba9430b933d953b94f2/ShellPkg/Application/Shell/ShellProtocol.c#L1700 Signed-off-by: Ayush Singh <ayush@beagleboard.org>
1 parent 8239a37 commit 1ed804d

File tree

1 file changed

+62
-3
lines changed

1 file changed

+62
-3
lines changed

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

+62-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use r_efi::protocols::simple_text_output;
22

33
use super::helpers;
4+
use crate::collections::BTreeMap;
45
pub use crate::ffi::OsString as EnvKey;
56
use crate::ffi::{OsStr, OsString};
67
use crate::num::{NonZero, NonZeroI32};
@@ -21,6 +22,7 @@ pub struct Command {
2122
args: Vec<OsString>,
2223
stdout: Option<Stdio>,
2324
stderr: Option<Stdio>,
25+
env: CommandEnv,
2426
}
2527

2628
// passed back to std::process with the pipes connected to the child, if any
@@ -40,15 +42,21 @@ pub enum Stdio {
4042

4143
impl Command {
4244
pub fn new(program: &OsStr) -> Command {
43-
Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None }
45+
Command {
46+
prog: program.to_os_string(),
47+
args: Vec::new(),
48+
stdout: None,
49+
stderr: None,
50+
env: Default::default(),
51+
}
4452
}
4553

4654
pub fn arg(&mut self, arg: &OsStr) {
4755
self.args.push(arg.to_os_string());
4856
}
4957

5058
pub fn env_mut(&mut self) -> &mut CommandEnv {
51-
panic!("unsupported")
59+
&mut self.env
5260
}
5361

5462
pub fn cwd(&mut self, _dir: &OsStr) {
@@ -76,7 +84,7 @@ impl Command {
7684
}
7785

7886
pub fn get_envs(&self) -> CommandEnvs<'_> {
79-
panic!("unsupported")
87+
self.env.iter()
8088
}
8189

8290
pub fn get_current_dir(&self) -> Option<&Path> {
@@ -140,8 +148,30 @@ impl Command {
140148
cmd.stderr_inherit()
141149
};
142150

151+
let env = env_changes(&self.env);
152+
153+
// Set any new vars
154+
if let Some(e) = &env {
155+
for (k, (_, v)) in e {
156+
match v {
157+
Some(v) => crate::env::set_var(k, v),
158+
None => crate::env::remove_var(k),
159+
}
160+
}
161+
}
162+
143163
let stat = cmd.start_image()?;
144164

165+
// Rollback any env changes
166+
if let Some(e) = env {
167+
for (k, (v, _)) in e {
168+
match v {
169+
Some(v) => crate::env::set_var(k, v),
170+
None => crate::env::remove_var(k),
171+
}
172+
}
173+
}
174+
145175
let stdout = cmd.stdout()?;
146176
let stderr = cmd.stderr()?;
147177

@@ -725,3 +755,32 @@ mod uefi_command_internal {
725755
res.into_boxed_slice()
726756
}
727757
}
758+
759+
/// Create a map of environment variable changes. Allows efficient setting and rolling back of
760+
/// enviroment variable changes.
761+
///
762+
/// Entry: (Old Value, New Value)
763+
fn env_changes(env: &CommandEnv) -> Option<BTreeMap<EnvKey, (Option<OsString>, Option<OsString>)>> {
764+
if env.is_unchanged() {
765+
return None;
766+
}
767+
768+
let mut result = BTreeMap::<EnvKey, (Option<OsString>, Option<OsString>)>::new();
769+
770+
// Check if we want to clear all prior variables
771+
if env.does_clear() {
772+
for (k, v) in crate::env::vars_os() {
773+
result.insert(k.into(), (Some(v), None));
774+
}
775+
}
776+
777+
for (k, v) in env.iter() {
778+
let v: Option<OsString> = v.map(Into::into);
779+
result
780+
.entry(k.into())
781+
.and_modify(|cur| *cur = (cur.0.clone(), v.clone()))
782+
.or_insert((crate::env::var_os(k), v));
783+
}
784+
785+
Some(result)
786+
}

0 commit comments

Comments
 (0)