xref: /dragonfly/contrib/lvm2/dist/lib/report/report.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1 /*        $NetBSD: report.c,v 1.1.1.3 2009/12/02 00:26:46 haad Exp $  */
2 
3 /*
4  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
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.
12  *
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
16  */
17 
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"
28 #include <stddef.h>
29 
30 struct lvm_report_object {
31           struct volume_group *vg;
32           struct logical_volume *lv;
33           struct physical_volume *pv;
34           struct lv_segment *seg;
35           struct pv_segment *pvseg;
36 };
37 
38 /*
39  * For macro use
40  */
41 static union {
42           struct physical_volume _pv;
43           struct logical_volume _lv;
44           struct volume_group _vg;
45           struct lv_segment _seg;
46           struct pv_segment _pvseg;
47 } _dummy;
48 
_alloc_policy_char(alloc_policy_t alloc)49 static char _alloc_policy_char(alloc_policy_t alloc)
50 {
51           switch (alloc) {
52           case ALLOC_CONTIGUOUS:
53                     return 'c';
54           case ALLOC_CLING:
55                     return 'l';
56           case ALLOC_NORMAL:
57                     return 'n';
58           case ALLOC_ANYWHERE:
59                     return 'a';
60           default:
61                     return 'i';
62           }
63 }
64 
65 static const uint64_t _minusone = UINT64_C(-1);
66 
67 /*
68  * Data-munging functions to prepare each data type for display and sorting
69  */
_string_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))70 static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
71                               struct dm_report_field *field,
72                               const void *data, void *private __attribute((unused)))
73 {
74           return dm_report_field_string(rh, field, (const char **) data);
75 }
76 
_dev_name_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))77 static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
78                                 struct dm_report_field *field,
79                                 const void *data, void *private __attribute((unused)))
80 {
81           const char *name = dev_name(*(const struct device **) data);
82 
83           return dm_report_field_string(rh, field, &name);
84 }
85 
_format_pvsegs(struct dm_pool * mem,struct dm_report_field * field,const void * data,int range_format)86 static int _format_pvsegs(struct dm_pool *mem, struct dm_report_field *field,
87                                 const void *data, int range_format)
88 {
89           const struct lv_segment *seg = (const struct lv_segment *) data;
90           unsigned int s;
91           const char *name = NULL;
92           uint32_t extent = 0;
93           char extent_str[32];
94 
95           if (!dm_pool_begin_object(mem, 256)) {
96                     log_error("dm_pool_begin_object failed");
97                     return 0;
98           }
99 
100           for (s = 0; s < seg->area_count; s++) {
101                     switch (seg_type(seg, s)) {
102                     case AREA_LV:
103                               name = seg_lv(seg, s)->name;
104                               extent = seg_le(seg, s);
105                               break;
106                     case AREA_PV:
107                               name = dev_name(seg_dev(seg, s));
108                               extent = seg_pe(seg, s);
109                               break;
110                     case AREA_UNASSIGNED:
111                               name = "unassigned";
112                               extent = 0;
113                     }
114 
115                     if (!dm_pool_grow_object(mem, name, strlen(name))) {
116                               log_error("dm_pool_grow_object failed");
117                               return 0;
118                     }
119 
120                     if (dm_snprintf(extent_str, sizeof(extent_str),
121                                         "%s%" PRIu32 "%s",
122                                         range_format ? ":" : "(", extent,
123                                         range_format ? "-"  : ")") < 0) {
124                               log_error("Extent number dm_snprintf failed");
125                               return 0;
126                     }
127                     if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
128                               log_error("dm_pool_grow_object failed");
129                               return 0;
130                     }
131 
132                     if (range_format) {
133                               if (dm_snprintf(extent_str, sizeof(extent_str),
134                                                   "%" PRIu32, extent + seg->area_len - 1) < 0) {
135                                         log_error("Extent number dm_snprintf failed");
136                                         return 0;
137                               }
138                               if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
139                                         log_error("dm_pool_grow_object failed");
140                                         return 0;
141                               }
142                     }
143 
144                     if ((s != seg->area_count - 1) &&
145                         !dm_pool_grow_object(mem, range_format ? " " : ",", 1)) {
146                               log_error("dm_pool_grow_object failed");
147                               return 0;
148                     }
149           }
150 
151           if (!dm_pool_grow_object(mem, "\0", 1)) {
152                     log_error("dm_pool_grow_object failed");
153                     return 0;
154           }
155 
156           dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
157 
158           return 1;
159 }
160 
_devices_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))161 static int _devices_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
162                                struct dm_report_field *field,
163                                const void *data, void *private __attribute((unused)))
164 {
165           return _format_pvsegs(mem, field, data, 0);
166 }
167 
_peranges_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))168 static int _peranges_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
169                                 struct dm_report_field *field,
170                                 const void *data, void *private __attribute((unused)))
171 {
172           return _format_pvsegs(mem, field, data, 1);
173 }
174 
_tags_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))175 static int _tags_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
176                           struct dm_report_field *field,
177                           const void *data, void *private __attribute((unused)))
178 {
179           const struct dm_list *tags = (const struct dm_list *) data;
180           struct str_list *sl;
181 
182           if (!dm_pool_begin_object(mem, 256)) {
183                     log_error("dm_pool_begin_object failed");
184                     return 0;
185           }
186 
187           dm_list_iterate_items(sl, tags) {
188                     if (!dm_pool_grow_object(mem, sl->str, strlen(sl->str)) ||
189                         (sl->list.n != tags && !dm_pool_grow_object(mem, ",", 1))) {
190                               log_error("dm_pool_grow_object failed");
191                               return 0;
192                     }
193           }
194 
195           if (!dm_pool_grow_object(mem, "\0", 1)) {
196                     log_error("dm_pool_grow_object failed");
197                     return 0;
198           }
199 
200           dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
201 
202           return 1;
203 }
204 
_modules_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)205 static int _modules_disp(struct dm_report *rh, struct dm_pool *mem,
206                                struct dm_report_field *field,
207                                const void *data, void *private)
208 {
209           const struct logical_volume *lv = (const struct logical_volume *) data;
210           struct dm_list *modules;
211 
212           if (!(modules = str_list_create(mem))) {
213                     log_error("modules str_list allocation failed");
214                     return 0;
215           }
216 
217           if (!list_lv_modules(mem, lv, modules))
218                     return_0;
219 
220           return _tags_disp(rh, mem, field, modules, private);
221 }
222 
_vgfmt_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)223 static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem,
224                            struct dm_report_field *field,
225                            const void *data, void *private)
226 {
227           const struct volume_group *vg = (const struct volume_group *) data;
228 
229           if (!vg->fid) {
230                     dm_report_field_set_value(field, "", NULL);
231                     return 1;
232           }
233 
234           return _string_disp(rh, mem, field, &vg->fid->fmt->name, private);
235 }
236 
_pvfmt_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)237 static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem,
238                            struct dm_report_field *field,
239                            const void *data, void *private)
240 {
241           const struct physical_volume *pv =
242               (const struct physical_volume *) data;
243 
244           if (!pv->fmt) {
245                     dm_report_field_set_value(field, "", NULL);
246                     return 1;
247           }
248 
249           return _string_disp(rh, mem, field, &pv->fmt->name, private);
250 }
251 
_lvkmaj_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))252 static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
253                               struct dm_report_field *field,
254                               const void *data, void *private __attribute((unused)))
255 {
256           const struct logical_volume *lv = (const struct logical_volume *) data;
257           struct lvinfo info;
258 
259           if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists)
260                     return dm_report_field_int(rh, field, &info.major);
261 
262           return dm_report_field_uint64(rh, field, &_minusone);
263 }
264 
_lvkmin_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))265 static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
266                               struct dm_report_field *field,
267                               const void *data, void *private __attribute((unused)))
268 {
269           const struct logical_volume *lv = (const struct logical_volume *) data;
270           struct lvinfo info;
271 
272           if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists)
273                     return dm_report_field_int(rh, field, &info.minor);
274 
275           return dm_report_field_uint64(rh, field, &_minusone);
276 }
277 
_lv_mimage_in_sync(const struct logical_volume * lv)278 static int _lv_mimage_in_sync(const struct logical_volume *lv)
279 {
280           float percent;
281           percent_range_t percent_range;
282           struct lv_segment *mirror_seg = find_mirror_seg(first_seg(lv));
283 
284           if (!(lv->status & MIRROR_IMAGE) || !mirror_seg)
285                     return_0;
286 
287           if (!lv_mirror_percent(lv->vg->cmd, mirror_seg->lv, 0, &percent,
288                                      &percent_range, NULL))
289                     return_0;
290 
291           return (percent_range == PERCENT_100) ? 1 : 0;
292 }
293 
_lvstatus_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))294 static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
295                                 struct dm_report_field *field,
296                                 const void *data, void *private __attribute((unused)))
297 {
298           const struct logical_volume *lv = (const struct logical_volume *) data;
299           struct lvinfo info;
300           char *repstr;
301           float snap_percent;
302           percent_range_t percent_range;
303 
304           if (!(repstr = dm_pool_zalloc(mem, 7))) {
305                     log_error("dm_pool_alloc failed");
306                     return 0;
307           }
308 
309           /* Blank if this is a "free space" LV. */
310           if (!*lv->name)
311                     goto out;
312 
313           if (lv->status & PVMOVE)
314                     repstr[0] = 'p';
315           else if (lv->status & CONVERTING)
316                     repstr[0] = 'c';
317           else if (lv->status & VIRTUAL)
318                     repstr[0] = 'v';
319           /* Origin takes precedence over Mirror */
320           else if (lv_is_origin(lv))
321                     repstr[0] = 'o';
322           else if (lv->status & MIRRORED) {
323                     if (lv->status & MIRROR_NOTSYNCED)
324                               repstr[0] = 'M';
325                     else
326                               repstr[0] = 'm';
327           }else if (lv->status & MIRROR_IMAGE)
328                     if (_lv_mimage_in_sync(lv))
329                               repstr[0] = 'i';
330                     else
331                               repstr[0] = 'I';
332           else if (lv->status & MIRROR_LOG)
333                     repstr[0] = 'l';
334           else if (lv_is_cow(lv))
335                     repstr[0] = 's';
336           else
337                     repstr[0] = '-';
338 
339           if (lv->status & PVMOVE)
340                     repstr[1] = '-';
341           else if (lv->status & LVM_WRITE)
342                     repstr[1] = 'w';
343           else if (lv->status & LVM_READ)
344                     repstr[1] = 'r';
345           else
346                     repstr[1] = '-';
347 
348           repstr[2] = _alloc_policy_char(lv->alloc);
349 
350           if (lv->status & LOCKED)
351                     repstr[2] = toupper(repstr[2]);
352 
353           if (lv->status & FIXED_MINOR)
354                     repstr[3] = 'm';    /* Fixed Minor */
355           else
356                     repstr[3] = '-';
357 
358           if (lv_info(lv->vg->cmd, lv, &info, 1, 0) && info.exists) {
359                     if (info.suspended)
360                               repstr[4] = 's';    /* Suspended */
361                     else if (info.live_table)
362                               repstr[4] = 'a';    /* Active */
363                     else if (info.inactive_table)
364                               repstr[4] = 'i';    /* Inactive with table */
365                     else
366                               repstr[4] = 'd';    /* Inactive without table */
367 
368                     /* Snapshot dropped? */
369                     if (info.live_table && lv_is_cow(lv) &&
370                         (!lv_snapshot_percent(lv, &snap_percent, &percent_range) ||
371                          percent_range == PERCENT_INVALID)) {
372                               repstr[0] = toupper(repstr[0]);
373                               if (info.suspended)
374                                         repstr[4] = 'S'; /* Susp Inv snapshot */
375                               else
376                                         repstr[4] = 'I'; /* Invalid snapshot */
377                     }
378 
379                     if (info.open_count)
380                               repstr[5] = 'o';    /* Open */
381                     else
382                               repstr[5] = '-';
383           } else {
384                     repstr[4] = '-';
385                     repstr[5] = '-';
386           }
387 
388 out:
389           dm_report_field_set_value(field, repstr, NULL);
390           return 1;
391 }
392 
_pvstatus_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))393 static int _pvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
394                                 struct dm_report_field *field,
395                                 const void *data, void *private __attribute((unused)))
396 {
397           const uint32_t status = *(const uint32_t *) data;
398           char *repstr;
399 
400           if (!(repstr = dm_pool_zalloc(mem, 3))) {
401                     log_error("dm_pool_alloc failed");
402                     return 0;
403           }
404 
405           if (status & ALLOCATABLE_PV)
406                     repstr[0] = 'a';
407           else
408                     repstr[0] = '-';
409 
410           if (status & EXPORTED_VG)
411                     repstr[1] = 'x';
412           else
413                     repstr[1] = '-';
414 
415           dm_report_field_set_value(field, repstr, NULL);
416           return 1;
417 }
418 
_vgstatus_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))419 static int _vgstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
420                                 struct dm_report_field *field,
421                                 const void *data, void *private __attribute((unused)))
422 {
423           const struct volume_group *vg = (const struct volume_group *) data;
424           char *repstr;
425 
426           if (!(repstr = dm_pool_zalloc(mem, 7))) {
427                     log_error("dm_pool_alloc failed");
428                     return 0;
429           }
430 
431           if (vg->status & LVM_WRITE)
432                     repstr[0] = 'w';
433           else
434                     repstr[0] = 'r';
435 
436           if (vg_is_resizeable(vg))
437                     repstr[1] = 'z';
438           else
439                     repstr[1] = '-';
440 
441           if (vg_is_exported(vg))
442                     repstr[2] = 'x';
443           else
444                     repstr[2] = '-';
445 
446           if (vg_missing_pv_count(vg))
447                     repstr[3] = 'p';
448           else
449                     repstr[3] = '-';
450 
451           repstr[4] = _alloc_policy_char(vg->alloc);
452 
453           if (vg_is_clustered(vg))
454                     repstr[5] = 'c';
455           else
456                     repstr[5] = '-';
457 
458           dm_report_field_set_value(field, repstr, NULL);
459           return 1;
460 }
461 
_segtype_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))462 static int _segtype_disp(struct dm_report *rh __attribute((unused)),
463                                struct dm_pool *mem __attribute((unused)),
464                                struct dm_report_field *field,
465                                const void *data, void *private __attribute((unused)))
466 {
467           const struct lv_segment *seg = (const struct lv_segment *) data;
468 
469           if (seg->area_count == 1) {
470                     dm_report_field_set_value(field, "linear", NULL);
471                     return 1;
472           }
473 
474           dm_report_field_set_value(field, seg->segtype->ops->name(seg), NULL);
475           return 1;
476 }
477 
_loglv_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))478 static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
479                            struct dm_report_field *field,
480                            const void *data, void *private __attribute((unused)))
481 {
482           const struct logical_volume *lv = (const struct logical_volume *) data;
483           struct lv_segment *seg;
484 
485           dm_list_iterate_items(seg, &lv->segments) {
486                     if (!seg_is_mirrored(seg) || !seg->log_lv)
487                               continue;
488                     return dm_report_field_string(rh, field,
489                                                         (const char **) &seg->log_lv->name);
490           }
491 
492           dm_report_field_set_value(field, "", NULL);
493           return 1;
494 }
495 
_lvname_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))496 static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
497                               struct dm_report_field *field,
498                               const void *data, void *private __attribute((unused)))
499 {
500           const struct logical_volume *lv = (const struct logical_volume *) data;
501           char *repstr, *lvname;
502           size_t len;
503 
504           if (lv_is_visible(lv)) {
505                     repstr = lv->name;
506                     return dm_report_field_string(rh, field, (const char **) &repstr);
507           }
508 
509           len = strlen(lv->name) + 3;
510           if (!(repstr = dm_pool_zalloc(mem, len))) {
511                     log_error("dm_pool_alloc failed");
512                     return 0;
513           }
514 
515           if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
516                     log_error("lvname snprintf failed");
517                     return 0;
518           }
519 
520           if (!(lvname = dm_pool_strdup(mem, lv->name))) {
521                     log_error("dm_pool_strdup failed");
522                     return 0;
523           }
524 
525           dm_report_field_set_value(field, repstr, lvname);
526 
527           return 1;
528 }
529 
_origin_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)530 static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
531                               struct dm_report_field *field,
532                               const void *data, void *private)
533 {
534           const struct logical_volume *lv = (const struct logical_volume *) data;
535 
536           if (lv_is_cow(lv))
537                     return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
538 
539           dm_report_field_set_value(field, "", NULL);
540           return 1;
541 }
542 
_movepv_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))543 static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
544                               struct dm_report_field *field,
545                               const void *data, void *private __attribute((unused)))
546 {
547           const struct logical_volume *lv = (const struct logical_volume *) data;
548           const char *name;
549           struct lv_segment *seg;
550 
551           dm_list_iterate_items(seg, &lv->segments) {
552                     if (!(seg->status & PVMOVE))
553                               continue;
554                     name = dev_name(seg_dev(seg, 0));
555                     return dm_report_field_string(rh, field, &name);
556           }
557 
558           dm_report_field_set_value(field, "", NULL);
559           return 1;
560 }
561 
_convertlv_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))562 static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
563                                  struct dm_report_field *field,
564                                  const void *data, void *private __attribute((unused)))
565 {
566           const struct logical_volume *lv = (const struct logical_volume *) data;
567           const char *name = NULL;
568           struct lv_segment *seg;
569 
570           if (lv->status & CONVERTING) {
571                     if (lv->status & MIRRORED) {
572                               seg = first_seg(lv);
573 
574                               /* Temporary mirror is always area_num == 0 */
575                               if (seg_type(seg, 0) == AREA_LV &&
576                                   is_temporary_mirror_layer(seg_lv(seg, 0)))
577                                         name = seg_lv(seg, 0)->name;
578                     }
579           }
580 
581           if (name)
582                     return dm_report_field_string(rh, field, &name);
583 
584           dm_report_field_set_value(field, "", NULL);
585           return 1;
586 }
587 
_size32_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)588 static int _size32_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
589                               struct dm_report_field *field,
590                               const void *data, void *private)
591 {
592           const uint32_t size = *(const uint32_t *) data;
593           const char *disp, *repstr;
594           uint64_t *sortval;
595 
596           if (!*(disp = display_size_units(private, (uint64_t) size)))
597                     return_0;
598 
599           if (!(repstr = dm_pool_strdup(mem, disp))) {
600                     log_error("dm_pool_strdup failed");
601                     return 0;
602           }
603 
604           if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
605                     log_error("dm_pool_alloc failed");
606                     return 0;
607           }
608 
609           *sortval = (const uint64_t) size;
610 
611           dm_report_field_set_value(field, repstr, sortval);
612 
613           return 1;
614 }
615 
_size64_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)616 static int _size64_disp(struct dm_report *rh __attribute((unused)),
617                               struct dm_pool *mem,
618                               struct dm_report_field *field,
619                               const void *data, void *private)
620 {
621           const uint64_t size = *(const uint64_t *) data;
622           const char *disp, *repstr;
623           uint64_t *sortval;
624 
625           if (!*(disp = display_size_units(private, size)))
626                     return_0;
627 
628           if (!(repstr = dm_pool_strdup(mem, disp))) {
629                     log_error("dm_pool_strdup failed");
630                     return 0;
631           }
632 
633           if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
634                     log_error("dm_pool_alloc failed");
635                     return 0;
636           }
637 
638           *sortval = size;
639           dm_report_field_set_value(field, repstr, sortval);
640 
641           return 1;
642 }
643 
_lvreadahead_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))644 static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
645                                    struct dm_report_field *field,
646                                    const void *data, void *private __attribute((unused)))
647 {
648           const struct logical_volume *lv = (const struct logical_volume *) data;
649 
650           if (lv->read_ahead == DM_READ_AHEAD_AUTO) {
651                     dm_report_field_set_value(field, "auto", &_minusone);
652                     return 1;
653           }
654 
655           return _size32_disp(rh, mem, field, &lv->read_ahead, private);
656 }
657 
_lvkreadahead_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)658 static int _lvkreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
659                                     struct dm_report_field *field,
660                                     const void *data,
661                                     void *private)
662 {
663           const struct logical_volume *lv = (const struct logical_volume *) data;
664           struct lvinfo info;
665 
666           if (!lv_info(lv->vg->cmd, lv, &info, 0, 1) || !info.exists)
667                     return dm_report_field_uint64(rh, field, &_minusone);
668 
669           return _size32_disp(rh, mem, field, &info.read_ahead, private);
670 }
671 
_vgsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)672 static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem,
673                               struct dm_report_field *field,
674                               const void *data, void *private)
675 {
676           const struct volume_group *vg = (const struct volume_group *) data;
677           uint64_t size;
678 
679           size = (uint64_t) vg_size(vg);
680 
681           return _size64_disp(rh, mem, field, &size, private);
682 }
683 
_segstart_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)684 static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem,
685                                 struct dm_report_field *field,
686                                 const void *data, void *private)
687 {
688           const struct lv_segment *seg = (const struct lv_segment *) data;
689           uint64_t start;
690 
691           start = (uint64_t) seg->le * seg->lv->vg->extent_size;
692 
693           return _size64_disp(rh, mem, field, &start, private);
694 }
695 
_segstartpe_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))696 static int _segstartpe_disp(struct dm_report *rh,
697                                   struct dm_pool *mem __attribute((unused)),
698                                   struct dm_report_field *field,
699                                   const void *data,
700                                   void *private __attribute((unused)))
701 {
702           const struct lv_segment *seg = (const struct lv_segment *) data;
703 
704           return dm_report_field_uint32(rh, field, &seg->le);
705 }
706 
_segsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)707 static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem,
708                                struct dm_report_field *field,
709                                const void *data, void *private)
710 {
711           const struct lv_segment *seg = (const struct lv_segment *) data;
712           uint64_t size;
713 
714           size = (uint64_t) seg->len * seg->lv->vg->extent_size;
715 
716           return _size64_disp(rh, mem, field, &size, private);
717 }
718 
_chunksize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)719 static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
720                                  struct dm_report_field *field,
721                                  const void *data, void *private)
722 {
723           const struct lv_segment *seg = (const struct lv_segment *) data;
724           uint64_t size;
725 
726           if (lv_is_cow(seg->lv))
727                     size = (uint64_t) find_cow(seg->lv)->chunk_size;
728           else
729                     size = UINT64_C(0);
730 
731           return _size64_disp(rh, mem, field, &size, private);
732 }
733 
_originsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)734 static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem,
735                                   struct dm_report_field *field,
736                                   const void *data, void *private)
737 {
738           const struct logical_volume *lv = (const struct logical_volume *) data;
739           uint64_t size;
740 
741           if (lv_is_cow(lv))
742                     size = (uint64_t) find_cow(lv)->len * lv->vg->extent_size;
743           else if (lv_is_origin(lv))
744                     size = lv->size;
745           else
746                     size = UINT64_C(0);
747 
748           return _size64_disp(rh, mem, field, &size, private);
749 }
750 
_pvused_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)751 static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem,
752                               struct dm_report_field *field,
753                               const void *data, void *private)
754 {
755           const struct physical_volume *pv =
756               (const struct physical_volume *) data;
757           uint64_t used;
758 
759           if (!pv->pe_count)
760                     used = 0LL;
761           else
762                     used = (uint64_t) pv->pe_alloc_count * pv->pe_size;
763 
764           return _size64_disp(rh, mem, field, &used, private);
765 }
766 
_pvfree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)767 static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem,
768                               struct dm_report_field *field,
769                               const void *data, void *private)
770 {
771           const struct physical_volume *pv =
772               (const struct physical_volume *) data;
773           uint64_t freespace;
774 
775           if (!pv->pe_count)
776                     freespace = pv->size;
777           else
778                     freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
779 
780           return _size64_disp(rh, mem, field, &freespace, private);
781 }
782 
_pvsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)783 static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem,
784                               struct dm_report_field *field,
785                               const void *data, void *private)
786 {
787           const struct physical_volume *pv =
788               (const struct physical_volume *) data;
789           uint64_t size;
790 
791           if (!pv->pe_count)
792                     size = pv->size;
793           else
794                     size = (uint64_t) pv->pe_count * pv->pe_size;
795 
796           return _size64_disp(rh, mem, field, &size, private);
797 }
798 
_devsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)799 static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem,
800                                struct dm_report_field *field,
801                                const void *data, void *private)
802 {
803           const struct device *dev = *(const struct device **) data;
804           uint64_t size;
805 
806           if (!dev_get_size(dev, &size))
807                     size = 0;
808 
809           return _size64_disp(rh, mem, field, &size, private);
810 }
811 
_vgfree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)812 static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem,
813                               struct dm_report_field *field,
814                               const void *data, void *private)
815 {
816           const struct volume_group *vg = (const struct volume_group *) data;
817           uint64_t freespace;
818 
819           freespace = (uint64_t) vg_free(vg);
820 
821           return _size64_disp(rh, mem, field, &freespace, private);
822 }
823 
_uuid_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))824 static int _uuid_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
825                           struct dm_report_field *field,
826                           const void *data, void *private __attribute((unused)))
827 {
828           char *repstr = NULL;
829 
830           if (!(repstr = dm_pool_alloc(mem, 40))) {
831                     log_error("dm_pool_alloc failed");
832                     return 0;
833           }
834 
835           if (!id_write_format((const struct id *) data, repstr, 40))
836                     return_0;
837 
838           dm_report_field_set_value(field, repstr, NULL);
839           return 1;
840 }
841 
_uint32_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))842 static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
843                               struct dm_report_field *field,
844                               const void *data, void *private __attribute((unused)))
845 {
846           return dm_report_field_uint32(rh, field, data);
847 }
848 
_int32_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))849 static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
850                            struct dm_report_field *field,
851                            const void *data, void *private __attribute((unused)))
852 {
853           return dm_report_field_int32(rh, field, data);
854 }
855 
_pvmdas_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)856 static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem,
857                               struct dm_report_field *field,
858                               const void *data, void *private)
859 {
860           uint32_t count;
861           const struct physical_volume *pv =
862               (const struct physical_volume *) data;
863 
864           count = pv_mda_count(pv);
865 
866           return _uint32_disp(rh, mem, field, &count, private);
867 }
868 
_vgmdas_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)869 static int _vgmdas_disp(struct dm_report *rh, struct dm_pool *mem,
870                               struct dm_report_field *field,
871                               const void *data, void *private)
872 {
873           const struct volume_group *vg = (const struct volume_group *) data;
874           uint32_t count;
875 
876           count = vg_mda_count(vg);
877 
878           return _uint32_disp(rh, mem, field, &count, private);
879 }
880 
_pvmdafree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)881 static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
882                                  struct dm_report_field *field,
883                                  const void *data, void *private)
884 {
885           struct lvmcache_info *info;
886           uint64_t freespace = UINT64_MAX, mda_free;
887           const char *pvid = (const char *)(&((struct id *) data)->uuid);
888           struct metadata_area *mda;
889 
890           if ((info = info_from_pvid(pvid, 0)))
891                     dm_list_iterate_items(mda, &info->mdas) {
892                               if (!mda->ops->mda_free_sectors)
893                                         continue;
894                               mda_free = mda->ops->mda_free_sectors(mda);
895                               if (mda_free < freespace)
896                                         freespace = mda_free;
897                     }
898 
899           if (freespace == UINT64_MAX)
900                     freespace = UINT64_C(0);
901 
902           return _size64_disp(rh, mem, field, &freespace, private);
903 }
904 
_find_min_mda_size(struct dm_list * mdas)905 static uint64_t _find_min_mda_size(struct dm_list *mdas)
906 {
907           uint64_t min_mda_size = UINT64_MAX, mda_size;
908           struct metadata_area *mda;
909 
910           dm_list_iterate_items(mda, mdas) {
911                     if (!mda->ops->mda_total_sectors)
912                               continue;
913                     mda_size = mda->ops->mda_total_sectors(mda);
914                     if (mda_size < min_mda_size)
915                               min_mda_size = mda_size;
916           }
917 
918           if (min_mda_size == UINT64_MAX)
919                     min_mda_size = UINT64_C(0);
920 
921           return min_mda_size;
922 }
923 
_pvmdasize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)924 static int _pvmdasize_disp(struct dm_report *rh, struct dm_pool *mem,
925                                  struct dm_report_field *field,
926                                  const void *data, void *private)
927 {
928           struct lvmcache_info *info;
929           uint64_t min_mda_size = 0;
930           const char *pvid = (const char *)(&((struct id *) data)->uuid);
931 
932           /* PVs could have 2 mdas of different sizes (rounding effect) */
933           if ((info = info_from_pvid(pvid, 0)))
934                     min_mda_size = _find_min_mda_size(&info->mdas);
935 
936           return _size64_disp(rh, mem, field, &min_mda_size, private);
937 }
938 
_vgmdasize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)939 static int _vgmdasize_disp(struct dm_report *rh, struct dm_pool *mem,
940                                  struct dm_report_field *field,
941                                  const void *data, void *private)
942 {
943           const struct volume_group *vg = (const struct volume_group *) data;
944           uint64_t min_mda_size;
945 
946           min_mda_size = _find_min_mda_size(&vg->fid->metadata_areas);
947 
948           return _size64_disp(rh, mem, field, &min_mda_size, private);
949 }
950 
_vgmdafree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)951 static int _vgmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
952                                  struct dm_report_field *field,
953                                  const void *data, void *private)
954 {
955           const struct volume_group *vg = (const struct volume_group *) data;
956           uint64_t freespace = UINT64_MAX, mda_free;
957           struct metadata_area *mda;
958 
959           dm_list_iterate_items(mda, &vg->fid->metadata_areas) {
960                     if (!mda->ops->mda_free_sectors)
961                               continue;
962                     mda_free = mda->ops->mda_free_sectors(mda);
963                     if (mda_free < freespace)
964                               freespace = mda_free;
965           }
966 
967           if (freespace == UINT64_MAX)
968                     freespace = UINT64_C(0);
969 
970           return _size64_disp(rh, mem, field, &freespace, private);
971 }
972 
_lvcount_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)973 static int _lvcount_disp(struct dm_report *rh, struct dm_pool *mem,
974                                struct dm_report_field *field,
975                                const void *data, void *private)
976 {
977           const struct volume_group *vg = (const struct volume_group *) data;
978           uint32_t count;
979 
980           count = vg_visible_lvs(vg);
981 
982           return _uint32_disp(rh, mem, field, &count, private);
983 }
984 
_lvsegcount_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)985 static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem,
986                                   struct dm_report_field *field,
987                                   const void *data, void *private)
988 {
989           const struct logical_volume *lv = (const struct logical_volume *) data;
990           uint32_t count;
991 
992           count = dm_list_size(&lv->segments);
993 
994           return _uint32_disp(rh, mem, field, &count, private);
995 }
996 
_snapcount_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)997 static int _snapcount_disp(struct dm_report *rh, struct dm_pool *mem,
998                                  struct dm_report_field *field,
999                                  const void *data, void *private)
1000 {
1001           const struct volume_group *vg = (const struct volume_group *) data;
1002           uint32_t count;
1003 
1004           count = snapshot_count(vg);
1005 
1006           return _uint32_disp(rh, mem, field, &count, private);
1007 }
1008 
_snpercent_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))1009 static int _snpercent_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
1010                                  struct dm_report_field *field,
1011                                  const void *data, void *private __attribute((unused)))
1012 {
1013           const struct logical_volume *lv = (const struct logical_volume *) data;
1014           struct lvinfo info;
1015           float snap_percent;
1016           percent_range_t percent_range;
1017           uint64_t *sortval;
1018           char *repstr;
1019 
1020           /* Suppress snapshot percentage if not using driver */
1021           if (!activation()) {
1022                     dm_report_field_set_value(field, "", NULL);
1023                     return 1;
1024           }
1025 
1026           if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
1027                     log_error("dm_pool_alloc failed");
1028                     return 0;
1029           }
1030 
1031           if (!lv_is_cow(lv) ||
1032               (lv_info(lv->vg->cmd, lv, &info, 0, 0) && !info.exists)) {
1033                     *sortval = UINT64_C(0);
1034                     dm_report_field_set_value(field, "", sortval);
1035                     return 1;
1036           }
1037 
1038           if (!lv_snapshot_percent(lv, &snap_percent, &percent_range) ||
1039                                          (percent_range == PERCENT_INVALID)) {
1040                     *sortval = UINT64_C(100);
1041                     dm_report_field_set_value(field, "100.00", sortval);
1042                     return 1;
1043           }
1044 
1045           if (!(repstr = dm_pool_zalloc(mem, 8))) {
1046                     log_error("dm_pool_alloc failed");
1047                     return 0;
1048           }
1049 
1050           if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) {
1051                     log_error("snapshot percentage too large");
1052                     return 0;
1053           }
1054 
1055           *sortval = snap_percent * UINT64_C(1000);
1056           dm_report_field_set_value(field, repstr, sortval);
1057 
1058           return 1;
1059 }
1060 
_copypercent_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))1061 static int _copypercent_disp(struct dm_report *rh __attribute((unused)),
1062                                    struct dm_pool *mem,
1063                                    struct dm_report_field *field,
1064                                    const void *data, void *private __attribute((unused)))
1065 {
1066           struct logical_volume *lv = (struct logical_volume *) data;
1067           float percent;
1068           percent_range_t percent_range;
1069           uint64_t *sortval;
1070           char *repstr;
1071 
1072           if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
1073                     log_error("dm_pool_alloc failed");
1074                     return 0;
1075           }
1076 
1077           if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
1078               !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, &percent_range,
1079                                      NULL) || (percent_range == PERCENT_INVALID)) {
1080                     *sortval = UINT64_C(0);
1081                     dm_report_field_set_value(field, "", sortval);
1082                     return 1;
1083           }
1084 
1085           percent = copy_percent(lv, &percent_range);
1086 
1087           if (!(repstr = dm_pool_zalloc(mem, 8))) {
1088                     log_error("dm_pool_alloc failed");
1089                     return 0;
1090           }
1091 
1092           if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) {
1093                     log_error("copy percentage too large");
1094                     return 0;
1095           }
1096 
1097           *sortval = percent * UINT64_C(1000);
1098           dm_report_field_set_value(field, repstr, sortval);
1099 
1100           return 1;
1101 }
1102 
1103 /* Report object types */
1104 
1105 /* necessary for displaying something for PVs not belonging to VG */
1106 static struct format_instance _dummy_fid = {
1107           .metadata_areas = { &(_dummy_fid.metadata_areas), &(_dummy_fid.metadata_areas) },
1108 };
1109 
1110 static struct volume_group _dummy_vg = {
1111           .fid = &_dummy_fid,
1112           .name = (char *) "",
1113           .system_id = (char *) "",
1114           .pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) },
1115           .lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) },
1116           .tags = { &(_dummy_vg.tags), &(_dummy_vg.tags) },
1117 };
1118 
_obj_get_vg(void * obj)1119 static void *_obj_get_vg(void *obj)
1120 {
1121           struct volume_group *vg = ((struct lvm_report_object *)obj)->vg;
1122 
1123           return vg ? vg : &_dummy_vg;
1124 }
1125 
_obj_get_lv(void * obj)1126 static void *_obj_get_lv(void *obj)
1127 {
1128           return ((struct lvm_report_object *)obj)->lv;
1129 }
1130 
_obj_get_pv(void * obj)1131 static void *_obj_get_pv(void *obj)
1132 {
1133           return ((struct lvm_report_object *)obj)->pv;
1134 }
1135 
_obj_get_seg(void * obj)1136 static void *_obj_get_seg(void *obj)
1137 {
1138           return ((struct lvm_report_object *)obj)->seg;
1139 }
1140 
_obj_get_pvseg(void * obj)1141 static void *_obj_get_pvseg(void *obj)
1142 {
1143           return ((struct lvm_report_object *)obj)->pvseg;
1144 }
1145 
1146 static const struct dm_report_object_type _report_types[] = {
1147           { VGS, "Volume Group", "vg_", _obj_get_vg },
1148           { LVS, "Logical Volume", "lv_", _obj_get_lv },
1149           { PVS, "Physical Volume", "pv_", _obj_get_pv },
1150           { LABEL, "Physical Volume Label", "pv_", _obj_get_pv },
1151           { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
1152           { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
1153           { 0, "", "", NULL },
1154 };
1155 
1156 /*
1157  * Import column definitions
1158  */
1159 
1160 #define STR DM_REPORT_FIELD_TYPE_STRING
1161 #define NUM DM_REPORT_FIELD_TYPE_NUMBER
1162 #define FIELD(type, strct, sorttype, head, field, width, func, id, desc) {type, sorttype, offsetof(struct strct, field), width, id, head, &_ ## func ## _disp, desc},
1163 
1164 static struct dm_report_field_type _fields[] = {
1165 #define lv          logical_volume
1166 #define pv          physical_volume
1167 #define vg          volume_group
1168 #define seg         lv_segment
1169 #define pvseg       pv_segment
1170 #include "columns.h"
1171 {0, 0, 0, 0, "", "", NULL, NULL},
1172 #undef lv
1173 #undef pv
1174 #undef vg
1175 #undef seg
1176 #undef pvseg
1177 };
1178 
1179 #undef STR
1180 #undef NUM
1181 #undef FIELD
1182 
report_init(struct cmd_context * cmd,const char * format,const char * keys,report_type_t * report_type,const char * separator,int aligned,int buffered,int headings,int field_prefixes,int quoted,int columns_as_rows)1183 void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
1184                       report_type_t *report_type, const char *separator,
1185                       int aligned, int buffered, int headings, int field_prefixes,
1186                       int quoted, int columns_as_rows)
1187 {
1188           uint32_t report_flags = 0;
1189           void *rh;
1190 
1191           if (aligned)
1192                     report_flags |= DM_REPORT_OUTPUT_ALIGNED;
1193 
1194           if (buffered)
1195                     report_flags |= DM_REPORT_OUTPUT_BUFFERED;
1196 
1197           if (headings)
1198                     report_flags |= DM_REPORT_OUTPUT_HEADINGS;
1199 
1200           if (field_prefixes)
1201                     report_flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
1202 
1203           if (!quoted)
1204                     report_flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
1205 
1206           if (columns_as_rows)
1207                     report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
1208 
1209           rh = dm_report_init(report_type, _report_types, _fields, format,
1210                                   separator, report_flags, keys, cmd);
1211 
1212           if (rh && field_prefixes)
1213                     dm_report_set_output_field_name_prefix(rh, "lvm2_");
1214 
1215           return rh;
1216 }
1217 
1218 /*
1219  * Create a row of data for an object
1220  */
report_object(void * handle,struct volume_group * vg,struct logical_volume * lv,struct physical_volume * pv,struct lv_segment * seg,struct pv_segment * pvseg)1221 int report_object(void *handle, struct volume_group *vg,
1222                       struct logical_volume *lv, struct physical_volume *pv,
1223                       struct lv_segment *seg, struct pv_segment *pvseg)
1224 {
1225           struct lvm_report_object obj;
1226 
1227           /* The two format fields might as well match. */
1228           if (!vg && pv)
1229                     _dummy_fid.fmt = pv->fmt;
1230 
1231           obj.vg = vg;
1232           obj.lv = lv;
1233           obj.pv = pv;
1234           obj.seg = seg;
1235           obj.pvseg = pvseg;
1236 
1237           return dm_report_object(handle, &obj);
1238 }
1239