]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/ceph-dencoder/ceph_dencoder.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / tools / ceph-dencoder / ceph_dencoder.cc
CommitLineData
7c673cae
FG
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>
20effc67
TL
17
18#include <filesystem>
19#include <iomanip>
20
7c673cae 21#include "ceph_ver.h"
9f95a23c 22#include "include/types.h"
7c673cae 23#include "common/Formatter.h"
9f95a23c 24#include "common/ceph_argparse.h"
7c673cae 25#include "common/errno.h"
20effc67 26#include "denc_plugin.h"
9f95a23c 27#include "denc_registry.h"
7c673cae
FG
28
29#define MB(m) ((m) * 1024 * 1024)
30
20effc67
TL
31namespace fs = std::filesystem;
32
33using namespace std;
34
7c673cae
FG
35void 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";
f67539c2
TL
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";
7c673cae
FG
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}
20effc67
TL
64
65vector<DencoderPlugin> load_plugins()
7c673cae 66{
20effc67
TL
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 }
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;
75 return {};
76 }
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) {
82 continue;
83 }
84 DencoderPlugin plugin(entry);
85 if (!plugin.good()) {
86 continue;
87 }
88 dencoder_plugins.push_back(std::move(plugin));
89 }
90 return dencoder_plugins;
91}
7c673cae 92
20effc67
TL
93int main(int argc, const char **argv)
94{
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);
100 }
101 }
7c673cae 102
20effc67 103 auto args = argv_to_vec(argc, argv);
7c673cae
FG
104 env_to_vec(args);
105
106 Dencoder *den = NULL;
107 uint64_t features = CEPH_FEATURES_SUPPORTED_DEFAULT;
108 bufferlist encbl;
109 uint64_t skip = 0;
110
111 if (args.empty()) {
112 cerr << "-h for help" << std::endl;
20effc67 113 return 1;
7c673cae
FG
114 }
115 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ++i) {
116 string err;
117
20effc67 118 auto& dencoders = registry.get();
7c673cae
FG
119 if (*i == string("help") || *i == string("-h") || *i == string("--help")) {
120 usage(cout);
20effc67 121 return 0;
7c673cae
FG
122 } else if (*i == string("version")) {
123 cout << CEPH_GIT_NICE_VER << std::endl;
124 } else if (*i == string("list_types")) {
9f95a23c
TL
125 for (auto& dencoder : dencoders)
126 cout << dencoder.first << std::endl;
20effc67 127 return 0;
7c673cae
FG
128 } else if (*i == string("type")) {
129 ++i;
130 if (i == args.end()) {
131 cerr << "expecting type" << std::endl;
20effc67 132 return 1;
7c673cae
FG
133 }
134 string cname = *i;
135 if (!dencoders.count(cname)) {
136 cerr << "class '" << cname << "' unknown" << std::endl;
20effc67 137 return 1;
7c673cae 138 }
20effc67 139 den = dencoders[cname];
7c673cae
FG
140 den->generate();
141 } else if (*i == string("skip")) {
142 ++i;
143 if (i == args.end()) {
144 cerr << "expecting byte count" << std::endl;
20effc67 145 return 1;
7c673cae
FG
146 }
147 skip = atoi(*i);
148 } else if (*i == string("get_features")) {
149 cout << CEPH_FEATURES_SUPPORTED_DEFAULT << std::endl;
20effc67 150 return 0;
7c673cae
FG
151 } else if (*i == string("set_features")) {
152 ++i;
153 if (i == args.end()) {
154 cerr << "expecting features" << std::endl;
20effc67 155 return 1;
7c673cae
FG
156 }
157 features = atoll(*i);
158 } else if (*i == string("encode")) {
159 if (!den) {
160 cerr << "must first select type with 'type <name>'" << std::endl;
20effc67 161 return 1;
7c673cae
FG
162 }
163 den->encode(encbl, features | CEPH_FEATURE_RESERVED); // hack for OSDMap
164 } else if (*i == string("decode")) {
165 if (!den) {
166 cerr << "must first select type with 'type <name>'" << std::endl;
20effc67 167 return 1;
7c673cae
FG
168 }
169 err = den->decode(encbl, skip);
170 } else if (*i == string("copy_ctor")) {
171 if (!den) {
172 cerr << "must first select type with 'type <name>'" << std::endl;
20effc67 173 return 1;
7c673cae
FG
174 }
175 den->copy_ctor();
176 } else if (*i == string("copy")) {
177 if (!den) {
178 cerr << "must first select type with 'type <name>'" << std::endl;
20effc67 179 return 1;
7c673cae
FG
180 }
181 den->copy();
182 } else if (*i == string("dump_json")) {
183 if (!den) {
184 cerr << "must first select type with 'type <name>'" << std::endl;
20effc67 185 return 1;
7c673cae
FG
186 }
187 JSONFormatter jf(true);
188 jf.open_object_section("object");
189 den->dump(&jf);
190 jf.close_section();
191 jf.flush(cout);
192 cout << std::endl;
193
194 } else if (*i == string("hexdump")) {
195 encbl.hexdump(cout);
f67539c2
TL
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;
7c673cae
FG
200 } else if (*i == string("import")) {
201 ++i;
202 if (i == args.end()) {
203 cerr << "expecting filename" << std::endl;
20effc67 204 return 1;
7c673cae
FG
205 }
206 int r;
207 if (*i == string("-")) {
208 *i = "stdin";
209 // Read up to 1mb if stdin specified
210 r = encbl.read_fd(STDIN_FILENO, MB(1));
211 } else {
212 r = encbl.read_file(*i, &err);
213 }
214 if (r < 0) {
215 cerr << "error reading " << *i << ": " << err << std::endl;
20effc67 216 return 1;
7c673cae
FG
217 }
218
219 } else if (*i == string("export")) {
220 ++i;
221 if (i == args.end()) {
222 cerr << "expecting filename" << std::endl;
20effc67 223 return 1;
7c673cae 224 }
f67539c2 225 int fd = ::open(*i, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
7c673cae
FG
226 if (fd < 0) {
227 cerr << "error opening " << *i << " for write: " << cpp_strerror(errno) << std::endl;
20effc67 228 return 1;
7c673cae
FG
229 }
230 int r = encbl.write_fd(fd);
231 if (r < 0) {
232 cerr << "error writing " << *i << ": " << cpp_strerror(errno) << std::endl;
20effc67 233 return 1;
7c673cae
FG
234 }
235 ::close(fd);
236
237 } else if (*i == string("count_tests")) {
238 if (!den) {
239 cerr << "must first select type with 'type <name>'" << std::endl;
20effc67 240 return 1;
7c673cae
FG
241 }
242 cout << den->num_generated() << std::endl;
243 } else if (*i == string("select_test")) {
244 if (!den) {
245 cerr << "must first select type with 'type <name>'" << std::endl;
20effc67 246 return 1;
7c673cae
FG
247 }
248 ++i;
249 if (i == args.end()) {
250 cerr << "expecting instance number" << std::endl;
20effc67 251 return 1;
7c673cae
FG
252 }
253 int n = atoi(*i);
254 err = den->select_generated(n);
255 } else if (*i == string("is_deterministic")) {
256 if (!den) {
257 cerr << "must first select type with 'type <name>'" << std::endl;
20effc67 258 return 1;
7c673cae
FG
259 }
260 if (den->is_deterministic())
20effc67 261 return 0;
7c673cae 262 else
20effc67 263 return 1;
7c673cae
FG
264 } else {
265 cerr << "unknown option '" << *i << "'" << std::endl;
20effc67 266 return 1;
7c673cae
FG
267 }
268 if (err.length()) {
269 cerr << "error: " << err << std::endl;
20effc67 270 return 1;
7c673cae
FG
271 }
272 }
273 return 0;
274}