]>
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 "common/errno.h" | |
8 | #include "common/Formatter.h" | |
9 | #include "common/TextTable.h" | |
10 | #include <iostream> | |
11 | #include <boost/program_options.hpp> | |
12 | ||
13 | namespace rbd { | |
14 | namespace action { | |
15 | namespace diff { | |
16 | ||
17 | namespace at = argument_types; | |
18 | namespace po = boost::program_options; | |
19 | ||
20 | struct output_method { | |
21 | output_method() : f(NULL), t(NULL), empty(true) {} | |
22 | Formatter *f; | |
23 | TextTable *t; | |
24 | bool empty; | |
25 | }; | |
26 | ||
27 | static int diff_cb(uint64_t ofs, size_t len, int exists, void *arg) | |
28 | { | |
29 | output_method *om = static_cast<output_method *>(arg); | |
30 | om->empty = false; | |
31 | if (om->f) { | |
32 | om->f->open_object_section("extent"); | |
33 | om->f->dump_unsigned("offset", ofs); | |
34 | om->f->dump_unsigned("length", len); | |
35 | om->f->dump_string("exists", exists ? "true" : "false"); | |
36 | om->f->close_section(); | |
37 | } else { | |
11fdf7f2 | 38 | ceph_assert(om->t); |
7c673cae FG |
39 | *(om->t) << ofs << len << (exists ? "data" : "zero") << TextTable::endrow; |
40 | } | |
41 | return 0; | |
42 | } | |
43 | ||
44 | static int do_diff(librbd::Image& image, const char *fromsnapname, | |
45 | bool whole_object, Formatter *f) | |
46 | { | |
47 | int r; | |
48 | librbd::image_info_t info; | |
49 | ||
50 | r = image.stat(info, sizeof(info)); | |
51 | if (r < 0) | |
52 | return r; | |
53 | ||
54 | output_method om; | |
55 | if (f) { | |
56 | om.f = f; | |
57 | f->open_array_section("extents"); | |
58 | } else { | |
59 | om.t = new TextTable(); | |
60 | om.t->define_column("Offset", TextTable::LEFT, TextTable::LEFT); | |
61 | om.t->define_column("Length", TextTable::LEFT, TextTable::LEFT); | |
62 | om.t->define_column("Type", TextTable::LEFT, TextTable::LEFT); | |
63 | } | |
64 | ||
65 | r = image.diff_iterate2(fromsnapname, 0, info.size, true, whole_object, | |
66 | diff_cb, &om); | |
67 | if (f) { | |
68 | f->close_section(); | |
69 | f->flush(std::cout); | |
70 | } else { | |
71 | if (!om.empty) | |
72 | std::cout << *om.t; | |
73 | delete om.t; | |
74 | } | |
75 | return r; | |
76 | } | |
77 | ||
78 | void get_arguments(po::options_description *positional, | |
79 | po::options_description *options) { | |
80 | at::add_image_or_snap_spec_options(positional, options, | |
81 | at::ARGUMENT_MODIFIER_NONE); | |
82 | options->add_options() | |
83 | (at::FROM_SNAPSHOT_NAME.c_str(), po::value<std::string>(), | |
84 | "snapshot starting point") | |
85 | (at::WHOLE_OBJECT.c_str(), po::bool_switch(), "compare whole object"); | |
86 | at::add_format_options(options); | |
87 | } | |
88 | ||
11fdf7f2 TL |
89 | int execute(const po::variables_map &vm, |
90 | const std::vector<std::string> &ceph_global_init_args) { | |
7c673cae FG |
91 | size_t arg_index = 0; |
92 | std::string pool_name; | |
11fdf7f2 | 93 | std::string namespace_name; |
7c673cae FG |
94 | std::string image_name; |
95 | std::string snap_name; | |
96 | int r = utils::get_pool_image_snapshot_names( | |
11fdf7f2 TL |
97 | vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name, |
98 | &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_PERMITTED, | |
7c673cae FG |
99 | utils::SPEC_VALIDATION_NONE); |
100 | if (r < 0) { | |
101 | return r; | |
102 | } | |
103 | ||
104 | std::string from_snap_name; | |
105 | if (vm.count(at::FROM_SNAPSHOT_NAME)) { | |
106 | from_snap_name = vm[at::FROM_SNAPSHOT_NAME].as<std::string>(); | |
107 | } | |
108 | ||
109 | bool diff_whole_object = vm[at::WHOLE_OBJECT].as<bool>(); | |
110 | ||
111 | at::Format::Formatter formatter; | |
112 | r = utils::get_formatter(vm, &formatter); | |
113 | if (r < 0) { | |
114 | return r; | |
115 | } | |
116 | ||
117 | librados::Rados rados; | |
118 | librados::IoCtx io_ctx; | |
119 | librbd::Image image; | |
11fdf7f2 TL |
120 | r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", |
121 | snap_name, true, &rados, &io_ctx, &image); | |
7c673cae FG |
122 | if (r < 0) { |
123 | return r; | |
124 | } | |
125 | ||
126 | r = do_diff(image, from_snap_name.empty() ? nullptr : from_snap_name.c_str(), | |
127 | diff_whole_object, formatter.get()); | |
128 | if (r < 0) { | |
129 | std::cerr << "rbd: diff error: " << cpp_strerror(r) << std::endl; | |
130 | return -r; | |
131 | } | |
132 | return 0; | |
133 | } | |
134 | ||
7c673cae FG |
135 | Shell::Action action( |
136 | {"diff"}, {}, | |
137 | "Print extents that differ since a previous snap, or image creation.", "", | |
138 | &get_arguments, &execute); | |
139 | ||
140 | } // namespace diff | |
141 | } // namespace action | |
142 | } // namespace rbd |