]>
Commit | Line | Data |
---|---|---|
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 |
31 | namespace fs = std::filesystem; |
32 | ||
33 | using namespace std; | |
34 | ||
7c673cae FG |
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"; | |
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 | |
65 | vector<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 |
93 | int 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 | } |