Skip to content

Commit

Permalink
Merge pull request #716 from cgwalters/ensure-home
Browse files Browse the repository at this point in the history
main: Set HOME very early on if unset
  • Loading branch information
cgwalters authored Jul 22, 2024
2 parents affe394 + f5edb0b commit a9cd10f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
31 changes: 27 additions & 4 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use anyhow::Result;

async fn run() -> Result<()> {
/// The code called after we've done process global init and created
/// an async runtime.
async fn async_main() -> Result<()> {
// Don't include timestamps and such because they're not really useful and
// too verbose, and plus several log targets such as journald will already
// include timestamps.
Expand All @@ -15,12 +17,33 @@ async fn run() -> Result<()> {
.with_writer(std::io::stderr)
.init();
tracing::trace!("starting");
// As you can see, the role of this file is mostly to just be a shim
// to call into the code that lives in the internal shared library.
bootc_lib::cli::run_from_iter(std::env::args()).await
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
if let Err(e) = run().await {
/// Perform process global initialization, then create an async runtime
/// and do the rest of the work there.
fn run() -> Result<()> {
// Initialize global state before we've possibly created other threads, etc.
bootc_lib::cli::global_init()?;
// We only use the "current thread" runtime because we don't perform
// a lot of CPU heavy work in async tasks. Where we do work on the CPU,
// or we do want explicit concurrency, we typically use
// tokio::task::spawn_blocking to create a new OS thread explicitly.
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("Failed to build tokio runtime");
// And invoke the async_main
runtime.block_on(async move { async_main().await })
}

fn main() {
// In order to print the error in a custom format (with :#) our
// main simply invokes a run() where all the work is done.
// This code just captures any errors.
if let Err(e) = run() {
tracing::error!("{:#}", e);
std::process::exit(1);
}
Expand Down
15 changes: 15 additions & 0 deletions lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,21 @@ async fn usroverlay() -> Result<()> {
.into());
}

/// Perform process global initialization. This should be called as early as possible
/// in the standard `main` function.
pub fn global_init() -> Result<()> {
let am_root = rustix::process::getuid().is_root();
// Work around bootc-image-builder not setting HOME, in combination with podman (really c/common)
// bombing out if it is unset.
if std::env::var_os("HOME").is_none() && am_root {
// Setting the environment is thread-unsafe, but we ask calling code
// to invoke this as early as possible. (In practice, that's just the cli's `main.rs`)
// xref https://internals.rust-lang.org/t/synchronized-ffi-access-to-posix-environment-variable-functions/15475
std::env::set_var("HOME", "/root");
}
Ok(())
}

/// Parse the provided arguments and execute.
/// Calls [`structopt::clap::Error::exit`] on failure, printing the error message and aborting the program.
pub async fn run_from_iter<I>(args: I) -> Result<()>
Expand Down

0 comments on commit a9cd10f

Please sign in to comment.