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