1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2015 Red Hat
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
22 #include "include/types.h"
23 #include "common/Formatter.h"
24 #include "common/ceph_argparse.h"
25 #include "common/errno.h"
26 #include "denc_plugin.h"
27 #include "denc_registry.h"
29 #define MB(m) ((m) * 1024 * 1024)
31 namespace fs
= std::filesystem
;
35 void usage(ostream
&out
)
37 out
<< "usage: ceph-dencoder [commands ...]" << std::endl
;
39 out
<< " version print version string (to stdout)\n";
41 out
<< " import <encfile> read encoded data from encfile\n";
42 out
<< " export <outfile> write encoded data to outfile\n";
44 out
<< " set_features <num> set feature bits used for encoding\n";
45 out
<< " get_features print feature bits (int) to stdout\n";
47 out
<< " list_types list supported types\n";
48 out
<< " type <classname> select in-memory type\n";
49 out
<< " skip <num> skip <num> leading bytes before decoding\n";
50 out
<< " decode decode into in-memory object\n";
51 out
<< " encode encode in-memory object\n";
52 out
<< " dump_json dump in-memory object as json (to stdout)\n";
53 out
<< " hexdump print encoded data in hex\n";
54 out
<< " get_struct_v print version of the encoded object\n";
55 out
<< " get_struct_compat print the oldest version of decoder that can decode the encoded object\n";
57 out
<< " copy copy object (via operator=)\n";
58 out
<< " copy_ctor copy object (via copy ctor)\n";
60 out
<< " count_tests print number of generated test objects (to stdout)\n";
61 out
<< " select_test <n> select generated test object as in-memory object\n";
62 out
<< " is_deterministic exit w/ success if type encodes deterministically\n";
65 vector
<DencoderPlugin
> load_plugins()
67 fs::path mod_dir
{CEPH_DENC_MOD_DIR
};
68 if (auto ceph_lib
= getenv("CEPH_LIB"); ceph_lib
) {
70 } else if (fs::is_regular_file("CMakeCache.txt")) {
71 mod_dir
= std::filesystem::canonical("lib");
73 if (!fs::is_directory(mod_dir
)) {
74 std::cerr
<< "unable to load dencoders from "
75 << std::quoted(mod_dir
.native()) << ". "
76 << "it is not a directory." << std::endl
;
79 vector
<DencoderPlugin
> dencoder_plugins
;
80 for (auto& entry
: fs::directory_iterator(mod_dir
)) {
81 static const string_view DENC_MOD_PREFIX
= "denc-mod-";
82 if (entry
.path().stem().string().compare(0, DENC_MOD_PREFIX
.size(),
83 DENC_MOD_PREFIX
) != 0) {
86 DencoderPlugin
plugin(entry
);
90 dencoder_plugins
.push_back(std::move(plugin
));
92 return dencoder_plugins
;
95 int main(int argc
, const char **argv
)
97 vector
<DencoderPlugin
> plugins
= load_plugins();
98 DencoderRegistry registry
;
99 for (auto& plugin
: plugins
) {
100 for (auto& [name
, denc
] : plugin
.register_dencoders()) {
101 registry
.register_dencoder(name
, denc
);
105 auto args
= argv_to_vec(argc
, argv
);
108 Dencoder
*den
= NULL
;
109 uint64_t features
= CEPH_FEATURES_SUPPORTED_DEFAULT
;
114 cerr
<< "-h for help" << std::endl
;
117 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ++i
) {
120 auto& dencoders
= registry
.get();
121 if (*i
== string("help") || *i
== string("-h") || *i
== string("--help")) {
124 } else if (*i
== string("version")) {
125 cout
<< CEPH_GIT_NICE_VER
<< std::endl
;
126 } else if (*i
== string("list_types")) {
127 for (auto& dencoder
: dencoders
)
128 cout
<< dencoder
.first
<< std::endl
;
130 } else if (*i
== string("type")) {
132 if (i
== args
.end()) {
133 cerr
<< "expecting type" << std::endl
;
137 if (!dencoders
.count(cname
)) {
138 cerr
<< "class '" << cname
<< "' unknown" << std::endl
;
141 den
= dencoders
[cname
];
143 } else if (*i
== string("skip")) {
145 if (i
== args
.end()) {
146 cerr
<< "expecting byte count" << std::endl
;
150 } else if (*i
== string("get_features")) {
151 cout
<< CEPH_FEATURES_SUPPORTED_DEFAULT
<< std::endl
;
153 } else if (*i
== string("set_features")) {
155 if (i
== args
.end()) {
156 cerr
<< "expecting features" << std::endl
;
159 features
= atoll(*i
);
160 } else if (*i
== string("encode")) {
162 cerr
<< "must first select type with 'type <name>'" << std::endl
;
165 den
->encode(encbl
, features
| CEPH_FEATURE_RESERVED
); // hack for OSDMap
166 } else if (*i
== string("decode")) {
168 cerr
<< "must first select type with 'type <name>'" << std::endl
;
171 err
= den
->decode(encbl
, skip
);
172 } else if (*i
== string("copy_ctor")) {
174 cerr
<< "must first select type with 'type <name>'" << std::endl
;
178 } else if (*i
== string("copy")) {
180 cerr
<< "must first select type with 'type <name>'" << std::endl
;
184 } else if (*i
== string("dump_json")) {
186 cerr
<< "must first select type with 'type <name>'" << std::endl
;
189 JSONFormatter
jf(true);
190 jf
.open_object_section("object");
196 } else if (*i
== string("hexdump")) {
198 } else if (*i
== string("get_struct_v")) {
199 std::cout
<< den
->get_struct_v(encbl
, 0) << std::endl
;
200 } else if (*i
== string("get_struct_compat")) {
201 std::cout
<< den
->get_struct_v(encbl
, sizeof(uint8_t)) << std::endl
;
202 } else if (*i
== string("import")) {
204 if (i
== args
.end()) {
205 cerr
<< "expecting filename" << std::endl
;
209 if (*i
== string("-")) {
211 // Read up to 1mb if stdin specified
212 r
= encbl
.read_fd(STDIN_FILENO
, MB(1));
214 r
= encbl
.read_file(*i
, &err
);
217 cerr
<< "error reading " << *i
<< ": " << err
<< std::endl
;
221 } else if (*i
== string("export")) {
223 if (i
== args
.end()) {
224 cerr
<< "expecting filename" << std::endl
;
227 int fd
= ::open(*i
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
, 0644);
229 cerr
<< "error opening " << *i
<< " for write: " << cpp_strerror(errno
) << std::endl
;
232 int r
= encbl
.write_fd(fd
);
234 cerr
<< "error writing " << *i
<< ": " << cpp_strerror(errno
) << std::endl
;
239 } else if (*i
== string("count_tests")) {
241 cerr
<< "must first select type with 'type <name>'" << std::endl
;
244 cout
<< den
->num_generated() << std::endl
;
245 } else if (*i
== string("select_test")) {
247 cerr
<< "must first select type with 'type <name>'" << std::endl
;
251 if (i
== args
.end()) {
252 cerr
<< "expecting instance number" << std::endl
;
256 err
= den
->select_generated(n
);
257 } else if (*i
== string("is_deterministic")) {
259 cerr
<< "must first select type with 'type <name>'" << std::endl
;
262 if (den
->is_deterministic())
267 cerr
<< "unknown option '" << *i
<< "'" << std::endl
;
271 cerr
<< "error: " << err
<< std::endl
;