xref: /dragonfly/contrib/lvm2/dist/tools/reporter.c (revision d4ef6694)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
438 int vgs(struct cmd_context *cmd, int argc, char **argv)
439 {
440 	return _report(cmd, argc, argv, VGS);
441 }
442 
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