add environment variable configuration

This commit is contained in:
Ryan Heywood 2025-08-10 22:17:56 -04:00
parent f5273c1fd3
commit 795bdbe4d7
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
3 changed files with 60 additions and 5 deletions

View File

@ -1,3 +1,8 @@
use std::{
io::{BufRead, BufReader},
path::PathBuf,
};
use crate::platform::{self, Platform};
use crate::result::{Context, Result};
@ -12,6 +17,31 @@ pub struct Config {
pub platform: Option<Box<dyn Platform>>,
pub mode: Mode,
pub target: String,
pub environment: Vec<String>,
}
pub fn get_environment() -> Result<Vec<String>> {
let mut environment = vec![];
let environment_file = PathBuf::from("/etc/environment");
// NOTE: We should never have to care about permissions. Therefore, we don't use .try_exists()
// As for TOCTOU... we're init, and this is the first code to run.
if environment_file.exists() {
let file = std::fs::File::open(&environment_file).context(format_args!(
"could not open: {environment_file}",
environment_file = environment_file.display(),
))?;
let reader = BufReader::new(file);
for line in reader.lines() {
let line = line.context(format_args!(
"could not read line from: {environment_file}",
environment_file = environment_file.display()
))?;
environment.push(line);
}
}
Ok(environment)
}
pub fn get_config() -> Result<Config> {
@ -39,7 +69,16 @@ pub fn get_config() -> Result<Config> {
let platform = platform::get_current_platform(values.remove("platform").as_deref())?;
let target = values.remove("target").unwrap_or(String::from("/usr/bin/hello"));
let target = values
.remove("target")
.unwrap_or(String::from("/usr/bin/hello"));
Ok(Config { platform, mode, target })
let environment = get_environment()?;
Ok(Config {
platform,
mode,
target,
environment,
})
}

View File

@ -17,6 +17,7 @@ fn main() {
}
}
#[allow(dead_code)]
extern "C" fn handle_sigchld(_sig: i32) {
// wait on all dead processes
while system::syscall::waitpid(-1, libc::WNOHANG).is_ok() {
@ -66,7 +67,8 @@ fn init() -> Result<()> {
}
config::Mode::Exec => {
dmesg(format!("pivoting to {command}"));
system::syscall::execv(command, &[])?;
let envs = config.environment.iter().map(|e| &**e).collect::<Vec<_>>();
system::syscall::execve(command, &[], &envs)?;
}
}

View File

@ -193,7 +193,7 @@ pub fn close(fd: RawFd) -> Result<()> {
}
}
pub fn execv(command: impl AsRef<Path>, args: &[&str]) -> Result<()> {
pub fn execve(command: impl AsRef<Path>, args: &[&str], envs: &[&str]) -> Result<()> {
let command = command.as_ref();
let command_cstr = CString::new(command.as_os_str().as_encoded_bytes())
@ -213,7 +213,21 @@ pub fn execv(command: impl AsRef<Path>, args: &[&str]) -> Result<()> {
.chain(std::iter::once(std::ptr::null()))
.collect();
if unsafe { libc::execv(command_cstr.as_ptr().cast(), args_ptrs.as_ptr().cast()) } == -1 {
let mut envs_cstr = vec![command_cstr.clone()];
for env in envs {
let cur_env_cstr = CString::new(env.as_bytes()).context(format_args!("bad env: {env}"))?;
envs_cstr.push(cur_env_cstr);
}
// NOTE: The last env must be a null pointer, but we can't construct a CString from nullptr, so
// we construct an array of pointers and use that
let envs_ptrs: Vec<_> = envs_cstr
.iter()
.map(|s| s.as_ptr())
.chain(std::iter::once(std::ptr::null()))
.collect();
if unsafe { libc::execve(command_cstr.as_ptr().cast(), args_ptrs.as_ptr().cast(), envs_ptrs.as_ptr().cast()) } == -1 {
return ctx_os_error(format_args!(
"error calling exec({command}, {args:?})",
command = command.display()