[thin_dump] --format custom=<shared lib>
Allow people to use their own emitters held in a shared library. Put a trivial emitter in contrib/ as an example.
This commit is contained in:
parent
872a933072
commit
c7813e07e4
@ -91,6 +91,7 @@ SOURCE=\
|
|||||||
thin-provisioning/restore_emitter.cc \
|
thin-provisioning/restore_emitter.cc \
|
||||||
thin-provisioning/rmap_visitor.cc \
|
thin-provisioning/rmap_visitor.cc \
|
||||||
thin-provisioning/superblock.cc \
|
thin-provisioning/superblock.cc \
|
||||||
|
thin-provisioning/shared_library_emitter.cc \
|
||||||
thin-provisioning/thin_check.cc \
|
thin-provisioning/thin_check.cc \
|
||||||
thin-provisioning/thin_delta.cc \
|
thin-provisioning/thin_delta.cc \
|
||||||
thin-provisioning/thin_dump.cc \
|
thin-provisioning/thin_dump.cc \
|
||||||
@ -123,9 +124,9 @@ STRIP:=@STRIP@
|
|||||||
OBJECTS:=$(subst .cc,.o,$(SOURCE))
|
OBJECTS:=$(subst .cc,.o,$(SOURCE))
|
||||||
TOP_DIR:=@top_srcdir@
|
TOP_DIR:=@top_srcdir@
|
||||||
TOP_BUILDDIR:=@top_builddir@
|
TOP_BUILDDIR:=@top_builddir@
|
||||||
CFLAGS+=-g -Wall -O3
|
CFLAGS+=-g -Wall -O3 -fPIC
|
||||||
CFLAGS+=@LFS_FLAGS@
|
CFLAGS+=@LFS_FLAGS@
|
||||||
CXXFLAGS+=-g -Wall -fno-strict-aliasing -std=c++11
|
CXXFLAGS+=-g -Wall -fPIC -fno-strict-aliasing -std=c++11
|
||||||
|
|
||||||
ifeq ("@DEVTOOLS@", "yes")
|
ifeq ("@DEVTOOLS@", "yes")
|
||||||
CXXFLAGS+=-DDEV_TOOLS
|
CXXFLAGS+=-DDEV_TOOLS
|
||||||
@ -260,6 +261,7 @@ endif
|
|||||||
|
|
||||||
ifeq ("@TESTING@", "yes")
|
ifeq ("@TESTING@", "yes")
|
||||||
include unit-tests/Makefile
|
include unit-tests/Makefile
|
||||||
|
include contrib/Makefile
|
||||||
|
|
||||||
.PHONEY: features
|
.PHONEY: features
|
||||||
|
|
||||||
|
@ -188,6 +188,7 @@ dnl -- First and last lines should not contain files to generate in order to
|
|||||||
dnl -- keep utility scripts running properly
|
dnl -- keep utility scripts running properly
|
||||||
AC_CONFIG_FILES([
|
AC_CONFIG_FILES([
|
||||||
Makefile
|
Makefile
|
||||||
|
contrib/Makefile
|
||||||
unit-tests/Makefile
|
unit-tests/Makefile
|
||||||
version.h
|
version.h
|
||||||
])
|
])
|
||||||
|
7
contrib/Makefile.in
Normal file
7
contrib/Makefile.in
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
contrib: contrib/thin_sexp_emitter.so
|
||||||
|
|
||||||
|
contrib/thin_sexp_emitter.so: contrib/thin_sexp_emitter.o
|
||||||
|
$(V)echo " [LD] $@"
|
||||||
|
$(V)$(CC) -shared -Wl,-soname,thin_sexp_emitter.so -o contrib/thin_sexp_emitter.so contrib/thin_sexp_emitter.o
|
||||||
|
|
||||||
|
|
120
contrib/thin_sexp_emitter.cc
Normal file
120
contrib/thin_sexp_emitter.cc
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#include "base/indented_stream.h"
|
||||||
|
#include "thin-provisioning/emitter.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace thin_provisioning;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class sexp_emitter : public emitter {
|
||||||
|
public:
|
||||||
|
sexp_emitter(ostream &out)
|
||||||
|
: out_(out) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void begin_superblock(std::string const &uuid,
|
||||||
|
uint64_t time,
|
||||||
|
uint64_t trans_id,
|
||||||
|
boost::optional<uint32_t> flags,
|
||||||
|
boost::optional<uint32_t> version,
|
||||||
|
uint32_t data_block_size,
|
||||||
|
uint64_t nr_data_blocks,
|
||||||
|
boost::optional<uint64_t> metadata_snap) {
|
||||||
|
open("superblock");
|
||||||
|
out_.indent();
|
||||||
|
out_ << "((uuid \"" << uuid << "\")\n";
|
||||||
|
kv("time", time);
|
||||||
|
kv("trans_id", trans_id);
|
||||||
|
kv("flags", flags);
|
||||||
|
kv("version", version);
|
||||||
|
kv("data_block_size", data_block_size);
|
||||||
|
kv("nr_data_blocks", nr_data_blocks);
|
||||||
|
kv("metadata_snap", metadata_snap);
|
||||||
|
out_.indent();
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void end_superblock() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void begin_device(uint32_t dev_id,
|
||||||
|
uint64_t mapped_blocks,
|
||||||
|
uint64_t trans_id,
|
||||||
|
uint64_t creation_time,
|
||||||
|
uint64_t snap_time) {
|
||||||
|
open("device");
|
||||||
|
out_.indent();
|
||||||
|
out_ << "((dev_id " << dev_id << ")\n";
|
||||||
|
kv("mapped_blocks", mapped_blocks);
|
||||||
|
kv("trans_id", trans_id);
|
||||||
|
kv("creation_time", creation_time);
|
||||||
|
kv("snap_time", snap_time);
|
||||||
|
out_.indent();
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void end_device() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void begin_named_mapping(std::string const &name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void end_named_mapping() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void identifier(std::string const &name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void range_map(uint64_t origin_begin, uint64_t data_begin, uint32_t time, uint64_t len) {
|
||||||
|
out_.indent();
|
||||||
|
out_ << "(range (origin_begin " << origin_begin
|
||||||
|
<< ") (data_begin " << data_begin
|
||||||
|
<< ") (time " << time
|
||||||
|
<< ") (len " << len << "))\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void single_map(uint64_t origin_block, uint64_t data_block, uint32_t time) {
|
||||||
|
out_.indent();
|
||||||
|
out_ << "(single (origin_block " << origin_block
|
||||||
|
<< ") (data_block " << data_block
|
||||||
|
<< ") (time " << time << "))\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void open(char const *tag) {
|
||||||
|
out_.indent();
|
||||||
|
out_ << "(" << tag << "\n";
|
||||||
|
out_.inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
out_.dec();
|
||||||
|
out_.indent();
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void kv(char const *k, T const &v) {
|
||||||
|
out_.indent();
|
||||||
|
out_ << " (" << k << " " << v << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
indented_stream out_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
emitter::ptr create_emitter(ostream &out) {
|
||||||
|
return emitter::ptr(new sexp_emitter(out));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
@ -26,8 +26,13 @@ in order to put it back onto a metadata
|
|||||||
|
|
||||||
This tool cannot be run on live metadata unless the \fB\-\-metadata\-snap\fP option is used.
|
This tool cannot be run on live metadata unless the \fB\-\-metadata\-snap\fP option is used.
|
||||||
|
|
||||||
.IP "\fB\-f, \-\-format\fP \fI{xml|human_readable}\fP".
|
.IP "\fB\-f, \-\-format\fP \fI{xml|human_readable|custom}\fP".
|
||||||
Print output in XML or human readable format.
|
|
||||||
|
Print output in XML or human readable format. Custom formats are
|
||||||
|
supported via shared library plugins. They should be specified as in
|
||||||
|
this example:
|
||||||
|
.sp
|
||||||
|
.B thin_dump --format custom=mylib.so /dev/sda
|
||||||
|
|
||||||
.IP "\fB\-r, \-\-repair\fP".
|
.IP "\fB\-r, \-\-repair\fP".
|
||||||
Repair the metadata whilst dumping it.
|
Repair the metadata whilst dumping it.
|
||||||
|
29
thin-provisioning/shared_library_emitter.cc
Normal file
29
thin-provisioning/shared_library_emitter.cc
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "thin-provisioning/shared_library_emitter.h"
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace thin_provisioning;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
emitter::ptr
|
||||||
|
thin_provisioning::create_custom_emitter(string const &shared_lib, ostream &out)
|
||||||
|
{
|
||||||
|
emitter::ptr (*create_fn)(ostream &out);
|
||||||
|
void *handle = dlopen(shared_lib.c_str(), RTLD_LAZY);
|
||||||
|
if (!handle)
|
||||||
|
throw runtime_error(dlerror());
|
||||||
|
|
||||||
|
dlerror(); // Clear any existing error
|
||||||
|
create_fn = reinterpret_cast<emitter::ptr (*)(ostream &)>(dlsym(handle, "create_emitter"));
|
||||||
|
|
||||||
|
char *error = dlerror();
|
||||||
|
if (error)
|
||||||
|
throw runtime_error(error);
|
||||||
|
|
||||||
|
return create_fn(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
14
thin-provisioning/shared_library_emitter.h
Normal file
14
thin-provisioning/shared_library_emitter.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef THIN_PROVISIONING_SHARED_LIBRARY_EMITTER_H
|
||||||
|
#define THIN_PROVISIONING_SHARED_LIBRARY_EMITTER_H
|
||||||
|
|
||||||
|
#include "thin-provisioning/emitter.h"
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace thin_provisioning {
|
||||||
|
emitter::ptr create_custom_emitter(std::string const &shared_lib, std::ostream &out);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif
|
@ -21,13 +21,14 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
|
||||||
#include "human_readable_format.h"
|
|
||||||
#include "metadata_dumper.h"
|
|
||||||
#include "metadata.h"
|
|
||||||
#include "xml_format.h"
|
|
||||||
#include "version.h"
|
|
||||||
#include "thin-provisioning/commands.h"
|
|
||||||
#include "persistent-data/file_utils.h"
|
#include "persistent-data/file_utils.h"
|
||||||
|
#include "thin-provisioning/commands.h"
|
||||||
|
#include "thin-provisioning/human_readable_format.h"
|
||||||
|
#include "thin-provisioning/metadata.h"
|
||||||
|
#include "thin-provisioning/metadata_dumper.h"
|
||||||
|
#include "thin-provisioning/shared_library_emitter.h"
|
||||||
|
#include "thin-provisioning/xml_format.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
using namespace persistent_data;
|
using namespace persistent_data;
|
||||||
@ -56,6 +57,10 @@ namespace {
|
|||||||
return md;
|
return md;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool begins_with(string const &str, string const &prefix) {
|
||||||
|
return str.substr(0, prefix.length()) == prefix;
|
||||||
|
}
|
||||||
|
|
||||||
emitter::ptr create_emitter(string const &format, ostream &out) {
|
emitter::ptr create_emitter(string const &format, ostream &out) {
|
||||||
emitter::ptr e;
|
emitter::ptr e;
|
||||||
|
|
||||||
@ -65,9 +70,13 @@ namespace {
|
|||||||
else if (format == "human_readable")
|
else if (format == "human_readable")
|
||||||
e = create_human_readable_emitter(out);
|
e = create_human_readable_emitter(out);
|
||||||
|
|
||||||
|
else if (begins_with(format, "custom="))
|
||||||
|
e = create_custom_emitter(format.substr(7), out);
|
||||||
|
|
||||||
else {
|
else {
|
||||||
cerr << "unknown format '" << format << "'" << endl;
|
ostringstream msg;
|
||||||
exit(1);
|
msg << "unknown format '" << format << "'";
|
||||||
|
throw runtime_error(msg.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
Loading…
Reference in New Issue
Block a user