diff --git a/Makefile.in b/Makefile.in index 2c6349a..e3f8222 100644 --- a/Makefile.in +++ b/Makefile.in @@ -25,6 +25,7 @@ PROGRAMS=\ thin_check \ thin_dump \ thin_restore \ + thin_repair \ thin_rmap all: $(PROGRAMS) @@ -69,6 +70,7 @@ PROGRAM_SOURCE=\ thin-provisioning/thin_check.cc \ thin-provisioning/thin_dump.cc \ thin-provisioning/thin_restore.cc \ + thin-provisioning/thin_repair.cc \ thin-provisioning/thin_rmap.cc CXX:=@CXX@ @@ -124,6 +126,7 @@ lib/libpdata.a: $(PDATA_OBJECTS) THIN_DEBUG_SOURCE=$(SOURCE) THIN_DUMP_SOURCE=$(SOURCE) +THIN_REPAIR_SOURCE=$(SOURCE) THIN_RESTORE_SOURCE=$(SOURCE) THIN_CHECK_SOURCE=\ persistent-data/checksum.cc \ @@ -164,6 +167,7 @@ THIN_RMAP_SOURCE=\ THIN_DEBUG_OBJECTS=$(subst .cc,.o,$(THIN_DEBUG_SOURCE)) THIN_DUMP_OBJECTS=$(subst .cc,.o,$(THIN_DUMP_SOURCE)) +THIN_REPAIR_OBJECTS=$(subst .cc,.o,$(THIN_REPAIR_SOURCE)) THIN_RESTORE_OBJECTS=$(subst .cc,.o,$(THIN_RESTORE_SOURCE)) THIN_CHECK_OBJECTS=$(subst .cc,.o,$(THIN_CHECK_SOURCE)) THIN_RMAP_OBJECTS=$(subst .cc,.o,$(THIN_RMAP_SOURCE)) @@ -172,6 +176,10 @@ thin_debug: $(THIN_DEBUG_OBJECTS) thin-provisioning/thin_debug.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) +thin_repair: $(THIN_REPAIR_OBJECTS) thin-provisioning/thin_repair.o + @echo " [LD] $@" + $(V) $(CXX) $(CXXFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) + thin_dump: $(THIN_DUMP_OBJECTS) thin-provisioning/thin_dump.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) diff --git a/thin-provisioning/thin_repair.cc b/thin-provisioning/thin_repair.cc new file mode 100644 index 0000000..4921ee9 --- /dev/null +++ b/thin-provisioning/thin_repair.cc @@ -0,0 +1,94 @@ +#include +#include +#include + +#include "human_readable_format.h" +#include "metadata_dumper.h" +#include "metadata.h" +#include "restore_emitter.h" +#include "version.h" + +using namespace persistent_data; +using namespace std; +using namespace thin_provisioning; + +namespace { + int repair(string const &old_path, string const &new_path) { + try { + // block size gets updated by the restorer + metadata::ptr new_md(new metadata(new_path, metadata::CREATE, 128, 0)); + emitter::ptr e = create_restore_emitter(new_md); + + metadata::ptr old_md(new metadata(old_path, metadata::OPEN)); + metadata_dump(old_md, e, true); + + } catch (std::exception &e) { + cerr << e.what() << endl; + return 1; + } + + return 0; + } + + void usage(ostream &out, string const &cmd) { + out << "Usage: " << cmd << " [options] {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-i|--input} " << endl + << " {-o|--output} " << endl + << " {-V|--version}" << endl; + } +} + +int main(int argc, char **argv) +{ + int c; + boost::optional input_path, output_path; + const char shortopts[] = "hi:o:V"; + + const struct option longopts[] = { + { "help", no_argument, NULL, 'h'}, + { "input", required_argument, NULL, 'i'}, + { "output", required_argument, NULL, 'o'}, + { "version", no_argument, NULL, 'V'}, + { NULL, no_argument, NULL, 0 } + }; + + while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + switch(c) { + case 'h': + usage(cout, basename(argv[0])); + return 0; + + case 'i': + input_path = optarg; + break; + + case 'o': + output_path = optarg; + break; + + case 'V': + cout << THIN_PROVISIONING_TOOLS_VERSION << endl; + return 0; + + default: + usage(cerr, basename(argv[0])); + return 1; + } + } + + if (!input_path) { + cerr << "no input file provided" << endl; + usage(cerr, basename(argv[0])); + return 1; + } + + if (!output_path) { + cerr << "no output file provided" << endl; + usage(cerr, basename(argv[0])); + return 1; + } + + return repair(*input_path, *output_path); +}