2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
5 * This file is part of LVM2.
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.
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
19 static int _vgs_single(struct cmd_context
*cmd
__attribute__((unused
)),
20 const char *vg_name
, struct volume_group
*vg
,
23 if (!report_object(handle
, vg
, NULL
, NULL
, NULL
, NULL
)) {
28 check_current_backup(vg
);
30 return ECMD_PROCESSED
;
33 static int _lvs_single(struct cmd_context
*cmd
, struct logical_volume
*lv
,
36 if (!report_object(handle
, lv
->vg
, lv
, NULL
, NULL
, NULL
)) {
41 return ECMD_PROCESSED
;
44 static int _segs_single(struct cmd_context
*cmd
__attribute__((unused
)),
45 struct lv_segment
*seg
, void *handle
)
47 if (!report_object(handle
, seg
->lv
->vg
, seg
->lv
, NULL
, seg
, NULL
)) {
52 return ECMD_PROCESSED
;
54 static int _pvsegs_sub_single(struct cmd_context
*cmd
,
55 struct volume_group
*vg
,
56 struct pv_segment
*pvseg
, void *handle
)
58 int ret
= ECMD_PROCESSED
;
59 struct lv_segment
*seg
= pvseg
->lvseg
;
61 struct volume_group _free_vg
= {
67 struct logical_volume _free_logical_volume
= {
68 .vg
= vg
?: &_free_vg
,
76 struct lv_segment _free_lv_segment
= {
77 .lv
= &_free_logical_volume
,
92 _free_lv_segment
.segtype
= get_segtype_from_string(cmd
, "free");
93 _free_lv_segment
.len
= pvseg
->len
;
94 dm_list_init(&_free_vg
.pvs
);
95 dm_list_init(&_free_vg
.lvs
);
96 dm_list_init(&_free_vg
.tags
);
97 dm_list_init(&_free_lv_segment
.tags
);
98 dm_list_init(&_free_lv_segment
.origin_list
);
99 dm_list_init(&_free_logical_volume
.tags
);
100 dm_list_init(&_free_logical_volume
.segments
);
101 dm_list_init(&_free_logical_volume
.segs_using_this_lv
);
102 dm_list_init(&_free_logical_volume
.snapshot_segs
);
104 if (!report_object(handle
, vg
, seg
? seg
->lv
: &_free_logical_volume
, pvseg
->pv
,
105 seg
? : &_free_lv_segment
, pvseg
)) {
114 static int _lvsegs_single(struct cmd_context
*cmd
, struct logical_volume
*lv
,
117 if (!arg_count(cmd
, all_ARG
) && !lv_is_visible(lv
))
118 return ECMD_PROCESSED
;
120 return process_each_segment_in_lv(cmd
, lv
, handle
, _segs_single
);
123 static int _pvsegs_single(struct cmd_context
*cmd
, struct volume_group
*vg
,
124 struct physical_volume
*pv
, void *handle
)
126 return process_each_segment_in_pv(cmd
, vg
, pv
, handle
,
130 static int _pvs_single(struct cmd_context
*cmd
, struct volume_group
*vg
,
131 struct physical_volume
*pv
, void *handle
)
134 int ret
= ECMD_PROCESSED
;
135 const char *vg_name
= NULL
;
136 struct volume_group
*old_vg
= vg
;
137 char uuid
[64] __attribute__((aligned(8)));
139 if (is_pv(pv
) && !is_orphan(pv
) && !vg
) {
140 vg_name
= pv_vg_name(pv
);
142 vg
= vg_read(cmd
, vg_name
, (char *)&pv
->vgid
, 0);
143 if (vg_read_error(vg
)) {
144 log_error("Skipping volume group %s", vg_name
);
150 * Replace possibly incomplete PV structure with new one
151 * allocated in vg_read.
153 if (!is_missing_pv(pv
)) {
154 if (!(pvl
= find_pv_in_vg(vg
, pv_dev_name(pv
)))) {
155 log_error("Unable to find \"%s\" in volume group \"%s\"",
156 pv_dev_name(pv
), vg
->name
);
160 } else if (!(pvl
= find_pv_in_vg_by_uuid(vg
, &pv
->id
))) {
161 if (!id_write_format(&pv
->id
, uuid
, sizeof(uuid
))) {
166 log_error("Unable to find missing PV %s in volume group %s",
175 if (!report_object(handle
, vg
, NULL
, pv
, NULL
, NULL
)) {
182 unlock_vg(cmd
, vg_name
);
190 static int _label_single(struct cmd_context
*cmd
, struct volume_group
*vg
,
191 struct physical_volume
*pv
, void *handle
)
193 if (!report_object(handle
, vg
, NULL
, pv
, NULL
, NULL
)) {
198 return ECMD_PROCESSED
;
201 static int _pvs_in_vg(struct cmd_context
*cmd
, const char *vg_name
,
202 struct volume_group
*vg
,
205 if (vg_read_error(vg
)) {
210 return process_each_pv_in_vg(cmd
, vg
, NULL
, handle
, &_pvs_single
);
213 static int _pvsegs_in_vg(struct cmd_context
*cmd
, const char *vg_name
,
214 struct volume_group
*vg
,
217 if (vg_read_error(vg
)) {
222 return process_each_pv_in_vg(cmd
, vg
, NULL
, handle
, &_pvsegs_single
);
225 static int _report(struct cmd_context
*cmd
, int argc
, char **argv
,
226 report_type_t report_type
)
231 const char *keys
= NULL
, *options
= NULL
, *separator
;
232 int r
= ECMD_PROCESSED
;
233 int aligned
, buffered
, headings
, field_prefixes
, quoted
;
235 unsigned args_are_pvs
;
237 aligned
= find_config_tree_int(cmd
, "report/aligned",
238 DEFAULT_REP_ALIGNED
);
239 buffered
= find_config_tree_int(cmd
, "report/buffered",
240 DEFAULT_REP_BUFFERED
);
241 headings
= find_config_tree_int(cmd
, "report/headings",
242 DEFAULT_REP_HEADINGS
);
243 separator
= find_config_tree_str(cmd
, "report/separator",
244 DEFAULT_REP_SEPARATOR
);
245 field_prefixes
= find_config_tree_int(cmd
, "report/prefixes",
246 DEFAULT_REP_PREFIXES
);
247 quoted
= find_config_tree_int(cmd
, "report/quoted",
249 columns_as_rows
= find_config_tree_int(cmd
, "report/columns_as_rows",
250 DEFAULT_REP_COLUMNS_AS_ROWS
);
252 args_are_pvs
= (report_type
== PVS
||
253 report_type
== LABEL
||
254 report_type
== PVSEGS
) ? 1 : 0;
256 switch (report_type
) {
258 keys
= find_config_tree_str(cmd
, "report/lvs_sort",
260 if (!arg_count(cmd
, verbose_ARG
))
261 options
= find_config_tree_str(cmd
,
265 options
= find_config_tree_str(cmd
,
266 "report/lvs_cols_verbose",
267 DEFAULT_LVS_COLS_VERB
);
270 keys
= find_config_tree_str(cmd
, "report/vgs_sort",
272 if (!arg_count(cmd
, verbose_ARG
))
273 options
= find_config_tree_str(cmd
,
277 options
= find_config_tree_str(cmd
,
278 "report/vgs_cols_verbose",
279 DEFAULT_VGS_COLS_VERB
);
283 keys
= find_config_tree_str(cmd
, "report/pvs_sort",
285 if (!arg_count(cmd
, verbose_ARG
))
286 options
= find_config_tree_str(cmd
,
290 options
= find_config_tree_str(cmd
,
291 "report/pvs_cols_verbose",
292 DEFAULT_PVS_COLS_VERB
);
295 keys
= find_config_tree_str(cmd
, "report/segs_sort",
297 if (!arg_count(cmd
, verbose_ARG
))
298 options
= find_config_tree_str(cmd
,
302 options
= find_config_tree_str(cmd
,
303 "report/segs_cols_verbose",
304 DEFAULT_SEGS_COLS_VERB
);
307 keys
= find_config_tree_str(cmd
, "report/pvsegs_sort",
308 DEFAULT_PVSEGS_SORT
);
309 if (!arg_count(cmd
, verbose_ARG
))
310 options
= find_config_tree_str(cmd
,
311 "report/pvsegs_cols",
312 DEFAULT_PVSEGS_COLS
);
314 options
= find_config_tree_str(cmd
,
315 "report/pvsegs_cols_verbose",
316 DEFAULT_PVSEGS_COLS_VERB
);
319 log_error(INTERNAL_ERROR
"Unknown report type.");
323 /* If -o supplied use it, else use default for report_type */
324 if (arg_count(cmd
, options_ARG
)) {
325 opts
= arg_str_value(cmd
, options_ARG
, "");
326 if (!opts
|| !*opts
) {
327 log_error("Invalid options string: %s", opts
);
328 return EINVALID_CMD_LINE
;
331 if (!(str
= dm_pool_alloc(cmd
->mem
,
332 strlen(options
) + strlen(opts
) + 1))) {
333 log_error("options string allocation failed");
336 strcpy(str
, options
);
338 strcat(str
, opts
+ 1);
344 /* -O overrides default sort settings */
345 keys
= arg_str_value(cmd
, sort_ARG
, keys
);
347 separator
= arg_str_value(cmd
, separator_ARG
, separator
);
348 if (arg_count(cmd
, separator_ARG
))
350 if (arg_count(cmd
, aligned_ARG
))
352 if (arg_count(cmd
, unbuffered_ARG
) && !arg_count(cmd
, sort_ARG
))
354 if (arg_count(cmd
, noheadings_ARG
))
356 if (arg_count(cmd
, nameprefixes_ARG
)) {
360 if (arg_count(cmd
, unquoted_ARG
))
362 if (arg_count(cmd
, rows_ARG
))
365 if (!(report_handle
= report_init(cmd
, options
, keys
, &report_type
,
366 separator
, aligned
, buffered
,
367 headings
, field_prefixes
, quoted
,
369 if (!strcasecmp(options
, "help") || !strcmp(options
, "?"))
375 /* Ensure options selected are compatible */
376 if (report_type
& SEGS
)
378 if (report_type
& PVSEGS
)
380 if ((report_type
& LVS
) && (report_type
& (PVS
| LABEL
)) && !args_are_pvs
) {
381 log_error("Can't report LV and PV fields at the same time");
382 dm_report_free(report_handle
);
386 /* Change report type if fields specified makes this necessary */
387 if ((report_type
& PVSEGS
) ||
388 ((report_type
& (PVS
| LABEL
)) && (report_type
& LVS
)))
389 report_type
= PVSEGS
;
390 else if ((report_type
& LABEL
) && (report_type
& VGS
))
392 else if (report_type
& PVS
)
394 else if (report_type
& SEGS
)
396 else if (report_type
& LVS
)
399 switch (report_type
) {
401 r
= process_each_lv(cmd
, argc
, argv
, 0, report_handle
,
405 r
= process_each_vg(cmd
, argc
, argv
, 0,
406 report_handle
, &_vgs_single
);
409 r
= process_each_pv(cmd
, argc
, argv
, NULL
, READ_WITHOUT_LOCK
,
410 1, report_handle
, &_label_single
);
414 r
= process_each_pv(cmd
, argc
, argv
, NULL
, 0,
415 0, report_handle
, &_pvs_single
);
417 r
= process_each_vg(cmd
, argc
, argv
, 0,
418 report_handle
, &_pvs_in_vg
);
421 r
= process_each_lv(cmd
, argc
, argv
, 0, report_handle
,
426 r
= process_each_pv(cmd
, argc
, argv
, NULL
, 0,
427 0, report_handle
, &_pvsegs_single
);
429 r
= process_each_vg(cmd
, argc
, argv
, 0,
430 report_handle
, &_pvsegs_in_vg
);
434 dm_report_output(report_handle
);
436 dm_report_free(report_handle
);
440 int lvs(struct cmd_context
*cmd
, int argc
, char **argv
)
444 if (arg_count(cmd
, segments_ARG
))
449 return _report(cmd
, argc
, argv
, type
);
452 int vgs(struct cmd_context
*cmd
, int argc
, char **argv
)
454 return _report(cmd
, argc
, argv
, VGS
);
457 int pvs(struct cmd_context
*cmd
, int argc
, char **argv
)
461 if (arg_count(cmd
, segments_ARG
))
466 return _report(cmd
, argc
, argv
, type
);