//! `brokerd`: the broker role. `serve` takes the audit lock, binds both sockets, and serves. use std::path::PathBuf; use std::process::ExitCode; use std::sync::Arc; use brokerd::audit::{AuditError, RECOVERED_NOTICE}; use brokerd::config::Config; use brokerd::runner::Refusing; use brokerd::serve::{self, ServeError}; const USAGE: &str = "usage: brokerd serve --config [--accept-break]"; fn main() -> ExitCode { // The first argument must be `serve`. let mut args = std::env::args().skip(1); match args.next() { Some(command) if command == "serve" => {} _ => return usage(), } // `--config ` exactly once and `--accept-break` at most once, in any order. let (config_path, accept_break) = match parse_serve(args) { Ok(pair) => pair, Err(()) => return usage(), }; // Read the config before touching the filesystem: a bad config must make nothing. let cfg = match Config::load(&config_path) { Ok(cfg) => cfg, Err(e) => { eprintln!("brokerd: {e}"); return ExitCode::from(1); } }; // Keep the socket paths for the serving notice, before `cfg` is moved into `start`. let broker_path = cfg.broker_socket(); let admin_path = cfg.admin_socket(); let started = match serve::start( cfg, accept_break, Box::new(Refusing), Arc::new(|line: &str| eprintln!("{line}")), ) { Ok(started) => started, Err(ServeError::Audit(e @ AuditError::NothingToAccept)) => { eprintln!("brokerd: {e}"); return ExitCode::from(2); } Err(e) => { eprintln!("brokerd: {e}"); return ExitCode::from(1); } }; if started.recovered { eprintln!("{RECOVERED_NOTICE}"); } if let Some(failure) = &started.accepted { eprintln!( "audit: accepted the break at {}:{}: {}", failure.file, failure.line, failure.what ); } eprintln!( "brokerd: serving tools on {} and approvals on {}", broker_path.display(), admin_path.display() ); match started.run() { Ok(()) => ExitCode::SUCCESS, Err(e) => { eprintln!("brokerd: {e}"); ExitCode::from(1) } } } /// The argument list was not `serve --config [--accept-break]`. fn usage() -> ExitCode { eprintln!("{USAGE}"); ExitCode::from(2) } /// The `--config` and `--accept-break` flags after `serve`, or `Err(())` for a bad list. fn parse_serve>(mut args: I) -> Result<(PathBuf, bool), ()> { let mut config: Option = None; let mut accept_break = false; loop { match args.next() { None => { return match config { Some(path) => Ok((PathBuf::from(path), accept_break)), None => Err(()), }; } Some(arg) => match arg.as_str() { "--config" => match args.next() { Some(path) => { if config.is_some() { return Err(()); } config = Some(path); } None => return Err(()), }, "--accept-break" => { if accept_break { return Err(()); } accept_break = true; } _ => return Err(()), }, } } }