return 0;
}
+int get_image_or_snap_spec(const po::variables_map &vm, std::string *spec) {
+ size_t arg_index = 0;
+ std::string pool_name;
+ std::string image_name;
+ std::string snap_name;
+ int r = utils::get_pool_image_snapshot_names(
+ vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
+ &snap_name, utils::SNAPSHOT_PRESENCE_PERMITTED,
+ utils::SPEC_VALIDATION_NONE);
+ if (r < 0) {
+ return r;
+ }
+
+ spec->append(pool_name);
+ spec->append("/");
+ spec->append(image_name);
+ if (!snap_name.empty()) {
+ spec->append("@");
+ spec->append(snap_name);
+ }
+
+ return 0;
+}
+
void get_show_arguments(po::options_description *positional,
po::options_description *options)
{ }
int execute_map(const po::variables_map &vm)
{
- size_t arg_index = 0;
- std::string pool_name;
- std::string image_name;
- std::string snap_name;
- int r = utils::get_pool_image_snapshot_names(
- vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
- &snap_name, utils::SNAPSHOT_PRESENCE_PERMITTED,
- utils::SPEC_VALIDATION_NONE);
- if (r < 0) {
- return r;
- }
-
std::vector<const char*> args;
args.push_back("map");
std::string img;
- img.append(pool_name);
- img.append("/");
- img.append(image_name);
- if (!snap_name.empty()) {
- img.append("@");
- img.append(snap_name);
+ int r = get_image_or_snap_spec(vm, &img);
+ if (r < 0) {
+ return r;
}
args.push_back(img.c_str());
po::options_description *options)
{
positional->add_options()
- ("device-spec", "specify nbd device");
+ ("image-or-snap-or-device-spec",
+ "image, snapshot, or device specification\n"
+ "[<pool-name>/]<image-name>[@<snapshot-name>] or <device-path>");
+ at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE);
+ at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE);
+ at::add_snap_option(options, at::ARGUMENT_MODIFIER_NONE);
}
int execute_unmap(const po::variables_map &vm)
device_name.clear();
}
+ std::string image_name;
if (device_name.empty()) {
- std::cerr << "rbd: nbd unmap requires device path" << std::endl;
+ int r = get_image_or_snap_spec(vm, &image_name);
+ if (r < 0) {
+ return r;
+ }
+ }
+
+ if (device_name.empty() && image_name.empty()) {
+ std::cerr << "rbd: unmap requires either image name or device path"
+ << std::endl;
return -EINVAL;
}
std::vector<const char*> args;
args.push_back("unmap");
- args.push_back(device_name.c_str());
+ args.push_back(device_name.empty() ? image_name.c_str() :
+ device_name.c_str());
return call_nbd_cmd(vm, args);
}
#include <iostream>
#include <fstream>
#include <boost/regex.hpp>
+#include <boost/algorithm/string/predicate.hpp>
#include "mon/MonClient.h"
#include "common/config.h"
static void usage()
{
std::cout << "Usage: rbd-nbd [options] map <image-or-snap-spec> Map an image to nbd device\n"
- << " unmap <device path> Unmap nbd device\n"
+ << " unmap <device|image-or-snap-spec> Unmap nbd device\n"
<< " list-mapped List mapped nbd devices\n"
<< "Options:\n"
<< " --device <device path> Specify nbd device path\n"
static int nbd = -1;
-static enum {
+enum Command {
None,
Connect,
Disconnect,
List
-} cmd = None;
+};
+
+static Command cmd = None;
#define RBD_NBD_BLKSIZE 512UL
#endif
#define htonll(a) ntohll(a)
-static int parse_args(vector<const char*>& args, std::ostream *err_msg, Config *cfg);
+static int parse_args(vector<const char*>& args, std::ostream *err_msg,
+ Command *command, Config *cfg);
static void handle_signal(int signum)
{
}
};
+class NBDListIterator {
+public:
+ bool get(int *pid, Config *cfg) {
+ while (true) {
+ std::string nbd_path = "/sys/block/nbd" + stringify(m_index);
+ if(access(nbd_path.c_str(), F_OK) != 0) {
+ return false;
+ }
+
+ *cfg = Config();
+ cfg->devpath = "/dev/nbd" + stringify(m_index++);
+
+ std::ifstream ifs;
+ ifs.open(nbd_path + "/pid", std::ifstream::in);
+ if (!ifs.is_open()) {
+ continue;
+ }
+ ifs >> *pid;
+
+ int r = get_mapped_info(*pid, cfg);
+ if (r < 0) {
+ continue;
+ }
+
+ return true;
+ }
+ }
+
+private:
+ int m_index = 0;
+
+ int get_mapped_info(int pid, Config *cfg) {
+ int r;
+ std::string path = "/proc/" + stringify(pid) + "/cmdline";
+ std::ifstream ifs;
+ std::string cmdline;
+ std::vector<const char*> args;
+
+ ifs.open(path.c_str(), std::ifstream::in);
+ if (!ifs.is_open())
+ return -1;
+ ifs >> cmdline;
+
+ for (unsigned i = 0; i < cmdline.size(); i++) {
+ const char *arg = &cmdline[i];
+ if (i == 0) {
+ if (strcmp(basename(arg) , "rbd-nbd") != 0) {
+ return -EINVAL;
+ }
+ } else {
+ args.push_back(arg);
+ }
+
+ while (cmdline[i] != '\0') {
+ i++;
+ }
+ }
+
+ std::ostringstream err_msg;
+ Command command;
+ r = parse_args(args, &err_msg, &command, cfg);
+ if (r < 0) {
+ return r;
+ }
+
+ if (command != Connect) {
+ return -ENOENT;
+ }
+
+ return 0;
+ }
+};
+
static int open_device(const char* path, Config *cfg = nullptr, bool try_load_module = false)
{
int nbd = open(path, O_RDWR);
bool loaded_module = false;
-
+
if (nbd < 0 && try_load_module && access("/sys/module/nbd", F_OK) != 0) {
ostringstream param;
int r;
cerr << "rbd-nbd: ignoring kernel module parameter options: nbd module already loaded"
<< std::endl;
}
-
+
return nbd;
}
NBDServer server(fd[1], image);
server.start();
-
+
init_async_signal_handler();
register_async_signal_handler(SIGHUP, sighup_handler);
register_async_signal_handler_oneshot(SIGINT, handle_signal);
register_async_signal_handler_oneshot(SIGTERM, handle_signal);
ioctl(nbd, NBD_DO_IT);
-
+
unregister_async_signal_handler(SIGHUP, sighup_handler);
unregister_async_signal_handler(SIGINT, handle_signal);
unregister_async_signal_handler(SIGTERM, handle_signal);
return r;
}
-static int parse_imgpath(const std::string &imgpath, Config *cfg)
-{
+static int parse_imgpath(const std::string &imgpath, Config *cfg,
+ std::ostream *err_msg) {
boost::regex pattern("^(?:([^/@]+)/)?([^/@]+)(?:@([^/@]+))?$");
boost::smatch match;
if (!boost::regex_match(imgpath, match, pattern)) {
- std::cerr << "rbd-nbd: invalid spec '" << imgpath << "'" << std::endl;
+ *err_msg << "rbd-nbd: invalid spec '" << imgpath << "'";
return -EINVAL;
}
return 0;
}
-static int get_mapped_info(int pid, Config *cfg)
-{
- int r;
- std::string path = "/proc/" + stringify(pid) + "/cmdline";
- std::ifstream ifs;
- std::string cmdline;
- std::vector<const char*> args;
-
- ifs.open(path.c_str(), std::ifstream::in);
- if (!ifs.is_open())
- return -1;
- ifs >> cmdline;
-
- for (unsigned i = 0; i < cmdline.size(); i++) {
- const char *arg = &cmdline[i];
- if (i == 0) {
- if (strcmp(basename(arg) , "rbd-nbd") != 0) {
- return -EINVAL;
- }
- } else {
- args.push_back(arg);
- }
-
- while (cmdline[i] != '\0') {
- i++;
- }
- }
-
- std::ostringstream err_msg;
- r = parse_args(args, &err_msg, cfg);
- return r;
-}
-
-static int get_map_pid(const std::string& pid_path)
-{
- int pid = 0;
- std::ifstream ifs;
- ifs.open(pid_path.c_str(), std::ifstream::in);
- if (!ifs.is_open()) {
- return 0;
- }
- ifs >> pid;
- return pid;
-}
-
static int do_list_mapped_devices()
{
- int r;
bool should_print = false;
- int index = 0;
- int pid = 0;
-
- std::string default_pool_name;
-
TextTable tbl;
tbl.define_column("pid", TextTable::LEFT, TextTable::LEFT);
tbl.define_column("image", TextTable::LEFT, TextTable::LEFT);
tbl.define_column("snap", TextTable::LEFT, TextTable::LEFT);
tbl.define_column("device", TextTable::LEFT, TextTable::LEFT);
-
- while (true) {
- std::string nbd_path = "/sys/block/nbd" + stringify(index);
- if(access(nbd_path.c_str(), F_OK) != 0) {
- break;
- }
- std::string pid_path = nbd_path + "/pid";
- pid = get_map_pid(pid_path);
- if(pid > 0) {
- Config cfg;
- r = get_mapped_info(pid, &cfg);
- if (r < 0) {
- index++;
- continue;
- }
- should_print = true;
- if (cfg.snapname.empty()) {
- cfg.snapname = "-";
- }
- tbl << pid << cfg.poolname << cfg.imgname << cfg.snapname
- << "/dev/nbd" + stringify(index) << TextTable::endrow;
+ int pid;
+ Config cfg;
+ NBDListIterator it;
+ while (it.get(&pid, &cfg)) {
+ should_print = true;
+ if (cfg.snapname.empty()) {
+ cfg.snapname = "-";
}
-
- index++;
+ tbl << pid << cfg.poolname << cfg.imgname << cfg.snapname << cfg.devpath
+ << TextTable::endrow;
}
if (should_print) {
return 0;
}
-static int parse_args(vector<const char*>& args, std::ostream *err_msg, Config *cfg)
-{
+static bool find_mapped_dev_by_spec(Config *cfg) {
+ int pid;
+ Config c;
+ NBDListIterator it;
+ while (it.get(&pid, &c)) {
+ if (c.poolname == cfg->poolname && c.imgname == cfg->imgname &&
+ c.snapname == cfg->snapname) {
+ *cfg = c;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+static int parse_args(vector<const char*>& args, std::ostream *err_msg,
+ Command *command, Config *cfg) {
std::string conf_file_list;
std::string cluster;
CephInitParameters iparams = ceph_argparse_early_args(
}
}
+ Command cmd = None;
if (args.begin() != args.end()) {
if (strcmp(*args.begin(), "map") == 0) {
cmd = Connect;
*err_msg << "rbd-nbd: must specify image-or-snap-spec";
return -EINVAL;
}
- if (parse_imgpath(string(*args.begin()), cfg) < 0)
+ if (parse_imgpath(*args.begin(), cfg, err_msg) < 0) {
return -EINVAL;
+ }
args.erase(args.begin());
break;
case Disconnect:
if (args.begin() == args.end()) {
- *err_msg << "rbd-nbd: must specify nbd device path";
+ *err_msg << "rbd-nbd: must specify nbd device or image-or-snap-spec";
return -EINVAL;
}
- cfg->devpath = *args.begin();
+ if (boost::starts_with(*args.begin(), "/dev/")) {
+ cfg->devpath = *args.begin();
+ } else {
+ if (parse_imgpath(*args.begin(), cfg, err_msg) < 0) {
+ return -EINVAL;
+ }
+ if (!find_mapped_dev_by_spec(cfg)) {
+ *err_msg << "rbd-nbd: " << *args.begin() << " is not mapped";
+ return -ENOENT;
+ }
+ }
args.erase(args.begin());
break;
default:
return -EINVAL;
}
+ *command = cmd;
return 0;
}
argv_to_vec(argc, argv, args);
std::ostringstream err_msg;
- r = parse_args(args, &err_msg, &cfg);
+ r = parse_args(args, &err_msg, &cmd, &cfg);
if (r == HELP_INFO) {
usage();
ceph_abort();