use std::fs::DirBuilder;
use std::os::unix::fs::DirBuilderExt;
use std::path::{Path, PathBuf};
use anyhow::{Context, Result, bail};
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::fmt;
use tracing_subscriber::prelude::*;
use firebrick_daemon::secrets::{self, SecretStore};
use firebrick_daemon::{runtime, sandboxes, server, ssh};
fn main() -> Result<()> {
let secrets_path = firebrick_utils::secrets_path().context(firebrick_utils::NO_DATA_DIR)?;
let log_dir = firebrick_utils::log_dir().context(firebrick_utils::NO_LOG_DIR)?;
use_firebrick_msb_home()?;
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.context("failed to start the Tokio runtime")?
.block_on(run(&log_dir, secrets_path))
}
fn use_firebrick_msb_home() -> Result<()> {
if std::env::var_os("MSB_HOME").is_some_and(|home| !home.is_empty()) {
return Ok(());
}
let Some(home) = firebrick_utils::msb_home() else {
bail!(
"can't choose a microsandbox home: set HOME or XDG_STATE_HOME to an absolute path, \
or set MSB_HOME"
);
};
DirBuilder::new()
.recursive(true)
.mode(0o700)
.create(&home)
.with_context(|| format!("failed to create the microsandbox home {}", home.display()))?;
unsafe { std::env::set_var("MSB_HOME", &home) };
Ok(())
}
async fn run(log_dir: &Path, secrets_path: PathBuf) -> Result<()> {
let _log_guard = init_logging(log_dir)?;
let socket_path = firebrick_utils::socket_path();
if socket_path.exists() {
bail!(server::ServerError::SocketAlreadyInUse());
}
let msb_config =
microsandbox::config::config().context("failed to load the microsandbox configuration")?;
runtime::ensure(&msb_config).await?;
secrets::protect_database(&msb_config.home())
.context("failed to protect the microsandbox database")?;
ssh::ensure_keys()?;
sandboxes::sync_ssh_config().await;
tracing::info!(path = %log_dir.display(), "writing logs");
tracing::info!(path = %msb_config.home().display(), "using microsandbox home");
tracing::info!(
path = socket_path.to_str().unwrap(),
"listening on unix socket"
);
Ok(server::run(&socket_path, SecretStore::new(secrets_path)).await?)
}
fn init_logging(log_dir: &Path) -> Result<WorkerGuard> {
std::fs::create_dir_all(log_dir)?;
let (log_writer, log_guard) =
tracing_appender::non_blocking(tracing_appender::rolling::daily(log_dir, "fbkd.log"));
tracing_subscriber::registry()
.with(fmt::layer())
.with(fmt::layer().with_ansi(false).with_writer(log_writer))
.with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")))
.init();
Ok(log_guard)
}