diff --git a/.github/workflows/fedora.yml b/.github/workflows/fedora.yml index f0f78b7281..7b13c28235 100644 --- a/.github/workflows/fedora.yml +++ b/.github/workflows/fedora.yml @@ -51,7 +51,7 @@ jobs: - task: PROFILEDIR=debug make -f Makefile build-no-ipc toolchain: 1.75.0 # CURRENT DEVELOPMENT RUST TOOLCHAIN components: cargo - - task: PROFILEDIR=debug make -f Makefile stratis-dumpmetadata + - task: PROFILEDIR=debug make -f Makefile stratisd-tools toolchain: 1.75.0 # CURRENT DEVELOPMENT RUST TOOLCHAIN components: cargo - task: make -f Makefile docs-ci diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 918191ba38..7f72a5551b 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -51,7 +51,7 @@ jobs: - task: PROFILEDIR=debug make -f Makefile build-no-ipc toolchain: 1.75.0 # CURRENT DEVELOPMENT RUST TOOLCHAIN components: cargo - - task: PROFILEDIR=debug make -f Makefile stratis-dumpmetadata + - task: PROFILEDIR=debug make -f Makefile stratisd-tools toolchain: 1.75.0 # CURRENT DEVELOPMENT RUST TOOLCHAIN components: cargo - task: make -f Makefile docs-ci diff --git a/Cargo.toml b/Cargo.toml index 205b075d4d..942cd19646 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ name = "stratisd" required-features = ["engine"] [[bin]] -name = "stratis-dumpmetadata" +name = "stratisd-tools" required-features = ["engine", "extras", "min"] [[bin]] diff --git a/Makefile b/Makefile index d0bb1d7806..0269ede4c1 100644 --- a/Makefile +++ b/Makefile @@ -165,7 +165,7 @@ audit-all-rust: build-all-rust ./target/${PROFILEDIR}/stratis-utils \ ./target/${PROFILEDIR}/stratis-str-cmp \ ./target/${PROFILEDIR}/stratis-base32-decode \ - ./target/${PROFILEDIR}/stratis-dumpmetadata + ./target/${PROFILEDIR}/stratisd-tools ## Check for spelling errors check-typos: @@ -253,12 +253,12 @@ build-stratis-base32-decode: # so we use two distinct targets to build the two binaries build-udev-utils: build-stratis-str-cmp build-stratis-base32-decode -## Build the stratis-dumpmetadata program -stratis-dumpmetadata: +## Build the stratisd-tools program +stratisd-tools: PKG_CONFIG_ALLOW_CROSS=1 \ RUSTFLAGS="${DENY}" \ cargo ${BUILD} ${RELEASE_FLAG} \ - --bin=stratis-dumpmetadata ${EXTRAS_FEATURES} ${TARGET_ARGS} + --bin=stratisd-tools ${EXTRAS_FEATURES} ${TARGET_ARGS} ## Build stratis-min for early userspace stratis-min: @@ -314,8 +314,11 @@ install-binaries: mkdir -p $(DESTDIR)$(BINDIR) mkdir -p $(DESTDIR)$(UNITGENDIR) $(INSTALL) -Dpm0755 -t $(DESTDIR)$(BINDIR) target/$(PROFILEDIR)/stratis-min + + $(INSTALL) -Dpm0755 -t $(DESTDIR)$(BINDIR) target/$(PROFILEDIR)/stratisd-tools + ln --force --verbose $(DESTDIR)$(BINDIR)/stratisd-tools $(DESTDIR)$(BINDIR)/stratis-dumpmetadata + $(INSTALL) -Dpm0755 -t $(DESTDIR)$(BINDIR) target/$(PROFILEDIR)/stratis-utils - $(INSTALL) -Dpm0755 -t $(DESTDIR)$(BINDIR) target/$(PROFILEDIR)/stratis-dumpmetadata mv --force --verbose $(DESTDIR)$(BINDIR)/stratis-utils $(DESTDIR)$(BINDIR)/stratis-predict-usage ln --force --verbose $(DESTDIR)$(BINDIR)/stratis-predict-usage $(DESTDIR)$(UNITGENDIR)/stratis-clevis-setup-generator ln --force --verbose $(DESTDIR)$(BINDIR)/stratis-predict-usage $(DESTDIR)$(UNITGENDIR)/stratis-setup-generator @@ -341,7 +344,7 @@ install-daemons: install: install-udev-cfg install-man-cfg install-dbus-cfg install-dracut-cfg install-systemd-cfg install-binaries install-udev-binaries install-fstab-script install-daemons ## Build all Rust artifacts -build-all-rust: build build-min build-udev-utils stratis-dumpmetadata +build-all-rust: build build-min build-udev-utils stratisd-tools ## Build all man pages build-all-man: docs/stratisd.8 docs/stratis-dumpmetadata.8 @@ -366,6 +369,7 @@ clean-ancillary: rm -fv $(DESTDIR)$(UDEVDIR)/stratis-str-cmp rm -fv $(DESTDIR)$(UDEVDIR)/stratis-base32-decode rm -fv $(DESTDIR)$(BINDIR)/stratis-predict-usage + rm -fv $(DESTDIR)$(BINDIR)/stratisd-tools rm -fv $(DESTDIR)$(BINDIR)/stratis-dumpmetadata rm -fv $(DESTDIR)$(UNITGENDIR)/stratis-setup-generator rm -fv $(DESTDIR)$(UNITGENDIR)/stratis-clevis-setup-generator diff --git a/src/bin/stratisd-tools.rs b/src/bin/stratisd-tools.rs new file mode 100644 index 0000000000..281b5a6360 --- /dev/null +++ b/src/bin/stratisd-tools.rs @@ -0,0 +1,84 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +mod tools; + +use std::{env, path::Path, process}; + +use clap::{Arg, Command}; +use env_logger::Builder; + +use crate::tools::cmds; + +fn basename(path: &str) -> Option<&Path> { + Path::new(path).file_name().map(Path::new) +} + +/// Configure and initialize the logger. +/// Read log configuration parameters from the environment if RUST_LOG +/// is set. Otherwise, just accept the default configuration, which is +/// to log at the severity of error only. +fn initialize_log() { + let mut builder = Builder::new(); + + if let Ok(s) = env::var("RUST_LOG") { + builder.parse_filters(&s); + } + + builder.init() +} + +fn main() { + initialize_log(); + + let executable_name = "stratisd-tools"; + + let args = env::args().collect::>(); + let argv1 = &args[0]; + + let stripped_args = if basename(argv1.as_str()) + .map(|n| n == Path::new(executable_name)) + .unwrap_or(false) + { + let command = Command::new(executable_name) + .arg( + Arg::new("executable") + .required(true) + .value_name("EXECUTABLE") + .value_parser(cmds().iter().map(|x| x.name()).collect::>()), + ) + .arg_required_else_help(true); + + let truncated_args = if args.len() > 1 { + vec![argv1, &args[1]] + } else { + vec![argv1] + }; + + command.get_matches_from(truncated_args); + args[1..].to_vec() + } else { + args + }; + + let command_name = match basename(&stripped_args[0]).and_then(|n| n.to_str()) { + Some(name) => name, + None => { + process::exit(1); + } + }; + + if let Some(c) = cmds().iter().find(|x| command_name == x.name()) { + match c.run(stripped_args) { + Ok(()) => {} + Err(e) => { + eprintln!("Error encountered: {e}"); + process::exit(1); + } + } + } else { + eprintln!("Unknown executable name {command_name}"); + process::exit(2); + } +} diff --git a/src/bin/tools/cmds.rs b/src/bin/tools/cmds.rs new file mode 100644 index 0000000000..8f6384a1a7 --- /dev/null +++ b/src/bin/tools/cmds.rs @@ -0,0 +1,80 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use clap::{Arg, ArgAction, Command}; + +use crate::tools::dump_metadata; + +pub trait ToolCommand<'a> { + fn name(&self) -> &'a str; + fn run(&self, command_line_args: Vec) -> Result<(), String>; +} + +struct StratisDumpMetadata; + +impl StratisDumpMetadata { + fn cmd() -> Command { + Command::new("stratis-dumpmetadata") + .next_line_help(true) + .arg( + Arg::new("dev") + .required(true) + .help("Print metadata of given device"), + ) + .arg( + Arg::new("print_bytes") + .long("print-bytes") + .action(ArgAction::SetTrue) + .num_args(0) + .short('b') + .help("Print byte buffer of signature block"), + ) + .arg( + Arg::new("only") + .long("only") + .action(ArgAction::Set) + .value_name("PORTION") + .value_parser(["pool"]) + .help("Only print specified portion of the metadata"), + ) + } +} + +impl<'a> ToolCommand<'a> for StratisDumpMetadata { + fn name(&self) -> &'a str { + "stratis-dumpmetadata" + } + + fn run(&self, command_line_args: Vec) -> Result<(), String> { + let matches = StratisDumpMetadata::cmd().get_matches_from(command_line_args); + let devpath = matches + .get_one::("dev") + .map(|s| s.as_str()) + .expect("'dev' is a mandatory argument"); + + dump_metadata::run( + devpath, + matches.get_flag("print_bytes"), + matches + .get_one::("only") + .map(|v| v == "pool") + .unwrap_or(false), + ) + } +} + +pub fn cmds<'a>() -> Vec>> { + vec![Box::new(StratisDumpMetadata)] +} + +#[cfg(test)] +mod tests { + + use super::StratisDumpMetadata; + + #[test] + fn test_dumpmetadata_parse_args() { + StratisDumpMetadata::cmd().debug_assert(); + } +} diff --git a/src/bin/stratis-dumpmetadata.rs b/src/bin/tools/dump_metadata.rs similarity index 69% rename from src/bin/stratis-dumpmetadata.rs rename to src/bin/tools/dump_metadata.rs index ea146bad46..7fc2dfe70f 100644 --- a/src/bin/stratis-dumpmetadata.rs +++ b/src/bin/tools/dump_metadata.rs @@ -3,16 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use std::{ - env, fs::OpenOptions, io::{Seek, SeekFrom}, - process, }; -use env_logger::Builder; - -use clap::{Arg, ArgAction, Command}; - use pretty_hex::pretty_hex; use serde_json::Value; @@ -112,26 +106,12 @@ fn print_pool_metadata(pool_metadata: &Option>, only_pool: bool) -> Resu Ok(()) } -/// Configure and initialize the logger. -/// Read log configuration parameters from the environment if RUST_LOG -/// is set. Otherwise, just accept the default configuration, which is -/// to log at the severity of error only. -fn initialize_log() { - let mut builder = Builder::new(); - - if let Ok(s) = env::var("RUST_LOG") { - builder.parse_filters(&s); - } - - builder.init() -} - // Print metadata, such as StaticHeaders, BDA, and Pool Metadata of given device. // If sigblocks match, display the StaticHeader fields of a single sigblock, // Otherwise display the StaticHeader fields of both sigblocks. // If print_bytes flag is set to True, display the bytes buffer // of the sigblock alongside the StaticHeader. -fn run(devpath: &str, print_bytes: bool, pool_only: bool) -> Result<(), String> { +pub fn run(devpath: &str, print_bytes: bool, pool_only: bool) -> Result<(), String> { let mut devfile = OpenOptions::new() .read(true) .open(devpath) @@ -163,64 +143,3 @@ fn run(devpath: &str, print_bytes: bool, pool_only: bool) -> Result<(), String> Ok(()) } - -fn parse_args() -> Command { - Command::new("stratis-dumpmetadata") - .next_line_help(true) - .arg( - Arg::new("dev") - .required(true) - .help("Print metadata of given device"), - ) - .arg( - Arg::new("print_bytes") - .long("print-bytes") - .action(ArgAction::SetTrue) - .num_args(0) - .short('b') - .help("Print byte buffer of signature block"), - ) - .arg( - Arg::new("only") - .long("only") - .action(ArgAction::Set) - .value_name("PORTION") - .value_parser(["pool"]) - .help("Only print specified portion of the metadata"), - ) -} - -fn main() { - let matches = parse_args().get_matches(); - let devpath = matches - .get_one::("dev") - .map(|s| s.as_str()) - .expect("'dev' is a mandatory argument"); - - initialize_log(); - - match run( - devpath, - matches.get_flag("print_bytes"), - matches - .get_one::("only") - .map(|v| v == "pool") - .unwrap_or(false), - ) { - Ok(()) => {} - Err(e) => { - eprintln!("Error encountered: {}", e); - process::exit(1); - } - } -} - -#[cfg(test)] -mod tests { - use super::parse_args; - - #[test] - fn test_dumpmetadata_parse_args() { - parse_args().debug_assert(); - } -} diff --git a/src/bin/tools/mod.rs b/src/bin/tools/mod.rs new file mode 100644 index 0000000000..b7d2ac52d2 --- /dev/null +++ b/src/bin/tools/mod.rs @@ -0,0 +1,8 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +mod cmds; +pub mod dump_metadata; + +pub use cmds::cmds;