Merge rust tools into a single pdata_tools exe
This commit is contained in:
@@ -1,105 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use atty::Stream;
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
|
||||
use thinp::cache::check::{check, CacheCheckOptions};
|
||||
use thinp::file_utils;
|
||||
use thinp::report::*;
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("cache_check")
|
||||
.version(thinp::version::tools_version())
|
||||
// flags
|
||||
.arg(
|
||||
Arg::with_name("ASYNC_IO")
|
||||
.help("Force use of io_uring for synchronous io")
|
||||
.long("async-io")
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("AUTO_REPAIR")
|
||||
.help("Auto repair trivial issues.")
|
||||
.long("auto-repair"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("IGNORE_NON_FATAL")
|
||||
.help("Only return a non-zero exit code if a fatal error is found.")
|
||||
.long("ignore-non-fatal-errors"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("QUIET")
|
||||
.help("Suppress output messages, return only exit code.")
|
||||
.short("q")
|
||||
.long("quiet"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SB_ONLY")
|
||||
.help("Only check the superblock.")
|
||||
.long("super-block-only"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SKIP_MAPPINGS")
|
||||
.help("Don't check the mapping array")
|
||||
.long("skip-mappings"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SKIP_HINTS")
|
||||
.help("Don't check the hint array")
|
||||
.long("skip-hints"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SKIP_DISCARDS")
|
||||
.help("Don't check the discard bitset")
|
||||
.long("skip-discards"),
|
||||
)
|
||||
// arguments
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify the input device to check")
|
||||
.required(true)
|
||||
.index(1),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
|
||||
if let Err(e) = file_utils::is_file_or_blk(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let report;
|
||||
if matches.is_present("QUIET") {
|
||||
report = std::sync::Arc::new(mk_quiet_report());
|
||||
} else if atty::is(Stream::Stdout) {
|
||||
report = std::sync::Arc::new(mk_progress_bar_report());
|
||||
} else {
|
||||
report = Arc::new(mk_simple_report());
|
||||
}
|
||||
|
||||
let opts = CacheCheckOptions {
|
||||
dev: &input_file,
|
||||
async_io: matches.is_present("ASYNC_IO"),
|
||||
sb_only: matches.is_present("SB_ONLY"),
|
||||
skip_mappings: matches.is_present("SKIP_MAPPINGS"),
|
||||
skip_hints: matches.is_present("SKIP_HINTS"),
|
||||
skip_discards: matches.is_present("SKIP_DISCARDS"),
|
||||
ignore_non_fatal: matches.is_present("IGNORE_NON_FATAL"),
|
||||
auto_repair: matches.is_present("AUTO_REPAIR"),
|
||||
report: report.clone(),
|
||||
};
|
||||
|
||||
if let Err(reason) = check(opts) {
|
||||
report.fatal(&format!("{}", reason));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
@@ -1,71 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use thinp::cache::dump::{dump, CacheDumpOptions};
|
||||
use thinp::file_utils;
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("cache_dump")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Dump the cache metadata to stdout in XML format")
|
||||
// flags
|
||||
.arg(
|
||||
Arg::with_name("ASYNC_IO")
|
||||
.help("Force use of io_uring for synchronous io")
|
||||
.long("async-io")
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("REPAIR")
|
||||
.help("Repair the metadata whilst dumping it")
|
||||
.short("r")
|
||||
.long("repair"),
|
||||
)
|
||||
// options
|
||||
.arg(
|
||||
Arg::with_name("OUTPUT")
|
||||
.help("Specify the output file rather than stdout")
|
||||
.short("o")
|
||||
.long("output")
|
||||
.value_name("FILE"),
|
||||
)
|
||||
// arguments
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify the input device to dump")
|
||||
.required(true)
|
||||
.index(1),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
let output_file = if matches.is_present("OUTPUT") {
|
||||
Some(Path::new(matches.value_of("OUTPUT").unwrap()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Err(e) = file_utils::is_file_or_blk(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let opts = CacheDumpOptions {
|
||||
input: input_file,
|
||||
output: output_file,
|
||||
async_io: matches.is_present("ASYNC_IO"),
|
||||
repair: matches.is_present("REPAIR"),
|
||||
};
|
||||
|
||||
if let Err(reason) = dump(opts) {
|
||||
eprintln!("{}", reason);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
@@ -1,78 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use atty::Stream;
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use thinp::cache::repair::{repair, CacheRepairOptions};
|
||||
use thinp::file_utils;
|
||||
use thinp::report::*;
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("cache_repair")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Repair binary cache metadata, and write it to a different device or file")
|
||||
// flags
|
||||
.arg(
|
||||
Arg::with_name("ASYNC_IO")
|
||||
.help("Force use of io_uring for synchronous io")
|
||||
.long("async-io")
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("QUIET")
|
||||
.help("Suppress output messages, return only exit code.")
|
||||
.short("q")
|
||||
.long("quiet"),
|
||||
)
|
||||
// options
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify the input device")
|
||||
.short("i")
|
||||
.long("input")
|
||||
.value_name("FILE")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("OUTPUT")
|
||||
.help("Specify the output device")
|
||||
.short("o")
|
||||
.long("output")
|
||||
.value_name("FILE")
|
||||
.required(true),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
let output_file = Path::new(matches.value_of("OUTPUT").unwrap());
|
||||
|
||||
if let Err(e) = file_utils::is_file_or_blk(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let report;
|
||||
|
||||
if matches.is_present("QUIET") {
|
||||
report = std::sync::Arc::new(mk_quiet_report());
|
||||
} else if atty::is(Stream::Stdout) {
|
||||
report = std::sync::Arc::new(mk_progress_bar_report());
|
||||
} else {
|
||||
report = Arc::new(mk_simple_report());
|
||||
}
|
||||
|
||||
let opts = CacheRepairOptions {
|
||||
input: &input_file,
|
||||
output: &output_file,
|
||||
async_io: matches.is_present("ASYNC_IO"),
|
||||
report: report.clone(),
|
||||
};
|
||||
|
||||
if let Err(reason) = repair(opts) {
|
||||
report.fatal(&format!("{}", reason));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use atty::Stream;
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use thinp::cache::restore::{restore, CacheRestoreOptions};
|
||||
use thinp::file_utils;
|
||||
use thinp::report::*;
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("cache_restore")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Convert XML format metadata to binary.")
|
||||
// flags
|
||||
.arg(
|
||||
Arg::with_name("ASYNC_IO")
|
||||
.help("Force use of io_uring for synchronous io")
|
||||
.long("async-io")
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("QUIET")
|
||||
.help("Suppress output messages, return only exit code.")
|
||||
.short("q")
|
||||
.long("quiet"),
|
||||
)
|
||||
// options
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify the input xml")
|
||||
.short("i")
|
||||
.long("input")
|
||||
.value_name("FILE")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("OUTPUT")
|
||||
.help("Specify the output device to check")
|
||||
.short("o")
|
||||
.long("output")
|
||||
.value_name("FILE")
|
||||
.required(true),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
let output_file = Path::new(matches.value_of("OUTPUT").unwrap());
|
||||
|
||||
if let Err(e) = file_utils::is_file(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
if let Err(e) = file_utils::check_output_file_requirements(output_file) {
|
||||
eprintln!("{}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let report;
|
||||
|
||||
if matches.is_present("QUIET") {
|
||||
report = std::sync::Arc::new(mk_quiet_report());
|
||||
} else if atty::is(Stream::Stdout) {
|
||||
report = std::sync::Arc::new(mk_progress_bar_report());
|
||||
} else {
|
||||
report = Arc::new(mk_simple_report());
|
||||
}
|
||||
|
||||
let opts = CacheRestoreOptions {
|
||||
input: &input_file,
|
||||
output: &output_file,
|
||||
async_io: matches.is_present("ASYNC_IO"),
|
||||
report: report.clone(),
|
||||
};
|
||||
|
||||
if let Err(reason) = restore(opts) {
|
||||
report.fatal(&format!("{}", reason));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
69
src/bin/pdata_tools.rs
Normal file
69
src/bin/pdata_tools.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use anyhow::{anyhow, ensure, Result};
|
||||
use std::ffi::OsString;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use thinp::commands::*;
|
||||
|
||||
fn name_eq(name: &Path, cmd: &str) -> bool {
|
||||
name == Path::new(cmd)
|
||||
}
|
||||
|
||||
fn main_() -> Result<()> {
|
||||
let mut args = std::env::args_os();
|
||||
ensure!(args.len() > 0);
|
||||
|
||||
let mut os_name = args.next().unwrap();
|
||||
let mut name = Path::new(&os_name);
|
||||
name = Path::new(name.file_name().unwrap());
|
||||
|
||||
if name == Path::new("pdata_tools") {
|
||||
os_name = args.next().unwrap();
|
||||
name = Path::new(&os_name);
|
||||
}
|
||||
|
||||
let mut new_args = vec![OsString::from(&name)];
|
||||
for a in args.into_iter() {
|
||||
new_args.push(OsString::from(a));
|
||||
}
|
||||
|
||||
if name_eq(name, "cache_check") {
|
||||
cache_check::run(&new_args);
|
||||
} else if name_eq(name, "cache_dump") {
|
||||
cache_dump::run(&new_args);
|
||||
} else if name_eq(name, "cache_repair") {
|
||||
cache_repair::run(&new_args);
|
||||
} else if name_eq(name, "cache_restore") {
|
||||
cache_restore::run(&new_args);
|
||||
} else if name_eq(name, "thin_check") {
|
||||
thin_check::run(&new_args);
|
||||
} else if name_eq(name, "thin_dump") {
|
||||
thin_dump::run(&new_args);
|
||||
} else if name_eq(name, "thin_metadata_pack") {
|
||||
thin_metadata_pack::run(&new_args);
|
||||
} else if name_eq(name, "thin_metadata_unpack") {
|
||||
thin_metadata_unpack::run(&new_args);
|
||||
} else if name_eq(name, "thin_repair") {
|
||||
thin_repair::run(&new_args);
|
||||
} else if name_eq(name, "thin_restore") {
|
||||
thin_restore::run(&new_args);
|
||||
} else if name_eq(name, "thin_shrink") {
|
||||
thin_shrink::run(&new_args);
|
||||
} else {
|
||||
return Err(anyhow!("unrecognised command"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let code = match main_() {
|
||||
Ok(()) => 0,
|
||||
Err(_) => {
|
||||
// We don't print out the error since -q may be set
|
||||
// eprintln!("{}", e);
|
||||
1
|
||||
}
|
||||
};
|
||||
|
||||
exit(code)
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use atty::Stream;
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use thinp::file_utils;
|
||||
use thinp::io_engine::*;
|
||||
use thinp::report::*;
|
||||
use thinp::thin::check::{check, ThinCheckOptions, MAX_CONCURRENT_IO};
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("thin_check")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Validates thin provisioning metadata on a device or file.")
|
||||
// flags
|
||||
.arg(
|
||||
Arg::with_name("ASYNC_IO")
|
||||
.help("Force use of io_uring for synchronous io")
|
||||
.long("async-io")
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("AUTO_REPAIR")
|
||||
.help("Auto repair trivial issues.")
|
||||
.long("auto-repair")
|
||||
.conflicts_with_all(&[
|
||||
"IGNORE_NON_FATAL",
|
||||
"METADATA_SNAPSHOT",
|
||||
"OVERRIDE_MAPPING_ROOT",
|
||||
"SB_ONLY",
|
||||
"SKIP_MAPPINGS",
|
||||
]),
|
||||
)
|
||||
.arg(
|
||||
// Using --clear-needs-check along with --skip-mappings is allowed
|
||||
// (but not recommended) for backward compatibility (commit 1fe8a0d)
|
||||
Arg::with_name("CLEAR_NEEDS_CHECK")
|
||||
.help("Clears the 'needs_check' flag in the superblock")
|
||||
.long("clear-needs-check-flag")
|
||||
.conflicts_with_all(&[
|
||||
"IGNORE_NON_FATAL",
|
||||
"METADATA_SNAPSHOT",
|
||||
"OVERRIDE_MAPPING_ROOT",
|
||||
"SB_ONLY",
|
||||
]),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("IGNORE_NON_FATAL")
|
||||
.help("Only return a non-zero exit code if a fatal error is found.")
|
||||
.long("ignore-non-fatal-errors"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("METADATA_SNAPSHOT")
|
||||
.help("Check the metadata snapshot on a live pool")
|
||||
.short("m")
|
||||
.long("metadata-snapshot"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("QUIET")
|
||||
.help("Suppress output messages, return only exit code.")
|
||||
.short("q")
|
||||
.long("quiet"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SB_ONLY")
|
||||
.help("Only check the superblock.")
|
||||
.long("super-block-only"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SKIP_MAPPINGS")
|
||||
.help("Don't check the mapping tree")
|
||||
.long("skip-mappings"),
|
||||
)
|
||||
// options
|
||||
.arg(
|
||||
Arg::with_name("OVERRIDE_MAPPING_ROOT")
|
||||
.help("Specify a mapping root to use")
|
||||
.long("override-mapping-root")
|
||||
.value_name("OVERRIDE_MAPPING_ROOT")
|
||||
.takes_value(true),
|
||||
)
|
||||
// arguments
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify the input device to check")
|
||||
.required(true)
|
||||
.index(1),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
|
||||
if let Err(e) = file_utils::is_file_or_blk(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let report;
|
||||
|
||||
if matches.is_present("QUIET") {
|
||||
report = std::sync::Arc::new(mk_quiet_report());
|
||||
} else if atty::is(Stream::Stdout) {
|
||||
report = std::sync::Arc::new(mk_progress_bar_report());
|
||||
} else {
|
||||
report = Arc::new(mk_simple_report());
|
||||
}
|
||||
|
||||
let engine: Arc<dyn IoEngine + Send + Sync>;
|
||||
let writable = matches.is_present("AUTO_REPAIR") || matches.is_present("CLEAR_NEEDS_CHECK");
|
||||
|
||||
if matches.is_present("ASYNC_IO") {
|
||||
engine = Arc::new(
|
||||
AsyncIoEngine::new(&input_file, MAX_CONCURRENT_IO, writable)
|
||||
.expect("unable to open input file"),
|
||||
);
|
||||
} else {
|
||||
let nr_threads = std::cmp::max(8, num_cpus::get() * 2);
|
||||
engine = Arc::new(
|
||||
SyncIoEngine::new(&input_file, nr_threads, writable)
|
||||
.expect("unable to open input file"),
|
||||
);
|
||||
}
|
||||
|
||||
let opts = ThinCheckOptions {
|
||||
engine,
|
||||
sb_only: matches.is_present("SB_ONLY"),
|
||||
skip_mappings: matches.is_present("SKIP_MAPPINGS"),
|
||||
ignore_non_fatal: matches.is_present("IGNORE_NON_FATAL"),
|
||||
auto_repair: matches.is_present("AUTO_REPAIR"),
|
||||
clear_needs_check: matches.is_present("CLEAR_NEEDS_CHECK"),
|
||||
report: report.clone(),
|
||||
};
|
||||
|
||||
if let Err(reason) = check(opts) {
|
||||
report.fatal(&format!("{}", reason));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use atty::Stream;
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use thinp::file_utils;
|
||||
use thinp::report::*;
|
||||
use thinp::thin::dump::{dump, ThinDumpOptions};
|
||||
use thinp::thin::metadata_repair::SuperblockOverrides;
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("thin_dump")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Dump thin-provisioning metadata to stdout in XML format")
|
||||
// flags
|
||||
.arg(
|
||||
Arg::with_name("ASYNC_IO")
|
||||
.help("Force use of io_uring for synchronous io")
|
||||
.long("async-io")
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("QUIET")
|
||||
.help("Suppress output messages, return only exit code.")
|
||||
.short("q")
|
||||
.long("quiet"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("REPAIR")
|
||||
.help("Repair the metadata whilst dumping it")
|
||||
.short("r")
|
||||
.long("repair"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SKIP_MAPPINGS")
|
||||
.help("Do not dump the mappings")
|
||||
.long("skip-mappings"),
|
||||
)
|
||||
// options
|
||||
.arg(
|
||||
Arg::with_name("DATA_BLOCK_SIZE")
|
||||
.help("Provide the data block size for repairing")
|
||||
.long("data-block-size")
|
||||
.value_name("SECTORS"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("METADATA_SNAPSHOT")
|
||||
.help("Access the metadata snapshot on a live pool")
|
||||
.short("m")
|
||||
.long("metadata-snapshot")
|
||||
.value_name("METADATA_SNAPSHOT"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("NR_DATA_BLOCKS")
|
||||
.help("Override the number of data blocks if needed")
|
||||
.long("nr-data-blocks")
|
||||
.value_name("NUM"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("OUTPUT")
|
||||
.help("Specify the output file rather than stdout")
|
||||
.short("o")
|
||||
.long("output")
|
||||
.value_name("FILE"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("TRANSACTION_ID")
|
||||
.help("Override the transaction id if needed")
|
||||
.long("transaction-id")
|
||||
.value_name("NUM"),
|
||||
)
|
||||
// arguments
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify the input device to dump")
|
||||
.required(true)
|
||||
.index(1),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
let output_file = if matches.is_present("OUTPUT") {
|
||||
Some(Path::new(matches.value_of("OUTPUT").unwrap()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Err(e) = file_utils::is_file_or_blk(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let transaction_id = matches.value_of("TRANSACTION_ID").map(|s| {
|
||||
s.parse::<u64>().unwrap_or_else(|_| {
|
||||
eprintln!("Couldn't parse transaction_id");
|
||||
process::exit(1);
|
||||
})
|
||||
});
|
||||
|
||||
let data_block_size = matches.value_of("DATA_BLOCK_SIZE").map(|s| {
|
||||
s.parse::<u32>().unwrap_or_else(|_| {
|
||||
eprintln!("Couldn't parse data_block_size");
|
||||
process::exit(1);
|
||||
})
|
||||
});
|
||||
|
||||
let nr_data_blocks = matches.value_of("NR_DATA_BLOCKS").map(|s| {
|
||||
s.parse::<u64>().unwrap_or_else(|_| {
|
||||
eprintln!("Couldn't parse nr_data_blocks");
|
||||
process::exit(1);
|
||||
})
|
||||
});
|
||||
|
||||
let report;
|
||||
|
||||
if matches.is_present("QUIET") {
|
||||
report = std::sync::Arc::new(mk_quiet_report());
|
||||
} else if atty::is(Stream::Stdout) {
|
||||
report = std::sync::Arc::new(mk_progress_bar_report());
|
||||
} else {
|
||||
report = Arc::new(mk_simple_report());
|
||||
}
|
||||
|
||||
let opts = ThinDumpOptions {
|
||||
input: input_file,
|
||||
output: output_file,
|
||||
async_io: matches.is_present("ASYNC_IO"),
|
||||
report: report.clone(),
|
||||
repair: matches.is_present("REPAIR"),
|
||||
overrides: SuperblockOverrides {
|
||||
transaction_id,
|
||||
data_block_size,
|
||||
nr_data_blocks,
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(reason) = dump(opts) {
|
||||
report.fatal(&format!("{}", reason));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use thinp::file_utils;
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("thin_metadata_pack")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Produces a compressed file of thin metadata. Only packs metadata blocks that are actually used.")
|
||||
.arg(Arg::with_name("INPUT")
|
||||
.help("Specify thinp metadata binary device/file")
|
||||
.required(true)
|
||||
.short("i")
|
||||
.value_name("DEV")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("OUTPUT")
|
||||
.help("Specify packed output file")
|
||||
.required(true)
|
||||
.short("o")
|
||||
.value_name("FILE")
|
||||
.takes_value(true));
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
let output_file = Path::new(matches.value_of("OUTPUT").unwrap());
|
||||
|
||||
if let Err(e) = file_utils::is_file_or_blk(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if let Err(reason) = thinp::pack::toplevel::pack(&input_file, &output_file) {
|
||||
println!("Application error: {}\n", reason);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use thinp::file_utils;
|
||||
|
||||
use std::process::exit;
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("thin_metadata_unpack")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Unpack a compressed file of thin metadata.")
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify thinp metadata binary device/file")
|
||||
.required(true)
|
||||
.short("i")
|
||||
.value_name("DEV")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("OUTPUT")
|
||||
.help("Specify packed output file")
|
||||
.required(true)
|
||||
.short("o")
|
||||
.value_name("FILE")
|
||||
.takes_value(true),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
let output_file = Path::new(matches.value_of("OUTPUT").unwrap());
|
||||
|
||||
if let Err(e) = file_utils::is_file(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if let Err(reason) = thinp::pack::toplevel::unpack(&input_file, &output_file) {
|
||||
eprintln!("Application error: {}", reason);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use atty::Stream;
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use thinp::file_utils;
|
||||
use thinp::report::*;
|
||||
use thinp::thin::metadata_repair::SuperblockOverrides;
|
||||
use thinp::thin::repair::{repair, ThinRepairOptions};
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("thin_repair")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Repair thin-provisioning metadata, and write it to different device or file")
|
||||
// flags
|
||||
.arg(
|
||||
Arg::with_name("ASYNC_IO")
|
||||
.help("Force use of io_uring for synchronous io")
|
||||
.long("async-io")
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("QUIET")
|
||||
.help("Suppress output messages, return only exit code.")
|
||||
.short("q")
|
||||
.long("quiet"),
|
||||
)
|
||||
// options
|
||||
.arg(
|
||||
Arg::with_name("DATA_BLOCK_SIZE")
|
||||
.help("Provide the data block size for repairing")
|
||||
.long("data-block-size")
|
||||
.value_name("SECTORS"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify the input device")
|
||||
.short("i")
|
||||
.long("input")
|
||||
.value_name("FILE")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("NR_DATA_BLOCKS")
|
||||
.help("Override the number of data blocks if needed")
|
||||
.long("nr-data-blocks")
|
||||
.value_name("NUM"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("OUTPUT")
|
||||
.help("Specify the output device")
|
||||
.short("o")
|
||||
.long("output")
|
||||
.value_name("FILE")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("TRANSACTION_ID")
|
||||
.help("Override the transaction id if needed")
|
||||
.long("transaction-id")
|
||||
.value_name("NUM"),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
let output_file = Path::new(matches.value_of("OUTPUT").unwrap());
|
||||
|
||||
if let Err(e) = file_utils::is_file_or_blk(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let transaction_id = matches.value_of("TRANSACTION_ID").map(|s| {
|
||||
s.parse::<u64>().unwrap_or_else(|_| {
|
||||
eprintln!("Couldn't parse transaction_id");
|
||||
process::exit(1);
|
||||
})
|
||||
});
|
||||
|
||||
let data_block_size = matches.value_of("DATA_BLOCK_SIZE").map(|s| {
|
||||
s.parse::<u32>().unwrap_or_else(|_| {
|
||||
eprintln!("Couldn't parse data_block_size");
|
||||
process::exit(1);
|
||||
})
|
||||
});
|
||||
|
||||
let nr_data_blocks = matches.value_of("NR_DATA_BLOCKS").map(|s| {
|
||||
s.parse::<u64>().unwrap_or_else(|_| {
|
||||
eprintln!("Couldn't parse nr_data_blocks");
|
||||
process::exit(1);
|
||||
})
|
||||
});
|
||||
|
||||
let report;
|
||||
|
||||
if matches.is_present("QUIET") {
|
||||
report = std::sync::Arc::new(mk_quiet_report());
|
||||
} else if atty::is(Stream::Stdout) {
|
||||
report = std::sync::Arc::new(mk_progress_bar_report());
|
||||
} else {
|
||||
report = Arc::new(mk_simple_report());
|
||||
}
|
||||
|
||||
let opts = ThinRepairOptions {
|
||||
input: &input_file,
|
||||
output: &output_file,
|
||||
async_io: matches.is_present("ASYNC_IO"),
|
||||
report: report.clone(),
|
||||
overrides: SuperblockOverrides {
|
||||
transaction_id,
|
||||
data_block_size,
|
||||
nr_data_blocks,
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(reason) = repair(opts) {
|
||||
report.fatal(&format!("{}", reason));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use atty::Stream;
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use thinp::file_utils;
|
||||
use thinp::report::*;
|
||||
use thinp::thin::restore::{restore, ThinRestoreOptions};
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("thin_restore")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Convert XML format metadata to binary.")
|
||||
// flags
|
||||
.arg(
|
||||
Arg::with_name("ASYNC_IO")
|
||||
.help("Force use of io_uring for synchronous io")
|
||||
.long("async-io")
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("QUIET")
|
||||
.help("Suppress output messages, return only exit code.")
|
||||
.short("q")
|
||||
.long("quiet"),
|
||||
)
|
||||
// options
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify the input xml")
|
||||
.short("i")
|
||||
.long("input")
|
||||
.value_name("FILE")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("OUTPUT")
|
||||
.help("Specify the output device")
|
||||
.short("o")
|
||||
.long("output")
|
||||
.value_name("FILE")
|
||||
.required(true),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
let output_file = Path::new(matches.value_of("OUTPUT").unwrap());
|
||||
|
||||
if let Err(e) = file_utils::is_file(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
if let Err(e) = file_utils::check_output_file_requirements(output_file) {
|
||||
eprintln!("{}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let report;
|
||||
|
||||
if matches.is_present("QUIET") {
|
||||
report = std::sync::Arc::new(mk_quiet_report());
|
||||
} else if atty::is(Stream::Stdout) {
|
||||
report = std::sync::Arc::new(mk_progress_bar_report());
|
||||
} else {
|
||||
report = Arc::new(mk_simple_report());
|
||||
}
|
||||
|
||||
let opts = ThinRestoreOptions {
|
||||
input: &input_file,
|
||||
output: &output_file,
|
||||
async_io: matches.is_present("ASYNC_IO"),
|
||||
report: report.clone(),
|
||||
};
|
||||
|
||||
if let Err(reason) = restore(opts) {
|
||||
report.fatal(&format!("{}", reason));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// This work is based on the implementation by Nikhil Kshirsagar which
|
||||
// can be found here:
|
||||
// https://github.com/nkshirsagar/thinpool_shrink/blob/split_ranges/thin_shrink.py
|
||||
|
||||
extern crate clap;
|
||||
extern crate thinp;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use thinp::file_utils;
|
||||
|
||||
fn main() {
|
||||
let parser = App::new("thin_shrink")
|
||||
.version(thinp::version::tools_version())
|
||||
.about("Rewrite xml metadata and move data in an inactive pool.")
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("Specify thinp metadata xml file")
|
||||
.required(true)
|
||||
.short("i")
|
||||
.long("input")
|
||||
.value_name("FILE")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("OUTPUT")
|
||||
.help("Specify output xml file")
|
||||
.required(true)
|
||||
.short("o")
|
||||
.long("output")
|
||||
.value_name("FILE")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("DATA")
|
||||
.help("Specify pool data device where data will be moved")
|
||||
.required(true)
|
||||
.long("data")
|
||||
.value_name("DATA")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("NOCOPY")
|
||||
.help("Skip the copying of data, useful for benchmarking")
|
||||
.required(false)
|
||||
.long("no-copy")
|
||||
.value_name("NOCOPY")
|
||||
.takes_value(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SIZE")
|
||||
.help("Specify new size for the pool (in data blocks)")
|
||||
.required(true)
|
||||
.long("nr-blocks")
|
||||
.value_name("SIZE")
|
||||
.takes_value(true),
|
||||
);
|
||||
|
||||
let matches = parser.get_matches();
|
||||
|
||||
// FIXME: check these look like xml
|
||||
let input_file = Path::new(matches.value_of("INPUT").unwrap());
|
||||
let output_file = Path::new(matches.value_of("OUTPUT").unwrap());
|
||||
let size = matches.value_of("SIZE").unwrap().parse::<u64>().unwrap();
|
||||
let data_file = Path::new(matches.value_of("DATA").unwrap());
|
||||
let do_copy = !matches.is_present("NOCOPY");
|
||||
|
||||
if let Err(e) = file_utils::is_file_or_blk(input_file) {
|
||||
eprintln!("Invalid input file '{}': {}.", input_file.display(), e);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if let Err(reason) =
|
||||
thinp::shrink::toplevel::shrink(&input_file, &output_file, &data_file, size, do_copy)
|
||||
{
|
||||
eprintln!("Application error: {}\n", reason);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user