Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / lib / report / report.c
blob8a489470b24590973ebb2828ffeac45394fcb277
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #include "lib.h"
19 #include "metadata.h"
20 #include "report.h"
21 #include "toolcontext.h"
22 #include "lvm-string.h"
23 #include "display.h"
24 #include "activate.h"
25 #include "segtype.h"
26 #include "str_list.h"
27 #include "lvmcache.h"
29 struct lvm_report_object {
30 struct volume_group *vg;
31 struct logical_volume *lv;
32 struct physical_volume *pv;
33 struct lv_segment *seg;
34 struct pv_segment *pvseg;
38 * For macro use
40 static union {
41 struct physical_volume _pv;
42 struct logical_volume _lv;
43 struct volume_group _vg;
44 struct lv_segment _seg;
45 struct pv_segment _pvseg;
46 } _dummy;
48 static char _alloc_policy_char(alloc_policy_t alloc)
50 switch (alloc) {
51 case ALLOC_CONTIGUOUS:
52 return 'c';
53 case ALLOC_CLING:
54 return 'l';
55 case ALLOC_NORMAL:
56 return 'n';
57 case ALLOC_ANYWHERE:
58 return 'a';
59 default:
60 return 'i';
64 static const uint64_t _minusone = UINT64_C(-1);
67 * Data-munging functions to prepare each data type for display and sorting
69 static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
70 struct dm_report_field *field,
71 const void *data, void *private __attribute((unused)))
73 return dm_report_field_string(rh, field, (const char **) data);
76 static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
77 struct dm_report_field *field,
78 const void *data, void *private __attribute((unused)))
80 const char *name = dev_name(*(const struct device **) data);
82 return dm_report_field_string(rh, field, &name);
85 static int _format_pvsegs(struct dm_pool *mem, struct dm_report_field *field,
86 const void *data, int range_format)
88 const struct lv_segment *seg = (const struct lv_segment *) data;
89 unsigned int s;
90 const char *name = NULL;
91 uint32_t extent = 0;
92 char extent_str[32];
94 if (!dm_pool_begin_object(mem, 256)) {
95 log_error("dm_pool_begin_object failed");
96 return 0;
99 for (s = 0; s < seg->area_count; s++) {
100 switch (seg_type(seg, s)) {
101 case AREA_LV:
102 name = seg_lv(seg, s)->name;
103 extent = seg_le(seg, s);
104 break;
105 case AREA_PV:
106 name = dev_name(seg_dev(seg, s));
107 extent = seg_pe(seg, s);
108 break;
109 case AREA_UNASSIGNED:
110 name = "unassigned";
111 extent = 0;
114 if (!dm_pool_grow_object(mem, name, strlen(name))) {
115 log_error("dm_pool_grow_object failed");
116 return 0;
119 if (dm_snprintf(extent_str, sizeof(extent_str),
120 "%s%" PRIu32 "%s",
121 range_format ? ":" : "(", extent,
122 range_format ? "-" : ")") < 0) {
123 log_error("Extent number dm_snprintf failed");
124 return 0;
126 if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
127 log_error("dm_pool_grow_object failed");
128 return 0;
131 if (range_format) {
132 if (dm_snprintf(extent_str, sizeof(extent_str),
133 "%" PRIu32, extent + seg->area_len - 1) < 0) {
134 log_error("Extent number dm_snprintf failed");
135 return 0;
137 if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
138 log_error("dm_pool_grow_object failed");
139 return 0;
143 if ((s != seg->area_count - 1) &&
144 !dm_pool_grow_object(mem, range_format ? " " : ",", 1)) {
145 log_error("dm_pool_grow_object failed");
146 return 0;
150 if (!dm_pool_grow_object(mem, "\0", 1)) {
151 log_error("dm_pool_grow_object failed");
152 return 0;
155 dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
157 return 1;
160 static int _devices_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
161 struct dm_report_field *field,
162 const void *data, void *private __attribute((unused)))
164 return _format_pvsegs(mem, field, data, 0);
167 static int _peranges_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
168 struct dm_report_field *field,
169 const void *data, void *private __attribute((unused)))
171 return _format_pvsegs(mem, field, data, 1);
174 static int _tags_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
175 struct dm_report_field *field,
176 const void *data, void *private __attribute((unused)))
178 const struct dm_list *tags = (const struct dm_list *) data;
179 struct str_list *sl;
181 if (!dm_pool_begin_object(mem, 256)) {
182 log_error("dm_pool_begin_object failed");
183 return 0;
186 dm_list_iterate_items(sl, tags) {
187 if (!dm_pool_grow_object(mem, sl->str, strlen(sl->str)) ||
188 (sl->list.n != tags && !dm_pool_grow_object(mem, ",", 1))) {
189 log_error("dm_pool_grow_object failed");
190 return 0;
194 if (!dm_pool_grow_object(mem, "\0", 1)) {
195 log_error("dm_pool_grow_object failed");
196 return 0;
199 dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
201 return 1;
204 static int _modules_disp(struct dm_report *rh, struct dm_pool *mem,
205 struct dm_report_field *field,
206 const void *data, void *private)
208 const struct logical_volume *lv = (const struct logical_volume *) data;
209 struct dm_list *modules;
211 if (!(modules = str_list_create(mem))) {
212 log_error("modules str_list allocation failed");
213 return 0;
216 if (!list_lv_modules(mem, lv, modules))
217 return_0;
219 return _tags_disp(rh, mem, field, modules, private);
222 static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem,
223 struct dm_report_field *field,
224 const void *data, void *private)
226 const struct volume_group *vg = (const struct volume_group *) data;
228 if (!vg->fid) {
229 dm_report_field_set_value(field, "", NULL);
230 return 1;
233 return _string_disp(rh, mem, field, &vg->fid->fmt->name, private);
236 static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem,
237 struct dm_report_field *field,
238 const void *data, void *private)
240 const struct physical_volume *pv =
241 (const struct physical_volume *) data;
243 if (!pv->fmt) {
244 dm_report_field_set_value(field, "", NULL);
245 return 1;
248 return _string_disp(rh, mem, field, &pv->fmt->name, private);
251 static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
252 struct dm_report_field *field,
253 const void *data, void *private __attribute((unused)))
255 const struct logical_volume *lv = (const struct logical_volume *) data;
256 struct lvinfo info;
258 if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists)
259 return dm_report_field_int(rh, field, &info.major);
261 return dm_report_field_uint64(rh, field, &_minusone);
264 static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
265 struct dm_report_field *field,
266 const void *data, void *private __attribute((unused)))
268 const struct logical_volume *lv = (const struct logical_volume *) data;
269 struct lvinfo info;
271 if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists)
272 return dm_report_field_int(rh, field, &info.minor);
274 return dm_report_field_uint64(rh, field, &_minusone);
277 static int _lv_mimage_in_sync(const struct logical_volume *lv)
279 float percent;
280 percent_range_t percent_range;
281 struct lv_segment *mirror_seg = find_mirror_seg(first_seg(lv));
283 if (!(lv->status & MIRROR_IMAGE) || !mirror_seg)
284 return_0;
286 if (!lv_mirror_percent(lv->vg->cmd, mirror_seg->lv, 0, &percent,
287 &percent_range, NULL))
288 return_0;
290 return (percent_range == PERCENT_100) ? 1 : 0;
293 static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
294 struct dm_report_field *field,
295 const void *data, void *private __attribute((unused)))
297 const struct logical_volume *lv = (const struct logical_volume *) data;
298 struct lvinfo info;
299 char *repstr;
300 float snap_percent;
301 percent_range_t percent_range;
303 if (!(repstr = dm_pool_zalloc(mem, 7))) {
304 log_error("dm_pool_alloc failed");
305 return 0;
308 /* Blank if this is a "free space" LV. */
309 if (!*lv->name)
310 goto out;
312 if (lv->status & PVMOVE)
313 repstr[0] = 'p';
314 else if (lv->status & CONVERTING)
315 repstr[0] = 'c';
316 else if (lv->status & VIRTUAL)
317 repstr[0] = 'v';
318 /* Origin takes precedence over Mirror */
319 else if (lv_is_origin(lv))
320 repstr[0] = 'o';
321 else if (lv->status & MIRRORED) {
322 if (lv->status & MIRROR_NOTSYNCED)
323 repstr[0] = 'M';
324 else
325 repstr[0] = 'm';
326 }else if (lv->status & MIRROR_IMAGE)
327 if (_lv_mimage_in_sync(lv))
328 repstr[0] = 'i';
329 else
330 repstr[0] = 'I';
331 else if (lv->status & MIRROR_LOG)
332 repstr[0] = 'l';
333 else if (lv_is_cow(lv))
334 repstr[0] = 's';
335 else
336 repstr[0] = '-';
338 if (lv->status & PVMOVE)
339 repstr[1] = '-';
340 else if (lv->status & LVM_WRITE)
341 repstr[1] = 'w';
342 else if (lv->status & LVM_READ)
343 repstr[1] = 'r';
344 else
345 repstr[1] = '-';
347 repstr[2] = _alloc_policy_char(lv->alloc);
349 if (lv->status & LOCKED)
350 repstr[2] = toupper(repstr[2]);
352 if (lv->status & FIXED_MINOR)
353 repstr[3] = 'm'; /* Fixed Minor */
354 else
355 repstr[3] = '-';
357 if (lv_info(lv->vg->cmd, lv, &info, 1, 0) && info.exists) {
358 if (info.suspended)
359 repstr[4] = 's'; /* Suspended */
360 else if (info.live_table)
361 repstr[4] = 'a'; /* Active */
362 else if (info.inactive_table)
363 repstr[4] = 'i'; /* Inactive with table */
364 else
365 repstr[4] = 'd'; /* Inactive without table */
367 /* Snapshot dropped? */
368 if (info.live_table && lv_is_cow(lv) &&
369 (!lv_snapshot_percent(lv, &snap_percent, &percent_range) ||
370 percent_range == PERCENT_INVALID)) {
371 repstr[0] = toupper(repstr[0]);
372 if (info.suspended)
373 repstr[4] = 'S'; /* Susp Inv snapshot */
374 else
375 repstr[4] = 'I'; /* Invalid snapshot */
378 if (info.open_count)
379 repstr[5] = 'o'; /* Open */
380 else
381 repstr[5] = '-';
382 } else {
383 repstr[4] = '-';
384 repstr[5] = '-';
387 out:
388 dm_report_field_set_value(field, repstr, NULL);
389 return 1;
392 static int _pvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
393 struct dm_report_field *field,
394 const void *data, void *private __attribute((unused)))
396 const uint32_t status = *(const uint32_t *) data;
397 char *repstr;
399 if (!(repstr = dm_pool_zalloc(mem, 3))) {
400 log_error("dm_pool_alloc failed");
401 return 0;
404 if (status & ALLOCATABLE_PV)
405 repstr[0] = 'a';
406 else
407 repstr[0] = '-';
409 if (status & EXPORTED_VG)
410 repstr[1] = 'x';
411 else
412 repstr[1] = '-';
414 dm_report_field_set_value(field, repstr, NULL);
415 return 1;
418 static int _vgstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
419 struct dm_report_field *field,
420 const void *data, void *private __attribute((unused)))
422 const struct volume_group *vg = (const struct volume_group *) data;
423 char *repstr;
425 if (!(repstr = dm_pool_zalloc(mem, 7))) {
426 log_error("dm_pool_alloc failed");
427 return 0;
430 if (vg->status & LVM_WRITE)
431 repstr[0] = 'w';
432 else
433 repstr[0] = 'r';
435 if (vg_is_resizeable(vg))
436 repstr[1] = 'z';
437 else
438 repstr[1] = '-';
440 if (vg_is_exported(vg))
441 repstr[2] = 'x';
442 else
443 repstr[2] = '-';
445 if (vg_missing_pv_count(vg))
446 repstr[3] = 'p';
447 else
448 repstr[3] = '-';
450 repstr[4] = _alloc_policy_char(vg->alloc);
452 if (vg_is_clustered(vg))
453 repstr[5] = 'c';
454 else
455 repstr[5] = '-';
457 dm_report_field_set_value(field, repstr, NULL);
458 return 1;
461 static int _segtype_disp(struct dm_report *rh __attribute((unused)),
462 struct dm_pool *mem __attribute((unused)),
463 struct dm_report_field *field,
464 const void *data, void *private __attribute((unused)))
466 const struct lv_segment *seg = (const struct lv_segment *) data;
468 if (seg->area_count == 1) {
469 dm_report_field_set_value(field, "linear", NULL);
470 return 1;
473 dm_report_field_set_value(field, seg->segtype->ops->name(seg), NULL);
474 return 1;
477 static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
478 struct dm_report_field *field,
479 const void *data, void *private __attribute((unused)))
481 const struct logical_volume *lv = (const struct logical_volume *) data;
482 struct lv_segment *seg;
484 dm_list_iterate_items(seg, &lv->segments) {
485 if (!seg_is_mirrored(seg) || !seg->log_lv)
486 continue;
487 return dm_report_field_string(rh, field,
488 (const char **) &seg->log_lv->name);
491 dm_report_field_set_value(field, "", NULL);
492 return 1;
495 static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
496 struct dm_report_field *field,
497 const void *data, void *private __attribute((unused)))
499 const struct logical_volume *lv = (const struct logical_volume *) data;
500 char *repstr, *lvname;
501 size_t len;
503 if (lv_is_visible(lv)) {
504 repstr = lv->name;
505 return dm_report_field_string(rh, field, (const char **) &repstr);
508 len = strlen(lv->name) + 3;
509 if (!(repstr = dm_pool_zalloc(mem, len))) {
510 log_error("dm_pool_alloc failed");
511 return 0;
514 if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
515 log_error("lvname snprintf failed");
516 return 0;
519 if (!(lvname = dm_pool_strdup(mem, lv->name))) {
520 log_error("dm_pool_strdup failed");
521 return 0;
524 dm_report_field_set_value(field, repstr, lvname);
526 return 1;
529 static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
530 struct dm_report_field *field,
531 const void *data, void *private)
533 const struct logical_volume *lv = (const struct logical_volume *) data;
535 if (lv_is_cow(lv))
536 return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
538 dm_report_field_set_value(field, "", NULL);
539 return 1;
542 static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
543 struct dm_report_field *field,
544 const void *data, void *private __attribute((unused)))
546 const struct logical_volume *lv = (const struct logical_volume *) data;
547 const char *name;
548 struct lv_segment *seg;
550 dm_list_iterate_items(seg, &lv->segments) {
551 if (!(seg->status & PVMOVE))
552 continue;
553 name = dev_name(seg_dev(seg, 0));
554 return dm_report_field_string(rh, field, &name);
557 dm_report_field_set_value(field, "", NULL);
558 return 1;
561 static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
562 struct dm_report_field *field,
563 const void *data, void *private __attribute((unused)))
565 const struct logical_volume *lv = (const struct logical_volume *) data;
566 const char *name = NULL;
567 struct lv_segment *seg;
569 if (lv->status & CONVERTING) {
570 if (lv->status & MIRRORED) {
571 seg = first_seg(lv);
573 /* Temporary mirror is always area_num == 0 */
574 if (seg_type(seg, 0) == AREA_LV &&
575 is_temporary_mirror_layer(seg_lv(seg, 0)))
576 name = seg_lv(seg, 0)->name;
580 if (name)
581 return dm_report_field_string(rh, field, &name);
583 dm_report_field_set_value(field, "", NULL);
584 return 1;
587 static int _size32_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
588 struct dm_report_field *field,
589 const void *data, void *private)
591 const uint32_t size = *(const uint32_t *) data;
592 const char *disp, *repstr;
593 uint64_t *sortval;
595 if (!*(disp = display_size_units(private, (uint64_t) size)))
596 return_0;
598 if (!(repstr = dm_pool_strdup(mem, disp))) {
599 log_error("dm_pool_strdup failed");
600 return 0;
603 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
604 log_error("dm_pool_alloc failed");
605 return 0;
608 *sortval = (const uint64_t) size;
610 dm_report_field_set_value(field, repstr, sortval);
612 return 1;
615 static int _size64_disp(struct dm_report *rh __attribute((unused)),
616 struct dm_pool *mem,
617 struct dm_report_field *field,
618 const void *data, void *private)
620 const uint64_t size = *(const uint64_t *) data;
621 const char *disp, *repstr;
622 uint64_t *sortval;
624 if (!*(disp = display_size_units(private, size)))
625 return_0;
627 if (!(repstr = dm_pool_strdup(mem, disp))) {
628 log_error("dm_pool_strdup failed");
629 return 0;
632 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
633 log_error("dm_pool_alloc failed");
634 return 0;
637 *sortval = size;
638 dm_report_field_set_value(field, repstr, sortval);
640 return 1;
643 static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
644 struct dm_report_field *field,
645 const void *data, void *private __attribute((unused)))
647 const struct logical_volume *lv = (const struct logical_volume *) data;
649 if (lv->read_ahead == DM_READ_AHEAD_AUTO) {
650 dm_report_field_set_value(field, "auto", &_minusone);
651 return 1;
654 return _size32_disp(rh, mem, field, &lv->read_ahead, private);
657 static int _lvkreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
658 struct dm_report_field *field,
659 const void *data,
660 void *private)
662 const struct logical_volume *lv = (const struct logical_volume *) data;
663 struct lvinfo info;
665 if (!lv_info(lv->vg->cmd, lv, &info, 0, 1) || !info.exists)
666 return dm_report_field_uint64(rh, field, &_minusone);
668 return _size32_disp(rh, mem, field, &info.read_ahead, private);
671 static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem,
672 struct dm_report_field *field,
673 const void *data, void *private)
675 const struct volume_group *vg = (const struct volume_group *) data;
676 uint64_t size;
678 size = (uint64_t) vg_size(vg);
680 return _size64_disp(rh, mem, field, &size, private);
683 static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem,
684 struct dm_report_field *field,
685 const void *data, void *private)
687 const struct lv_segment *seg = (const struct lv_segment *) data;
688 uint64_t start;
690 start = (uint64_t) seg->le * seg->lv->vg->extent_size;
692 return _size64_disp(rh, mem, field, &start, private);
695 static int _segstartpe_disp(struct dm_report *rh,
696 struct dm_pool *mem __attribute((unused)),
697 struct dm_report_field *field,
698 const void *data,
699 void *private __attribute((unused)))
701 const struct lv_segment *seg = (const struct lv_segment *) data;
703 return dm_report_field_uint32(rh, field, &seg->le);
706 static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem,
707 struct dm_report_field *field,
708 const void *data, void *private)
710 const struct lv_segment *seg = (const struct lv_segment *) data;
711 uint64_t size;
713 size = (uint64_t) seg->len * seg->lv->vg->extent_size;
715 return _size64_disp(rh, mem, field, &size, private);
718 static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
719 struct dm_report_field *field,
720 const void *data, void *private)
722 const struct lv_segment *seg = (const struct lv_segment *) data;
723 uint64_t size;
725 if (lv_is_cow(seg->lv))
726 size = (uint64_t) find_cow(seg->lv)->chunk_size;
727 else
728 size = UINT64_C(0);
730 return _size64_disp(rh, mem, field, &size, private);
733 static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem,
734 struct dm_report_field *field,
735 const void *data, void *private)
737 const struct logical_volume *lv = (const struct logical_volume *) data;
738 uint64_t size;
740 if (lv_is_cow(lv))
741 size = (uint64_t) find_cow(lv)->len * lv->vg->extent_size;
742 else if (lv_is_origin(lv))
743 size = lv->size;
744 else
745 size = UINT64_C(0);
747 return _size64_disp(rh, mem, field, &size, private);
750 static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem,
751 struct dm_report_field *field,
752 const void *data, void *private)
754 const struct physical_volume *pv =
755 (const struct physical_volume *) data;
756 uint64_t used;
758 if (!pv->pe_count)
759 used = 0LL;
760 else
761 used = (uint64_t) pv->pe_alloc_count * pv->pe_size;
763 return _size64_disp(rh, mem, field, &used, private);
766 static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem,
767 struct dm_report_field *field,
768 const void *data, void *private)
770 const struct physical_volume *pv =
771 (const struct physical_volume *) data;
772 uint64_t freespace;
774 if (!pv->pe_count)
775 freespace = pv->size;
776 else
777 freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
779 return _size64_disp(rh, mem, field, &freespace, private);
782 static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem,
783 struct dm_report_field *field,
784 const void *data, void *private)
786 const struct physical_volume *pv =
787 (const struct physical_volume *) data;
788 uint64_t size;
790 if (!pv->pe_count)
791 size = pv->size;
792 else
793 size = (uint64_t) pv->pe_count * pv->pe_size;
795 return _size64_disp(rh, mem, field, &size, private);
798 static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem,
799 struct dm_report_field *field,
800 const void *data, void *private)
802 const struct device *dev = *(const struct device **) data;
803 uint64_t size;
805 if (!dev_get_size(dev, &size))
806 size = 0;
808 return _size64_disp(rh, mem, field, &size, private);
811 static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem,
812 struct dm_report_field *field,
813 const void *data, void *private)
815 const struct volume_group *vg = (const struct volume_group *) data;
816 uint64_t freespace;
818 freespace = (uint64_t) vg_free(vg);
820 return _size64_disp(rh, mem, field, &freespace, private);
823 static int _uuid_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
824 struct dm_report_field *field,
825 const void *data, void *private __attribute((unused)))
827 char *repstr = NULL;
829 if (!(repstr = dm_pool_alloc(mem, 40))) {
830 log_error("dm_pool_alloc failed");
831 return 0;
834 if (!id_write_format((const struct id *) data, repstr, 40))
835 return_0;
837 dm_report_field_set_value(field, repstr, NULL);
838 return 1;
841 static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
842 struct dm_report_field *field,
843 const void *data, void *private __attribute((unused)))
845 return dm_report_field_uint32(rh, field, data);
848 static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
849 struct dm_report_field *field,
850 const void *data, void *private __attribute((unused)))
852 return dm_report_field_int32(rh, field, data);
855 static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem,
856 struct dm_report_field *field,
857 const void *data, void *private)
859 uint32_t count;
860 const struct physical_volume *pv =
861 (const struct physical_volume *) data;
863 count = pv_mda_count(pv);
865 return _uint32_disp(rh, mem, field, &count, private);
868 static int _vgmdas_disp(struct dm_report *rh, struct dm_pool *mem,
869 struct dm_report_field *field,
870 const void *data, void *private)
872 const struct volume_group *vg = (const struct volume_group *) data;
873 uint32_t count;
875 count = vg_mda_count(vg);
877 return _uint32_disp(rh, mem, field, &count, private);
880 static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
881 struct dm_report_field *field,
882 const void *data, void *private)
884 struct lvmcache_info *info;
885 uint64_t freespace = UINT64_MAX, mda_free;
886 const char *pvid = (const char *)(&((struct id *) data)->uuid);
887 struct metadata_area *mda;
889 if ((info = info_from_pvid(pvid, 0)))
890 dm_list_iterate_items(mda, &info->mdas) {
891 if (!mda->ops->mda_free_sectors)
892 continue;
893 mda_free = mda->ops->mda_free_sectors(mda);
894 if (mda_free < freespace)
895 freespace = mda_free;
898 if (freespace == UINT64_MAX)
899 freespace = UINT64_C(0);
901 return _size64_disp(rh, mem, field, &freespace, private);
904 static uint64_t _find_min_mda_size(struct dm_list *mdas)
906 uint64_t min_mda_size = UINT64_MAX, mda_size;
907 struct metadata_area *mda;
909 dm_list_iterate_items(mda, mdas) {
910 if (!mda->ops->mda_total_sectors)
911 continue;
912 mda_size = mda->ops->mda_total_sectors(mda);
913 if (mda_size < min_mda_size)
914 min_mda_size = mda_size;
917 if (min_mda_size == UINT64_MAX)
918 min_mda_size = UINT64_C(0);
920 return min_mda_size;
923 static int _pvmdasize_disp(struct dm_report *rh, struct dm_pool *mem,
924 struct dm_report_field *field,
925 const void *data, void *private)
927 struct lvmcache_info *info;
928 uint64_t min_mda_size = 0;
929 const char *pvid = (const char *)(&((struct id *) data)->uuid);
931 /* PVs could have 2 mdas of different sizes (rounding effect) */
932 if ((info = info_from_pvid(pvid, 0)))
933 min_mda_size = _find_min_mda_size(&info->mdas);
935 return _size64_disp(rh, mem, field, &min_mda_size, private);
938 static int _vgmdasize_disp(struct dm_report *rh, struct dm_pool *mem,
939 struct dm_report_field *field,
940 const void *data, void *private)
942 const struct volume_group *vg = (const struct volume_group *) data;
943 uint64_t min_mda_size;
945 min_mda_size = _find_min_mda_size(&vg->fid->metadata_areas);
947 return _size64_disp(rh, mem, field, &min_mda_size, private);
950 static int _vgmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
951 struct dm_report_field *field,
952 const void *data, void *private)
954 const struct volume_group *vg = (const struct volume_group *) data;
955 uint64_t freespace = UINT64_MAX, mda_free;
956 struct metadata_area *mda;
958 dm_list_iterate_items(mda, &vg->fid->metadata_areas) {
959 if (!mda->ops->mda_free_sectors)
960 continue;
961 mda_free = mda->ops->mda_free_sectors(mda);
962 if (mda_free < freespace)
963 freespace = mda_free;
966 if (freespace == UINT64_MAX)
967 freespace = UINT64_C(0);
969 return _size64_disp(rh, mem, field, &freespace, private);
972 static int _lvcount_disp(struct dm_report *rh, struct dm_pool *mem,
973 struct dm_report_field *field,
974 const void *data, void *private)
976 const struct volume_group *vg = (const struct volume_group *) data;
977 uint32_t count;
979 count = vg_visible_lvs(vg);
981 return _uint32_disp(rh, mem, field, &count, private);
984 static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem,
985 struct dm_report_field *field,
986 const void *data, void *private)
988 const struct logical_volume *lv = (const struct logical_volume *) data;
989 uint32_t count;
991 count = dm_list_size(&lv->segments);
993 return _uint32_disp(rh, mem, field, &count, private);
996 static int _snapcount_disp(struct dm_report *rh, struct dm_pool *mem,
997 struct dm_report_field *field,
998 const void *data, void *private)
1000 const struct volume_group *vg = (const struct volume_group *) data;
1001 uint32_t count;
1003 count = snapshot_count(vg);
1005 return _uint32_disp(rh, mem, field, &count, private);
1008 static int _snpercent_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
1009 struct dm_report_field *field,
1010 const void *data, void *private __attribute((unused)))
1012 const struct logical_volume *lv = (const struct logical_volume *) data;
1013 struct lvinfo info;
1014 float snap_percent;
1015 percent_range_t percent_range;
1016 uint64_t *sortval;
1017 char *repstr;
1019 /* Suppress snapshot percentage if not using driver */
1020 if (!activation()) {
1021 dm_report_field_set_value(field, "", NULL);
1022 return 1;
1025 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
1026 log_error("dm_pool_alloc failed");
1027 return 0;
1030 if (!lv_is_cow(lv) ||
1031 (lv_info(lv->vg->cmd, lv, &info, 0, 0) && !info.exists)) {
1032 *sortval = UINT64_C(0);
1033 dm_report_field_set_value(field, "", sortval);
1034 return 1;
1037 if (!lv_snapshot_percent(lv, &snap_percent, &percent_range) ||
1038 (percent_range == PERCENT_INVALID)) {
1039 *sortval = UINT64_C(100);
1040 dm_report_field_set_value(field, "100.00", sortval);
1041 return 1;
1044 if (!(repstr = dm_pool_zalloc(mem, 8))) {
1045 log_error("dm_pool_alloc failed");
1046 return 0;
1049 if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) {
1050 log_error("snapshot percentage too large");
1051 return 0;
1054 *sortval = snap_percent * UINT64_C(1000);
1055 dm_report_field_set_value(field, repstr, sortval);
1057 return 1;
1060 static int _copypercent_disp(struct dm_report *rh __attribute((unused)),
1061 struct dm_pool *mem,
1062 struct dm_report_field *field,
1063 const void *data, void *private __attribute((unused)))
1065 struct logical_volume *lv = (struct logical_volume *) data;
1066 float percent;
1067 percent_range_t percent_range;
1068 uint64_t *sortval;
1069 char *repstr;
1071 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
1072 log_error("dm_pool_alloc failed");
1073 return 0;
1076 if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
1077 !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, &percent_range,
1078 NULL) || (percent_range == PERCENT_INVALID)) {
1079 *sortval = UINT64_C(0);
1080 dm_report_field_set_value(field, "", sortval);
1081 return 1;
1084 percent = copy_percent(lv, &percent_range);
1086 if (!(repstr = dm_pool_zalloc(mem, 8))) {
1087 log_error("dm_pool_alloc failed");
1088 return 0;
1091 if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) {
1092 log_error("copy percentage too large");
1093 return 0;
1096 *sortval = percent * UINT64_C(1000);
1097 dm_report_field_set_value(field, repstr, sortval);
1099 return 1;
1102 /* Report object types */
1104 /* necessary for displaying something for PVs not belonging to VG */
1105 static struct format_instance _dummy_fid = {
1106 .metadata_areas = { &(_dummy_fid.metadata_areas), &(_dummy_fid.metadata_areas) },
1109 static struct volume_group _dummy_vg = {
1110 .fid = &_dummy_fid,
1111 .name = (char *) "",
1112 .system_id = (char *) "",
1113 .pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) },
1114 .lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) },
1115 .tags = { &(_dummy_vg.tags), &(_dummy_vg.tags) },
1118 static void *_obj_get_vg(void *obj)
1120 struct volume_group *vg = ((struct lvm_report_object *)obj)->vg;
1122 return vg ? vg : &_dummy_vg;
1125 static void *_obj_get_lv(void *obj)
1127 return ((struct lvm_report_object *)obj)->lv;
1130 static void *_obj_get_pv(void *obj)
1132 return ((struct lvm_report_object *)obj)->pv;
1135 static void *_obj_get_seg(void *obj)
1137 return ((struct lvm_report_object *)obj)->seg;
1140 static void *_obj_get_pvseg(void *obj)
1142 return ((struct lvm_report_object *)obj)->pvseg;
1145 static const struct dm_report_object_type _report_types[] = {
1146 { VGS, "Volume Group", "vg_", _obj_get_vg },
1147 { LVS, "Logical Volume", "lv_", _obj_get_lv },
1148 { PVS, "Physical Volume", "pv_", _obj_get_pv },
1149 { LABEL, "Physical Volume Label", "pv_", _obj_get_pv },
1150 { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
1151 { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
1152 { 0, "", "", NULL },
1156 * Import column definitions
1159 #define STR DM_REPORT_FIELD_TYPE_STRING
1160 #define NUM DM_REPORT_FIELD_TYPE_NUMBER
1161 #define FIELD(type, strct, sorttype, head, field, width, func, id, desc) {type, sorttype, (off_t)((uintptr_t)&_dummy._ ## strct.field - (uintptr_t)&_dummy._ ## strct), width, id, head, &_ ## func ## _disp, desc},
1163 static struct dm_report_field_type _fields[] = {
1164 #include "columns.h"
1165 {0, 0, 0, 0, "", "", NULL, NULL},
1168 #undef STR
1169 #undef NUM
1170 #undef FIELD
1172 void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
1173 report_type_t *report_type, const char *separator,
1174 int aligned, int buffered, int headings, int field_prefixes,
1175 int quoted, int columns_as_rows)
1177 uint32_t report_flags = 0;
1178 void *rh;
1180 if (aligned)
1181 report_flags |= DM_REPORT_OUTPUT_ALIGNED;
1183 if (buffered)
1184 report_flags |= DM_REPORT_OUTPUT_BUFFERED;
1186 if (headings)
1187 report_flags |= DM_REPORT_OUTPUT_HEADINGS;
1189 if (field_prefixes)
1190 report_flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
1192 if (!quoted)
1193 report_flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
1195 if (columns_as_rows)
1196 report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
1198 rh = dm_report_init(report_type, _report_types, _fields, format,
1199 separator, report_flags, keys, cmd);
1201 if (rh && field_prefixes)
1202 dm_report_set_output_field_name_prefix(rh, "lvm2_");
1204 return rh;
1208 * Create a row of data for an object
1210 int report_object(void *handle, struct volume_group *vg,
1211 struct logical_volume *lv, struct physical_volume *pv,
1212 struct lv_segment *seg, struct pv_segment *pvseg)
1214 struct lvm_report_object obj;
1216 /* The two format fields might as well match. */
1217 if (!vg && pv)
1218 _dummy_fid.fmt = pv->fmt;
1220 obj.vg = vg;
1221 obj.lv = lv;
1222 obj.pv = pv;
1223 obj.seg = seg;
1224 obj.pvseg = pvseg;
1226 return dm_report_object(handle, &obj);