Skip to content

Commit f5edb0b

Browse files
committed
main: Set HOME very early on if unset
This works around bootc-image-builder not setting HOME, in combination with `podman` bombing if it's unset. Needed for bound images as part of bootc-image-builder. Signed-off-by: Colin Walters <[email protected]>
1 parent affe394 commit f5edb0b

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

cli/src/main.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use anyhow::Result;
22

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

21-
#[tokio::main(flavor = "current_thread")]
22-
async fn main() {
23-
if let Err(e) = run().await {
25+
/// Perform process global initialization, then create an async runtime
26+
/// and do the rest of the work there.
27+
fn run() -> Result<()> {
28+
// Initialize global state before we've possibly created other threads, etc.
29+
bootc_lib::cli::global_init()?;
30+
// We only use the "current thread" runtime because we don't perform
31+
// a lot of CPU heavy work in async tasks. Where we do work on the CPU,
32+
// or we do want explicit concurrency, we typically use
33+
// tokio::task::spawn_blocking to create a new OS thread explicitly.
34+
let runtime = tokio::runtime::Builder::new_current_thread()
35+
.enable_all()
36+
.build()
37+
.expect("Failed to build tokio runtime");
38+
// And invoke the async_main
39+
runtime.block_on(async move { async_main().await })
40+
}
41+
42+
fn main() {
43+
// In order to print the error in a custom format (with :#) our
44+
// main simply invokes a run() where all the work is done.
45+
// This code just captures any errors.
46+
if let Err(e) = run() {
2447
tracing::error!("{:#}", e);
2548
std::process::exit(1);
2649
}

lib/src/cli.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,21 @@ async fn usroverlay() -> Result<()> {
711711
.into());
712712
}
713713

714+
/// Perform process global initialization. This should be called as early as possible
715+
/// in the standard `main` function.
716+
pub fn global_init() -> Result<()> {
717+
let am_root = rustix::process::getuid().is_root();
718+
// Work around bootc-image-builder not setting HOME, in combination with podman (really c/common)
719+
// bombing out if it is unset.
720+
if std::env::var_os("HOME").is_none() && am_root {
721+
// Setting the environment is thread-unsafe, but we ask calling code
722+
// to invoke this as early as possible. (In practice, that's just the cli's `main.rs`)
723+
// xref https://internals.rust-lang.org/t/synchronized-ffi-access-to-posix-environment-variable-functions/15475
724+
std::env::set_var("HOME", "/root");
725+
}
726+
Ok(())
727+
}
728+
714729
/// Parse the provided arguments and execute.
715730
/// Calls [`structopt::clap::Error::exit`] on failure, printing the error message and aborting the program.
716731
pub async fn run_from_iter<I>(args: I) -> Result<()>

0 commit comments

Comments
 (0)