]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/ceph-dencoder/ceph_dencoder.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / tools / ceph-dencoder / ceph_dencoder.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2015 Red Hat
7 *
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.
12 *
13 */
14
15
16 #include <errno.h>
17
18 #include <filesystem>
19 #include <iomanip>
20
21 #include "ceph_ver.h"
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"
28
29 #define MB(m) ((m) * 1024 * 1024)
30
31 namespace fs = std::filesystem;
32
33 using namespace std;
34
35 void usage(ostream &out)
36 {
37 out << "usage: ceph-dencoder [commands ...]" << std::endl;
38 out << "\n";
39 out << " version print version string (to stdout)\n";
40 out << "\n";
41 out << " import <encfile> read encoded data from encfile\n";
42 out << " export <outfile> write encoded data to outfile\n";
43 out << "\n";
44 out << " set_features <num> set feature bits used for encoding\n";
45 out << " get_features print feature bits (int) to stdout\n";
46 out << "\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";
56 out << "\n";
57 out << " copy copy object (via operator=)\n";
58 out << " copy_ctor copy object (via copy ctor)\n";
59 out << "\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";
63 }
64
65 vector<DencoderPlugin> load_plugins()
66 {
67 fs::path mod_dir{CEPH_DENC_MOD_DIR};
68 if (auto ceph_lib = getenv("CEPH_LIB"); ceph_lib) {
69 mod_dir = ceph_lib;
70 } else if (fs::is_regular_file("CMakeCache.txt")) {
71 mod_dir = std::filesystem::canonical("lib");
72 }
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;
77 return {};
78 }
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) {
84 continue;
85 }
86 DencoderPlugin plugin(entry);
87 if (!plugin.good()) {
88 continue;
89 }
90 dencoder_plugins.push_back(std::move(plugin));
91 }
92 return dencoder_plugins;
93 }
94
95 int main(int argc, const char **argv)
96 {
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);
102 }
103 }
104
105 auto args = argv_to_vec(argc, argv);
106 env_to_vec(args);
107
108 Dencoder *den = NULL;
109 uint64_t features = CEPH_FEATURES_SUPPORTED_DEFAULT;
110 bufferlist encbl;
111 uint64_t skip = 0;
112
113 if (args.empty()) {
114 cerr << "-h for help" << std::endl;
115 return 1;
116 }
117 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ++i) {
118 string err;
119
120 auto& dencoders = registry.get();
121 if (*i == string("help") || *i == string("-h") || *i == string("--help")) {
122 usage(cout);
123 return 0;
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;
129 return 0;
130 } else if (*i == string("type")) {
131 ++i;
132 if (i == args.end()) {
133 cerr << "expecting type" << std::endl;
134 return 1;
135 }
136 string cname = *i;
137 if (!dencoders.count(cname)) {
138 cerr << "class '" << cname << "' unknown" << std::endl;
139 return 1;
140 }
141 den = dencoders[cname];
142 den->generate();
143 } else if (*i == string("skip")) {
144 ++i;
145 if (i == args.end()) {
146 cerr << "expecting byte count" << std::endl;
147 return 1;
148 }
149 skip = atoi(*i);
150 } else if (*i == string("get_features")) {
151 cout << CEPH_FEATURES_SUPPORTED_DEFAULT << std::endl;
152 return 0;
153 } else if (*i == string("set_features")) {
154 ++i;
155 if (i == args.end()) {
156 cerr << "expecting features" << std::endl;
157 return 1;
158 }
159 features = atoll(*i);
160 } else if (*i == string("encode")) {
161 if (!den) {
162 cerr << "must first select type with 'type <name>'" << std::endl;
163 return 1;
164 }
165 den->encode(encbl, features | CEPH_FEATURE_RESERVED); // hack for OSDMap
166 } else if (*i == string("decode")) {
167 if (!den) {
168 cerr << "must first select type with 'type <name>'" << std::endl;
169 return 1;
170 }
171 err = den->decode(encbl, skip);
172 } else if (*i == string("copy_ctor")) {
173 if (!den) {
174 cerr << "must first select type with 'type <name>'" << std::endl;
175 return 1;
176 }
177 den->copy_ctor();
178 } else if (*i == string("copy")) {
179 if (!den) {
180 cerr << "must first select type with 'type <name>'" << std::endl;
181 return 1;
182 }
183 den->copy();
184 } else if (*i == string("dump_json")) {
185 if (!den) {
186 cerr << "must first select type with 'type <name>'" << std::endl;
187 return 1;
188 }
189 JSONFormatter jf(true);
190 jf.open_object_section("object");
191 den->dump(&jf);
192 jf.close_section();
193 jf.flush(cout);
194 cout << std::endl;
195
196 } else if (*i == string("hexdump")) {
197 encbl.hexdump(cout);
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")) {
203 ++i;
204 if (i == args.end()) {
205 cerr << "expecting filename" << std::endl;
206 return 1;
207 }
208 int r;
209 if (*i == string("-")) {
210 *i = "stdin";
211 // Read up to 1mb if stdin specified
212 r = encbl.read_fd(STDIN_FILENO, MB(1));
213 } else {
214 r = encbl.read_file(*i, &err);
215 }
216 if (r < 0) {
217 cerr << "error reading " << *i << ": " << err << std::endl;
218 return 1;
219 }
220
221 } else if (*i == string("export")) {
222 ++i;
223 if (i == args.end()) {
224 cerr << "expecting filename" << std::endl;
225 return 1;
226 }
227 int fd = ::open(*i, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
228 if (fd < 0) {
229 cerr << "error opening " << *i << " for write: " << cpp_strerror(errno) << std::endl;
230 return 1;
231 }
232 int r = encbl.write_fd(fd);
233 if (r < 0) {
234 cerr << "error writing " << *i << ": " << cpp_strerror(errno) << std::endl;
235 return 1;
236 }
237 ::close(fd);
238
239 } else if (*i == string("count_tests")) {
240 if (!den) {
241 cerr << "must first select type with 'type <name>'" << std::endl;
242 return 1;
243 }
244 cout << den->num_generated() << std::endl;
245 } else if (*i == string("select_test")) {
246 if (!den) {
247 cerr << "must first select type with 'type <name>'" << std::endl;
248 return 1;
249 }
250 ++i;
251 if (i == args.end()) {
252 cerr << "expecting instance number" << std::endl;
253 return 1;
254 }
255 int n = atoi(*i);
256 err = den->select_generated(n);
257 } else if (*i == string("is_deterministic")) {
258 if (!den) {
259 cerr << "must first select type with 'type <name>'" << std::endl;
260 return 1;
261 }
262 if (den->is_deterministic())
263 return 0;
264 else
265 return 1;
266 } else {
267 cerr << "unknown option '" << *i << "'" << std::endl;
268 return 1;
269 }
270 if (err.length()) {
271 cerr << "error: " << err << std::endl;
272 return 1;
273 }
274 }
275 return 0;
276 }