[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:
Joe Thornber 2016-03-24 13:10:37 +00:00
parent 872a933072
commit c7813e07e4
8 changed files with 199 additions and 12 deletions

View File

@ -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

View File

@ -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
View 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

View 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));
}
}
//----------------------------------------------------------------

View File

@ -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.

View 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);
}
//----------------------------------------------------------------

View 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

View File

@ -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;