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/predicate.hpp>
11 #include <boost/scope_exit.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<const char*> &args)
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");
30 if (snprintf(exe_path + exe_path_bytes,
31 sizeof(exe_path) - exe_path_bytes,
37 SubProcess process(exe_path, SubProcess::KEEP, SubProcess::KEEP, SubProcess::KEEP);
39 if (vm.count("conf")) {
40 process.add_cmd_arg("--conf");
41 process.add_cmd_arg(vm["conf"].as<std::string>().c_str());
43 if (vm.count("cluster")) {
44 process.add_cmd_arg("--cluster");
45 process.add_cmd_arg(vm["cluster"].as<std::string>().c_str());
48 process.add_cmd_arg("--id");
49 process.add_cmd_arg(vm["id"].as<std::string>().c_str());
51 if (vm.count("name")) {
52 process.add_cmd_arg("--name");
53 process.add_cmd_arg(vm["name"].as<std::string>().c_str());
55 if (vm.count("mon_host")) {
56 process.add_cmd_arg("--mon_host");
57 process.add_cmd_arg(vm["mon_host"].as<std::string>().c_str());
59 if (vm.count("keyfile")) {
60 process.add_cmd_arg("--keyfile");
61 process.add_cmd_arg(vm["keyfile"].as<std::string>().c_str());
63 if (vm.count("keyring")) {
64 process.add_cmd_arg("--keyring");
65 process.add_cmd_arg(vm["keyring"].as<std::string>().c_str());
68 for (std::vector<const char*>::const_iterator p = args.begin();
70 process.add_cmd_arg(*p);
72 if (process.spawn()) {
73 std::cerr << "rbd: failed to run rbd-nbd: " << process.err() << std::endl;
75 } else if (process.join()) {
76 std::cerr << "rbd: rbd-nbd failed with error: " << process.err() << std::endl;
83 void get_show_arguments(po::options_description *positional,
84 po::options_description *options)
87 int execute_show(const po::variables_map &vm)
89 std::vector<const char*> args;
91 args.push_back("list-mapped");
93 return call_nbd_cmd(vm, args);
96 void get_map_arguments(po::options_description *positional,
97 po::options_description *options)
99 at::add_image_or_snap_spec_options(positional, options,
100 at::ARGUMENT_MODIFIER_NONE);
101 options->add_options()
102 ("read-only", po::bool_switch(), "map read-only")
103 ("exclusive", po::bool_switch(), "forbid writes by other clients")
104 ("device", po::value<std::string>(), "specify nbd device")
105 ("nbds_max", po::value<std::string>(), "override module param nbds_max")
106 ("max_part", po::value<std::string>(), "override module param max_part");
109 int execute_map(const po::variables_map &vm)
111 size_t arg_index = 0;
112 std::string pool_name;
113 std::string image_name;
114 std::string snap_name;
115 int r = utils::get_pool_image_snapshot_names(
116 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
117 &snap_name, utils::SNAPSHOT_PRESENCE_PERMITTED,
118 utils::SPEC_VALIDATION_NONE);
123 std::vector<const char*> args;
125 args.push_back("map");
127 img.append(pool_name);
129 img.append(image_name);
130 if (!snap_name.empty()) {
132 img.append(snap_name);
134 args.push_back(img.c_str());
136 if (vm["read-only"].as<bool>())
137 args.push_back("--read-only");
139 if (vm["exclusive"].as<bool>())
140 args.push_back("--exclusive");
142 if (vm.count("device")) {
143 args.push_back("--device");
144 args.push_back(vm["device"].as<std::string>().c_str());
146 if (vm.count("nbds_max")) {
147 args.push_back("--nbds_max");
148 args.push_back(vm["nbds_max"].as<std::string>().c_str());
150 if (vm.count("max_part")) {
151 args.push_back("--max_part");
152 args.push_back(vm["max_part"].as<std::string>().c_str());
155 return call_nbd_cmd(vm, args);
158 void get_unmap_arguments(po::options_description *positional,
159 po::options_description *options)
161 positional->add_options()
162 ("device-spec", "specify nbd device");
165 int execute_unmap(const po::variables_map &vm)
167 std::string device_name = utils::get_positional_argument(vm, 0);
168 if (!boost::starts_with(device_name, "/dev/")) {
172 if (device_name.empty()) {
173 std::cerr << "rbd: nbd unmap requires device path" << std::endl;
177 std::vector<const char*> args;
179 args.push_back("unmap");
180 args.push_back(device_name.c_str());
182 return call_nbd_cmd(vm, args);
185 Shell::SwitchArguments switched_arguments({"read-only"});
187 Shell::Action action_show(
188 {"nbd", "list"}, {"nbd", "ls"}, "List the nbd devices already used.", "",
189 &get_show_arguments, &execute_show);
191 Shell::Action action_map(
192 {"nbd", "map"}, {}, "Map image to a nbd device.", "",
193 &get_map_arguments, &execute_map);
195 Shell::Action action_unmap(
196 {"nbd", "unmap"}, {}, "Unmap a nbd device.", "",
197 &get_unmap_arguments, &execute_unmap);
200 } // namespace action