[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:
		| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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
									
								
							
							
						
						
									
										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. | ||||
|  | ||||
| .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. | ||||
|   | ||||
							
								
								
									
										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 <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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user