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