summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlasdair Kergon <agk@redhat.com>2002-12-12 20:55:49 +0000
committerAlasdair Kergon <agk@redhat.com>2002-12-12 20:55:49 +0000
commit4c64ed4ced7dcd3a98a63da1cd3a6f2f1f2d1701 (patch)
tree2c0968a82423acbddbc610bfea5518b212429f91
parenteb537fa130c9c9fca9c10319b2b955d800ba3742 (diff)
downloadlvm2-4c64ed4ced7dcd3a98a63da1cd3a6f2f1f2d1701.tar.gz
lvm2-4c64ed4ced7dcd3a98a63da1cd3a6f2f1f2d1701.tar.xz
lvm2-4c64ed4ced7dcd3a98a63da1cd3a6f2f1f2d1701.zip
New column-based reporting tools: lvs, pvs & vgs.
-rw-r--r--VERSION2
-rw-r--r--include/.symlinks1
-rw-r--r--lib/Makefile.in1
-rw-r--r--lib/commands/toolcontext.c15
-rw-r--r--lib/commands/toolcontext.h3
-rw-r--r--lib/config/config.c2
-rw-r--r--lib/config/config.h4
-rw-r--r--lib/config/defaults.h22
-rw-r--r--lib/datastruct/list.h25
-rw-r--r--lib/display/display.c216
-rw-r--r--lib/display/display.h9
-rw-r--r--lib/format1/format1.c27
-rw-r--r--lib/log/log.h7
-rw-r--r--lib/report/columns.h52
-rw-r--r--lib/report/report.c1067
-rw-r--r--lib/report/report.h43
-rw-r--r--libdm/datastruct/list.h25
-rw-r--r--man/Makefile.in6
-rw-r--r--man/lvs.864
-rw-r--r--man/pvs.854
-rw-r--r--man/vgs.858
-rw-r--r--tools/Makefile.in5
-rw-r--r--tools/args.h9
-rw-r--r--tools/commands.h174
-rw-r--r--tools/lvcreate.c12
-rw-r--r--tools/lvdisplay.c15
-rw-r--r--tools/lvm.c14
-rw-r--r--tools/lvmdiskscan.c21
-rw-r--r--tools/lvresize.c23
-rw-r--r--tools/lvscan.c9
-rw-r--r--tools/pvcreate.c4
-rw-r--r--tools/pvdisplay.c66
-rw-r--r--tools/pvscan.c41
-rw-r--r--tools/report.c235
-rw-r--r--tools/toollib.c65
-rw-r--r--tools/toollib.h13
-rw-r--r--tools/tools.h14
-rw-r--r--tools/vgck.c1
-rw-r--r--tools/vgconvert.c2
-rw-r--r--tools/vgdisplay.c17
40 files changed, 2193 insertions, 250 deletions
diff --git a/VERSION b/VERSION
index 146b0f6a..91055e9a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.95.11-cvs (2002-11-18)
+1.95.12-cvs (2002-12-12)
diff --git a/include/.symlinks b/include/.symlinks
index 30c49c87..b8232bb9 100644
--- a/include/.symlinks
+++ b/include/.symlinks
@@ -32,4 +32,5 @@
../lib/misc/lvm-string.h
../lib/misc/sharedlib.h
../lib/regex/matcher.h
+../lib/report/report.h
../lib/uuid/uuid.h
diff --git a/lib/Makefile.in b/lib/Makefile.in
index d208a2e7..32399606 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -56,6 +56,7 @@ SOURCES=\
regex/matcher.c \
regex/parse_rx.c \
regex/ttree.c \
+ report/report.c \
uuid/uuid.c
ifeq ("@LVM1@", "internal")
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index c3fcbda2..2019720a 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -20,6 +20,7 @@
#include "lvm-file.h"
#include "format-text.h"
#include "sharedlib.h"
+#include "display.h"
#ifdef LVM1_INTERNAL
#include "format1.h"
@@ -153,6 +154,20 @@ static int _process_config(struct cmd_context *cmd)
DEFAULT_ACTIVATION);
set_activation(cmd->default_settings.activation);
+ cmd->default_settings.suffix = find_config_int(cmd->cf->root,
+ "global/suffix",
+ '/', DEFAULT_SUFFIX);
+
+ if (!(cmd->default_settings.unit_factor =
+ units_to_bytes(find_config_str(cmd->cf->root,
+ "global/units",
+ '/',
+ DEFAULT_UNITS),
+ &cmd->default_settings.unit_type))) {
+ log_error("Invalid units specification");
+ return 0;
+ }
+
return 1;
}
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index 396cea7c..f3ecddf3 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -25,6 +25,9 @@ struct config_info {
int test;
int syslog;
int activation;
+ int suffix;
+ uint64_t unit_factor;
+ char unit_type;
const char *msg_prefix;
int cmd_name; /* Show command name? */
diff --git a/lib/config/config.c b/lib/config/config.c
index d2105afa..3bd9765e 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -715,7 +715,7 @@ struct config_node *find_config_node(struct config_node *cn,
}
const char *find_config_str(struct config_node *cn,
- const char *path, char sep, const char *fail)
+ const char *path, const char sep, const char *fail)
{
struct config_node *n = find_config_node(cn, path, sep);
diff --git a/lib/config/config.h b/lib/config/config.h
index f1ceda0a..d2c05fe4 100644
--- a/lib/config/config.h
+++ b/lib/config/config.h
@@ -51,10 +51,10 @@ int write_config_file(struct config_tree *cf, const char *file);
int reload_config_file(struct config_tree **cf);
struct config_node *find_config_node(struct config_node *cn,
- const char *path, char seperator);
+ const char *path, char separator);
const char *find_config_str(struct config_node *cn,
- const char *path, char sep, const char *fail);
+ const char *path, const char sep, const char *fail);
int find_config_int(struct config_node *cn, const char *path,
char sep, int fail);
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index eeaf647a..7a35aacc 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -47,6 +47,8 @@
#define DEFAULT_VERBOSE 0
#define DEFAULT_LOGLEVEL 0
#define DEFAULT_INDENT 1
+#define DEFAULT_UNITS "h"
+#define DEFAULT_SUFFIX 1
#define DEFAULT_ACTIVATION 1
@@ -54,4 +56,24 @@
#define DEFAULT_MAX_HISTORY 100
#endif
+#define DEFAULT_REP_ALIGNED 1
+#define DEFAULT_REP_BUFFERED 1
+#define DEFAULT_REP_HEADINGS 1
+#define DEFAULT_REP_SEPARATOR " "
+
+#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent"
+#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
+#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
+#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
+
+#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_minor,origin,snap_percent,lv_uuid"
+#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
+#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_uuid"
+#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
+
+#define DEFAULT_LVS_SORT "vg_name,lv_name"
+#define DEFAULT_VGS_SORT "vg_name"
+#define DEFAULT_PVS_SORT "pv_name"
+#define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
+
#endif /* _LVM_DEFAULTS_H */
diff --git a/lib/datastruct/list.h b/lib/datastruct/list.h
index 5f2e14c1..4aeb7b40 100644
--- a/lib/datastruct/list.h
+++ b/lib/datastruct/list.h
@@ -13,11 +13,13 @@ struct list {
struct list *n, *p;
};
-static inline void list_init(struct list *head) {
+static inline void list_init(struct list *head)
+{
head->n = head->p = head;
}
-static inline void list_add(struct list *head, struct list *elem) {
+static inline void list_add(struct list *head, struct list *elem)
+{
assert(head->n);
elem->n = head;
@@ -27,7 +29,8 @@ static inline void list_add(struct list *head, struct list *elem) {
head->p = elem;
}
-static inline void list_add_h(struct list *head, struct list *elem) {
+static inline void list_add_h(struct list *head, struct list *elem)
+{
assert(head->n);
elem->n = head->n;
@@ -37,27 +40,35 @@ static inline void list_add_h(struct list *head, struct list *elem) {
head->n = elem;
}
-static inline void list_del(struct list *elem) {
+static inline void list_del(struct list *elem)
+{
elem->n->p = elem->p;
elem->p->n = elem->n;
}
-static inline int list_empty(struct list *head) {
+static inline int list_empty(struct list *head)
+{
return head->n == head;
}
+static inline int list_end(struct list *head, struct list *elem)
+{
+ return elem->n == head;
+}
+
#define list_iterate(v, head) \
for (v = (head)->n; v != head; v = v->n)
#define list_iterate_safe(v, t, head) \
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
-static inline int list_size(struct list *head) {
+static inline int list_size(struct list *head)
+{
int s = 0;
struct list *v;
list_iterate(v, head)
- s++;
+ s++;
return s;
}
diff --git a/lib/display/display.c b/lib/display/display.c
index f96d1500..8574fb3d 100644
--- a/lib/display/display.c
+++ b/lib/display/display.c
@@ -49,6 +49,72 @@ static struct {
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
static int _num_segtypes = sizeof(_segtypes) / sizeof(*_segtypes);
+uint64_t units_to_bytes(const char *units, char *unit_type)
+{
+
+ char *ptr;
+ uint64_t v;
+
+ ptr = (char *) units;
+
+ if (isdigit(*units)) {
+ v = (uint64_t) strtod(units, &ptr);
+ if (ptr == units)
+ return 0;
+ } else
+ v = 1;
+
+ if (v == 1)
+ *unit_type = *ptr;
+ else
+ *unit_type = 'U';
+
+ switch (*ptr) {
+ case 'h':
+ case 'H':
+ v = 1ULL;
+ *unit_type = *ptr;
+ break;
+ case 's':
+ v *= SECTOR_SIZE;
+ case 'b':
+ case 'B':
+ v *= 1ULL;
+ break;
+ case 'k':
+ v *= 1024ULL;
+ break;
+ case 'm':
+ v *= 1024ULL * 1024ULL;
+ break;
+ case 'g':
+ v *= 1024ULL * 1024ULL * 1024ULL;
+ break;
+ case 't':
+ v *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
+ break;
+ case 'K':
+ v *= 1000ULL;
+ break;
+ case 'M':
+ v *= 1000ULL * 1000ULL;
+ break;
+ case 'G':
+ v *= 1000ULL * 1000ULL * 1000ULL;
+ break;
+ case 'T':
+ v *= 1000ULL * 1000ULL * 1000ULL * 1000ULL;
+ break;
+ default:
+ return 0;
+ }
+
+ if (*(ptr + 1))
+ return 0;
+
+ return v;
+}
+
const char *get_alloc_string(alloc_policy_t alloc)
{
int i;
@@ -68,7 +134,7 @@ const char *get_segtype_string(segment_type_t segtype)
if (_segtypes[i].segtype == segtype)
return _segtypes[i].str;
- return NULL;
+ return "unknown";
}
alloc_policy_t get_alloc_from_string(const char *str)
@@ -95,36 +161,60 @@ segment_type_t get_segtype_from_string(const char *str)
return SEG_STRIPED;
}
-char *display_size(uint64_t size, size_len_t sl)
+const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
{
int s;
- ulong byte = 1024 * 1024 * 1024;
+ int suffix = 1;
+ uint64_t byte;
+ uint64_t units = 1024ULL;
char *size_buf = NULL;
- char *size_str[][2] = {
- {" Terabyte", "TB"},
- {" Gigabyte", "GB"},
- {" Megabyte", "MB"},
- {" Kilobyte", "KB"},
- {"", ""},
- {" ", " "}
+ char *size_str[][3] = {
+ {" Terabyte", " TB", "T"},
+ {" Gigabyte", " GB", "G"},
+ {" Megabyte", " MB", "M"},
+ {" Kilobyte", " KB", "K"},
+ {"", "", ""},
+ {" Byte ", " B ", "B"},
+ {" Units ", " Un", "U"},
+ {" Sectors ", " Se", "S"},
+ {" ", " ", " "},
};
- if (!(size_buf = dbg_malloc(SIZE_BUF))) {
+ if (!(size_buf = pool_alloc(cmd->mem, SIZE_BUF))) {
log_error("no memory for size display buffer");
- return NULL;
+ return "";
+ }
+
+ suffix = cmd->current_settings.suffix;
+
+ for (s = 0; s < 8; s++)
+ if (toupper((int) cmd->current_settings.unit_type) ==
+ *size_str[s][2])
+ break;
+
+ if (size == 0ULL) {
+ sprintf(size_buf, "0%s", suffix ? size_str[s][sl] : "");
+ return size_buf;
}
- if (size == 0LL)
- sprintf(size_buf, "0%s", size_str[5][sl]);
- else {
+ if (s < 8) {
+ byte = cmd->current_settings.unit_factor;
+ size *= 1024ULL;
+ } else {
+ suffix = 1;
+ if (cmd->current_settings.unit_type == 'H')
+ units = 1000ULL;
+ else
+ units = 1024ULL;
+ byte = units * units * units;
s = 0;
while (size_str[s] && size < byte)
- s++, byte /= 1024;
- snprintf(size_buf, SIZE_BUF - 1,
- "%.2f%s", (float) size / byte, size_str[s][sl]);
+ s++, byte /= units;
}
- /* Caller to deallocate */
+ snprintf(size_buf, SIZE_BUF - 1, "%.2f%s", (float) size / byte,
+ suffix ? size_str[s][sl] : "");
+
return size_buf;
}
@@ -155,10 +245,11 @@ void pvdisplay_colons(struct physical_volume *pv)
}
/* FIXME Include label fields */
-void pvdisplay_full(struct physical_volume *pv, void *handle)
+void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
+ void *handle)
{
char uuid[64];
- char *size, *size1; /*, *size2; */
+ const char *size;
uint64_t pe_free;
@@ -175,23 +266,21 @@ void pvdisplay_full(struct physical_volume *pv, void *handle)
log_print("VG Name %s%s", pv->vg_name,
pv->status & EXPORTED_VG ? " (exported)" : "");
- size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
+ size = display_size(cmd, (uint64_t) pv->size / 2, SIZE_SHORT);
if (pv->pe_size && pv->pe_count) {
- size1 = display_size((pv->size - pv->pe_count * pv->pe_size)
- / 2, SIZE_SHORT);
/******** FIXME display LVM on-disk data size
size2 = display_size(pv->size / 2, SIZE_SHORT);
********/
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
- size, size1); /* , size2); */
+ size, display_size(cmd,
+ (pv->size -
+ pv->pe_count * pv->pe_size) / 2,
+ SIZE_SHORT));
- dbg_free(size1);
- /* dbg_free(size2); */
} else
log_print("PV Size %s", size);
- dbg_free(size);
/* PV number not part of LVM2 design
log_print("PV# %u", pv->pv_number);
@@ -265,7 +354,6 @@ void lvdisplay_colons(struct logical_volume *lv)
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
- char *size;
struct dm_info info;
int inkernel, snap_active;
char uuid[64];
@@ -326,10 +414,10 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
if (inkernel)
log_print("# open %u", info.open_count);
- size = display_size(snap ? snap->origin->size / 2 : lv->size / 2,
- SIZE_SHORT);
- log_print("LV Size %s", size);
- dbg_free(size);
+ log_print("LV Size %s",
+ display_size(cmd,
+ snap ? snap->origin->size / 2 : lv->size / 2,
+ SIZE_SHORT));
log_print("Current LE %u",
snap ? snap->origin->le_count : lv->le_count);
@@ -348,9 +436,8 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
if (snap_percent == -1)
snap_percent = 100;
- size = display_size(snap->chunk_size / 2, SIZE_SHORT);
- log_print("Snapshot chunk size %s", size);
- dbg_free(size);
+ log_print("Snapshot chunk size %s",
+ display_size(cmd, snap->chunk_size / 2, SIZE_SHORT));
/*
size = display_size(lv->size / 2, SIZE_SHORT);
@@ -451,7 +538,6 @@ void vgdisplay_full(struct volume_group *vg)
{
uint32_t access;
uint32_t active_pvs;
- char *s1;
char uuid[64];
if (vg->status & PARTIAL_VG)
@@ -497,28 +583,33 @@ void vgdisplay_full(struct volume_group *vg)
log_print("Cur PV %u", vg->pv_count);
log_print("Act PV %u", active_pvs);
- s1 = display_size((uint64_t) vg->extent_count * (vg->extent_size / 2),
- SIZE_SHORT);
- log_print("VG Size %s", s1);
- dbg_free(s1);
+ log_print("VG Size %s",
+ display_size(vg->cmd,
+ (uint64_t) vg->extent_count * (vg->extent_size /
+ 2), SIZE_SHORT));
- s1 = display_size(vg->extent_size / 2, SIZE_SHORT);
- log_print("PE Size %s", s1);
- dbg_free(s1);
+ log_print("PE Size %s",
+ display_size(vg->cmd, vg->extent_size / 2, SIZE_SHORT));
log_print("Total PE %u", vg->extent_count);
- s1 = display_size(((uint64_t)
- vg->extent_count - vg->free_count) *
- (vg->extent_size / 2), SIZE_SHORT);
log_print("Alloc PE / Size %u / %s",
- vg->extent_count - vg->free_count, s1);
- dbg_free(s1);
-
- s1 = display_size((uint64_t) vg->free_count * (vg->extent_size / 2),
- SIZE_SHORT);
- log_print("Free PE / Size %u / %s", vg->free_count, s1);
- dbg_free(s1);
+ vg->extent_count - vg->free_count, display_size(vg->cmd,
+ ((uint64_t)
+ vg->
+ extent_count
+ -
+ vg->
+ free_count) *
+ (vg->
+ extent_size /
+ 2),
+ SIZE_SHORT));
+
+ log_print("Free PE / Size %u / %s", vg->free_count,
+ display_size(vg->cmd,
+ (uint64_t) vg->free_count * (vg->extent_size /
+ 2), SIZE_SHORT));
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
stack;
@@ -538,16 +629,15 @@ void vgdisplay_colons(struct volume_group *vg)
void vgdisplay_short(struct volume_group *vg)
{
- char *s1, *s2, *s3;
- s1 = display_size(vg->extent_count * vg->extent_size / 2, SIZE_SHORT);
- s2 = display_size((vg->extent_count -
- vg->free_count) * vg->extent_size / 2, SIZE_SHORT);
- s3 = display_size(vg->free_count * vg->extent_size / 2, SIZE_SHORT);
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
- s1, s2, s3);
- dbg_free(s1);
- dbg_free(s2);
- dbg_free(s3);
+ display_size(vg->cmd, vg->extent_count * vg->extent_size / 2,
+ SIZE_SHORT), display_size(vg->cmd,
+ (vg->extent_count -
+ vg->free_count) *
+ vg->extent_size / 2,
+ SIZE_SHORT),
+ display_size(vg->cmd, vg->free_count * vg->extent_size / 2,
+ SIZE_SHORT));
return;
}
diff --git a/lib/display/display.h b/lib/display/display.h
index 3b59a5ee..578843fb 100644
--- a/lib/display/display.h
+++ b/lib/display/display.h
@@ -25,14 +25,17 @@
#include <stdint.h>
-typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1 } size_len_t;
+typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
+
+uint64_t units_to_bytes(const char *units, char *unit_type);
/* Specify size in KB */
-char *display_size(uint64_t size, size_len_t sl);
+const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
char *display_uuid(char *uuidstr);
void pvdisplay_colons(struct physical_volume *pv);
-void pvdisplay_full(struct physical_volume *pv, void *handle);
+void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
+ void *handle);
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv, void *handle);
diff --git a/lib/format1/format1.c b/lib/format1/format1.c
index 7e720539..e2953361 100644
--- a/lib/format1/format1.c
+++ b/lib/format1/format1.c
@@ -297,14 +297,11 @@ static int _pv_setup(struct format_type *fmt,
uint64_t pvmetadatasize, struct list *mdas,
struct physical_volume *pv, struct volume_group *vg)
{
- char *sz;
-
if (pv->size > MAX_PV_SIZE)
pv->size--;
if (pv->size > MAX_PV_SIZE) {
log_error("Physical volumes cannot be bigger than %s",
- sz = display_size(MAX_PV_SIZE / 2, SIZE_SHORT));
- dbg_free(sz);
+ display_size(fmt->cmd, MAX_PV_SIZE / 2, SIZE_SHORT));
return 0;
}
@@ -365,9 +362,9 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
return 0;
}
if (lv->size > max_size) {
- char *dummy = display_size(max_size / 2, SIZE_SHORT);
- log_error("logical volumes cannot be larger than %s", dummy);
- dbg_free(dummy);
+ log_error("logical volumes cannot be larger than %s",
+ display_size(fid->fmt->cmd, max_size / 2,
+ SIZE_SHORT));
return 0;
}
@@ -447,22 +444,20 @@ int _vg_setup(struct format_instance *fid, struct volume_group *vg)
vg->max_pv = MAX_PV - 1;
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
- char *dummy, *dummy2;
-
log_error("Extent size must be between %s and %s",
- (dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
- (dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
+ display_size(fid->fmt->cmd, MIN_PE_SIZE / 2,
+ SIZE_SHORT), display_size(fid->fmt->cmd,
+ MAX_PE_SIZE /
+ 2,
+ SIZE_SHORT));
- dbg_free(dummy);
- dbg_free(dummy2);
return 0;
}
if (vg->extent_size % MIN_PE_SIZE) {
- char *dummy;
log_error("Extent size must be multiple of %s",
- (dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
- dbg_free(dummy);
+ display_size(fid->fmt->cmd, MIN_PE_SIZE / 2,
+ SIZE_SHORT));
return 0;
}
diff --git a/lib/log/log.h b/lib/log/log.h
index 6ed54016..d46a2a86 100644
--- a/lib/log/log.h
+++ b/lib/log/log.h
@@ -28,8 +28,8 @@
*
*/
-#include <stdio.h> /* FILE */
-#include <string.h> /* strerror() */
+#include <stdio.h> /* FILE */
+#include <string.h> /* strerror() */
#include <errno.h>
#define _LOG_DEBUG 7
@@ -65,7 +65,7 @@ int ignorelockingfailure(void);
void log_suppress(int suppress);
void print_log(int level, const char *file, int line, const char *format, ...)
- __attribute__ (( format (printf, 4, 5) ));
+ __attribute__ ((format(printf, 4, 5)));
#define plog(l, x...) print_log(l, __FILE__, __LINE__ , ## x)
@@ -90,4 +90,3 @@ void print_log(int level, const char *file, int line, const char *format, ...)
log_info("%s: %s failed: %s", y, x, strerror(errno))
#endif
-
diff --git a/lib/report/columns.h b/lib/report/columns.h
new file mode 100644
index 00000000..b2eb3cad
--- /dev/null
+++ b/lib/report/columns.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the LGPL.
+ */
+
+/* Report type, Containing struct, Field type, Report heading,
+ * Data field with struct to pass to display function, Minimum display width,
+ * Display Fn, Unique format identifier */
+FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
+FIELD(LVS, lv, STR, "LV", name, 4, string, "lv_name")
+FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
+FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
+FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size")
+FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count")
+FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
+FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
+
+FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
+FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
+FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size")
+FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free")
+FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used")
+FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name")
+FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr")
+FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count")
+FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count")
+
+FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt")
+FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid")
+FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name")
+FIELD(VGS, vg, STR, "Attr", status, 4, vgstatus, "vg_attr")
+FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size")
+FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free")
+FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid")
+FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size")
+FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count")
+FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count")
+FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv")
+FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv")
+FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count")
+FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count")
+FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count")
+FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno")
+
+FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
+FIELD(SEGS, seg, NUM, "#Str", stripes, 4, uint32, "stripes")
+FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
+FIELD(SEGS, seg, NUM, "Chunk", chunk_size, 5, size32, "chunksize")
+FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
+FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
+
diff --git a/lib/report/report.c b/lib/report/report.c
new file mode 100644
index 00000000..f789380a
--- /dev/null
+++ b/lib/report/report.c
@@ -0,0 +1,1067 @@
+/*
+ * Copyright (C) 2002 Sistina Software
+ *
+ * This LVM library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This LVM library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this LVM library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ *
+ */
+
+#include "lib.h"
+#include "metadata.h"
+#include "report.h"
+#include "toolcontext.h"
+#include "pool.h"
+#include "lvm-string.h"
+#include "display.h"
+#include "activate.h"
+
+#include <sys/types.h>
+
+/*
+ * For macro use
+ */
+static union {
+ struct physical_volume _pv;
+ struct logical_volume _lv;
+ struct volume_group _vg;
+ struct lv_segment _seg;
+} _dummy;
+
+/*
+ * Report handle flags
+ */
+#define RH_SORT_REQUIRED 0x00000001
+#define RH_HEADINGS_PRINTED 0x00000002
+#define RH_BUFFERED 0x00000004
+#define RH_ALIGNED 0x00000008
+#define RH_HEADINGS 0x00000010
+
+struct report_handle {
+ struct cmd_context *cmd;
+ struct pool *mem;
+
+ report_type_t type;
+ char *field_prefix;
+ uint32_t flags;
+ const char *separator;
+
+ uint32_t keys_count;
+
+ /* Ordered list of fields needed for this report */
+ struct list field_props;
+
+ /* Rows of report data */
+ struct list rows;
+};
+
+/*
+ * Per-field flags
+ */
+#define FLD_ALIGN_LEFT 0x00000001
+#define FLD_ALIGN_RIGHT 0x00000002
+#define FLD_STRING 0x00000004
+#define FLD_NUMBER 0x00000008
+#define FLD_HIDDEN 0x00000010
+#define FLD_SORT_KEY 0x00000020
+#define FLD_ASCENDING 0x00000040
+#define FLD_DESCENDING 0x00000080
+
+struct field_properties {
+ struct list list;
+ uint32_t field_num;
+ uint32_t sort_posn;
+ int width;
+ uint32_t flags;
+};
+
+/*
+ * Report data
+ */
+struct field {
+ struct list list;
+ struct field_properties *props;
+
+ char *report_string; /* Formatted ready for display */
+ void *sort_value; /* Raw value for sorting */
+};
+
+struct row {
+ struct list list;
+ struct report_handle *rh;
+ struct list fields; /* Fields in display order */
+ struct field *(*sort_fields)[]; /* Fields in sort order */
+};
+
+/*
+ * Data-munging functions to prepare each data type for display and sorting
+ */
+static int _string_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ if (!(field->report_string = pool_strdup(rh->mem, *(char **) data))) {
+ log_error("pool_strdup failed");
+ return 0;
+ }
+
+ field->sort_value = (void *) field->report_string;
+
+ return 1;
+}
+
+static int _dev_name_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ const char *name = dev_name(*(struct device **) data);
+
+ return _string_disp(rh, field, &name);
+}
+
+static int _vgfmt_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct volume_group *vg = (struct volume_group *) data;
+
+ if (!vg->fid) {
+ field->report_string = "";
+ field->sort_value = (void *) field->report_string;
+ return 1;
+ }
+
+ return _string_disp(rh, field, &vg->fid->fmt->name);
+}
+
+static int _pvfmt_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct physical_volume *pv = (struct physical_volume *) data;
+
+ if (!pv->fmt) {
+ field->report_string = "";
+ field->sort_value = (void *) field->report_string;
+ return 1;
+ }
+
+ return _string_disp(rh, field, &pv->fmt->name);
+}
+
+static int _lvstatus_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct logical_volume *lv = (struct logical_volume *) data;
+ struct dm_info info;
+
+ if (!(field->report_string = pool_zalloc(rh->mem, 7))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ if (lv_is_origin(lv))
+ field->report_string[0] = 'o';
+ else if (find_cow(lv))
+ field->report_string[0] = 's';
+ else
+ field->report_string[0] = '-';
+
+ if (lv->status & LVM_WRITE)
+ field->report_string[1] = 'w';
+ else
+ field->report_string[1] = 'r';
+
+ if (lv->alloc == ALLOC_CONTIGUOUS)
+ field->report_string[2] = 'c';
+ else
+ field->report_string[2] = 'n';
+
+ if (lv->status & FIXED_MINOR)
+ field->report_string[3] = 'm'; /* Fixed Minor */
+ else
+ field->report_string[3] = '-';
+
+ if (lv_info(lv, &info) && info.exists) {
+ if (info.suspended)
+ field->report_string[4] = 's'; /* Suspended */
+ else
+ field->report_string[4] = 'a'; /* Active */
+ if (info.open_count)
+ field->report_string[5] = 'o'; /* Open */
+ else
+ field->report_string[5] = '-';
+ } else {
+ field->report_string[4] = '-';
+ field->report_string[5] = '-';
+ }
+
+ field->sort_value = (void *) field->report_string;
+
+ return 1;
+}
+
+static int _pvstatus_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ uint32_t status = *(uint32_t *) data;
+
+ if (!(field->report_string = pool_zalloc(rh->mem, 4))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ if (status & ALLOCATABLE_PV)
+ field->report_string[0] = 'a';
+ else
+ field->report_string[0] = '-';
+
+ if (status & EXPORTED_VG)
+ field->report_string[1] = 'x';
+ else
+ field->report_string[1] = '-';
+
+ field->sort_value = (void *) field->report_string;
+
+ return 1;
+}
+
+static int _vgstatus_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ uint32_t status = *(uint32_t *) data;
+
+ if (!(field->report_string = pool_zalloc(rh->mem, 5))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ if (status & LVM_WRITE)
+ field->report_string[0] = 'w';
+ else
+ field->report_string[0] = 'r';
+
+ if (status & RESIZEABLE_VG)
+ field->report_string[1] = 'z';
+ else
+ field->report_string[1] = '-';
+
+ if (status & EXPORTED_VG)
+ field->report_string[2] = 'x';
+ else
+ field->report_string[2] = '-';
+
+ if (status & PARTIAL_VG)
+ field->report_string[3] = 'p';
+ else
+ field->report_string[3] = '-';
+
+ field->sort_value = (void *) field->report_string;
+
+ return 1;
+}
+
+static int _segtype_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct lv_segment *seg = (struct lv_segment *) data;
+
+ if (seg->stripes == 1)
+ field->report_string = "linear";
+ else
+ field->report_string = (char *) get_segtype_string(seg->type);
+ field->sort_value = (void *) field->report_string;
+
+ return 1;
+}
+
+static int _origin_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct logical_volume *lv = (struct logical_volume *) data;
+ struct snapshot *snap;
+
+ if ((snap = find_cow(lv)))
+ return _string_disp(rh, field, &snap->origin->name);
+
+ field->report_string = "";
+ field->sort_value = (void *) field->report_string;
+
+ return 1;
+}
+
+static int _size32_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ uint32_t size = *(uint32_t *) data;
+ const char *disp;
+
+ if (!*(disp = display_size(rh->cmd, (uint64_t) size / 2, SIZE_UNIT))) {
+ stack;
+ return 0;
+ }
+
+ if (!(field->report_string = pool_strdup(rh->mem, disp))) {
+ log_error("pool_strdup failed");
+ return 0;
+ }
+
+ if (!(field->sort_value = pool_alloc(rh->mem, sizeof(uint64_t)))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ *(uint64_t *) field->sort_value = (uint64_t) size;
+
+ return 1;
+}
+
+static int _size64_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ uint64_t size = *(uint64_t *) data;
+ const char *disp;
+
+ if (!*(disp = display_size(rh->cmd, size / 2, SIZE_UNIT))) {
+ stack;
+ return 0;
+ }
+
+ if (!(field->report_string = pool_strdup(rh->mem, disp))) {
+ log_error("pool_strdup failed");
+ return 0;
+ }
+
+ if (!(field->sort_value = pool_alloc(rh->mem, sizeof(uint64_t)))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ *(uint64_t *) field->sort_value = size;
+
+ return 1;
+}
+
+static int _vgsize_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct volume_group *vg = (struct volume_group *) data;
+ uint64_t size;
+
+ size = vg->extent_count * vg->extent_size;
+
+ return _size64_disp(rh, field, &size);
+}
+
+static int _segstart_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct lv_segment *seg = (struct lv_segment *) data;
+ uint64_t start;
+
+ start = seg->le * seg->lv->vg->extent_size;
+
+ return _size64_disp(rh, field, &start);
+}
+
+static int _segsize_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct lv_segment *seg = (struct lv_segment *) data;
+ uint64_t size;
+
+ size = seg->len * seg->lv->vg->extent_size;
+
+ return _size64_disp(rh, field, &size);
+}
+
+static int _pvused_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct physical_volume *pv = (struct physical_volume *) data;
+ uint64_t used;
+
+ if (!pv->pe_count)
+ used = 0LL;
+ else
+ used = pv->pe_alloc_count * pv->pe_size;
+
+ return _size64_disp(rh, field, &used);
+}
+
+static int _pvfree_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct physical_volume *pv = (struct physical_volume *) data;
+ uint64_t free;
+
+ if (!pv->pe_count)
+ free = pv->size;
+ else
+ free = (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
+
+ return _size64_disp(rh, field, &free);
+}
+
+static int _pvsize_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct physical_volume *pv = (struct physical_volume *) data;
+ uint64_t size;
+
+ if (!pv->pe_count)
+ size = pv->size;
+ else
+ size = pv->pe_count * pv->pe_size;
+
+ return _size64_disp(rh, field, &size);
+}
+
+static int _vgfree_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct volume_group *vg = (struct volume_group *) data;
+ uint64_t free;
+
+ free = vg->free_count * vg->extent_size;
+
+ return _size64_disp(rh, field, &free);
+}
+
+static int _uuid_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ if (!(field->report_string = pool_alloc(rh->mem, 40))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ if (!id_write_format((struct id *) data, field->report_string, 40)) {
+ stack;
+ return 0;
+ }
+
+ field->sort_value = (void *) field->report_string;
+
+ return 1;
+}
+
+static int _uint32_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ uint32_t value = *(uint32_t *) data;
+
+ if (!(field->report_string = pool_zalloc(rh->mem, 12))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ if (!(field->sort_value = pool_alloc(rh->mem, sizeof(uint64_t)))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ *(uint64_t *) field->sort_value = value;
+
+ if (lvm_snprintf(field->report_string, 11, "%u", value) < 0) {
+ log_error("uint32 too big: %u", value);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _int32_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ int32_t value = *(int32_t *) data;
+
+ if (!(field->report_string = pool_zalloc(rh->mem, 13))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ if (!(field->sort_value = pool_alloc(rh->mem, sizeof(int64_t)))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ *(int64_t *) field->sort_value = value;
+
+ if (lvm_snprintf(field->report_string, 12, "%d", value) < 0) {
+ log_error("int32 too big: %d", value);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _lvsegcount_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct logical_volume *lv = (struct logical_volume *) data;
+ uint32_t count;
+
+ count = list_size(&lv->segments);
+
+ return _uint32_disp(rh, field, &count);
+}
+
+static int _snpercent_disp(struct report_handle *rh, struct field *field,
+ const void *data)
+{
+ struct logical_volume *lv = (struct logical_volume *) data;
+ struct snapshot *snap;
+ float snap_percent;
+
+ if (!(field->sort_value = pool_alloc(rh->mem, sizeof(uint64_t)))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ if (!(snap = find_cow(lv))
+ || !lv_snapshot_percent(snap->cow, &snap_percent)) {
+ field->report_string = "";
+ *(uint64_t *) field->sort_value = 0LL;
+ return 1;
+ }
+
+ if (!(field->report_string = pool_zalloc(rh->mem, 8))) {
+ log_error("pool_alloc failed");
+ return 0;
+ }
+
+ if (snap_percent == -1)
+ snap_percent = 100;
+
+ *(uint64_t *) field->sort_value = snap_percent * 1000;
+
+ if (lvm_snprintf(field->report_string, 7, "%.2f", snap_percent) < 0) {
+ log_error("snapshot percentage too large");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Import column definitions
+ */
+
+#define STR (FLD_STRING | FLD_ALIGN_LEFT)
+#define NUM (FLD_NUMBER | FLD_ALIGN_RIGHT)
+#define FIELD(type, strct, sorttype, head, field, width, func, id) {type, id, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), head, width, sorttype, &_ ## func ## _disp},
+
+static struct {
+ report_type_t type;
+ const char id[30];
+ off_t offset;
+ const char heading[30];
+ int width;
+ uint32_t flags;
+ field_report_fn report_fn;
+} _fields[] = {
+#include "columns.h"
+};
+
+#undef STR
+#undef NUM
+#undef FIELD
+
+const int _num_fields = sizeof(_fields) / sizeof(_fields[0]);
+
+/*
+ * Initialise report handle
+ */
+static int _field_match(struct report_handle *rh, const char *field, int len)
+{
+ uint32_t f, l;
+ struct field_properties *fp;
+
+ if (!len)
+ return 0;
+
+ for (f = 0; f < _num_fields; f++) {
+ if ((!strncasecmp(_fields[f].id, field, len) &&
+ strlen(_fields[f].id) == len) ||
+ (l = strlen(rh->field_prefix),
+ !strncasecmp(rh->field_prefix, _fields[f].id, l) &&
+ !strncasecmp(_fields[f].id + l, field, len) &&
+ strlen(_fields[f].id) == l + len)) {
+ rh->type |= _fields[f].type;
+ if (!(fp = pool_zalloc(rh->mem, sizeof(*fp)))) {
+ log_error("struct field_properties allocation "
+ "failed");
+ return 0;
+ }
+ fp->field_num = f;
+ fp->width = _fields[f].width;
+ fp->flags = _fields[f].flags;
+
+ /* Suppress snapshot percentage if not using driver */
+ if (!activation()
+ && !strncmp(field, "snap_percent", len))
+ fp->flags |= FLD_HIDDEN;
+
+ list_add(&rh->field_props, &fp->list);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int _add_sort_key(struct report_handle *rh, uint32_t field_num,
+ uint32_t flags)
+{
+ struct list *fh;
+ struct field_properties *fp, *found = NULL;
+
+ list_iterate(fh, &rh->field_props) {
+ fp = list_item(fh, struct field_properties);
+
+ if (fp->field_num == field_num) {
+ found = fp;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Add as a non-display field */
+ if (!(fp = pool_zalloc(rh->mem, sizeof(*fp)))) {
+ log_error("struct field_properties allocation failed");
+ return 0;
+ }
+
+ rh->type |= _fields[field_num].type;
+ fp->field_num = field_num;
+ fp->width = _fields[field_num].width;
+ fp->flags = _fields[field_num].flags | FLD_HIDDEN;
+
+ list_add(&rh->field_props, &fp->list);
+ }
+
+ if (fp->flags & FLD_SORT_KEY) {
+ log_error("Ignoring duplicate sort field: %s",
+ _fields[field_num].id);
+ return 1;
+ }
+
+ fp->flags |= FLD_SORT_KEY;
+ fp->sort_posn = rh->keys_count++;
+ fp->flags |= flags;
+
+ return 1;
+}
+
+static int _key_match(struct report_handle *rh, const char *key, int len)
+{
+ uint32_t f, l;
+ uint32_t flags = 0;
+
+ if (!len)
+ return 0;
+
+ if (*key == '+') {
+ key++;
+ len--;
+ flags = FLD_ASCENDING;
+ } else if (*key == '-') {
+ key++;
+ len--;
+ flags = FLD_DESCENDING;
+ } else
+ flags = FLD_ASCENDING;
+
+ if (!len) {
+ log_error("Missing sort field name");
+ return 0;
+ }
+
+ for (f = 0; f < _num_fields; f++) {
+ if ((!strncasecmp(_fields[f].id, key, len) &&
+ strlen(_fields[f].id) == len) ||
+ (l = strlen(rh->field_prefix),
+ !strncasecmp(rh->field_prefix, _fields[f].id, l) &&
+ !strncasecmp(_fields[f].id + l, key, len) &&
+ strlen(_fields[f].id) == l + len)) {
+ return _add_sort_key(rh, f, flags);
+ }
+ }
+
+ return 0;
+}
+
+static int _parse_options(struct report_handle *rh, const char *format)
+{
+ const char *ws; /* Word start */
+ const char *we = format; /* Word end */
+
+ while (*we) {
+ /* Allow consecutive commas */
+ while (*we && *we == ',')
+ we++;
+ ws = we;
+ while (*we && *we != ',')
+ we++;
+ if (!_field_match(rh, ws, we - ws)) {
+ log_error("Unrecognised field: %.*s", we - ws, ws);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int _parse_keys(struct report_handle *rh, const char *keys)
+{
+ const char *ws; /* Word start */
+ const char *we = keys; /* Word end */
+
+ while (*we) {
+ /* Allow consecutive commas */
+ while (*we && *we == ',')
+ we++;
+ ws = we;
+ while (*we && *we != ',')
+ we++;
+ if (!_key_match(rh, ws, we - ws)) {
+ log_error("Unrecognised field: %.*s", we - ws, ws);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
+ report_type_t *report_type, const char *separator,
+ int aligned, int buffered, int headings)
+{
+ struct report_handle *rh;
+
+ if (!(rh = pool_zalloc(cmd->mem, sizeof(*rh)))) {
+ log_error("report_handle pool_zalloc failed");
+ return 0;
+ }
+
+ rh->cmd = cmd;
+ rh->type = *report_type;
+ rh->separator = separator;
+
+ if (aligned)
+ rh->flags |= RH_ALIGNED;
+
+ if (buffered)
+ rh->flags |= RH_BUFFERED | RH_SORT_REQUIRED;
+
+ if (headings)
+ rh->flags |= RH_HEADINGS;
+
+ list_init(&rh->field_props);
+ list_init(&rh->rows);
+
+ switch (rh->type) {
+ case PVS:
+ rh->field_prefix = "pv_";
+ break;
+ case LVS:
+ rh->field_prefix = "lv_";
+ break;
+ case VGS:
+ rh->field_prefix = "vg_";
+ break;
+ case SEGS:
+ rh->field_prefix = "seg_";
+ break;
+ default:
+ rh->field_prefix = "";
+ }
+
+ if (!(rh->mem = pool_create(10 * 1024))) {
+ log_error("Allocation of memory pool for report failed");
+ return NULL;
+ }
+
+ /* Generate list of fields for output based on format string & flags */
+ if (!_parse_options(rh, format))
+ return NULL;
+
+ if (!_parse_keys(rh, keys))
+ return NULL;
+
+ /* Ensure options selected are compatible */
+ if (rh->type & SEGS)
+ rh->type |= LVS;
+ if ((rh->type & LVS) && (rh->type & PVS)) {
+ log_error("Can't report LV and PV fields at the same time");
+ return NULL;
+ }
+
+ /* Change report type if fields specified makes this necessary */
+ if (rh->type & SEGS)
+ *report_type = SEGS;
+ else if (rh->type & LVS)
+ *report_type = LVS;
+ else if (rh->type & PVS)
+ *report_type = PVS;
+
+ return rh;
+}
+
+void report_free(void *handle)
+{
+ struct report_handle *rh = handle;
+
+ pool_destroy(rh->mem);
+
+ return;
+}
+
+/*
+ * Create a row of data for an object
+ */
+int report_object(void *handle, struct volume_group *vg,
+ struct logical_volume *lv, struct physical_volume *pv,
+ struct lv_segment *seg)
+{
+ struct report_handle *rh = handle;
+ struct list *fh;
+ struct field_properties *fp;
+ struct row *row;
+ struct field *field;
+ void *data;
+
+ if (lv && pv) {
+ log_error("report_object: One of *lv and *pv must be NULL!");
+ return 0;
+ }
+
+ if (!(row = pool_zalloc(rh->mem, sizeof(*row)))) {
+ log_error("struct row allocation failed");
+ return 0;
+ }
+
+ row->rh = rh;
+
+ if ((rh->flags & RH_SORT_REQUIRED) &&
+ !(row->sort_fields = pool_zalloc(rh->mem, sizeof(struct field *) *
+ rh->keys_count))) {
+ log_error("row sort value structure allocation failed");
+ return 0;
+ }
+
+ list_init(&row->fields);
+ list_add(&rh->rows, &row->list);
+
+ /* For each field to be displayed, call its report_fn */
+ list_iterate(fh, &rh->field_props) {
+ fp = list_item(fh, struct field_properties);
+
+ if (!(field = pool_zalloc(rh->mem, sizeof(*field)))) {
+ log_error("struct field allocation failed");
+ return 0;
+ }
+ field->props = fp;
+
+ switch (_fields[fp->field_num].type) {
+ case LVS:
+ data = (void *) lv + _fields[fp->field_num].offset;
+ break;
+ case VGS:
+ data = (void *) vg + _fields[fp->field_num].offset;
+ break;
+ case PVS:
+ data = (void *) pv + _fields[fp->field_num].offset;
+ break;
+ case SEGS:
+ data = (void *) seg + _fields[fp->field_num].offset;
+ }
+
+ if (!_fields[fp->field_num].report_fn(rh, field, data)) {
+ log_error("report function failed for field %s",
+ _fields[fp->field_num].id);
+ return 0;
+ }
+
+ if ((strlen(field->report_string) > field->props->width))
+ field->props->width = strlen(field->report_string);
+
+ if ((rh->flags & RH_SORT_REQUIRED) &&
+ (field->props->flags & FLD_SORT_KEY)) {
+ (*row->sort_fields)[field->props->sort_posn] = field;
+ }
+ list_add(&row->fields, &field->list);
+ }
+
+ if (!(rh->flags & RH_BUFFERED))
+ report_output(handle);
+
+ return 1;
+}
+
+/*
+ * Print row of headings
+ */
+int report_headings(void *handle)
+{
+ struct report_handle *rh = handle;
+ struct list *fh;
+ struct field_properties *fp;
+
+ if (rh->flags & RH_HEADINGS_PRINTED)
+ return 1;
+
+ if (!(rh->flags & RH_HEADINGS))
+ goto out;
+
+ /* First heading line */
+ list_iterate(fh, &rh->field_props) {
+ fp = list_item(fh, struct field_properties);
+ if (fp->flags & FLD_HIDDEN)
+ continue;
+ if (rh->flags & RH_ALIGNED)
+ printf("%-*.*s", fp->width, fp->width,
+ _fields[fp->field_num].heading);
+ else
+ printf("%s", _fields[fp->field_num].heading);
+ if (!list_end(&rh->field_props, fh))
+ printf("%s", rh->separator);
+ }
+ printf("\n");
+
+ out:
+ rh->flags |= RH_HEADINGS_PRINTED;
+
+ return 1;
+}
+
+/*
+ * Sort rows of data
+ */
+static int _row_compare(const void *a, const void *b)
+{
+ struct row *rowa = *(struct row **) a;
+ struct row *rowb = *(struct row **) b;
+ struct field *sfa, *sfb;
+ int32_t cnt = -1;
+
+ for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
+ sfa = (*rowa->sort_fields)[cnt];
+ sfb = (*rowb->sort_fields)[cnt];
+ if (sfa->props->flags & FLD_NUMBER) {
+ uint64_t numa = *(uint64_t *) sfa->sort_value;
+ uint64_t numb = *(uint64_t *) sfb->sort_value;
+
+ if (numa == numb)
+ continue;
+
+ if (sfa->props->flags & FLD_ASCENDING) {
+ return (numa > numb) ? 1 : -1;
+ } else { /* FLD_DESCENDING */
+ return (numa < numb) ? 1 : -1;
+ }
+ } else { /* FLD_STRING */
+ char *stra = (char *) sfa->sort_value;
+ char *strb = (char *) sfb->sort_value;
+ int cmp = strcmp(stra, strb);
+
+ if (!cmp)
+ continue;
+
+ if (sfa->props->flags & FLD_ASCENDING) {
+ return (cmp > 0) ? 1 : -1;
+ } else { /* FLD_DESCENDING */
+ return (cmp < 0) ? 1 : -1;
+ }
+ }
+ }
+
+ return 0; /* Identical */
+}
+
+static int _sort_rows(struct report_handle *rh)
+{
+ struct row *(*rows)[];
+ struct list *rowh;
+ uint32_t count = 0;
+ struct row *row;
+
+ if (!(rows = pool_alloc(rh->mem, sizeof(**rows) *
+ list_size(&rh->rows)))) {
+ log_error("sort array allocation failed");
+ return 0;
+ }
+
+ list_iterate(rowh, &rh->rows) {
+ row = list_item(rowh, struct row);
+ (*rows)[count++] = row;
+ }
+
+ qsort(rows, count, sizeof(**rows), _row_compare);
+
+ list_init(&rh->rows);
+ while (count--)
+ list_add_h(&rh->rows, &(*rows)[count]->list);
+
+ return 1;
+}
+
+/*
+ * Produce report output
+ */
+int report_output(void *handle)
+{
+ struct report_handle *rh = handle;
+ struct list *fh, *rowh, *ftmp, *rtmp;
+ struct row *row = NULL;
+ struct field *field;
+
+ if (list_empty(&rh->rows))
+ return 1;
+
+ /* Sort rows */
+ if ((rh->flags & RH_SORT_REQUIRED))
+ _sort_rows(rh);
+
+ /* If headings not printed yet, calculate field widths and print them */
+ if (!(rh->flags & RH_HEADINGS_PRINTED))
+ report_headings(rh);
+
+ /* Print and clear buffer */
+ list_iterate_safe(rowh, rtmp, &rh->rows) {
+ row = list_item(rowh, struct row);
+ list_iterate_safe(fh, ftmp, &row->fields) {
+ field = list_item(fh, struct field);
+ if (field->props->flags & FLD_HIDDEN)
+ continue;
+ if (!(rh->flags & RH_ALIGNED))
+ printf("%s", field->report_string);
+ else if (field->props->flags & FLD_ALIGN_LEFT)
+ printf("%-*.*s", field->props->width,
+ field->props->width,
+ field->report_string);
+ else if (field->props->flags & FLD_ALIGN_RIGHT)
+ printf("%*.*s", field->props->width,
+ field->props->width,
+ field->report_string);
+ if (!list_end(&row->fields, fh))
+ printf("%s", rh->separator);
+ list_del(&field->list);
+ }
+ printf("\n");
+ list_del(&row->list);
+ }
+
+ if (row)
+ pool_free(rh->mem, row);
+
+ return 1;
+}
diff --git a/lib/report/report.h b/lib/report/report.h
new file mode 100644
index 00000000..a9259601
--- /dev/null
+++ b/lib/report/report.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2002 Sistina Software
+ *
+ * This LVM library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This LVM library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this LVM library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ *
+ */
+
+#ifndef _LVM_REPORT_H
+#define _LVM_REPORT_H
+
+#include "metadata.h"
+
+typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8 } report_type_t;
+
+struct field;
+struct report_handle;
+
+typedef int (*field_report_fn) (struct report_handle * dh, struct field * field,
+ const void *data);
+
+void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
+ report_type_t *report_type, const char *separator,
+ int aligned, int buffered, int headings);
+void report_free(void *handle);
+int report_object(void *handle, struct volume_group *vg,
+ struct logical_volume *lv, struct physical_volume *pv,
+ struct lv_segment *seg);
+int report_output(void *handle);
+
+#endif
diff --git a/libdm/datastruct/list.h b/libdm/datastruct/list.h
index 5f2e14c1..4aeb7b40 100644
--- a/libdm/datastruct/list.h
+++ b/libdm/datastruct/list.h
@@ -13,11 +13,13 @@ struct list {
struct list *n, *p;
};
-static inline void list_init(struct list *head) {
+static inline void list_init(struct list *head)
+{
head->n = head->p = head;
}
-static inline void list_add(struct list *head, struct list *elem) {
+static inline void list_add(struct list *head, struct list *elem)
+{
assert(head->n);
elem->n = head;
@@ -27,7 +29,8 @@ static inline void list_add(struct list *head, struct list *elem) {
head->p = elem;
}
-static inline void list_add_h(struct list *head, struct list *elem) {
+static inline void list_add_h(struct list *head, struct list *elem)
+{
assert(head->n);
elem->n = head->n;
@@ -37,27 +40,35 @@ static inline void list_add_h(struct list *head, struct list *elem) {
head->n = elem;
}
-static inline void list_del(struct list *elem) {
+static inline void list_del(struct list *elem)
+{
elem->n->p = elem->p;
elem->p->n = elem->n;
}
-static inline int list_empty(struct list *head) {
+static inline int list_empty(struct list *head)
+{
return head->n == head;
}
+static inline int list_end(struct list *head, struct list *elem)
+{
+ return elem->n == head;
+}
+
#define list_iterate(v, head) \
for (v = (head)->n; v != head; v = v->n)
#define list_iterate_safe(v, t, head) \
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
-static inline int list_size(struct list *head) {
+static inline int list_size(struct list *head)
+{
int s = 0;
struct list *v;
list_iterate(v, head)
- s++;
+ s++;
return s;
}
diff --git a/man/Makefile.in b/man/Makefile.in
index 0b688cb4..30c70b2e 100644
--- a/man/Makefile.in
+++ b/man/Makefile.in
@@ -22,11 +22,11 @@ VPATH = @srcdir@
MAN5=lvm.conf.5
MAN8=lvchange.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 lvmchange.8 \
- lvreduce.8 lvremove.8 lvrename.8 lvscan.8 pvchange.8 \
- pvcreate.8 pvdisplay.8 pvremove.8 pvscan.8 vgcfgbackup.8 \
+ lvreduce.8 lvremove.8 lvrename.8 lvs.8 lvscan.8 pvchange.8 \
+ pvcreate.8 pvdisplay.8 pvremove.8 pvs.8 pvscan.8 vgcfgbackup.8 \
vgcfgrestore.8 vgchange.8 vgck.8 vgcreate.8 \
vgconvert.8 vgdisplay.8 vgextend.8 vgmerge.8 vgreduce.8 vgremove.8 \
- vgrename.8 vgscan.8
+ vgrename.8 vgs.8 vgscan.8
MAN5DIR=${mandir}/man5
MAN8DIR=${mandir}/man8
diff --git a/man/lvs.8 b/man/lvs.8
new file mode 100644
index 00000000..08d5eacc
--- /dev/null
+++ b/man/lvs.8
@@ -0,0 +1,64 @@
+.TH LVS 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
+.SH NAME
+lvs \- report information about logical volumes
+.SH SYNOPSIS
+.B lvs
+[\-\-aligned] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-\-ignorelockingfailure] [\-\-noheadings] [\-\-nosuffix]
+[\-o/\-\-options [+]Field[,Field]]
+[\-O/\-\-sort [+/-]Key1[,[+/-]Key2[,...]]]
+[\-P/\-\-partial] [\-\-segments]
+[\-\-separator Separator] [\-\-unbuffered]
+[\-\-units hsbkmgtHKMGT]
+[\-v/\-\-verbose]
+[\-\-version] [VolumeGroupName [VolumeGroupName...]]
+.SH DESCRIPTION
+vgs produces formatted output about volume groups
+.SH OPTIONS
+See \fBlvm\fP for common options.
+.TP
+.I \-\-aligned
+Use with \-\-separator to align the output columns.
+.TP
+.I \-\-noheadings
+Suppress the headings line that is normally the first line of output.
+Useful if grepping the output.
+.TP
+.I \-\-nosuffix
+Suppress the suffix on output sizes. Use with \-\-units (except h and H)
+if processing the output.
+.TP
+.I \-o, \-\-options
+Comma-separated ordered list of columns. Precede the list with '+' to append
+to the default selection of columns. Column names are:
+lv_uuid, lv_name, lv_attr, lv_minor, lv_size, seg_count, origin,
+snap_percent (suppressed if no kernel driver), segtype, stripes,
+stripesize, chunksize, seg_start, seg_size.
+With \-\-segments, any "seg_" prefixes are optional; otherwise any "lv_"
+prefixes are optional. Columns mentioned in \fBvgs (8)\fP
+can also be chosen
+The lv_attr bits are: (o)rigin, (s)napshot, (w)riteable, (r)eadonly,
+(c)ontiguous allocation, (n)ext free allocation, fixed (m)inor, (s)uspended,
+(a)ctive, device (o)pen.
+.TP
+.I \-\-segments
+Use default columns that emphasize segment information.
+.TP
+.I \-O, \-\-sort
+Comma-separated ordered list of columns to sort by. Replaces the default
+selection. Precede any column with - for a reverse sort on that column.
+.TP
+.I \-\-separator Separator
+String to use to separate each column. Useful if grepping the output.
+.TP
+.I \-\-unbuffered
+Produce output immediately without sorting or aligning the columns properly.
+.TP
+.I \-\-units hsbkmgtHKMGT
+All sizes are output in these units: (h)uman-readable, (s)ectors, (b)ytes,
+(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes. Capitalise to use multiples
+of 1000 (S.I.) instead of 1024. Can also specify custom (u)nits e.g.
+\-\-units 3M
+.SH SEE ALSO
+.BR pvs (8),
+.BR vgs (8)
diff --git a/man/pvs.8 b/man/pvs.8
new file mode 100644
index 00000000..d3d83d97
--- /dev/null
+++ b/man/pvs.8
@@ -0,0 +1,54 @@
+.TH PVS 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
+.SH NAME
+pvs \- report information about physical volumes
+.SH SYNOPSIS
+.B pvs
+[\-\-aligned] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-\-ignorelockingfailure] [\-\-noheadings] [\-\-nosuffix]
+[\-o/\-\-options [+]Field[,Field]]
+[\-O/\-\-sort [+/-]Key1[,[+/-]Key2[,...]]]
+[\-\-separator Separator] [\-\-unbuffered]
+[\-\-units hsbkmgtHKMGT]
+[\-v/\-\-verbose]
+[\-\-version] [PhysicalVolume [PhysicalVolume...]]
+.SH DESCRIPTION
+pvs produces formatted output about physical volumes
+.SH OPTIONS
+See \fBlvm\fP for common options.
+.TP
+.I \-\-aligned
+Use with \-\-separator to align the output columns.
+.TP
+.I \-\-noheadings
+Suppress the headings line that is normally the first line of output.
+Useful if grepping the output.
+.TP
+.I \-\-nosuffix
+Suppress the suffix on output sizes. Use with \-\-units (except h and H)
+if processing the output.
+.TP
+.I \-o, \-\-options
+Comma-separated ordered list of columns. Precede the list with '+' to append
+to the default selection of columns. Column names are: pv_fmt, pv_uuid,
+pv_size, pv_free, pv_used, pv_name, pv_attr, pv_pe_count, pv_pe_alloc_count.
+The "pv_" prefix is optional. Columns mentioned in \fBvgs (8)\fP can also
+be chosen. The pv_attr bits are: (a)llocatable and e(x)ported.
+.TP
+.I \-O, \-\-sort
+Comma-separated ordered list of columns to sort by. Replaces the default
+selection. Precede any column with - for a reverse sort on that column.
+.TP
+.I \-\-separator Separator
+String to use to separate each column. Useful if grepping the output.
+.TP
+.I \-\-unbuffered
+Produce output immediately without sorting or aligning the columns properly.
+.TP
+.I \-\-units hsbkmgtHKMGT
+All sizes are output in these units: (h)uman-readable, (s)ectors, (b)ytes,
+(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes. Capitalise to use multiples
+of 1000 (S.I.) instead of 1024. Can also specify custom (u)nits e.g.
+\-\-units 3M
+.SH SEE ALSO
+.BR lvs (8),
+.BR vgs (8)
diff --git a/man/vgs.8 b/man/vgs.8
new file mode 100644
index 00000000..0f47235c
--- /dev/null
+++ b/man/vgs.8
@@ -0,0 +1,58 @@
+.TH VGS 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
+.SH NAME
+vgs \- report information about volume groups
+.SH SYNOPSIS
+.B vgs
+[\-\-aligned] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-\-ignorelockingfailure] [\-\-noheadings] [\-\-nosuffix]
+[\-o/\-\-options [+]Field[,Field]]
+[\-O/\-\-sort [+/-]Key1[,[+/-]Key2[,...]]]
+[\-P/\-\-partial]
+[\-\-separator Separator] [\-\-unbuffered]
+[\-\-units hsbkmgtHKMGT]
+[\-v/\-\-verbose]
+[\-\-version] [VolumeGroupName [VolumeGroupName...]]
+.SH DESCRIPTION
+vgs produces formatted output about volume groups
+.SH OPTIONS
+See \fBlvm\fP for common options.
+.TP
+.I \-\-aligned
+Use with \-\-separator to align the output columns.
+.TP
+.I \-\-noheadings
+Suppress the headings line that is normally the first line of output.
+Useful if grepping the output.
+.TP
+.I \-\-nosuffix
+Suppress the suffix on output sizes. Use with \-\-units (except h and H)
+if processing the output.
+.TP
+.I \-o, \-\-options
+Comma-separated ordered list of columns. Precede the list with '+' to append
+to the default selection of columns. Column names are: vg_fmt, vg_uuid,
+vg_name, vg_attr, vg_size, vg_free, vg_sysid, vg_extent_size, vg_extent_count,
+vg_free_count, max_lv, max_pv, pv_count, lv_count, snap_count, vg_seqno.
+Any "vg_" prefixes are optional. Columns mentioned in either \fBpvs (8)\fP
+or \fBlvs (8)\fP can also be chosen, but columns cannot be taken from both
+at the same time. The vg_attr bits are: (w)riteable, (r)eadonly,
+resi(z)eable, e(x)ported, (p)artial.
+.TP
+.I \-O, \-\-sort
+Comma-separated ordered list of columns to sort by. Replaces the default
+selection. Precede any column with - for a reverse sort on that column.
+.TP
+.I \-\-separator Separator
+String to use to separate each column. Useful if grepping the output.
+.TP
+.I \-\-unbuffered
+Produce output immediately without sorting or aligning the columns properly.
+.TP
+.I \-\-units hsbkmgtHKMGT
+All sizes are output in these units: (h)uman-readable, (s)ectors, (b)ytes,
+(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes. Capitalise to use multiples
+of 1000 (S.I.) instead of 1024. Can also specify custom (u)nits e.g.
+\-\-units 3M
+.SH SEE ALSO
+.BR pvs (8),
+.BR lvs (8)
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 42ae8aef..604e942b 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -39,6 +39,7 @@ SOURCES=\
pvdisplay.c \
pvremove.c \
pvscan.c \
+ report.c \
toollib.c \
vgcfgbackup.c \
vgcfgrestore.c \
@@ -67,8 +68,8 @@ lvm: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
$(CC) -o lvm $(OBJECTS) $(LD_FLAGS) -L$(top_srcdir)/lib \
-L$(DESTDIR)/lib -llvm -ldevmapper $(LIBS) -ldl -rdynamic
-.commands: commands.h cmdnames.h
- $(CC) -E -P cmdnames.h | grep -v help > .commands
+.commands: commands.h cmdnames.h Makefile
+ $(CC) -E -P cmdnames.h | egrep -v '(help|version)' > .commands
install: $(TARGETS)
$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) lvm \
diff --git a/tools/args.h b/tools/args.h
index d859f16a..06d5a0a2 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -17,6 +17,12 @@ arg(metadatasize_ARG, '\0', "metadatasize", size_mb_arg)
arg(restorefile_ARG, '\0', "restorefile", string_arg)
arg(labelsector_ARG, '\0', "labelsector", int_arg)
arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg)
+arg(aligned_ARG, '\0', "aligned", NULL)
+arg(unbuffered_ARG, '\0', "unbuffered", NULL)
+arg(noheadings_ARG, '\0', "noheadings", NULL)
+arg(segments_ARG, '\0', "segments", NULL)
+arg(units_ARG, '\0', "units", string_arg)
+arg(nosuffix_ARG, '\0', "nosuffix", NULL)
/* Allow some variations */
arg(resizable_ARG, '\0', "resizable", yes_no_arg)
@@ -32,6 +38,7 @@ arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL)
arg(blockdevice_ARG, 'b', "blockdevice", NULL)
arg(chunksize_ARG, 'c', "chunksize", size_kb_arg)
arg(colon_ARG, 'c', "colon", NULL)
+arg(columns_ARG, 'C', "columns", NULL)
arg(contiguous_ARG, 'C', "contiguous", yes_no_arg)
arg(debug_ARG, 'd', "debug", NULL)
arg(disk_ARG, 'D', "disk", NULL)
@@ -61,6 +68,7 @@ arg(oldpath_ARG, 'n', "oldpath", NULL)
arg(nofsck_ARG, 'n', "nofsck", NULL)
arg(novolumegroup_ARG, 'n', "novolumegroup", NULL)
arg(options_ARG, 'o', "options", string_arg)
+arg(sort_ARG, 'O', "sort", string_arg)
arg(permission_ARG, 'p', "permission", permission_arg)
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg)
arg(partial_ARG, 'P', "partial", NULL)
@@ -68,6 +76,7 @@ arg(physicalvolume_ARG, 'P', "physicalvolume", NULL)
arg(readahead_ARG, 'r', "readahead", int_arg)
arg(reset_ARG, 'R', "reset", NULL)
arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg)
+arg(separator_ARG, 's', "separator", string_arg)
arg(stdin_ARG, 's', "stdin", NULL)
arg(snapshot_ARG, 's', "snapshot", NULL)
arg(short_ARG, 's', "short", NULL)
diff --git a/tools/commands.h b/tools/commands.h
index 5e984b42..2923f91d 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -62,6 +62,7 @@ xx(lvchange,
"\t[-r|--readahead ReadAheadSectors]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
autobackup_ARG, available_ARG, contiguous_ARG,
@@ -118,11 +119,34 @@ xx(lvdisplay,
"\t[-h|--help]\n"
"\t[--ignorelockingfailure]\n"
"\t[-m|--maps]\n"
+ "\t[--nosuffix]\n"
"\t[-P|--partial] " "\n"
+ "\t[--units hsbkmgtHKMGT]\n"
"\t[-v|--verbose]\n"
- "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
+ "\t[--version]" "\n"
+ "\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n"
+ "\n"
+ "lvdisplay --columns|-C\n"
+ "\t[--aligned]\n"
+ "\t[-d|--debug]\n"
+ "\t[-h|--help]\n"
+ "\t[--ignorelockingfailure]\n"
+ "\t[--noheadings]\n"
+ "\t[--nosuffix]\n"
+ "\t[-o|--options [+]Field[,Field]]\n"
+ "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+ "\t[-P|--partial] " "\n"
+ "\t[--segments]\n"
+ "\t[--separator Separator]\n"
+ "\t[--unbuffered]\n"
+ "\t[--units hsbkmgtHKMGT]\n"
+ "\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
+ "\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n",
- colon_ARG, disk_ARG, ignorelockingfailure_ARG, maps_ARG, partial_ARG)
+ aligned_ARG, colon_ARG, columns_ARG, disk_ARG, ignorelockingfailure_ARG,
+ maps_ARG, noheadings_ARG, nosuffix_ARG, options_ARG, sort_ARG,
+ partial_ARG, segments_ARG, separator_ARG, unbuffered_ARG, units_ARG)
xx(lvextend,
"Add space to a logical volume",
@@ -135,6 +159,7 @@ xx(lvextend,
"\t -L|--size [+]LogicalVolumeSize[kKmMgGtT]}\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
autobackup_ARG, extents_ARG, size_ARG, stripes_ARG,
@@ -146,7 +171,8 @@ xx(lvmchange,
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-R|--reset]\n"
- "\t[-v|--verbose]\n",
+ "\t[-v|--verbose]\n"
+ "\t[--version]" "\n",
reset_ARG)
@@ -155,7 +181,8 @@ xx(lvmdiskscan,
"lvmdiskscan\n"
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
- "\t[-l|--lvmpartition]\n",
+ "\t[-l|--lvmpartition]\n"
+ "\t[--version]" "\n",
lvmpartition_ARG)
@@ -165,6 +192,7 @@ xx(lvmsadc,
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\t[LogFilePath]\n" )
xx(lvmsar,
@@ -175,6 +203,7 @@ xx(lvmsar,
"\t[-h|--help]\n"
"\t[-s|--stdin]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tLogFilePath\n",
full_ARG, stdin_ARG)
@@ -190,6 +219,7 @@ xx(lvreduce,
"\t -L|--size [-]LogicalVolumeSize[kKmMgGtT]}\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tLogicalVolume[Path]\n",
autobackup_ARG, force_ARG, extents_ARG,
@@ -204,6 +234,7 @@ xx(lvremove,
"\t[-h|--help]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
autobackup_ARG, force_ARG, test_ARG)
@@ -233,11 +264,36 @@ xx(lvresize,
"\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtT]}\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
autobackup_ARG, extents_ARG, size_ARG, stripes_ARG, stripesize_ARG,
test_ARG)
+xx(lvs,
+ "Display information about logical volumes",
+ "lvs" "\n"
+ "\t[--aligned]\n"
+ "\t[-d|--debug]\n"
+ "\t[-h|--help]\n"
+ "\t[--ignorelockingfailure]\n"
+ "\t[--noheadings]\n"
+ "\t[--nosuffix]\n"
+ "\t[-o|--options [+]Field[,Field]]\n"
+ "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+ "\t[-P|--partial] " "\n"
+ "\t[--segments]\n"
+ "\t[--separator Separator]\n"
+ "\t[--unbuffered]\n"
+ "\t[--units hsbkmgtHKMGT]\n"
+ "\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
+ "\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n",
+
+ aligned_ARG, ignorelockingfailure_ARG, noheadings_ARG, nosuffix_ARG,
+ options_ARG, partial_ARG, segments_ARG, separator_ARG, sort_ARG,
+ unbuffered_ARG, units_ARG)
+
xx(lvscan,
"List all logical volumes in all volume groups",
"lvscan " "\n"
@@ -258,6 +314,7 @@ xx(pvchange,
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\t[-a|--all]\n"
"\t[-t|--test]\n"
"\t[-x|--allocatable y|n]\n"
@@ -307,18 +364,39 @@ xx(pvdata,
physicalvolume_ARG, uuidlist_ARG, volumegroup_ARG)
xx(pvdisplay,
- "Display various attributes of logical volume(s)",
+ "Display various attributes of physical volume(s)",
"pvdisplay\n"
"\t[-c|--colon]\n"
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[--ignorelockingfailure]\n"
"\t[-m|--maps]\n"
+ "\t[--nosuffix]\n"
"\t[-s|--short]\n"
+ "\t[--units hsbkmgtHKMGT]\n"
"\t[-v|--verbose]\n"
- "\tPhysicalVolumePath [PhysicalVolumePath...]\n",
+ "\t[--version]" "\n"
+ "\t[PhysicalVolumePath [PhysicalVolumePath...]]\n"
+ "\n"
+ "pvdisplay --columns|-C\n"
+ "\t[--aligned]\n"
+ "\t[-d|--debug]\n"
+ "\t[-h|--help]\n"
+ "\t[--ignorelockingfailure]\n"
+ "\t[--noheadings]\n"
+ "\t[--nosuffix]\n"
+ "\t[-o|--options [+]Field[,Field]]\n"
+ "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+ "\t[--separator Separator]\n"
+ "\t[--unbuffered]\n"
+ "\t[--units hsbkmgtHKMGT]\n"
+ "\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
+ "\t[PhysicalVolumePath [PhysicalVolumePath...]]\n",
- colon_ARG, ignorelockingfailure_ARG, maps_ARG, short_ARG)
+ aligned_ARG, colon_ARG, columns_ARG, ignorelockingfailure_ARG, maps_ARG,
+ noheadings_ARG, nosuffix_ARG, options_ARG, separator_ARG, short_ARG,
+ sort_ARG, unbuffered_ARG, units_ARG)
xx(pvmove,
"Move extents from one physical volume to another",
@@ -366,6 +444,27 @@ xx(pvresize,
***/
autobackup_ARG, physicalvolumesize_ARG)
+xx(pvs,
+ "Display information about physical volumes",
+ "pvs" "\n"
+ "\t[--aligned]\n"
+ "\t[-d|--debug]" "\n"
+ "\t[-h|-?|--help] " "\n"
+ "\t[--noheadings]\n"
+ "\t[--ignorelockingfailure]\n"
+ "\t[--nosuffix]\n"
+ "\t[-o|--options [+]Field[,Field]]\n"
+ "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+ "\t[--separator Separator]\n"
+ "\t[--unbuffered]\n"
+ "\t[--units hsbkmgtHKMGT]\n"
+ "\t[-v|--verbose]\n"
+ "\t[--version]\n"
+ "\t[PhysicalVolume [PhysicalVolume...]]\n",
+
+ aligned_ARG, ignorelockingfailure_ARG, noheadings_ARG, nosuffix_ARG,
+ options_ARG, separator_ARG, sort_ARG, unbuffered_ARG, units_ARG)
+
xx(pvscan,
"List all physical volumes",
"pvscan " "\n"
@@ -391,7 +490,7 @@ xx(vgcfgbackup,
"\t[--ignorelockingfailure]\n"
"\t[-P|--partial] " "\n"
"\t[-v|--verbose]" "\n"
- "\t[-V|--version] " "\n"
+ "\t[--version] " "\n"
"\t[VolumeGroupName...]\n",
file_ARG, ignorelockingfailure_ARG, partial_ARG)
@@ -437,6 +536,7 @@ xx(vgck,
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n",
"\t[VolumeGroupName...]\n" )
xx(vgconvert,
@@ -481,13 +581,33 @@ xx(vgdisplay,
"\t[-d|--debug] " "\n"
"\t[-h|--help] " "\n"
"\t[--ignorelockingfailure]" "\n"
+ "\t[--nosuffix]\n"
"\t[-P|--partial] " "\n"
+ "\t[--units hsbkmgtHKMGT]\n"
"\t[-A|--activevolumegroups | [-D|--disk]" "\n"
"\t[--version]" "\n"
- "\t[VolumeGroupName...] ]\n",
+ "\t[VolumeGroupName [VolumeGroupName...]]\n"
+ "\n"
+ "vgdisplay --columns|-C\n"
+ "\t[--aligned]\n"
+ "\t[-d|--debug] " "\n"
+ "\t[-h|--help] " "\n"
+ "\t[--ignorelockingfailure]" "\n"
+ "\t[--noheadings]\n"
+ "\t[--nosuffix]\n"
+ "\t[-o|--options [+]Field[,Field]]\n"
+ "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+ "\t[-P|--partial] " "\n"
+ "\t[--separator Separator]\n"
+ "\t[--unbuffered]\n"
+ "\t[--units hsbkmgtHKMGT]\n"
+ "\t[--verbose]" "\n"
+ "\t[--version]" "\n"
+ "\t[VolumeGroupName [VolumeGroupName...]]\n",
- activevolumegroups_ARG, colon_ARG, disk_ARG, ignorelockingfailure_ARG,
- short_ARG, partial_ARG)
+ activevolumegroups_ARG, aligned_ARG, colon_ARG, columns_ARG, disk_ARG,
+ ignorelockingfailure_ARG, noheadings_ARG, nosuffix_ARG, options_ARG,
+ partial_ARG, separator_ARG, short_ARG, sort_ARG, unbuffered_ARG, units_ARG)
xx(vgexport,
"Unregister volume group(s) from the system",
@@ -509,6 +629,7 @@ xx(vgextend,
"\t[-h|--help]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tVolumeGroupName PhysicalDevicePath [PhysicalDevicePath...]\n",
autobackup_ARG, test_ARG)
@@ -522,6 +643,7 @@ xx(vgimport,
"\t[-h|--help] " "\n"
"\t[-t|--test] " "\n"
"\t[-v|--verbose]" "\n"
+ "\t[--version]" "\n"
"\tVolumeGroupName..." "\n",
all_ARG, force_ARG, test_ARG)
@@ -535,6 +657,7 @@ xx(vgmerge,
"\t[-l|--list]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tDestinationVolumeGroupName SourceVolumeGroupName\n",
autobackup_ARG, list_ARG, test_ARG)
@@ -545,6 +668,7 @@ xx(vgmknodes,
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\t[VolumeGroupName...]\n" )
xx(vgreduce,
@@ -556,6 +680,7 @@ xx(vgreduce,
"\t[-h|--help]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tVolumeGroupName\n"
"\t[PhysicalVolumePath...]\n",
@@ -568,6 +693,7 @@ xx(vgremove,
"\t[-h|--help]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tVolumeGroupName [VolumeGroupName...]\n",
test_ARG)
@@ -580,11 +706,34 @@ xx(vgrename,
"\t[-h|--help]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--version]" "\n"
"\tOldVolumeGroupPath NewVolumeGroupPath |\n"
"\tOldVolumeGroupName NewVolumeGroupName\n",
autobackup_ARG, force_ARG, test_ARG)
+xx(vgs,
+ "Display information about volume groups",
+ "vgs" "\n"
+ "\t[--aligned]\n"
+ "\t[-d|--debug]\n"
+ "\t[-h|--help]\n"
+ "\t[--ignorelockingfailure]\n"
+ "\t[--noheadings]\n"
+ "\t[--nosuffix]\n"
+ "\t[-o|--options [+]Field[,Field]]\n"
+ "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+ "\t[-P|--partial] " "\n"
+ "\t[--separator Separator]\n"
+ "\t[--unbuffered]\n"
+ "\t[--units hsbkmgtHKMGT]\n"
+ "\t[-v|--verbose]\n"
+ "\t[--version]\n"
+ "\t[VolumeGroupName [VolumeGroupName...]]\n",
+
+ aligned_ARG, ignorelockingfailure_ARG, noheadings_ARG, nosuffix_ARG,
+ options_ARG, partial_ARG, separator_ARG, sort_ARG, unbuffered_ARG, units_ARG)
+
xx(vgscan,
"Search for all volume groups",
"vgscan "
@@ -592,7 +741,8 @@ xx(vgscan,
"\t[-h|--help]\n"
"\t[--ignorelockingfailure]\n"
"\t[-P|--partial] " "\n"
- "\t[-v|--verbose]\n" ,
+ "\t[-v|--verbose]\n"
+ "\t[--version]" "\n",
ignorelockingfailure_ARG, partial_ARG)
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 176c7f4e..b7ca5315 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -144,7 +144,7 @@ static int _read_size_params(struct lvcreate_params *lp,
/* Size returned in kilobyte units; held in sectors */
if (arg_count(cmd, size_ARG))
- lp->size = arg_int64_value(cmd, size_ARG, 0) * 2ull;
+ lp->size = arg_uint64_value(cmd, size_ARG, 0) * 2ull;
return 1;
}
@@ -378,15 +378,11 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
lp->extents = lp->size;
if (lp->extents % vg->extent_size) {
- char *s1;
-
lp->extents += vg->extent_size - lp->extents %
vg->extent_size;
- log_print("Rounding up size to full physical "
- "extent %s",
- (s1 = display_size(lp->extents / 2,
- SIZE_SHORT)));
- dbg_free(s1);
+ log_print("Rounding up size to full physical extent %s",
+ display_size(cmd, lp->extents / 2,
+ SIZE_SHORT));
}
lp->extents /= vg->extent_size;
diff --git a/tools/lvdisplay.c b/tools/lvdisplay.c
index 69971b1b..47d546da 100644
--- a/tools/lvdisplay.c
+++ b/tools/lvdisplay.c
@@ -36,7 +36,20 @@ int lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv,
int lvdisplay(struct cmd_context *cmd, int argc, char **argv)
{
- /* FIXME Allow VG args via process_each */
+ if (arg_count(cmd, columns_ARG)) {
+ if (arg_count(cmd, colon_ARG) || arg_count(cmd, maps_ARG)) {
+ log_error("Incompatible options selected");
+ return EINVALID_CMD_LINE;
+ }
+ return lvs(cmd, argc, argv);
+ } else if (arg_count(cmd, aligned_ARG) ||
+ arg_count(cmd, noheadings_ARG) ||
+ arg_count(cmd, options_ARG) ||
+ arg_count(cmd, separator_ARG) ||
+ arg_count(cmd, sort_ARG) || arg_count(cmd, unbuffered_ARG)) {
+ log_error("Incompatible options selected");
+ return EINVALID_CMD_LINE;
+ }
if (arg_count(cmd, colon_ARG) && arg_count(cmd, verbose_ARG)) {
log_error("Options -v and -c are incompatible");
diff --git a/tools/lvm.c b/tools/lvm.c
index dbc295ff..66550319 100644
--- a/tools/lvm.c
+++ b/tools/lvm.c
@@ -157,7 +157,8 @@ static int _size_arg(struct cmd_context *cmd, struct arg *a, int factor)
v *= factor;
a->i_value = (uint32_t) v;
- a->i64_value = (uint64_t) v;
+ a->i64_value = (int64_t) v;
+ a->ui64_value = (uint64_t) v;
return 1;
}
@@ -547,6 +548,17 @@ static int _get_settings(struct cmd_context *cmd)
else
init_ignorelockingfailure(0);
+ if (arg_count(cmd, nosuffix_ARG))
+ cmd->current_settings.suffix = 0;
+
+ if (arg_count(cmd, units_ARG))
+ if (!(cmd->current_settings.unit_factor =
+ units_to_bytes(arg_str_value(cmd, units_ARG, ""),
+ &cmd->current_settings.unit_type))) {
+ log_error("Invalid units specification");
+ return EINVALID_CMD_LINE;
+ }
+
/* Handle synonyms */
if (!_merge_synonym(cmd, resizable_ARG, resizeable_ARG) ||
!_merge_synonym(cmd, allocation_ARG, allocatable_ARG) ||
diff --git a/tools/lvmdiskscan.c b/tools/lvmdiskscan.c
index a6edfa6b..a33c128e 100644
--- a/tools/lvmdiskscan.c
+++ b/tools/lvmdiskscan.c
@@ -52,19 +52,14 @@ static void _count(struct device *dev, int *disks, int *parts)
(*parts)++;
}
-static void _print(struct device *dev, uint64_t size, char *what)
+static void _print(struct cmd_context *cmd, struct device *dev, uint64_t size,
+ char *what)
{
- char *dummy = display_size(size / 2, SIZE_SHORT);
- const char *name = dev_name(dev);
-
- if (!what)
- what = "";
-
- log_print("%-*s [%15s] %s", max_len, name, dummy, what);
- dbg_free(dummy);
+ log_print("%-*s [%15s] %s", max_len, dev_name(dev),
+ display_size(cmd, size / 2, SIZE_SHORT), what ? : "");
}
-static int _check_device(struct device *dev)
+static int _check_device(struct cmd_context *cmd, struct device *dev)
{
char buffer;
uint64_t size;
@@ -79,7 +74,7 @@ static int _check_device(struct device *dev)
if (!dev_get_size(dev, &size)) {
log_error("Couldn't get size of \"%s\"", dev_name(dev));
}
- _print(dev, size, NULL);
+ _print(cmd, dev, size, NULL);
_count(dev, &disks_found, &parts_found);
if (!dev_close(dev)) {
log_error("dev_close on \"%s\" failed", dev_name(dev));
@@ -114,7 +109,7 @@ int lvmdiskscan(struct cmd_context *cmd, int argc, char **argv)
dev_name(dev));
continue;
}
- _print(dev, size, "LVM physical volume");
+ _print(cmd, dev, size, "LVM physical volume");
_count(dev, &pv_disks_found, &pv_parts_found);
continue;
}
@@ -123,7 +118,7 @@ int lvmdiskscan(struct cmd_context *cmd, int argc, char **argv)
continue;
/* What other device is it? */
- if (!_check_device(dev))
+ if (!_check_device(cmd, dev))
continue;
}
dev_iter_destroy(iter);
diff --git a/tools/lvresize.c b/tools/lvresize.c
index b058d8f5..163450b0 100644
--- a/tools/lvresize.c
+++ b/tools/lvresize.c
@@ -34,7 +34,6 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
sign_t sign = SIGN_NONE;
char *lv_name, *vg_name;
char *st;
- char *dummy;
const char *cmd_name;
struct list *pvh, *segh;
struct lv_list *lvl;
@@ -145,8 +144,6 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
extents = size * 2;
if (extents % vg->extent_size) {
- char *s1;
-
if (sign == SIGN_MINUS)
extents -= extents % vg->extent_size;
else
@@ -154,8 +151,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
(extents % vg->extent_size);
log_print("Rounding up size to full physical extent %s",
- (s1 = display_size(extents / 2, SIZE_SHORT)));
- dbg_free(s1);
+ display_size(cmd, extents / 2, SIZE_SHORT));
}
extents /= vg->extent_size;
@@ -310,16 +306,14 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
}
if (info.exists) {
- dummy = display_size((uint64_t)
- extents * (vg->extent_size / 2),
- SIZE_SHORT);
log_print("WARNING: Reducing active%s logical volume "
"to %s", info.open_count ? " and open" : "",
- dummy);
+ display_size(cmd, (uint64_t)
+ extents * (vg->extent_size / 2),
+ SIZE_SHORT));
log_print("THIS MAY DESTROY YOUR DATA "
"(filesystem etc.)");
- dbg_free(dummy);
}
if (!arg_count(cmd, force_ARG)) {
@@ -352,11 +346,10 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
/* Use full list from VG */
pvh = &vg->pvs;
}
- dummy = display_size((uint64_t)
- extents * (vg->extent_size / 2),
- SIZE_SHORT);
- log_print("Extending logical volume %s to %s", lv_name, dummy);
- dbg_free(dummy);
+ log_print("Extending logical volume %s to %s", lv_name,
+ display_size(cmd, (uint64_t)
+ extents * (vg->extent_size / 2),
+ SIZE_SHORT));
if (!lv_extend(vg->fid, lv, stripes, stripesize,
extents - lv->le_count, pvh))
diff --git a/tools/lvscan.c b/tools/lvscan.c
index d0449288..fd93d58e 100644
--- a/tools/lvscan.c
+++ b/tools/lvscan.c
@@ -27,7 +27,6 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
int lv_total = 0;
ulong lv_capacity_total = 0;
- char *dummy;
const char *active_str, *snapshot_str;
if (lv_info(lv, &info) && info.exists)
@@ -42,14 +41,11 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
else
snapshot_str = " ";
- dummy = display_size(lv->size / 2, SIZE_SHORT);
-
log_print("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str,
- cmd->dev_dir, lv->vg->name, lv->name, dummy,
+ cmd->dev_dir, lv->vg->name, lv->name,
+ display_size(cmd, lv->size / 2, SIZE_SHORT),
get_alloc_string(lv->alloc));
- dbg_free(dummy);
-
lv_total++;
lv_capacity_total += lv->size;
@@ -66,4 +62,5 @@ int lvscan(struct cmd_context *cmd, int argc, char **argv)
return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL,
&lvscan_single);
+
}
diff --git a/tools/pvcreate.c b/tools/pvcreate.c
index 7ca11ede..5534437d 100644
--- a/tools/pvcreate.c
+++ b/tools/pvcreate.c
@@ -130,9 +130,9 @@ static void pvcreate_single(struct cmd_context *cmd, const char *pv_name,
if (!pvcreate_check(cmd, pv_name))
goto error;
- size = arg_int64_value(cmd, physicalvolumesize_ARG, 0) * 2;
+ size = arg_uint64_value(cmd, physicalvolumesize_ARG, 0) * 2;
- pvmetadatasize = arg_int64_value(cmd, metadatasize_ARG, 0) * 2;
+ pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, 0) * 2;
if (!pvmetadatasize)
pvmetadatasize = find_config_int(cmd->cf->root,
"metadata/pvmetadatasize",
diff --git a/tools/pvdisplay.c b/tools/pvdisplay.c
index ff4d121a..2bb74ea4 100644
--- a/tools/pvdisplay.c
+++ b/tools/pvdisplay.c
@@ -20,10 +20,9 @@
#include "tools.h"
-void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv,
- void *handle)
+int pvdisplay_single(struct cmd_context *cmd, struct volume_group *vg,
+ struct physical_volume *pv, void *handle)
{
- char *sz;
uint64_t size;
const char *pv_name = dev_name(pv->dev);
@@ -34,67 +33,56 @@ void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv,
size = (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
if (arg_count(cmd, short_ARG)) {
- sz = display_size(size / 2, SIZE_SHORT);
- log_print("Device \"%s\" has a capacity of %s", pv_name, sz);
- dbg_free(sz);
- return;
+ log_print("Device \"%s\" has a capacity of %s", pv_name,
+ display_size(cmd, size / 2, SIZE_SHORT));
+ return 0;
}
if (pv->status & EXPORTED_VG)
log_print("Physical volume \"%s\" of volume group \"%s\" "
"is exported", pv_name, pv->vg_name);
- if (!pv->vg_name) {
+ if (!pv->vg_name)
log_print("\"%s\" is a new physical volume of \"%s\"",
- pv_name, (sz = display_size(size / 2, SIZE_SHORT)));
- dbg_free(sz);
- }
+ pv_name, display_size(cmd, size / 2, SIZE_SHORT));
if (arg_count(cmd, colon_ARG)) {
pvdisplay_colons(pv);
- return;
+ return 0;
}
- pvdisplay_full(pv, handle);
+ pvdisplay_full(cmd, pv, handle);
if (!arg_count(cmd, maps_ARG))
- return;
+ return 0;
- return;
+ return 0;
}
int pvdisplay(struct cmd_context *cmd, int argc, char **argv)
{
- int opt = 0;
-
- struct list *pvh, *pvs;
- struct physical_volume *pv;
+ if (arg_count(cmd, columns_ARG)) {
+ if (arg_count(cmd, colon_ARG) || arg_count(cmd, maps_ARG) ||
+ arg_count(cmd, short_ARG)) {
+ log_error("Incompatible options selected");
+ return EINVALID_CMD_LINE;
+ }
+ return pvs(cmd, argc, argv);
+ } else if (arg_count(cmd, aligned_ARG) ||
+ arg_count(cmd, noheadings_ARG) ||
+ arg_count(cmd, options_ARG) ||
+ arg_count(cmd, separator_ARG) ||
+ arg_count(cmd, sort_ARG) || arg_count(cmd, unbuffered_ARG)) {
+ log_error("Incompatible options selected");
+ return EINVALID_CMD_LINE;
+ }
if (arg_count(cmd, colon_ARG) && arg_count(cmd, maps_ARG)) {
log_error("Option -v not allowed with option -c");
return EINVALID_CMD_LINE;
}
- if (argc) {
- log_very_verbose("Using physical volume(s) on command line");
-
- for (; opt < argc; opt++) {
- if (!(pv = pv_read(cmd, argv[opt], NULL, NULL))) {
- log_error("Failed to read physical "
- "volume \"%s\"", argv[opt]);
- continue;
- }
- pvdisplay_single(cmd, pv, NULL);
- }
- } else {
- log_verbose("Scanning for physical volume names");
- if (!(pvs = get_pvs(cmd)))
- return ECMD_FAILED;
-
- list_iterate(pvh, pvs)
- pvdisplay_single(cmd, list_item(pvh, struct pv_list)->pv,
- NULL);
- }
+ process_each_pv(cmd, argc, argv, NULL, NULL, pvdisplay_single);
return 0;
}
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 3f3b2f1b..395a245a 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -29,8 +29,6 @@ void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv,
char uuid[64];
int vg_name_len = 0;
- char *s1, *s2;
-
char pv_tmp_name[NAME_LEN] = { 0, };
char vg_tmp_name[NAME_LEN] = { 0, };
char vg_name_this[NAME_LEN] = { 0, };
@@ -73,8 +71,7 @@ void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv,
pv_max_name_len, pv_tmp_name,
vg_max_name_len, " ",
pv->fmt ? pv->fmt->name : " ",
- (s1 = display_size(pv->size / 2, SIZE_SHORT)));
- dbg_free(s1);
+ display_size(cmd, pv->size / 2, SIZE_SHORT));
return;
}
@@ -83,14 +80,12 @@ void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv,
log_print("PV %-*s is in exported VG %s "
"[%s / %s free]",
pv_max_name_len, pv_tmp_name,
- vg_name_this, (s1 =
- display_size(pv->pe_count *
- pv->pe_size / 2,
- SIZE_SHORT)),
- (s2 = display_size((pv->pe_count - pv->pe_alloc_count)
- * pv->pe_size / 2, SIZE_SHORT)));
- dbg_free(s1);
- dbg_free(s2);
+ vg_name_this,
+ display_size(cmd, pv->pe_count *
+ pv->pe_size / 2,
+ SIZE_SHORT),
+ display_size(cmd, (pv->pe_count - pv->pe_alloc_count)
+ * pv->pe_size / 2, SIZE_SHORT));
return;
}
@@ -99,13 +94,10 @@ void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv,
("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len,
pv_tmp_name, vg_max_name_len, vg_tmp_name,
pv->fmt ? pv->fmt->name : " ",
- (s1 = display_size(pv->pe_count * pv->pe_size / 2, SIZE_SHORT)),
- (s2 =
- display_size((pv->pe_count - pv->pe_alloc_count) * pv->pe_size /
- 2, SIZE_SHORT)));
- dbg_free(s1);
- dbg_free(s2);
-
+ display_size(cmd, pv->pe_count * pv->pe_size / 2, SIZE_SHORT),
+ display_size(cmd,
+ (pv->pe_count - pv->pe_alloc_count) * pv->pe_size / 2,
+ SIZE_SHORT));
return;
}
@@ -113,7 +105,6 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
{
int new_pvs_found = 0;
int pvs_found = 0;
- char *s1, *s2, *s3;
struct list *pvs;
struct list *pvh;
@@ -205,14 +196,10 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
log_print("Total: %d [%s] / in use: %d [%s] / in no VG: %d [%s]",
pvs_found,
- (s1 = display_size(size_total / 2, SIZE_SHORT)),
+ display_size(cmd, size_total / 2, SIZE_SHORT),
pvs_found - new_pvs_found,
- (s2 =
- display_size((size_total - size_new) / 2, SIZE_SHORT)),
- new_pvs_found, (s3 = display_size(size_new / 2, SIZE_SHORT)));
- dbg_free(s1);
- dbg_free(s2);
- dbg_free(s3);
+ display_size(cmd, (size_total - size_new) / 2, SIZE_SHORT),
+ new_pvs_found, display_size(cmd, size_new / 2, SIZE_SHORT));
return 0;
}
diff --git a/tools/report.c b/tools/report.c
new file mode 100644
index 00000000..21b4afc1
--- /dev/null
+++ b/tools/report.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2001 Sistina Software
+ *
+ * LVM is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * LVM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LVM; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "tools.h"
+#include "report.h"
+#include "defaults.h"
+
+static int _vgs_single(struct cmd_context *cmd, const char *vg_name,
+ struct volume_group *vg, int consistent, void *handle)
+{
+ if (!vg) {
+ log_error("Volume group %s not found", vg_name);
+ return ECMD_FAILED;
+ }
+
+ if (!report_object(handle, vg, NULL, NULL, NULL))
+ return ECMD_FAILED;
+
+ return 0;
+}
+
+static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
+ void *handle)
+{
+ if (!report_object(handle, lv->vg, lv, NULL, NULL))
+ return ECMD_FAILED;
+
+ return 0;
+}
+
+static int _segs_single(struct cmd_context *cmd, struct lv_segment *seg,
+ void *handle)
+{
+ if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg))
+ return ECMD_FAILED;
+
+ return 0;
+}
+
+static int _lvsegs_single(struct cmd_context *cmd, struct logical_volume *lv,
+ void *handle)
+{
+ return process_each_segment_in_lv(cmd, lv, handle, _segs_single);
+}
+
+static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
+ struct physical_volume *pv, void *handle)
+{
+ int consistent = 0;
+
+ if (!lock_vol(cmd, pv->vg_name, LCK_VG_READ)) {
+ log_error("Can't lock %s: skipping", pv->vg_name);
+ return 0;
+ }
+ vg = vg_read(cmd, pv->vg_name, &consistent);
+
+ if (!report_object(handle, vg, NULL, pv, NULL))
+ return ECMD_FAILED;
+
+ unlock_vg(cmd, pv->vg_name);
+
+ return 0;
+}
+
+static int _report(struct cmd_context *cmd, int argc, char **argv,
+ report_type_t report_type)
+{
+ void *report_handle;
+ char *opts, *str;
+ const char *keys, *options, *separator;
+
+ int aligned, buffered, headings;
+
+ aligned = find_config_int(cmd->cf->root, "report/aligned", '/',
+ DEFAULT_REP_ALIGNED);
+ buffered = find_config_int(cmd->cf->root, "report/buffered", '/',
+ DEFAULT_REP_BUFFERED);
+ headings = find_config_int(cmd->cf->root, "report/headings", '/',
+ DEFAULT_REP_HEADINGS);
+ separator = find_config_str(cmd->cf->root, "report/separator", '/',
+ DEFAULT_REP_SEPARATOR);
+
+ switch (report_type) {
+ case LVS:
+ keys = find_config_str(cmd->cf->root, "report/lvs_sort", '/',
+ DEFAULT_LVS_SORT);
+ if (!arg_count(cmd, verbose_ARG))
+ options = find_config_str(cmd->cf->root,
+ "report/lvs_cols", '/',
+ DEFAULT_LVS_COLS);
+ else
+ options = find_config_str(cmd->cf->root,
+ "report/lvs_cols_verbose",
+ '/', DEFAULT_LVS_COLS_VERB);
+ break;
+ case VGS:
+ keys = find_config_str(cmd->cf->root, "report/vgs_sort", '/',
+ DEFAULT_VGS_SORT);
+ if (!arg_count(cmd, verbose_ARG))
+ options = find_config_str(cmd->cf->root,
+ "report/vgs_cols", '/',
+ DEFAULT_VGS_COLS);
+ else
+ options = find_config_str(cmd->cf->root,
+ "report/vgs_cols_verbose",
+ '/', DEFAULT_VGS_COLS_VERB);
+ break;
+ case PVS:
+ keys = find_config_str(cmd->cf->root, "report/pvs_sort", '/',
+ DEFAULT_PVS_SORT);
+ if (!arg_count(cmd, verbose_ARG))
+ options = find_config_str(cmd->cf->root,
+ "report/pvs_cols", '/',
+ DEFAULT_PVS_COLS);
+ else
+ options = find_config_str(cmd->cf->root,
+ "report/pvs_cols_verbose",
+ '/', DEFAULT_PVS_COLS_VERB);
+ break;
+ case SEGS:
+ keys = find_config_str(cmd->cf->root, "report/segs_sort", '/',
+ DEFAULT_SEGS_SORT);
+ if (!arg_count(cmd, verbose_ARG))
+ options = find_config_str(cmd->cf->root,
+ "report/segs_cols", '/',
+ DEFAULT_SEGS_COLS);
+ else
+ options = find_config_str(cmd->cf->root,
+ "report/segs_cols_verbose",
+ '/', DEFAULT_SEGS_COLS_VERB);
+ break;
+ }
+
+ /* If -o supplied use it, else use default for report_type */
+ if (arg_count(cmd, options_ARG)) {
+ opts = arg_str_value(cmd, options_ARG, "");
+ if (!opts || !*opts) {
+ log_error("Invalid options string: %s", opts);
+ return 0;
+ }
+ if (*opts == '+') {
+ *opts = ',';
+ str =
+ pool_alloc(cmd->mem,
+ strlen(options) + strlen(opts) + 1);
+ strcpy(str, options);
+ strcat(str, opts);
+ options = str;
+ } else
+ options = opts;
+ }
+
+ /* -O overrides default sort settings */
+ if (arg_count(cmd, sort_ARG))
+ keys = arg_str_value(cmd, sort_ARG, "");
+
+ if (arg_count(cmd, separator_ARG))
+ separator = arg_str_value(cmd, separator_ARG, " ");
+ if (arg_count(cmd, separator_ARG))
+ aligned = 0;
+ if (arg_count(cmd, aligned_ARG))
+ aligned = 1;
+ if (arg_count(cmd, unbuffered_ARG) && !arg_count(cmd, sort_ARG))
+ buffered = 0;
+ if (arg_count(cmd, noheadings_ARG))
+ headings = 0;
+
+ if (!(report_handle = report_init(cmd, options, keys, &report_type,
+ separator, aligned, buffered,
+ headings)))
+ return 0;
+
+ switch (report_type) {
+ case LVS:
+ process_each_lv(cmd, argc, argv, LCK_VG_READ, report_handle,
+ &_lvs_single);
+ break;
+ case VGS:
+ process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, report_handle,
+ &_vgs_single);
+ break;
+ case PVS:
+ process_each_pv(cmd, argc, argv, NULL, report_handle,
+ &_pvs_single);
+ break;
+ case SEGS:
+ process_each_lv(cmd, argc, argv, LCK_VG_READ, report_handle,
+ &_lvsegs_single);
+ break;
+ }
+
+ report_output(report_handle);
+
+ report_free(report_handle);
+ return ECMD_PROCESSED;
+}
+
+int lvs(struct cmd_context *cmd, int argc, char **argv)
+{
+ report_type_t type;
+
+ if (arg_count(cmd, segments_ARG))
+ type = SEGS;
+ else
+ type = LVS;
+
+ return _report(cmd, argc, argv, type);
+}
+
+int vgs(struct cmd_context *cmd, int argc, char **argv)
+{
+ return _report(cmd, argc, argv, VGS);
+}
+
+int pvs(struct cmd_context *cmd, int argc, char **argv)
+{
+ return _report(cmd, argc, argv, PVS);
+}
diff --git a/tools/toollib.c b/tools/toollib.c
index 917b4ff0..80d0fbee 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -202,6 +202,28 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
return ret_max;
}
+int process_each_segment_in_lv(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ void *handle,
+ int (*process_single) (struct cmd_context * cmd,
+ struct lv_segment * seg,
+ void *handle))
+{
+ struct list *segh;
+ struct lv_segment *seg;
+ int ret_max = 0;
+ int ret;
+
+ list_iterate(segh, &lv->segments) {
+ seg = list_item(segh, struct lv_segment);
+ ret = process_single(cmd, seg, handle);
+ if (ret > ret_max)
+ ret_max = ret;
+ }
+
+ return ret_max;
+}
+
int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
int lock_type, int consistent, void *handle,
int (*process_single) (struct cmd_context * cmd,
@@ -303,23 +325,50 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
int ret = 0;
struct pv_list *pvl;
+ struct physical_volume *pv;
+ struct list *pvs, *pvh;
if (argc) {
log_verbose("Using physical volume(s) on command line");
for (; opt < argc; opt++) {
- if (!(pvl = find_pv_in_vg(vg, argv[opt]))) {
- log_error("Physical Volume \"%s\" not found in "
- "Volume Group \"%s\"", argv[opt],
- vg->name);
- continue;
+ if (vg) {
+ if (!(pvl = find_pv_in_vg(vg, argv[opt]))) {
+ log_error("Physical Volume \"%s\" not "
+ "found in Volume Group "
+ "\"%s\"", argv[opt],
+ vg->name);
+ continue;
+ }
+ pv = pvl->pv;
+ } else {
+ if (!(pv = pv_read(cmd, argv[opt], NULL, NULL))) {
+ log_error("Failed to read physical "
+ "volume \"%s\"", argv[opt]);
+ continue;
+ }
}
- ret = process_single(cmd, vg, pvl->pv, handle);
+
+ ret = process_single(cmd, vg, pv, handle);
if (ret > ret_max)
ret_max = ret;
}
} else {
- log_verbose("Using all physical volume(s) in volume group");
- process_each_pv_in_vg(cmd, vg, handle, process_single);
+ if (vg) {
+ log_verbose("Using all physical volume(s) in "
+ "volume group");
+ process_each_pv_in_vg(cmd, vg, handle, process_single);
+ } else {
+ log_verbose("Scanning for physical volume names");
+ if (!(pvs = get_pvs(cmd)))
+ return ECMD_FAILED;
+
+ list_iterate(pvh, pvs) {
+ pv = list_item(pvh, struct pv_list)->pv;
+ ret = process_single(cmd, NULL, pv, handle);
+ if (ret > ret_max)
+ ret_max = ret;
+ }
+ }
}
return ret_max;
diff --git a/tools/toollib.h b/tools/toollib.h
index 8b5ef7ed..9390ff3e 100644
--- a/tools/toollib.h
+++ b/tools/toollib.h
@@ -35,10 +35,9 @@ struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname,
int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
int lock_type, int consistent, void *handle,
int (*process_single) (struct cmd_context * cmd,
- const char *vg_name,
- struct volume_group *vg,
- int consistent,
- void *handle));
+ const char *vg_name,
+ struct volume_group * vg,
+ int consistent, void *handle));
int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
struct volume_group *vg, void *handle,
@@ -53,6 +52,12 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
struct logical_volume * lv,
void *handle));
+int process_each_segment_in_lv(struct cmd_context *cmd,
+ struct logical_volume *lv, void *handle,
+ int (*process_single) (struct cmd_context * cmd,
+ struct lv_segment * seg,
+ void *handle));
+
int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
void *handle,
int (*process_single) (struct cmd_context * cmd,
diff --git a/tools/tools.h b/tools/tools.h
index 9a16b6c4..7e5fc9b7 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -74,7 +74,8 @@ struct arg {
int count;
char *value;
uint32_t i_value;
- uint64_t i64_value;
+ int64_t i64_value;
+ uint64_t ui64_value;
sign_t sign;
void *ptr;
};
@@ -102,6 +103,7 @@ int minor_arg(struct cmd_context *cmd, struct arg *a);
int string_arg(struct cmd_context *cmd, struct arg *a);
int permission_arg(struct cmd_context *cmd, struct arg *a);
int metadatatype_arg(struct cmd_context *cmd, struct arg *a);
+int units_arg(struct cmd_context *cmd, struct arg *a);
char yes_no_prompt(const char *prompt, ...);
@@ -127,12 +129,18 @@ static inline uint32_t arg_int_value(struct cmd_context *cmd, int a,
return arg_count(cmd, a) ? cmd->args[a].i_value : def;
}
-static inline uint64_t arg_int64_value(struct cmd_context *cmd, int a,
- uint64_t def)
+static inline int64_t arg_int64_value(struct cmd_context *cmd, int a,
+ uint64_t def)
{
return arg_count(cmd, a) ? cmd->args[a].i64_value : def;
}
+static inline uint64_t arg_uint64_value(struct cmd_context *cmd, int a,
+ uint64_t def)
+{
+ return arg_count(cmd, a) ? cmd->args[a].ui64_value : def;
+}
+
static inline void *arg_ptr_value(struct cmd_context *cmd, int a, void *def)
{
return arg_count(cmd, a) ? cmd->args[a].ptr : def;
diff --git a/tools/vgck.c b/tools/vgck.c
index 6a6eb1ec..5cd9a858 100644
--- a/tools/vgck.c
+++ b/tools/vgck.c
@@ -38,7 +38,6 @@ static int vgck_single(struct cmd_context *cmd, const char *vg_name,
return ECMD_FAILED;
}
- /* FIXME: free */
return 0;
}
diff --git a/tools/vgconvert.c b/tools/vgconvert.c
index 59043af7..5116b382 100644
--- a/tools/vgconvert.c
+++ b/tools/vgconvert.c
@@ -63,7 +63,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
}
if (cmd->fmt->features & FMT_MDAS) {
- pvmetadatasize = arg_int64_value(cmd, metadatasize_ARG, 0) * 2;
+ pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, 0) * 2;
if (!pvmetadatasize)
pvmetadatasize =
find_config_int(cmd->cf->root,
diff --git a/tools/vgdisplay.c b/tools/vgdisplay.c
index 72bc3b38..7a4e4bed 100644
--- a/tools/vgdisplay.c
+++ b/tools/vgdisplay.c
@@ -62,6 +62,23 @@ static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name,
int vgdisplay(struct cmd_context *cmd, int argc, char **argv)
{
+ if (arg_count(cmd, columns_ARG)) {
+ if (arg_count(cmd, colon_ARG) ||
+ arg_count(cmd, activevolumegroups_ARG) ||
+ arg_count(cmd, short_ARG)) {
+ log_error("Incompatible options selected");
+ return EINVALID_CMD_LINE;
+ }
+ return vgs(cmd, argc, argv);
+ } else if (arg_count(cmd, aligned_ARG) ||
+ arg_count(cmd, noheadings_ARG) ||
+ arg_count(cmd, options_ARG) ||
+ arg_count(cmd, separator_ARG) ||
+ arg_count(cmd, sort_ARG) || arg_count(cmd, unbuffered_ARG)) {
+ log_error("Incompatible options selected");
+ return EINVALID_CMD_LINE;
+ }
+
if (arg_count(cmd, colon_ARG) && arg_count(cmd, short_ARG)) {
log_error("Option -c is not allowed with option -s");
return EINVALID_CMD_LINE;