1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
10 #include <boost/algorithm/string.hpp>
11 #include <boost/algorithm/string/predicate.hpp>
12 #include <boost/program_options.hpp>
18 namespace at
= argument_types
;
19 namespace po
= boost::program_options
;
21 static int call_nbd_cmd(const po::variables_map
&vm
,
22 const std::vector
<std::string
> &args
,
23 const std::vector
<std::string
> &ceph_global_init_args
) {
24 #if defined(__FreeBSD__) || defined(_WIN32)
25 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
28 char exe_path
[PATH_MAX
];
29 ssize_t exe_path_bytes
= readlink("/proc/self/exe", exe_path
,
30 sizeof(exe_path
) - 1);
31 if (exe_path_bytes
< 0) {
32 strcpy(exe_path
, "rbd-nbd");
34 if (snprintf(exe_path
+ exe_path_bytes
,
35 sizeof(exe_path
) - exe_path_bytes
,
41 SubProcess
process(exe_path
, SubProcess::KEEP
, SubProcess::KEEP
, SubProcess::KEEP
);
43 for (auto &arg
: ceph_global_init_args
) {
44 process
.add_cmd_arg(arg
.c_str());
47 for (auto &arg
: args
) {
48 process
.add_cmd_arg(arg
.c_str());
51 if (process
.spawn()) {
52 std::cerr
<< "rbd: failed to run rbd-nbd: " << process
.err() << std::endl
;
54 } else if (process
.join()) {
55 std::cerr
<< "rbd: rbd-nbd failed with error: " << process
.err() << std::endl
;
63 #if !defined(__FreeBSD__) && !defined(_WIN32)
64 int get_image_or_snap_spec(const po::variables_map
&vm
, std::string
*spec
) {
66 std::string pool_name
;
67 std::string nspace_name
;
68 std::string image_name
;
69 std::string snap_name
;
70 int r
= utils::get_pool_image_snapshot_names(
71 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &nspace_name
,
72 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_PERMITTED
,
73 utils::SPEC_VALIDATION_NONE
);
78 if (pool_name
.empty()) {
79 // connect to the cluster to get the default pool
80 librados::Rados rados
;
81 r
= utils::init_rados(&rados
);
86 utils::normalize_pool_name(&pool_name
);
89 spec
->append(pool_name
);
91 if (!nspace_name
.empty()) {
92 spec
->append(nspace_name
);
95 spec
->append(image_name
);
96 if (!snap_name
.empty()) {
98 spec
->append(snap_name
);
104 int parse_options(const std::vector
<std::string
> &options
,
105 std::vector
<std::string
> *args
) {
106 for (auto &opts
: options
) {
107 std::vector
<std::string
> args_
;
108 boost::split(args_
, opts
, boost::is_any_of(","));
109 for (auto &o
: args_
) {
110 args
->push_back("--" + o
);
118 int execute_list(const po::variables_map
&vm
,
119 const std::vector
<std::string
> &ceph_global_init_args
) {
120 #if defined(__FreeBSD__) || defined(_WIN32)
121 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
124 std::vector
<std::string
> args
;
126 args
.push_back("list-mapped");
128 if (vm
.count("format")) {
129 args
.push_back("--format");
130 args
.push_back(vm
["format"].as
<at::Format
>().value
);
132 if (vm
["pretty-format"].as
<bool>()) {
133 args
.push_back("--pretty-format");
136 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
140 int execute_attach(const po::variables_map
&vm
,
141 const std::vector
<std::string
> &ceph_global_init_args
) {
142 #if defined(__FreeBSD__) || defined(_WIN32)
143 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
146 std::vector
<std::string
> args
;
147 std::string device_path
;
149 args
.push_back("attach");
151 int r
= get_image_or_snap_spec(vm
, &img
);
157 if (vm
.count("device")) {
158 device_path
= vm
["device"].as
<std::string
>();
159 args
.push_back("--device");
160 args
.push_back(device_path
);
162 std::cerr
<< "rbd: device was not specified" << std::endl
;
166 if (vm
["show-cookie"].as
<bool>()) {
167 args
.push_back("--show-cookie");
170 if (vm
.count("cookie")) {
171 args
.push_back("--cookie");
172 args
.push_back(vm
["cookie"].as
<std::string
>());
173 } else if (!vm
["force"].as
<bool>()) {
174 std::cerr
<< "rbd: could not validate attach request\n";
175 std::cerr
<< "rbd: mismatching the image and the device may lead to data corruption\n";
176 std::cerr
<< "rbd: must specify --cookie <arg> or --force to proceed" << std::endl
;
180 if (vm
["quiesce"].as
<bool>()) {
181 args
.push_back("--quiesce");
184 if (vm
["read-only"].as
<bool>()) {
185 args
.push_back("--read-only");
188 if (vm
["exclusive"].as
<bool>()) {
189 args
.push_back("--exclusive");
192 if (vm
.count("quiesce-hook")) {
193 args
.push_back("--quiesce-hook");
194 args
.push_back(vm
["quiesce-hook"].as
<std::string
>());
197 if (vm
.count("options")) {
198 r
= parse_options(vm
["options"].as
<std::vector
<std::string
>>(), &args
);
204 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
208 int execute_detach(const po::variables_map
&vm
,
209 const std::vector
<std::string
> &ceph_global_init_args
) {
210 #if defined(__FreeBSD__) || defined(_WIN32)
211 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
214 std::string device_name
= utils::get_positional_argument(vm
, 0);
215 if (!boost::starts_with(device_name
, "/dev/")) {
219 std::string image_name
;
220 if (device_name
.empty()) {
221 int r
= get_image_or_snap_spec(vm
, &image_name
);
227 if (device_name
.empty() && image_name
.empty()) {
228 std::cerr
<< "rbd: detach requires either image name or device path"
233 std::vector
<std::string
> args
;
235 args
.push_back("detach");
236 args
.push_back(device_name
.empty() ? image_name
: device_name
);
238 if (vm
.count("options")) {
239 int r
= parse_options(vm
["options"].as
<std::vector
<std::string
>>(), &args
);
245 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
249 int execute_map(const po::variables_map
&vm
,
250 const std::vector
<std::string
> &ceph_global_init_args
) {
251 #if defined(__FreeBSD__) || defined(_WIN32)
252 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
255 std::vector
<std::string
> args
;
257 args
.push_back("map");
259 int r
= get_image_or_snap_spec(vm
, &img
);
265 if (vm
["quiesce"].as
<bool>()) {
266 args
.push_back("--quiesce");
269 if (vm
["show-cookie"].as
<bool>()) {
270 args
.push_back("--show-cookie");
273 if (vm
.count("cookie")) {
274 args
.push_back("--cookie");
275 args
.push_back(vm
["cookie"].as
<std::string
>());
278 if (vm
["read-only"].as
<bool>()) {
279 args
.push_back("--read-only");
282 if (vm
["exclusive"].as
<bool>()) {
283 args
.push_back("--exclusive");
286 if (vm
.count("quiesce-hook")) {
287 args
.push_back("--quiesce-hook");
288 args
.push_back(vm
["quiesce-hook"].as
<std::string
>());
291 if (vm
.count("options")) {
292 r
= parse_options(vm
["options"].as
<std::vector
<std::string
>>(), &args
);
298 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
302 int execute_unmap(const po::variables_map
&vm
,
303 const std::vector
<std::string
> &ceph_global_init_args
) {
304 #if defined(__FreeBSD__) || defined(_WIN32)
305 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
308 std::string device_name
= utils::get_positional_argument(vm
, 0);
309 if (!boost::starts_with(device_name
, "/dev/")) {
313 std::string image_name
;
314 if (device_name
.empty()) {
315 int r
= get_image_or_snap_spec(vm
, &image_name
);
321 if (device_name
.empty() && image_name
.empty()) {
322 std::cerr
<< "rbd: unmap requires either image name or device path"
327 std::vector
<std::string
> args
;
329 args
.push_back("unmap");
330 args
.push_back(device_name
.empty() ? image_name
: device_name
);
332 if (vm
.count("options")) {
333 int r
= parse_options(vm
["options"].as
<std::vector
<std::string
>>(), &args
);
339 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
343 void get_list_arguments_deprecated(po::options_description
*positional
,
344 po::options_description
*options
) {
345 at::add_format_options(options
);
348 int execute_list_deprecated(const po::variables_map
&vm
,
349 const std::vector
<std::string
> &ceph_global_args
) {
350 std::cerr
<< "rbd: 'nbd list' command is deprecated, "
351 << "use 'device list -t nbd' instead" << std::endl
;
352 return execute_list(vm
, ceph_global_args
);
355 void get_map_arguments_deprecated(po::options_description
*positional
,
356 po::options_description
*options
) {
357 at::add_image_or_snap_spec_options(positional
, options
,
358 at::ARGUMENT_MODIFIER_NONE
);
359 options
->add_options()
360 ("read-only", po::bool_switch(), "map read-only")
361 ("exclusive", po::bool_switch(), "forbid writes by other clients")
362 ("device", po::value
<std::string
>(), "specify nbd device")
363 ("nbds_max", po::value
<std::string
>(), "override module param nbds_max")
364 ("max_part", po::value
<std::string
>(), "override module param max_part")
365 ("timeout", po::value
<std::string
>(), "set nbd request timeout (seconds)");
368 int execute_map_deprecated(const po::variables_map
&vm_deprecated
,
369 const std::vector
<std::string
> &ceph_global_args
) {
370 std::cerr
<< "rbd: 'nbd map' command is deprecated, "
371 << "use 'device map -t nbd' instead" << std::endl
;
373 po::options_description options
;
374 options
.add_options()
375 ("options,o", po::value
<std::vector
<std::string
>>()
376 ->default_value(std::vector
<std::string
>(), ""), "");
378 po::variables_map vm
= vm_deprecated
;
379 po::store(po::command_line_parser({}).options(options
).run(), vm
);
381 std::vector
<std::string
> opts
;
382 if (vm_deprecated
.count("device")) {
383 opts
.push_back("device=" + vm_deprecated
["device"].as
<std::string
>());
385 if (vm_deprecated
.count("nbds_max")) {
386 opts
.push_back("nbds_max=" + vm_deprecated
["nbds_max"].as
<std::string
>());
388 if (vm_deprecated
.count("max_part")) {
389 opts
.push_back("max_part=" + vm_deprecated
["max_part"].as
<std::string
>());
391 if (vm_deprecated
.count("timeout")) {
392 opts
.push_back("timeout=" + vm_deprecated
["timeout"].as
<std::string
>());
395 vm
.at("options").value() = boost::any(opts
);
397 return execute_map(vm
, ceph_global_args
);
400 void get_unmap_arguments_deprecated(po::options_description
*positional
,
401 po::options_description
*options
) {
402 positional
->add_options()
403 ("image-or-snap-or-device-spec",
404 "image, snapshot, or device specification\n"
405 "[<pool-name>/]<image-name>[@<snap-name>] or <device-path>");
406 at::add_pool_option(options
, at::ARGUMENT_MODIFIER_NONE
);
407 at::add_image_option(options
, at::ARGUMENT_MODIFIER_NONE
);
408 at::add_snap_option(options
, at::ARGUMENT_MODIFIER_NONE
);
411 int execute_unmap_deprecated(const po::variables_map
&vm
,
412 const std::vector
<std::string
> &ceph_global_args
) {
413 std::cerr
<< "rbd: 'nbd unmap' command is deprecated, "
414 << "use 'device unmap -t nbd' instead" << std::endl
;
415 return execute_unmap(vm
, ceph_global_args
);
418 Shell::Action
action_show_deprecated(
419 {"nbd", "list"}, {"nbd", "ls"}, "List the nbd devices already used.", "",
420 &get_list_arguments_deprecated
, &execute_list_deprecated
, false);
422 Shell::Action
action_map_deprecated(
423 {"nbd", "map"}, {}, "Map image to a nbd device.", "",
424 &get_map_arguments_deprecated
, &execute_map_deprecated
, false);
426 Shell::Action
action_unmap_deprecated(
427 {"nbd", "unmap"}, {}, "Unmap a nbd device.", "",
428 &get_unmap_arguments_deprecated
, &execute_unmap_deprecated
, false);
431 } // namespace action