Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "tools.h"
17 : : #include "report.h"
18 : :
19 : 0 : static int _vgs_single(struct cmd_context *cmd __attribute((unused)),
20 : : const char *vg_name, struct volume_group *vg,
21 : : void *handle)
22 : : {
23 [ # # ]: 0 : if (!report_object(handle, vg, NULL, NULL, NULL, NULL)) {
24 : 0 : stack;
25 : 0 : return ECMD_FAILED;
26 : : }
27 : :
28 : 0 : check_current_backup(vg);
29 : :
30 : 0 : return ECMD_PROCESSED;
31 : : }
32 : :
33 : 0 : static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
34 : : void *handle)
35 : : {
36 [ # # ][ # # ]: 0 : if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
37 : 0 : return ECMD_PROCESSED;
38 : :
39 [ # # ]: 0 : if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL)) {
40 : 0 : stack;
41 : 0 : return ECMD_FAILED;
42 : : }
43 : :
44 : 0 : return ECMD_PROCESSED;
45 : : }
46 : :
47 : 0 : static int _segs_single(struct cmd_context *cmd __attribute((unused)),
48 : : struct lv_segment *seg, void *handle)
49 : : {
50 [ # # ]: 0 : if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL)) {
51 : 0 : stack;
52 : 0 : return ECMD_FAILED;
53 : : }
54 : :
55 : 0 : return ECMD_PROCESSED;
56 : : }
57 : :
58 : 0 : static int _pvsegs_sub_single(struct cmd_context *cmd,
59 : : struct volume_group *vg,
60 : : struct pv_segment *pvseg, void *handle)
61 : : {
62 : 0 : int ret = ECMD_PROCESSED;
63 : 0 : struct lv_segment *seg = pvseg->lvseg;
64 : :
65 : : struct volume_group _free_vg = {
66 : : .cmd = cmd,
67 : : .name = (char *)"",
68 : 0 : };
69 : :
70 : : struct logical_volume _free_logical_volume = {
71 : 0 : .vg = vg ?: &_free_vg,
72 : : .name = (char *) "",
73 : : .snapshot = NULL,
74 : : .status = VISIBLE_LV,
75 : : .major = -1,
76 : : .minor = -1,
77 [ # # ]: 0 : };
78 : :
79 : : struct lv_segment _free_lv_segment = {
80 : : .lv = &_free_logical_volume,
81 : : .le = 0,
82 : : .status = 0,
83 : : .stripe_size = 0,
84 : : .area_count = 0,
85 : : .area_len = 0,
86 : : .origin = NULL,
87 : : .cow = NULL,
88 : : .chunk_size = 0,
89 : : .region_size = 0,
90 : : .extents_copied = 0,
91 : : .log_lv = NULL,
92 : : .areas = NULL,
93 : 0 : };
94 : :
95 : 0 : _free_lv_segment.segtype = get_segtype_from_string(cmd, "free");
96 : 0 : _free_lv_segment.len = pvseg->len;
97 : 0 : dm_list_init(&_free_vg.pvs);
98 : 0 : dm_list_init(&_free_vg.lvs);
99 : 0 : dm_list_init(&_free_vg.tags);
100 : 0 : dm_list_init(&_free_lv_segment.tags);
101 : 0 : dm_list_init(&_free_lv_segment.origin_list);
102 : 0 : dm_list_init(&_free_logical_volume.tags);
103 : 0 : dm_list_init(&_free_logical_volume.segments);
104 : 0 : dm_list_init(&_free_logical_volume.segs_using_this_lv);
105 : 0 : dm_list_init(&_free_logical_volume.snapshot_segs);
106 : :
107 [ # # ][ # # ]: 0 : if (!report_object(handle, vg, seg ? seg->lv : &_free_logical_volume, pvseg->pv,
[ # # ]
108 : 0 : seg ? : &_free_lv_segment, pvseg)) {
109 : 0 : stack;
110 : 0 : ret = ECMD_FAILED;
111 : : }
112 : :
113 : 0 : return ret;
114 : : }
115 : :
116 : 0 : static int _lvsegs_single(struct cmd_context *cmd, struct logical_volume *lv,
117 : : void *handle)
118 : : {
119 [ # # ][ # # ]: 0 : if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
120 : 0 : return ECMD_PROCESSED;
121 : :
122 : 0 : return process_each_segment_in_lv(cmd, lv, handle, _segs_single);
123 : : }
124 : :
125 : 0 : static int _pvsegs_single(struct cmd_context *cmd, struct volume_group *vg,
126 : : struct physical_volume *pv, void *handle)
127 : : {
128 : 0 : return process_each_segment_in_pv(cmd, vg, pv, handle,
129 : : _pvsegs_sub_single);
130 : : }
131 : :
132 : 0 : static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
133 : : struct physical_volume *pv, void *handle)
134 : : {
135 : : struct pv_list *pvl;
136 : 0 : int ret = ECMD_PROCESSED;
137 : 0 : const char *vg_name = NULL;
138 : 0 : struct volume_group *old_vg = vg;
139 : : char uuid[64] __attribute((aligned(8)));
140 : :
141 [ # # ][ # # ]: 0 : if (is_pv(pv) && !is_orphan(pv) && !vg) {
[ # # ]
142 : 0 : vg_name = pv_vg_name(pv);
143 : :
144 : 0 : vg = vg_read(cmd, vg_name, (char *)&pv->vgid, 0);
145 [ # # ]: 0 : if (vg_read_error(vg)) {
146 : 0 : log_error("Skipping volume group %s", vg_name);
147 : 0 : vg_release(vg);
148 : 0 : return ECMD_FAILED;
149 : : }
150 : :
151 : : /*
152 : : * Replace possibly incomplete PV structure with new one
153 : : * allocated in vg_read.
154 : : */
155 [ # # ]: 0 : if (!is_missing_pv(pv)) {
156 [ # # ]: 0 : if (!(pvl = find_pv_in_vg(vg, pv_dev_name(pv)))) {
157 : 0 : log_error("Unable to find \"%s\" in volume group \"%s\"",
158 : : pv_dev_name(pv), vg->name);
159 : 0 : ret = ECMD_FAILED;
160 : 0 : goto out;
161 : : }
162 [ # # ]: 0 : } else if (!(pvl = find_pv_in_vg_by_uuid(vg, &pv->id))) {
163 [ # # ]: 0 : if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
164 : 0 : stack;
165 : 0 : uuid[0] = '\0';
166 : : }
167 : :
168 : 0 : log_error("Unable to find missing PV %s in volume group %s",
169 : : uuid, vg->name);
170 : 0 : ret = ECMD_FAILED;
171 : 0 : goto out;
172 : : }
173 : :
174 : 0 : pv = pvl->pv;
175 : : }
176 : :
177 [ # # ]: 0 : if (!report_object(handle, vg, NULL, pv, NULL, NULL)) {
178 : 0 : stack;
179 : 0 : ret = ECMD_FAILED;
180 : : }
181 : :
182 : : out:
183 [ # # ]: 0 : if (vg_name)
184 : 0 : unlock_vg(cmd, vg_name);
185 : :
186 [ # # ]: 0 : if (!old_vg)
187 : 0 : vg_release(vg);
188 : :
189 : 0 : return ret;
190 : : }
191 : :
192 : 0 : static int _label_single(struct cmd_context *cmd, struct volume_group *vg,
193 : : struct physical_volume *pv, void *handle)
194 : : {
195 [ # # ]: 0 : if (!report_object(handle, vg, NULL, pv, NULL, NULL)) {
196 : 0 : stack;
197 : 0 : return ECMD_FAILED;
198 : : }
199 : :
200 : 0 : return ECMD_PROCESSED;
201 : : }
202 : :
203 : 0 : static int _pvs_in_vg(struct cmd_context *cmd, const char *vg_name,
204 : : struct volume_group *vg,
205 : : void *handle)
206 : : {
207 [ # # ]: 0 : if (vg_read_error(vg)) {
208 : 0 : stack;
209 : 0 : return ECMD_FAILED;
210 : : }
211 : :
212 : 0 : return process_each_pv_in_vg(cmd, vg, NULL, handle, &_pvs_single);
213 : : }
214 : :
215 : 0 : static int _pvsegs_in_vg(struct cmd_context *cmd, const char *vg_name,
216 : : struct volume_group *vg,
217 : : void *handle)
218 : : {
219 [ # # ]: 0 : if (vg_read_error(vg)) {
220 : 0 : stack;
221 : 0 : return ECMD_FAILED;
222 : : }
223 : :
224 : 0 : return process_each_pv_in_vg(cmd, vg, NULL, handle, &_pvsegs_single);
225 : : }
226 : :
227 : 1 : static int _report(struct cmd_context *cmd, int argc, char **argv,
228 : : report_type_t report_type)
229 : : {
230 : : void *report_handle;
231 : : const char *opts;
232 : : char *str;
233 : 1 : const char *keys = NULL, *options = NULL, *separator;
234 : 1 : int r = ECMD_PROCESSED;
235 : : int aligned, buffered, headings, field_prefixes, quoted;
236 : : int columns_as_rows;
237 : : unsigned args_are_pvs;
238 : :
239 : 1 : aligned = find_config_tree_int(cmd, "report/aligned",
240 : : DEFAULT_REP_ALIGNED);
241 : 1 : buffered = find_config_tree_int(cmd, "report/buffered",
242 : : DEFAULT_REP_BUFFERED);
243 : 1 : headings = find_config_tree_int(cmd, "report/headings",
244 : : DEFAULT_REP_HEADINGS);
245 : 1 : separator = find_config_tree_str(cmd, "report/separator",
246 : : DEFAULT_REP_SEPARATOR);
247 : 1 : field_prefixes = find_config_tree_int(cmd, "report/prefixes",
248 : : DEFAULT_REP_PREFIXES);
249 : 1 : quoted = find_config_tree_int(cmd, "report/quoted",
250 : : DEFAULT_REP_QUOTED);
251 : 1 : columns_as_rows = find_config_tree_int(cmd, "report/columns_as_rows",
252 : : DEFAULT_REP_COLUMNS_AS_ROWS);
253 : :
254 [ + - - + ]: 1 : args_are_pvs = (report_type == PVS ||
[ # # ]
255 : 1 : report_type == LABEL ||
256 : 0 : report_type == PVSEGS) ? 1 : 0;
257 : :
258 [ - - + - - : 1 : switch (report_type) {
- ]
259 : : case LVS:
260 : 0 : keys = find_config_tree_str(cmd, "report/lvs_sort",
261 : : DEFAULT_LVS_SORT);
262 [ # # ]: 0 : if (!arg_count(cmd, verbose_ARG))
263 : 0 : options = find_config_tree_str(cmd,
264 : : "report/lvs_cols",
265 : : DEFAULT_LVS_COLS);
266 : : else
267 : 0 : options = find_config_tree_str(cmd,
268 : : "report/lvs_cols_verbose",
269 : : DEFAULT_LVS_COLS_VERB);
270 : 0 : break;
271 : : case VGS:
272 : 0 : keys = find_config_tree_str(cmd, "report/vgs_sort",
273 : : DEFAULT_VGS_SORT);
274 [ # # ]: 0 : if (!arg_count(cmd, verbose_ARG))
275 : 0 : options = find_config_tree_str(cmd,
276 : : "report/vgs_cols",
277 : : DEFAULT_VGS_COLS);
278 : : else
279 : 0 : options = find_config_tree_str(cmd,
280 : : "report/vgs_cols_verbose",
281 : : DEFAULT_VGS_COLS_VERB);
282 : 0 : break;
283 : : case LABEL:
284 : : case PVS:
285 : 1 : keys = find_config_tree_str(cmd, "report/pvs_sort",
286 : : DEFAULT_PVS_SORT);
287 [ + - ]: 1 : if (!arg_count(cmd, verbose_ARG))
288 : 1 : options = find_config_tree_str(cmd,
289 : : "report/pvs_cols",
290 : : DEFAULT_PVS_COLS);
291 : : else
292 : 0 : options = find_config_tree_str(cmd,
293 : : "report/pvs_cols_verbose",
294 : : DEFAULT_PVS_COLS_VERB);
295 : 1 : break;
296 : : case SEGS:
297 : 0 : keys = find_config_tree_str(cmd, "report/segs_sort",
298 : : DEFAULT_SEGS_SORT);
299 [ # # ]: 0 : if (!arg_count(cmd, verbose_ARG))
300 : 0 : options = find_config_tree_str(cmd,
301 : : "report/segs_cols",
302 : : DEFAULT_SEGS_COLS);
303 : : else
304 : 0 : options = find_config_tree_str(cmd,
305 : : "report/segs_cols_verbose",
306 : : DEFAULT_SEGS_COLS_VERB);
307 : 0 : break;
308 : : case PVSEGS:
309 : 0 : keys = find_config_tree_str(cmd, "report/pvsegs_sort",
310 : : DEFAULT_PVSEGS_SORT);
311 [ # # ]: 0 : if (!arg_count(cmd, verbose_ARG))
312 : 0 : options = find_config_tree_str(cmd,
313 : : "report/pvsegs_cols",
314 : : DEFAULT_PVSEGS_COLS);
315 : : else
316 : 0 : options = find_config_tree_str(cmd,
317 : : "report/pvsegs_cols_verbose",
318 : : DEFAULT_PVSEGS_COLS_VERB);
319 : : break;
320 : : }
321 : :
322 : : /* If -o supplied use it, else use default for report_type */
323 [ - + ]: 1 : if (arg_count(cmd, options_ARG)) {
324 : 0 : opts = arg_str_value(cmd, options_ARG, "");
325 [ # # # # ]: 0 : if (!opts || !*opts) {
326 : 0 : log_error("Invalid options string: %s", opts);
327 : 0 : return EINVALID_CMD_LINE;
328 : : }
329 [ # # ]: 0 : if (*opts == '+') {
330 [ # # ]: 0 : if (!(str = dm_pool_alloc(cmd->mem,
331 : 0 : strlen(options) + strlen(opts) + 1))) {
332 : 0 : log_error("options string allocation failed");
333 : 0 : return ECMD_FAILED;
334 : : }
335 : 0 : strcpy(str, options);
336 : 0 : strcat(str, ",");
337 : 0 : strcat(str, opts + 1);
338 : 0 : options = str;
339 : : } else
340 : 0 : options = opts;
341 : : }
342 : :
343 : : /* -O overrides default sort settings */
344 : 1 : keys = arg_str_value(cmd, sort_ARG, keys);
345 : :
346 : 1 : separator = arg_str_value(cmd, separator_ARG, separator);
347 [ - + ]: 1 : if (arg_count(cmd, separator_ARG))
348 : 0 : aligned = 0;
349 [ - + ]: 1 : if (arg_count(cmd, aligned_ARG))
350 : 0 : aligned = 1;
351 [ - + ][ # # ]: 1 : if (arg_count(cmd, unbuffered_ARG) && !arg_count(cmd, sort_ARG))
352 : 0 : buffered = 0;
353 [ - + ]: 1 : if (arg_count(cmd, noheadings_ARG))
354 : 0 : headings = 0;
355 [ - + ]: 1 : if (arg_count(cmd, nameprefixes_ARG)) {
356 : 0 : aligned = 0;
357 : 0 : field_prefixes = 1;
358 : : }
359 [ - + ]: 1 : if (arg_count(cmd, unquoted_ARG))
360 : 0 : quoted = 0;
361 [ - + ]: 1 : if (arg_count(cmd, rows_ARG))
362 : 0 : columns_as_rows = 1;
363 : :
364 [ - + ]: 1 : if (!(report_handle = report_init(cmd, options, keys, &report_type,
365 : : separator, aligned, buffered,
366 : : headings, field_prefixes, quoted,
367 : : columns_as_rows))) {
368 : 0 : stack;
369 : 0 : return ECMD_FAILED;
370 : : }
371 : :
372 : : /* Ensure options selected are compatible */
373 [ - + ]: 1 : if (report_type & SEGS)
374 : 0 : report_type |= LVS;
375 [ - + ]: 1 : if (report_type & PVSEGS)
376 : 0 : report_type |= PVS;
377 [ - + ][ # # ]: 1 : if ((report_type & LVS) && (report_type & (PVS | LABEL)) && !args_are_pvs) {
[ # # ]
378 : 0 : log_error("Can't report LV and PV fields at the same time");
379 : 0 : dm_report_free(report_handle);
380 : 0 : return ECMD_FAILED;
381 : : }
382 : :
383 : : /* Change report type if fields specified makes this necessary */
384 [ + - ][ + - ]: 1 : if ((report_type & PVSEGS) ||
[ - + ]
385 : 2 : ((report_type & (PVS | LABEL)) && (report_type & LVS)))
386 : 0 : report_type = PVSEGS;
387 [ + - ][ + - ]: 1 : else if ((report_type & LABEL) && (report_type & VGS))
388 : 1 : report_type = PVS;
389 [ # # ]: 0 : else if (report_type & PVS)
390 : 0 : report_type = PVS;
391 [ # # ]: 0 : else if (report_type & SEGS)
392 : 0 : report_type = SEGS;
393 [ # # ]: 0 : else if (report_type & LVS)
394 : 0 : report_type = LVS;
395 : :
396 [ - - - + - : 1 : switch (report_type) {
- - ]
397 : : case LVS:
398 : 0 : r = process_each_lv(cmd, argc, argv, 0, report_handle,
399 : : &_lvs_single);
400 : 0 : break;
401 : : case VGS:
402 : 0 : r = process_each_vg(cmd, argc, argv, 0,
403 : : report_handle, &_vgs_single);
404 : 0 : break;
405 : : case LABEL:
406 : 0 : r = process_each_pv(cmd, argc, argv, NULL, READ_WITHOUT_LOCK,
407 : : 1, report_handle, &_label_single);
408 : 0 : break;
409 : : case PVS:
410 [ + - ]: 1 : if (args_are_pvs)
411 : 1 : r = process_each_pv(cmd, argc, argv, NULL, 0,
412 : : 0, report_handle, &_pvs_single);
413 : : else
414 : 0 : r = process_each_vg(cmd, argc, argv, 0,
415 : : report_handle, &_pvs_in_vg);
416 : 1 : break;
417 : : case SEGS:
418 : 0 : r = process_each_lv(cmd, argc, argv, 0, report_handle,
419 : : &_lvsegs_single);
420 : 0 : break;
421 : : case PVSEGS:
422 [ # # ]: 0 : if (args_are_pvs)
423 : 0 : r = process_each_pv(cmd, argc, argv, NULL, 0,
424 : : 0, report_handle, &_pvsegs_single);
425 : : else
426 : 0 : r = process_each_vg(cmd, argc, argv, 0,
427 : : report_handle, &_pvsegs_in_vg);
428 : : break;
429 : : }
430 : :
431 : 1 : dm_report_output(report_handle);
432 : :
433 : 1 : dm_report_free(report_handle);
434 : 1 : return r;
435 : : }
436 : :
437 : 0 : int lvs(struct cmd_context *cmd, int argc, char **argv)
438 : : {
439 : : report_type_t type;
440 : :
441 [ # # ]: 0 : if (arg_count(cmd, segments_ARG))
442 : 0 : type = SEGS;
443 : : else
444 : 0 : type = LVS;
445 : :
446 : 0 : return _report(cmd, argc, argv, type);
447 : : }
448 : :
449 : 0 : int vgs(struct cmd_context *cmd, int argc, char **argv)
450 : : {
451 : 0 : return _report(cmd, argc, argv, VGS);
452 : : }
453 : :
454 : 1 : int pvs(struct cmd_context *cmd, int argc, char **argv)
455 : : {
456 : : report_type_t type;
457 : :
458 [ - + ]: 1 : if (arg_count(cmd, segments_ARG))
459 : 0 : type = PVSEGS;
460 : : else
461 : 1 : type = LABEL;
462 : :
463 : 1 : return _report(cmd, argc, argv, type);
464 : : }
|