]>
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 "include/types.h" | |
9 | #include "common/errno.h" | |
10 | #include "common/Formatter.h" | |
11 | #include "common/TextTable.h" | |
12 | #include <iostream> | |
13 | #include <boost/program_options.hpp> | |
14 | ||
15 | namespace rbd { | |
16 | namespace action { | |
17 | namespace list { | |
18 | ||
19 | namespace at = argument_types; | |
20 | namespace po = boost::program_options; | |
21 | ||
22 | int do_list(librbd::RBD &rbd, librados::IoCtx& io_ctx, bool lflag, | |
23 | Formatter *f) { | |
24 | std::vector<std::string> names; | |
25 | int r = rbd.list(io_ctx, names); | |
26 | if (r == -ENOENT) | |
27 | r = 0; | |
28 | if (r < 0) | |
29 | return r; | |
30 | ||
31 | if (!lflag) { | |
32 | if (f) | |
33 | f->open_array_section("images"); | |
34 | for (std::vector<std::string>::const_iterator i = names.begin(); | |
35 | i != names.end(); ++i) { | |
36 | if (f) | |
37 | f->dump_string("name", *i); | |
38 | else | |
39 | std::cout << *i << std::endl; | |
40 | } | |
41 | if (f) { | |
42 | f->close_section(); | |
43 | f->flush(std::cout); | |
44 | } | |
45 | return 0; | |
46 | } | |
47 | ||
48 | TextTable tbl; | |
49 | ||
50 | if (f) { | |
51 | f->open_array_section("images"); | |
52 | } else { | |
53 | tbl.define_column("NAME", TextTable::LEFT, TextTable::LEFT); | |
54 | tbl.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT); | |
55 | tbl.define_column("PARENT", TextTable::LEFT, TextTable::LEFT); | |
56 | tbl.define_column("FMT", TextTable::RIGHT, TextTable::RIGHT); | |
57 | tbl.define_column("PROT", TextTable::LEFT, TextTable::LEFT); | |
58 | tbl.define_column("LOCK", TextTable::LEFT, TextTable::LEFT); | |
59 | } | |
60 | ||
61 | std::string pool, image, snap, parent; | |
62 | ||
63 | for (std::vector<std::string>::const_iterator i = names.begin(); | |
64 | i != names.end(); ++i) { | |
65 | librbd::image_info_t info; | |
66 | librbd::Image im; | |
67 | ||
68 | r = rbd.open_read_only(io_ctx, im, i->c_str(), NULL); | |
69 | // image might disappear between rbd.list() and rbd.open(); ignore | |
70 | // that, warn about other possible errors (EPERM, say, for opening | |
71 | // an old-format image, because you need execute permission for the | |
72 | // class method) | |
73 | if (r < 0) { | |
74 | if (r != -ENOENT) { | |
75 | std::cerr << "rbd: error opening " << *i << ": " << cpp_strerror(r) | |
76 | << std::endl; | |
77 | } | |
78 | // in any event, continue to next image | |
79 | continue; | |
80 | } | |
81 | ||
82 | // handle second-nth trips through loop | |
83 | parent.clear(); | |
84 | r = im.parent_info(&pool, &image, &snap); | |
85 | if (r < 0 && r != -ENOENT) | |
86 | goto out; | |
87 | bool has_parent = false; | |
88 | if (r != -ENOENT) { | |
89 | parent = pool + "/" + image + "@" + snap; | |
90 | has_parent = true; | |
91 | } | |
92 | ||
93 | if (im.stat(info, sizeof(info)) < 0) { | |
94 | r = -EINVAL; | |
95 | goto out; | |
96 | } | |
97 | ||
98 | uint8_t old_format; | |
99 | im.old_format(&old_format); | |
100 | ||
101 | std::list<librbd::locker_t> lockers; | |
102 | bool exclusive; | |
103 | r = im.list_lockers(&lockers, &exclusive, NULL); | |
104 | if (r < 0) | |
105 | goto out; | |
106 | std::string lockstr; | |
107 | if (!lockers.empty()) { | |
108 | lockstr = (exclusive) ? "excl" : "shr"; | |
109 | } | |
110 | ||
111 | if (f) { | |
112 | f->open_object_section("image"); | |
113 | f->dump_string("image", *i); | |
114 | f->dump_unsigned("size", info.size); | |
115 | if (has_parent) { | |
116 | f->open_object_section("parent"); | |
117 | f->dump_string("pool", pool); | |
118 | f->dump_string("image", image); | |
119 | f->dump_string("snapshot", snap); | |
120 | f->close_section(); | |
121 | } | |
122 | f->dump_int("format", old_format ? 1 : 2); | |
123 | if (!lockers.empty()) | |
124 | f->dump_string("lock_type", exclusive ? "exclusive" : "shared"); | |
125 | f->close_section(); | |
126 | } else { | |
127 | tbl << *i | |
128 | << stringify(si_t(info.size)) | |
129 | << parent | |
130 | << ((old_format) ? '1' : '2') | |
131 | << "" // protect doesn't apply to images | |
132 | << lockstr | |
133 | << TextTable::endrow; | |
134 | } | |
135 | ||
136 | std::vector<librbd::snap_info_t> snaplist; | |
137 | if (im.snap_list(snaplist) >= 0 && !snaplist.empty()) { | |
138 | for (std::vector<librbd::snap_info_t>::iterator s = snaplist.begin(); | |
139 | s != snaplist.end(); ++s) { | |
140 | bool is_protected; | |
141 | bool has_parent = false; | |
142 | parent.clear(); | |
143 | im.snap_set(s->name.c_str()); | |
144 | r = im.snap_is_protected(s->name.c_str(), &is_protected); | |
145 | if (r < 0) | |
146 | goto out; | |
147 | if (im.parent_info(&pool, &image, &snap) >= 0) { | |
148 | parent = pool + "/" + image + "@" + snap; | |
149 | has_parent = true; | |
150 | } | |
151 | if (f) { | |
152 | f->open_object_section("snapshot"); | |
153 | f->dump_string("image", *i); | |
154 | f->dump_string("snapshot", s->name); | |
155 | f->dump_unsigned("size", s->size); | |
156 | if (has_parent) { | |
157 | f->open_object_section("parent"); | |
158 | f->dump_string("pool", pool); | |
159 | f->dump_string("image", image); | |
160 | f->dump_string("snapshot", snap); | |
161 | f->close_section(); | |
162 | } | |
163 | f->dump_int("format", old_format ? 1 : 2); | |
164 | f->dump_string("protected", is_protected ? "true" : "false"); | |
165 | f->close_section(); | |
166 | } else { | |
167 | tbl << *i + "@" + s->name | |
168 | << stringify(si_t(s->size)) | |
169 | << parent | |
170 | << ((old_format) ? '1' : '2') | |
171 | << (is_protected ? "yes" : "") | |
172 | << "" // locks don't apply to snaps | |
173 | << TextTable::endrow; | |
174 | } | |
175 | } | |
176 | } | |
177 | } | |
178 | ||
179 | out: | |
180 | if (f) { | |
181 | f->close_section(); | |
182 | f->flush(std::cout); | |
183 | } else if (!names.empty()) { | |
184 | std::cout << tbl; | |
185 | } | |
186 | ||
187 | return r < 0 ? r : 0; | |
188 | } | |
189 | ||
190 | void get_arguments(po::options_description *positional, | |
191 | po::options_description *options) { | |
192 | options->add_options() | |
193 | ("long,l", po::bool_switch(), "long listing format"); | |
194 | at::add_pool_options(positional, options); | |
195 | at::add_format_options(options); | |
196 | } | |
197 | ||
198 | int execute(const po::variables_map &vm) { | |
199 | size_t arg_index = 0; | |
200 | std::string pool_name = utils::get_pool_name(vm, &arg_index); | |
201 | ||
202 | at::Format::Formatter formatter; | |
203 | int r = utils::get_formatter(vm, &formatter); | |
204 | if (r < 0) { | |
205 | return r; | |
206 | } | |
207 | ||
208 | librados::Rados rados; | |
209 | librados::IoCtx io_ctx; | |
210 | r = utils::init(pool_name, &rados, &io_ctx); | |
211 | if (r < 0) { | |
212 | return r; | |
213 | } | |
214 | ||
215 | librbd::RBD rbd; | |
216 | r = do_list(rbd, io_ctx, vm["long"].as<bool>(), formatter.get()); | |
217 | if (r < 0) { | |
218 | std::cerr << "rbd: list: " << cpp_strerror(r) << std::endl; | |
219 | return r; | |
220 | } | |
221 | ||
222 | return 0; | |
223 | } | |
224 | ||
225 | Shell::SwitchArguments switched_arguments({"long", "l"}); | |
226 | Shell::Action action( | |
227 | {"list"}, {"ls"}, "List rbd images.", "", &get_arguments, &execute); | |
228 | ||
229 | } // namespace list | |
230 | } // namespace action | |
231 | } // namespace rbd |