1 /* $NetBSD: display.c,v 1.1.1.1 2008/12/22 00:17:57 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2007 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 "lib.h" 19 #include "metadata.h" 20 #include "display.h" 21 #include "activate.h" 22 #include "toolcontext.h" 23 #include "segtype.h" 24 25 #define SIZE_BUF 128 26 27 typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t; 28 29 static const struct { 30 alloc_policy_t alloc; 31 const char str[12]; /* must be changed when size extends 11 chars */ 32 } _policies[] = { 33 { 34 ALLOC_CONTIGUOUS, "contiguous"}, { 35 ALLOC_CLING, "cling"}, { 36 ALLOC_NORMAL, "normal"}, { 37 ALLOC_ANYWHERE, "anywhere"}, { 38 ALLOC_INHERIT, "inherit"} 39 }; 40 41 static const int _num_policies = sizeof(_policies) / sizeof(*_policies); 42 43 uint64_t units_to_bytes(const char *units, char *unit_type) 44 { 45 char *ptr = NULL; 46 uint64_t v; 47 48 if (isdigit(*units)) { 49 v = (uint64_t) strtod(units, &ptr); 50 if (ptr == units) 51 return 0; 52 units = ptr; 53 } else 54 v = 1; 55 56 if (v == 1) 57 *unit_type = *units; 58 else 59 *unit_type = 'U'; 60 61 switch (*units) { 62 case 'h': 63 case 'H': 64 v = UINT64_C(1); 65 *unit_type = *units; 66 break; 67 case 's': 68 v *= SECTOR_SIZE; 69 break; 70 case 'b': 71 case 'B': 72 v *= UINT64_C(1); 73 break; 74 #define KILO UINT64_C(1024) 75 case 'k': 76 v *= KILO; 77 break; 78 case 'm': 79 v *= KILO * KILO; 80 break; 81 case 'g': 82 v *= KILO * KILO * KILO; 83 break; 84 case 't': 85 v *= KILO * KILO * KILO * KILO; 86 break; 87 case 'p': 88 v *= KILO * KILO * KILO * KILO * KILO; 89 break; 90 case 'e': 91 v *= KILO * KILO * KILO * KILO * KILO * KILO; 92 break; 93 #undef KILO 94 #define KILO UINT64_C(1000) 95 case 'K': 96 v *= KILO; 97 break; 98 case 'M': 99 v *= KILO * KILO; 100 break; 101 case 'G': 102 v *= KILO * KILO * KILO; 103 break; 104 case 'T': 105 v *= KILO * KILO * KILO * KILO; 106 break; 107 case 'P': 108 v *= KILO * KILO * KILO * KILO * KILO; 109 break; 110 case 'E': 111 v *= KILO * KILO * KILO * KILO * KILO * KILO; 112 break; 113 #undef KILO 114 default: 115 return 0; 116 } 117 118 if (*(units + 1)) 119 return 0; 120 121 return v; 122 } 123 124 const char *get_alloc_string(alloc_policy_t alloc) 125 { 126 int i; 127 128 for (i = 0; i < _num_policies; i++) 129 if (_policies[i].alloc == alloc) 130 return _policies[i].str; 131 132 return NULL; 133 } 134 135 alloc_policy_t get_alloc_from_string(const char *str) 136 { 137 int i; 138 139 for (i = 0; i < _num_policies; i++) 140 if (!strcmp(_policies[i].str, str)) 141 return _policies[i].alloc; 142 143 /* Special case for old metadata */ 144 if(!strcmp("next free", str)) 145 return ALLOC_NORMAL; 146 147 log_error("Unrecognised allocation policy %s", str); 148 return ALLOC_INVALID; 149 } 150 151 /* Size supplied in sectors */ 152 static const char *_display_size(const struct cmd_context *cmd, 153 uint64_t size, size_len_t sl) 154 { 155 int s; 156 int suffix = 1, precision; 157 uint64_t byte = UINT64_C(0); 158 uint64_t units = UINT64_C(1024); 159 char *size_buf = NULL; 160 const char * const size_str[][3] = { 161 {" Exabyte", " EB", "E"}, 162 {" Petabyte", " PB", "P"}, 163 {" Terabyte", " TB", "T"}, 164 {" Gigabyte", " GB", "G"}, 165 {" Megabyte", " MB", "M"}, 166 {" Kilobyte", " KB", "K"}, 167 {"", "", ""}, 168 {" Byte ", " B ", "B"}, 169 {" Units ", " Un", "U"}, 170 {" Sectors ", " Se", "S"}, 171 {" ", " ", " "}, 172 }; 173 174 if (!(size_buf = dm_pool_alloc(cmd->mem, SIZE_BUF))) { 175 log_error("no memory for size display buffer"); 176 return ""; 177 } 178 179 suffix = cmd->current_settings.suffix; 180 181 for (s = 0; s < 10; s++) 182 if (toupper((int) cmd->current_settings.unit_type) == 183 *size_str[s][2]) 184 break; 185 186 if (size == UINT64_C(0)) { 187 sprintf(size_buf, "0%s", suffix ? size_str[s][sl] : ""); 188 return size_buf; 189 } 190 191 size *= UINT64_C(512); 192 193 if (s < 10) 194 byte = cmd->current_settings.unit_factor; 195 else { 196 suffix = 1; 197 if (cmd->current_settings.unit_type == 'H') 198 units = UINT64_C(1000); 199 else 200 units = UINT64_C(1024); 201 byte = units * units * units * units * units * units; 202 s = 0; 203 while (size_str[s] && size < byte) 204 s++, byte /= units; 205 } 206 207 /* FIXME Make precision configurable */ 208 switch(toupper((int) cmd->current_settings.unit_type)) { 209 case 'B': 210 case 'S': 211 precision = 0; 212 break; 213 default: 214 precision = 2; 215 } 216 217 snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision, 218 (double) size / byte, suffix ? size_str[s][sl] : ""); 219 220 return size_buf; 221 } 222 223 const char *display_size_long(const struct cmd_context *cmd, uint64_t size) 224 { 225 return _display_size(cmd, size, SIZE_LONG); 226 } 227 228 const char *display_size_units(const struct cmd_context *cmd, uint64_t size) 229 { 230 return _display_size(cmd, size, SIZE_UNIT); 231 } 232 233 const char *display_size(const struct cmd_context *cmd, uint64_t size) 234 { 235 return _display_size(cmd, size, SIZE_SHORT); 236 } 237 238 void pvdisplay_colons(const struct physical_volume *pv) 239 { 240 char uuid[64] __attribute((aligned(8))); 241 242 if (!pv) 243 return; 244 245 if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { 246 stack; 247 return; 248 } 249 250 log_print("%s:%s:%" PRIu64 ":-1:%u:%u:-1:%" PRIu32 ":%u:%u:%u:%s", 251 pv_dev_name(pv), pv->vg_name, pv->size, 252 /* FIXME pv->pv_number, Derive or remove? */ 253 pv->status, /* FIXME Support old or new format here? */ 254 pv->status & ALLOCATABLE_PV, /* FIXME remove? */ 255 /* FIXME pv->lv_cur, Remove? */ 256 pv->pe_size / 2, 257 pv->pe_count, 258 pv->pe_count - pv->pe_alloc_count, 259 pv->pe_alloc_count, *uuid ? uuid : "none"); 260 261 return; 262 } 263 264 void pvdisplay_segments(const struct physical_volume *pv) 265 { 266 const struct pv_segment *pvseg; 267 268 if (pv->pe_size) 269 log_print("--- Physical Segments ---"); 270 271 dm_list_iterate_items(pvseg, &pv->segments) { 272 log_print("Physical extent %u to %u:", 273 pvseg->pe, pvseg->pe + pvseg->len - 1); 274 275 if (pvseg_is_allocated(pvseg)) { 276 log_print(" Logical volume\t%s%s/%s", 277 pvseg->lvseg->lv->vg->cmd->dev_dir, 278 pvseg->lvseg->lv->vg->name, 279 pvseg->lvseg->lv->name); 280 log_print(" Logical extents\t%d to %d", 281 pvseg->lvseg->le, pvseg->lvseg->le + 282 pvseg->lvseg->len - 1); 283 } else 284 log_print(" FREE"); 285 } 286 287 log_print(" "); 288 return; 289 } 290 291 /* FIXME Include label fields */ 292 void pvdisplay_full(const struct cmd_context *cmd, 293 const struct physical_volume *pv, 294 void *handle __attribute((unused))) 295 { 296 char uuid[64] __attribute((aligned(8))); 297 const char *size; 298 299 uint32_t pe_free; 300 uint64_t data_size, pvsize, unusable; 301 302 if (!pv) 303 return; 304 305 if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { 306 stack; 307 return; 308 } 309 310 log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW "); 311 log_print("PV Name %s", pv_dev_name(pv)); 312 log_print("VG Name %s%s", 313 is_orphan(pv) ? "" : pv->vg_name, 314 pv->status & EXPORTED_VG ? " (exported)" : ""); 315 316 data_size = (uint64_t) pv->pe_count * pv->pe_size; 317 if (pv->size > data_size + pv->pe_start) { 318 pvsize = pv->size; 319 unusable = pvsize - data_size; 320 } else { 321 pvsize = data_size + pv->pe_start; 322 unusable = pvsize - pv->size; 323 } 324 325 size = display_size(cmd, pvsize); 326 if (data_size) 327 log_print("PV Size %s / not usable %s", /* [LVM: %s]", */ 328 size, display_size(cmd, unusable)); 329 else 330 log_print("PV Size %s", size); 331 332 /* PV number not part of LVM2 design 333 log_print("PV# %u", pv->pv_number); 334 */ 335 336 pe_free = pv->pe_count - pv->pe_alloc_count; 337 if (pv->pe_count && (pv->status & ALLOCATABLE_PV)) 338 log_print("Allocatable yes %s", 339 (!pe_free && pv->pe_count) ? "(but full)" : ""); 340 else 341 log_print("Allocatable NO"); 342 343 /* LV count is no longer available when displaying PV 344 log_print("Cur LV %u", vg->lv_count); 345 */ 346 log_print("PE Size (KByte) %" PRIu32, pv->pe_size / 2); 347 log_print("Total PE %u", pv->pe_count); 348 log_print("Free PE %" PRIu32, pe_free); 349 log_print("Allocated PE %u", pv->pe_alloc_count); 350 log_print("PV UUID %s", *uuid ? uuid : "none"); 351 log_print(" "); 352 353 return; 354 } 355 356 int pvdisplay_short(const struct cmd_context *cmd __attribute((unused)), 357 const struct volume_group *vg __attribute((unused)), 358 const struct physical_volume *pv, 359 void *handle __attribute((unused))) 360 { 361 char uuid[64] __attribute((aligned(8))); 362 363 if (!pv) 364 return 0; 365 366 if (!id_write_format(&pv->id, uuid, sizeof(uuid))) 367 return_0; 368 369 log_print("PV Name %s ", pv_dev_name(pv)); 370 /* FIXME pv->pv_number); */ 371 log_print("PV UUID %s", *uuid ? uuid : "none"); 372 log_print("PV Status %sallocatable", 373 (pv->status & ALLOCATABLE_PV) ? "" : "NOT "); 374 log_print("Total PE / Free PE %u / %u", 375 pv->pe_count, pv->pe_count - pv->pe_alloc_count); 376 377 log_print(" "); 378 return 0; 379 } 380 381 void lvdisplay_colons(const struct logical_volume *lv) 382 { 383 int inkernel; 384 struct lvinfo info; 385 inkernel = lv_info(lv->vg->cmd, lv, &info, 1, 0) && info.exists; 386 387 log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d", 388 lv->vg->cmd->dev_dir, 389 lv->vg->name, 390 lv->name, 391 lv->vg->name, 392 (lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0, 393 /* FIXME lv->lv_number, */ 394 inkernel ? info.open_count : 0, lv->size, lv->le_count, 395 /* FIXME Add num allocated to struct! lv->lv_allocated_le, */ 396 (lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead, 397 inkernel ? info.major : -1, inkernel ? info.minor : -1); 398 return; 399 } 400 401 int lvdisplay_full(struct cmd_context *cmd, 402 const struct logical_volume *lv, 403 void *handle __attribute((unused))) 404 { 405 struct lvinfo info; 406 int inkernel, snap_active = 0; 407 char uuid[64] __attribute((aligned(8))); 408 struct lv_segment *snap_seg = NULL; 409 float snap_percent; /* fused, fsize; */ 410 411 if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) 412 return_0; 413 414 inkernel = lv_info(cmd, lv, &info, 1, 1) && info.exists; 415 416 log_print("--- Logical volume ---"); 417 418 log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir, 419 lv->vg->name, lv->name); 420 log_print("VG Name %s", lv->vg->name); 421 422 log_print("LV UUID %s", uuid); 423 424 log_print("LV Write Access %s", 425 (lv->status & LVM_WRITE) ? "read/write" : "read only"); 426 427 if (lv_is_origin(lv)) { 428 log_print("LV snapshot status source of"); 429 430 dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs, 431 origin_list) { 432 if (inkernel && 433 (snap_active = lv_snapshot_percent(snap_seg->cow, 434 &snap_percent))) 435 if (snap_percent < 0 || snap_percent >= 100) 436 snap_active = 0; 437 log_print(" %s%s/%s [%s]", 438 lv->vg->cmd->dev_dir, lv->vg->name, 439 snap_seg->cow->name, 440 (snap_active > 0) ? "active" : "INACTIVE"); 441 } 442 snap_seg = NULL; 443 } else if ((snap_seg = find_cow(lv))) { 444 if (inkernel && 445 (snap_active = lv_snapshot_percent(snap_seg->cow, 446 &snap_percent))) 447 if (snap_percent < 0 || snap_percent >= 100) 448 snap_active = 0; 449 450 log_print("LV snapshot status %s destination for %s%s/%s", 451 (snap_active > 0) ? "active" : "INACTIVE", 452 lv->vg->cmd->dev_dir, lv->vg->name, 453 snap_seg->origin->name); 454 } 455 456 if (inkernel && info.suspended) 457 log_print("LV Status suspended"); 458 else 459 log_print("LV Status %savailable", 460 inkernel ? "" : "NOT "); 461 462 /********* FIXME lv_number 463 log_print("LV # %u", lv->lv_number + 1); 464 ************/ 465 466 if (inkernel) 467 log_print("# open %u", info.open_count); 468 469 log_print("LV Size %s", 470 display_size(cmd, 471 snap_seg ? snap_seg->origin->size : lv->size)); 472 473 log_print("Current LE %u", 474 snap_seg ? snap_seg->origin->le_count : lv->le_count); 475 476 if (snap_seg) { 477 log_print("COW-table size %s", 478 display_size(cmd, (uint64_t) lv->size)); 479 log_print("COW-table LE %u", lv->le_count); 480 481 if (snap_active) 482 log_print("Allocated to snapshot %.2f%% ", snap_percent); 483 484 log_print("Snapshot chunk size %s", 485 display_size(cmd, (uint64_t) snap_seg->chunk_size)); 486 } 487 488 log_print("Segments %u", dm_list_size(&lv->segments)); 489 490 /********* FIXME Stripes & stripesize for each segment 491 log_print("Stripe size (KByte) %u", lv->stripesize / 2); 492 ***********/ 493 494 log_print("Allocation %s", get_alloc_string(lv->alloc)); 495 if (lv->read_ahead == DM_READ_AHEAD_AUTO) 496 log_print("Read ahead sectors auto"); 497 else if (lv->read_ahead == DM_READ_AHEAD_NONE) 498 log_print("Read ahead sectors 0"); 499 else 500 log_print("Read ahead sectors %u", lv->read_ahead); 501 502 if (inkernel && lv->read_ahead != info.read_ahead) 503 log_print("- currently set to %u", info.read_ahead); 504 505 if (lv->status & FIXED_MINOR) { 506 if (lv->major >= 0) 507 log_print("Persistent major %d", lv->major); 508 log_print("Persistent minor %d", lv->minor); 509 } 510 511 if (inkernel) 512 log_print("Block device %d:%d", info.major, 513 info.minor); 514 515 log_print(" "); 516 517 return 0; 518 } 519 520 void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre) 521 { 522 switch (seg_type(seg, s)) { 523 case AREA_PV: 524 /* FIXME Re-check the conditions for 'Missing' */ 525 log_print("%sPhysical volume\t%s", pre, 526 seg_pv(seg, s) ? 527 pv_dev_name(seg_pv(seg, s)) : 528 "Missing"); 529 530 if (seg_pv(seg, s)) 531 log_print("%sPhysical extents\t%d to %d", pre, 532 seg_pe(seg, s), 533 seg_pe(seg, s) + seg->area_len - 1); 534 break; 535 case AREA_LV: 536 log_print("%sLogical volume\t%s", pre, 537 seg_lv(seg, s) ? 538 seg_lv(seg, s)->name : "Missing"); 539 540 if (seg_lv(seg, s)) 541 log_print("%sLogical extents\t%d to %d", pre, 542 seg_le(seg, s), 543 seg_le(seg, s) + seg->area_len - 1); 544 break; 545 case AREA_UNASSIGNED: 546 log_print("%sUnassigned area", pre); 547 } 548 } 549 550 int lvdisplay_segments(const struct logical_volume *lv) 551 { 552 const struct lv_segment *seg; 553 554 log_print("--- Segments ---"); 555 556 dm_list_iterate_items(seg, &lv->segments) { 557 log_print("Logical extent %u to %u:", 558 seg->le, seg->le + seg->len - 1); 559 560 log_print(" Type\t\t%s", seg->segtype->ops->name(seg)); 561 562 if (seg->segtype->ops->display) 563 seg->segtype->ops->display(seg); 564 } 565 566 log_print(" "); 567 return 1; 568 } 569 570 void vgdisplay_extents(const struct volume_group *vg __attribute((unused))) 571 { 572 return; 573 } 574 575 void vgdisplay_full(const struct volume_group *vg) 576 { 577 uint32_t access_str; 578 uint32_t active_pvs; 579 uint32_t lv_count = 0; 580 struct lv_list *lvl; 581 char uuid[64] __attribute((aligned(8))); 582 583 active_pvs = vg->pv_count - vg_missing_pv_count(vg); 584 585 log_print("--- Volume group ---"); 586 log_print("VG Name %s", vg->name); 587 log_print("System ID %s", vg->system_id); 588 log_print("Format %s", vg->fid->fmt->name); 589 if (vg->fid->fmt->features & FMT_MDAS) { 590 log_print("Metadata Areas %d", 591 dm_list_size(&vg->fid->metadata_areas)); 592 log_print("Metadata Sequence No %d", vg->seqno); 593 } 594 access_str = vg->status & (LVM_READ | LVM_WRITE); 595 log_print("VG Access %s%s%s%s", 596 access_str == (LVM_READ | LVM_WRITE) ? "read/write" : "", 597 access_str == LVM_READ ? "read" : "", 598 access_str == LVM_WRITE ? "write" : "", 599 access_str == 0 ? "error" : ""); 600 log_print("VG Status %s%sresizable", 601 vg->status & EXPORTED_VG ? "exported/" : "", 602 vg->status & RESIZEABLE_VG ? "" : "NOT "); 603 /* vg number not part of LVM2 design 604 log_print ("VG # %u\n", vg->vg_number); 605 */ 606 if (vg_is_clustered(vg)) { 607 log_print("Clustered yes"); 608 log_print("Shared %s", 609 vg->status & SHARED ? "yes" : "no"); 610 } 611 612 dm_list_iterate_items(lvl, &vg->lvs) 613 if (lv_is_visible(lvl->lv) && !(lvl->lv->status & SNAPSHOT)) 614 lv_count++; 615 616 log_print("MAX LV %u", vg->max_lv); 617 log_print("Cur LV %u", lv_count); 618 log_print("Open LV %u", lvs_in_vg_opened(vg)); 619 /****** FIXME Max LV Size 620 log_print ( "MAX LV Size %s", 621 ( s1 = display_size ( LVM_LV_SIZE_MAX(vg)))); 622 free ( s1); 623 *********/ 624 log_print("Max PV %u", vg->max_pv); 625 log_print("Cur PV %u", vg->pv_count); 626 log_print("Act PV %u", active_pvs); 627 628 log_print("VG Size %s", 629 display_size(vg->cmd, 630 (uint64_t) vg->extent_count * vg->extent_size)); 631 632 log_print("PE Size %s", 633 display_size(vg->cmd, (uint64_t) vg->extent_size)); 634 635 log_print("Total PE %u", vg->extent_count); 636 637 log_print("Alloc PE / Size %u / %s", 638 vg->extent_count - vg->free_count, 639 display_size(vg->cmd, 640 ((uint64_t) vg->extent_count - vg->free_count) * 641 vg->extent_size)); 642 643 log_print("Free PE / Size %u / %s", vg->free_count, 644 display_size(vg->cmd, 645 (uint64_t) vg->free_count * vg->extent_size)); 646 647 if (!id_write_format(&vg->id, uuid, sizeof(uuid))) { 648 stack; 649 return; 650 } 651 652 log_print("VG UUID %s", uuid); 653 log_print(" "); 654 655 return; 656 } 657 658 void vgdisplay_colons(const struct volume_group *vg) 659 { 660 uint32_t active_pvs; 661 uint32_t lv_count; 662 struct lv_list *lvl; 663 const char *access_str; 664 char uuid[64] __attribute((aligned(8))); 665 666 active_pvs = vg->pv_count - vg_missing_pv_count(vg); 667 668 dm_list_iterate_items(lvl, &vg->lvs) 669 if (lv_is_visible(lvl->lv) && !(lvl->lv->status & SNAPSHOT)) 670 lv_count++; 671 672 switch (vg->status & (LVM_READ | LVM_WRITE)) { 673 case LVM_READ | LVM_WRITE: 674 access_str = "r/w"; 675 break; 676 case LVM_READ: 677 access_str = "r"; 678 break; 679 case LVM_WRITE: 680 access_str = "w"; 681 break; 682 default: 683 access_str = ""; 684 } 685 686 if (!id_write_format(&vg->id, uuid, sizeof(uuid))) { 687 stack; 688 return; 689 } 690 691 log_print("%s:%s:%d:-1:%u:%u:%u:-1:%u:%u:%u:%" PRIu64 ":%" PRIu32 692 ":%u:%u:%u:%s", 693 vg->name, 694 access_str, 695 vg->status, 696 /* internal volume group number; obsolete */ 697 vg->max_lv, 698 vg->lv_count, 699 lvs_in_vg_opened(vg), 700 /* FIXME: maximum logical volume size */ 701 vg->max_pv, 702 vg->pv_count, 703 active_pvs, 704 (uint64_t) vg->extent_count * (vg->extent_size / 2), 705 vg->extent_size / 2, 706 vg->extent_count, 707 vg->extent_count - vg->free_count, 708 vg->free_count, 709 uuid[0] ? uuid : "none"); 710 return; 711 } 712 713 void vgdisplay_short(const struct volume_group *vg) 714 { 715 log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name, 716 /********* FIXME if "open" print "/used" else print "/idle"??? ******/ 717 display_size(vg->cmd, 718 (uint64_t) vg->extent_count * vg->extent_size), 719 display_size(vg->cmd, 720 ((uint64_t) vg->extent_count - 721 vg->free_count) * vg->extent_size), 722 display_size(vg->cmd, 723 (uint64_t) vg->free_count * vg->extent_size)); 724 return; 725 } 726 727 void display_formats(const struct cmd_context *cmd) 728 { 729 const struct format_type *fmt; 730 731 dm_list_iterate_items(fmt, &cmd->formats) { 732 log_print("%s", fmt->name); 733 } 734 } 735 736 void display_segtypes(const struct cmd_context *cmd) 737 { 738 const struct segment_type *segtype; 739 740 dm_list_iterate_items(segtype, &cmd->segtypes) { 741 log_print("%s", segtype->name); 742 } 743 } 744 745 char yes_no_prompt(const char *prompt, ...) 746 { 747 int c = 0, ret = 0; 748 va_list ap; 749 750 sigint_allow(); 751 do { 752 if (c == '\n' || !c) { 753 va_start(ap, prompt); 754 vprintf(prompt, ap); 755 va_end(ap); 756 } 757 758 if ((c = getchar()) == EOF) { 759 ret = 'n'; 760 break; 761 } 762 763 c = tolower(c); 764 if ((c == 'y') || (c == 'n')) 765 ret = c; 766 } while (!ret || c != '\n'); 767 768 sigint_restore(); 769 770 if (c != '\n') 771 printf("\n"); 772 773 return ret; 774 } 775 776