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