[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/rmap_visitor.cc \
thin-provisioning/superblock.cc \
thin-provisioning/shared_library_emitter.cc \
thin-provisioning/thin_check.cc \
thin-provisioning/thin_delta.cc \
thin-provisioning/thin_dump.cc \
@ -123,9 +124,9 @@ STRIP:=@STRIP@
OBJECTS:=$(subst .cc,.o,$(SOURCE))
TOP_DIR:=@top_srcdir@
TOP_BUILDDIR:=@top_builddir@
CFLAGS+=-g -Wall -O3
CFLAGS+=-g -Wall -O3 -fPIC
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")
CXXFLAGS+=-DDEV_TOOLS
@ -260,6 +261,7 @@ endif
ifeq ("@TESTING@", "yes")
include unit-tests/Makefile
include contrib/Makefile
.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
AC_CONFIG_FILES([
Makefile
contrib/Makefile
unit-tests/Makefile
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.
.IP "\fB\-f, \-\-format\fP \fI{xml|human_readable}\fP".
Print output in XML or human readable format.
.IP "\fB\-f, \-\-format\fP \fI{xml|human_readable|custom}\fP".
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".
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 <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 "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 persistent_data;
@ -56,6 +57,10 @@ namespace {
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 e;
@ -65,9 +70,13 @@ namespace {
else if (format == "human_readable")
e = create_human_readable_emitter(out);
else if (begins_with(format, "custom="))
e = create_custom_emitter(format.substr(7), out);
else {
cerr << "unknown format '" << format << "'" << endl;
exit(1);
ostringstream msg;
msg << "unknown format '" << format << "'";
throw runtime_error(msg.str());
}
return e;