]>
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 | #include "tools/rbd/ArgumentTypes.h" | |
5 | #include "tools/rbd/Shell.h" | |
6 | #include "tools/rbd/Utils.h" | |
7 | #include "include/stringify.h" | |
8 | #include "common/SubProcess.h" | |
9 | #include <iostream> | |
11fdf7f2 | 10 | #include <boost/algorithm/string.hpp> |
7c673cae | 11 | #include <boost/algorithm/string/predicate.hpp> |
7c673cae FG |
12 | #include <boost/program_options.hpp> |
13 | ||
14 | namespace rbd { | |
15 | namespace action { | |
16 | namespace nbd { | |
17 | ||
18 | namespace at = argument_types; | |
19 | namespace po = boost::program_options; | |
20 | ||
21 | static int call_nbd_cmd(const po::variables_map &vm, | |
11fdf7f2 TL |
22 | const std::vector<std::string> &args, |
23 | const std::vector<std::string> &ceph_global_init_args) { | |
7c673cae FG |
24 | char exe_path[PATH_MAX]; |
25 | ssize_t exe_path_bytes = readlink("/proc/self/exe", exe_path, | |
26 | sizeof(exe_path) - 1); | |
27 | if (exe_path_bytes < 0) { | |
28 | strcpy(exe_path, "rbd-nbd"); | |
29 | } else { | |
30 | if (snprintf(exe_path + exe_path_bytes, | |
31 | sizeof(exe_path) - exe_path_bytes, | |
32 | "-nbd") < 0) { | |
33 | return -EOVERFLOW; | |
34 | } | |
35 | } | |
36 | ||
37 | SubProcess process(exe_path, SubProcess::KEEP, SubProcess::KEEP, SubProcess::KEEP); | |
38 | ||
11fdf7f2 TL |
39 | for (auto &arg : ceph_global_init_args) { |
40 | process.add_cmd_arg(arg.c_str()); | |
7c673cae FG |
41 | } |
42 | ||
11fdf7f2 TL |
43 | for (auto &arg : args) { |
44 | process.add_cmd_arg(arg.c_str()); | |
45 | } | |
7c673cae FG |
46 | |
47 | if (process.spawn()) { | |
48 | std::cerr << "rbd: failed to run rbd-nbd: " << process.err() << std::endl; | |
49 | return -EINVAL; | |
50 | } else if (process.join()) { | |
51 | std::cerr << "rbd: rbd-nbd failed with error: " << process.err() << std::endl; | |
52 | return -EINVAL; | |
53 | } | |
54 | ||
55 | return 0; | |
56 | } | |
57 | ||
11fdf7f2 | 58 | int get_image_or_snap_spec(const po::variables_map &vm, std::string *spec) { |
7c673cae FG |
59 | size_t arg_index = 0; |
60 | std::string pool_name; | |
11fdf7f2 | 61 | std::string nspace_name; |
7c673cae FG |
62 | std::string image_name; |
63 | std::string snap_name; | |
64 | int r = utils::get_pool_image_snapshot_names( | |
11fdf7f2 TL |
65 | vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &nspace_name, |
66 | &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_PERMITTED, | |
7c673cae FG |
67 | utils::SPEC_VALIDATION_NONE); |
68 | if (r < 0) { | |
69 | return r; | |
70 | } | |
71 | ||
11fdf7f2 TL |
72 | spec->append(pool_name); |
73 | spec->append("/"); | |
74 | if (!nspace_name.empty()) { | |
75 | spec->append(nspace_name); | |
76 | spec->append("/"); | |
77 | } | |
78 | spec->append(image_name); | |
79 | if (!snap_name.empty()) { | |
80 | spec->append("@"); | |
81 | spec->append(snap_name); | |
82 | } | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | int parse_options(const std::vector<std::string> &options, | |
88 | std::vector<std::string> *args) { | |
89 | for (auto &opts : options) { | |
90 | std::vector<std::string> args_; | |
91 | boost::split(args_, opts, boost::is_any_of(",")); | |
92 | for (auto &o : args_) { | |
93 | args->push_back("--" + o); | |
94 | } | |
95 | } | |
96 | ||
97 | return 0; | |
98 | } | |
99 | ||
100 | int execute_list(const po::variables_map &vm, | |
101 | const std::vector<std::string> &ceph_global_init_args) { | |
102 | #if defined(__FreeBSD__) | |
103 | std::cerr << "rbd: nbd device is not supported" << std::endl; | |
104 | return -EOPNOTSUPP; | |
105 | #endif | |
106 | std::vector<std::string> args; | |
107 | ||
108 | args.push_back("list-mapped"); | |
109 | ||
110 | if (vm.count("format")) { | |
111 | args.push_back("--format"); | |
112 | args.push_back(vm["format"].as<at::Format>().value); | |
113 | } | |
114 | if (vm["pretty-format"].as<bool>()) { | |
115 | args.push_back("--pretty-format"); | |
116 | } | |
117 | ||
118 | return call_nbd_cmd(vm, args, ceph_global_init_args); | |
119 | } | |
120 | ||
121 | int execute_map(const po::variables_map &vm, | |
122 | const std::vector<std::string> &ceph_global_init_args) { | |
123 | #if defined(__FreeBSD__) | |
124 | std::cerr << "rbd: nbd device is not supported" << std::endl; | |
125 | return -EOPNOTSUPP; | |
126 | #endif | |
127 | std::vector<std::string> args; | |
7c673cae FG |
128 | |
129 | args.push_back("map"); | |
130 | std::string img; | |
11fdf7f2 TL |
131 | int r = get_image_or_snap_spec(vm, &img); |
132 | if (r < 0) { | |
133 | return r; | |
7c673cae | 134 | } |
11fdf7f2 | 135 | args.push_back(img); |
7c673cae | 136 | |
11fdf7f2 | 137 | if (vm["read-only"].as<bool>()) { |
7c673cae | 138 | args.push_back("--read-only"); |
11fdf7f2 | 139 | } |
7c673cae | 140 | |
11fdf7f2 | 141 | if (vm["exclusive"].as<bool>()) { |
7c673cae | 142 | args.push_back("--exclusive"); |
7c673cae FG |
143 | } |
144 | ||
11fdf7f2 TL |
145 | if (vm.count("options")) { |
146 | r = parse_options(vm["options"].as<std::vector<std::string>>(), &args); | |
147 | if (r < 0) { | |
148 | return r; | |
149 | } | |
150 | } | |
7c673cae | 151 | |
11fdf7f2 | 152 | return call_nbd_cmd(vm, args, ceph_global_init_args); |
7c673cae FG |
153 | } |
154 | ||
11fdf7f2 TL |
155 | int execute_unmap(const po::variables_map &vm, |
156 | const std::vector<std::string> &ceph_global_init_args) { | |
157 | #if defined(__FreeBSD__) | |
158 | std::cerr << "rbd: nbd device is not supported" << std::endl; | |
159 | return -EOPNOTSUPP; | |
160 | #endif | |
7c673cae FG |
161 | std::string device_name = utils::get_positional_argument(vm, 0); |
162 | if (!boost::starts_with(device_name, "/dev/")) { | |
163 | device_name.clear(); | |
164 | } | |
165 | ||
11fdf7f2 | 166 | std::string image_name; |
7c673cae | 167 | if (device_name.empty()) { |
11fdf7f2 TL |
168 | int r = get_image_or_snap_spec(vm, &image_name); |
169 | if (r < 0) { | |
170 | return r; | |
171 | } | |
172 | } | |
173 | ||
174 | if (device_name.empty() && image_name.empty()) { | |
175 | std::cerr << "rbd: unmap requires either image name or device path" | |
176 | << std::endl; | |
7c673cae FG |
177 | return -EINVAL; |
178 | } | |
179 | ||
11fdf7f2 | 180 | std::vector<std::string> args; |
7c673cae FG |
181 | |
182 | args.push_back("unmap"); | |
11fdf7f2 TL |
183 | args.push_back(device_name.empty() ? image_name : device_name); |
184 | ||
185 | if (vm.count("options")) { | |
186 | int r = parse_options(vm["options"].as<std::vector<std::string>>(), &args); | |
187 | if (r < 0) { | |
188 | return r; | |
189 | } | |
190 | } | |
191 | ||
192 | return call_nbd_cmd(vm, args, ceph_global_init_args); | |
193 | } | |
194 | ||
195 | void get_list_arguments_deprecated(po::options_description *positional, | |
196 | po::options_description *options) { | |
197 | at::add_format_options(options); | |
198 | } | |
199 | ||
200 | int execute_list_deprecated(const po::variables_map &vm, | |
201 | const std::vector<std::string> &ceph_global_args) { | |
202 | std::cerr << "rbd: 'nbd list' command is deprecated, " | |
203 | << "use 'device list -t nbd' instead" << std::endl; | |
204 | return execute_list(vm, ceph_global_args); | |
205 | } | |
206 | ||
207 | void get_map_arguments_deprecated(po::options_description *positional, | |
208 | po::options_description *options) { | |
209 | at::add_image_or_snap_spec_options(positional, options, | |
210 | at::ARGUMENT_MODIFIER_NONE); | |
211 | options->add_options() | |
212 | ("read-only", po::bool_switch(), "map read-only") | |
213 | ("exclusive", po::bool_switch(), "forbid writes by other clients") | |
214 | ("device", po::value<std::string>(), "specify nbd device") | |
215 | ("nbds_max", po::value<std::string>(), "override module param nbds_max") | |
216 | ("max_part", po::value<std::string>(), "override module param max_part") | |
217 | ("timeout", po::value<std::string>(), "set nbd request timeout (seconds)"); | |
218 | } | |
219 | ||
220 | int execute_map_deprecated(const po::variables_map &vm_deprecated, | |
221 | const std::vector<std::string> &ceph_global_args) { | |
222 | std::cerr << "rbd: 'nbd map' command is deprecated, " | |
223 | << "use 'device map -t nbd' instead" << std::endl; | |
224 | ||
225 | po::options_description options; | |
226 | options.add_options() | |
227 | ("options,o", po::value<std::vector<std::string>>() | |
228 | ->default_value(std::vector<std::string>(), ""), ""); | |
229 | ||
230 | po::variables_map vm = vm_deprecated; | |
231 | po::store(po::command_line_parser({}).options(options).run(), vm); | |
232 | ||
233 | std::vector<std::string> opts; | |
234 | if (vm_deprecated.count("device")) { | |
235 | opts.push_back("device=" + vm_deprecated["device"].as<std::string>()); | |
236 | } | |
237 | if (vm_deprecated.count("nbds_max")) { | |
238 | opts.push_back("nbds_max=" + vm_deprecated["nbds_max"].as<std::string>()); | |
239 | } | |
240 | if (vm_deprecated.count("max_part")) { | |
241 | opts.push_back("max_part=" + vm_deprecated["max_part"].as<std::string>()); | |
242 | } | |
243 | if (vm_deprecated.count("timeout")) { | |
244 | opts.push_back("timeout=" + vm_deprecated["timeout"].as<std::string>()); | |
245 | } | |
246 | ||
247 | vm.at("options").value() = boost::any(opts); | |
248 | ||
249 | return execute_map(vm, ceph_global_args); | |
250 | } | |
251 | ||
252 | void get_unmap_arguments_deprecated(po::options_description *positional, | |
253 | po::options_description *options) { | |
254 | positional->add_options() | |
255 | ("image-or-snap-or-device-spec", | |
256 | "image, snapshot, or device specification\n" | |
257 | "[<pool-name>/]<image-name>[@<snapshot-name>] or <device-path>"); | |
258 | at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE); | |
259 | at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE); | |
260 | at::add_snap_option(options, at::ARGUMENT_MODIFIER_NONE); | |
261 | } | |
7c673cae | 262 | |
11fdf7f2 TL |
263 | int execute_unmap_deprecated(const po::variables_map &vm, |
264 | const std::vector<std::string> &ceph_global_args) { | |
265 | std::cerr << "rbd: 'nbd unmap' command is deprecated, " | |
266 | << "use 'device unmap -t nbd' instead" << std::endl; | |
267 | return execute_unmap(vm, ceph_global_args); | |
7c673cae FG |
268 | } |
269 | ||
11fdf7f2 | 270 | Shell::SwitchArguments switched_arguments({"read-only", "exclusive"}); |
7c673cae | 271 | |
11fdf7f2 | 272 | Shell::Action action_show_deprecated( |
7c673cae | 273 | {"nbd", "list"}, {"nbd", "ls"}, "List the nbd devices already used.", "", |
11fdf7f2 | 274 | &get_list_arguments_deprecated, &execute_list_deprecated, false); |
7c673cae | 275 | |
11fdf7f2 | 276 | Shell::Action action_map_deprecated( |
7c673cae | 277 | {"nbd", "map"}, {}, "Map image to a nbd device.", "", |
11fdf7f2 | 278 | &get_map_arguments_deprecated, &execute_map_deprecated, false); |
7c673cae | 279 | |
11fdf7f2 | 280 | Shell::Action action_unmap_deprecated( |
7c673cae | 281 | {"nbd", "unmap"}, {}, "Unmap a nbd device.", "", |
11fdf7f2 | 282 | &get_unmap_arguments_deprecated, &execute_unmap_deprecated, false); |
7c673cae FG |
283 | |
284 | } // namespace nbd | |
285 | } // namespace action | |
286 | } // namespace rbd |