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
) {
71 if (!fs::is_directory(mod_dir
)) {
72 std::cerr
<< "unable to load dencoders from "
73 << std::quoted(mod_dir
.native()) << ". "
74 << "it is not a directory." << std::endl
;
77 vector
<DencoderPlugin
> dencoder_plugins
;
78 for (auto& entry
: fs::directory_iterator(mod_dir
)) {
79 static const string_view DENC_MOD_PREFIX
= "denc-mod-";
80 if (entry
.path().stem().string().compare(0, DENC_MOD_PREFIX
.size(),
81 DENC_MOD_PREFIX
) != 0) {
84 DencoderPlugin
plugin(entry
);
88 dencoder_plugins
.push_back(std::move(plugin
));
90 return dencoder_plugins
;
93 int main(int argc
, const char **argv
)
95 vector
<DencoderPlugin
> plugins
= load_plugins();
96 DencoderRegistry registry
;
97 for (auto& plugin
: plugins
) {
98 for (auto& [name
, denc
] : plugin
.register_dencoders()) {
99 registry
.register_dencoder(name
, denc
);
103 auto args
= argv_to_vec(argc
, argv
);
106 Dencoder
*den
= NULL
;
107 uint64_t features
= CEPH_FEATURES_SUPPORTED_DEFAULT
;
112 cerr
<< "-h for help" << std::endl
;
115 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ++i
) {
118 auto& dencoders
= registry
.get();
119 if (*i
== string("help") || *i
== string("-h") || *i
== string("--help")) {
122 } else if (*i
== string("version")) {
123 cout
<< CEPH_GIT_NICE_VER
<< std::endl
;
124 } else if (*i
== string("list_types")) {
125 for (auto& dencoder
: dencoders
)
126 cout
<< dencoder
.first
<< std::endl
;
128 } else if (*i
== string("type")) {
130 if (i
== args
.end()) {
131 cerr
<< "expecting type" << std::endl
;
135 if (!dencoders
.count(cname
)) {
136 cerr
<< "class '" << cname
<< "' unknown" << std::endl
;
139 den
= dencoders
[cname
];
141 } else if (*i
== string("skip")) {
143 if (i
== args
.end()) {
144 cerr
<< "expecting byte count" << std::endl
;
148 } else if (*i
== string("get_features")) {
149 cout
<< CEPH_FEATURES_SUPPORTED_DEFAULT
<< std::endl
;
151 } else if (*i
== string("set_features")) {
153 if (i
== args
.end()) {
154 cerr
<< "expecting features" << std::endl
;
157 features
= atoll(*i
);
158 } else if (*i
== string("encode")) {
160 cerr
<< "must first select type with 'type <name>'" << std::endl
;
163 den
->encode(encbl
, features
| CEPH_FEATURE_RESERVED
); // hack for OSDMap
164 } else if (*i
== string("decode")) {
166 cerr
<< "must first select type with 'type <name>'" << std::endl
;
169 err
= den
->decode(encbl
, skip
);
170 } else if (*i
== string("copy_ctor")) {
172 cerr
<< "must first select type with 'type <name>'" << std::endl
;
176 } else if (*i
== string("copy")) {
178 cerr
<< "must first select type with 'type <name>'" << std::endl
;
182 } else if (*i
== string("dump_json")) {
184 cerr
<< "must first select type with 'type <name>'" << std::endl
;
187 JSONFormatter
jf(true);
188 jf
.open_object_section("object");
194 } else if (*i
== string("hexdump")) {
196 } else if (*i
== string("get_struct_v")) {
197 std::cout
<< den
->get_struct_v(encbl
, 0) << std::endl
;
198 } else if (*i
== string("get_struct_compat")) {
199 std::cout
<< den
->get_struct_v(encbl
, sizeof(uint8_t)) << std::endl
;
200 } else if (*i
== string("import")) {
202 if (i
== args
.end()) {
203 cerr
<< "expecting filename" << std::endl
;
207 if (*i
== string("-")) {
209 // Read up to 1mb if stdin specified
210 r
= encbl
.read_fd(STDIN_FILENO
, MB(1));
212 r
= encbl
.read_file(*i
, &err
);
215 cerr
<< "error reading " << *i
<< ": " << err
<< std::endl
;
219 } else if (*i
== string("export")) {
221 if (i
== args
.end()) {
222 cerr
<< "expecting filename" << std::endl
;
225 int fd
= ::open(*i
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
, 0644);
227 cerr
<< "error opening " << *i
<< " for write: " << cpp_strerror(errno
) << std::endl
;
230 int r
= encbl
.write_fd(fd
);
232 cerr
<< "error writing " << *i
<< ": " << cpp_strerror(errno
) << std::endl
;
237 } else if (*i
== string("count_tests")) {
239 cerr
<< "must first select type with 'type <name>'" << std::endl
;
242 cout
<< den
->num_generated() << std::endl
;
243 } else if (*i
== string("select_test")) {
245 cerr
<< "must first select type with 'type <name>'" << std::endl
;
249 if (i
== args
.end()) {
250 cerr
<< "expecting instance number" << std::endl
;
254 err
= den
->select_generated(n
);
255 } else if (*i
== string("is_deterministic")) {
257 cerr
<< "must first select type with 'type <name>'" << std::endl
;
260 if (den
->is_deterministic())
265 cerr
<< "unknown option '" << *i
<< "'" << std::endl
;
269 cerr
<< "error: " << err
<< std::endl
;