mirror of
https://github.com/NLnetLabs/dnst.git
synced 2026-08-31 04:09:45 +02:00
123 lines
3.6 KiB
Rust
123 lines
3.6 KiB
Rust
use std::ffi::OsString;
|
|
use std::path::Path;
|
|
|
|
use clap::Parser;
|
|
use commands::key2ds::Key2ds;
|
|
use commands::keygen::Keygen;
|
|
use commands::notify::Notify;
|
|
use commands::nsec3hash::Nsec3Hash;
|
|
use commands::signzone::SignZone;
|
|
use commands::update::Update;
|
|
use commands::LdnsCommand;
|
|
use domain::base::zonefile_fmt::DisplayKind;
|
|
use env::Env;
|
|
use error::Error;
|
|
use log::LogFormatter;
|
|
use tracing::level_filters::LevelFilter;
|
|
|
|
pub use self::args::Args;
|
|
|
|
pub mod args;
|
|
pub mod commands;
|
|
pub mod env;
|
|
pub mod error;
|
|
pub mod log;
|
|
pub mod parse;
|
|
pub mod util;
|
|
|
|
/// Define the way that we output zonefile records once for consistent use
|
|
/// everywhere.
|
|
pub const DISPLAY_KIND: DisplayKind = DisplayKind::Tabbed;
|
|
|
|
pub fn try_ldns_compatibility<I: IntoIterator<Item = OsString>>(
|
|
args: I,
|
|
) -> Result<Option<Args>, Error> {
|
|
let mut args_iter = args.into_iter();
|
|
let binary_path = args_iter.next().ok_or("Missing binary name")?;
|
|
|
|
let binary_name = extract_binary_name(Path::new(&binary_path))?;
|
|
|
|
// We only branch on the binary name for the ldns utilities. The rest we
|
|
// just handle as regular dnst.
|
|
let Some(binary_name) = binary_name.strip_prefix("ldns-") else {
|
|
return Ok(None);
|
|
};
|
|
|
|
let res = match binary_name {
|
|
"key2ds" => Key2ds::parse_ldns_args(args_iter),
|
|
"notify" => Notify::parse_ldns_args(args_iter),
|
|
"keygen" => Keygen::parse_ldns_args(args_iter),
|
|
"nsec3-hash" => Nsec3Hash::parse_ldns_args(args_iter),
|
|
"signzone" => SignZone::parse_ldns_args(args_iter),
|
|
"update" => Update::parse_ldns_args(args_iter),
|
|
_ => Err(format!("Unrecognized ldns command 'ldns-{binary_name}'").into()),
|
|
}?;
|
|
|
|
Ok(Some(res))
|
|
}
|
|
|
|
/// Get the binary name from a [`Path`].
|
|
///
|
|
/// The binary name is the file name without any extensions. It is similar
|
|
/// to the unstable `Path::file_stem`.
|
|
///
|
|
/// ```rust
|
|
/// use dnst::extract_binary_name;
|
|
/// use std::path::Path;
|
|
///
|
|
/// let bin = extract_binary_name(Path::new("foo/ldns-xxx")).unwrap();
|
|
/// assert_eq!(bin, "ldns-xxx");
|
|
///
|
|
/// let bin = extract_binary_name(Path::new("foo/ldns-xxx.real")).unwrap();
|
|
/// assert_eq!(bin, "ldns-xxx");
|
|
///
|
|
/// let bin = extract_binary_name(Path::new("./ldns-xxx.exe")).unwrap();
|
|
/// assert_eq!(bin, "ldns-xxx");
|
|
///
|
|
/// let bin = extract_binary_name(Path::new("ldns-xxx")).unwrap();
|
|
/// assert_eq!(bin, "ldns-xxx");
|
|
/// ```
|
|
pub fn extract_binary_name(path: &Path) -> Result<&str, Error> {
|
|
let filename = path
|
|
.file_name()
|
|
.ok_or("Missing binary file name")?
|
|
.to_str()
|
|
.ok_or("Binary file name is not valid unicode")?;
|
|
|
|
match filename.split_once('.') {
|
|
Some((binary, _)) => Ok(binary),
|
|
None => Ok(filename),
|
|
}
|
|
}
|
|
|
|
fn parse_args(env: impl Env) -> Result<Args, Error> {
|
|
if let Some(args) = try_ldns_compatibility(env.args_os())? {
|
|
return Ok(args);
|
|
}
|
|
let args = Args::try_parse_from(env.args_os())?;
|
|
Ok(args)
|
|
}
|
|
|
|
pub fn run(env: impl Env) -> u8 {
|
|
let stderr = env.stderr();
|
|
let mut subscriber = tracing_subscriber::FmtSubscriber::builder()
|
|
.with_ansi(stderr.is_terminal())
|
|
.with_writer(stderr)
|
|
.with_max_level(LevelFilter::WARN)
|
|
.event_format(LogFormatter {
|
|
program: env.args_os().next().unwrap().to_string_lossy().to_string(),
|
|
});
|
|
let res = parse_args(&env);
|
|
if let Ok(args) = &res {
|
|
subscriber = subscriber.with_max_level(args.verbosity);
|
|
}
|
|
tracing::subscriber::with_default(subscriber.finish(), || {
|
|
res.and_then(|args| args.execute(&env))
|
|
.map(|()| 0)
|
|
.unwrap_or_else(|err| {
|
|
err.pretty_print(&env);
|
|
err.exit_code()
|
|
})
|
|
})
|
|
}
|