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