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