* [PATCH] (1/4) dm_report support in libdevmapper
@ 2007-01-12 23:13 ` Jun'ichi Nomura
0 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:13 UTC (permalink / raw)
To: device-mapper development, LVM2 development
[-- Attachment #1: Type: text/plain, Size: 506 bytes --]
Hi,
Attached patch adds dm_report API to libdevmapper.
The code is based on LVM2 lib/report with a enhancement
to option format (e.g. "name=a" to report objects whose
"name" field is "a") and generalizations.
I would like to use this from dmsetup to make "dmsetup info -c"
more flexible like LVM2 lvs/pvs/vgs commands.
Also, LVM2 can use this API instead of its own lib/report.
(Patches for dmsetup and LVM2 will follow.)
Comments are welcome.
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: 01-libdm-report.patch --]
[-- Type: text/x-patch, Size: 33117 bytes --]
New dm_report API.
The code is based on LVM2 reporter function and act much like
lvs/pvs/vgs commands.
Main APIs are:
- dm_report_init
Register definition of reported object types and fields
and set options.
Returns a handle for following calls.
- dm_report_object
Generate report for one object.
The result will be sorted and bufferred until dm_report_output is called
if requested.
- dm_report_output
Output bufferred report.
- dm_report_free
Abandon the report handle.
There are some other functions for types and fields definition.
Details can be found in the patch.
And each field name passed by format parameter of dm_report_init can be
followed by the following comparison operator and the value or string:
= : equal to the value or string
!= : not equal to the value or string
>= : greater than or equal to the value
<= : lesser than or equal to the value
< : lesser than the value
> : greater than the value
=~ : contains the string
!~ : not contain the string
=~^ : contains the string as prefix
!~^ : not contain the string as prefix
If the field name is prefixed by "-" in "-o" option string,
the field is used only to check the condition and not displayed.
Index: device-mapper/lib/libdevmapper.h
===================================================================
--- device-mapper.orig/lib/libdevmapper.h 2007-01-12 15:21:52.000000000 -0500
+++ device-mapper/lib/libdevmapper.h 2007-01-12 15:36:55.000000000 -0500
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2007 NEC Corporation
*
* This file is part of the device-mapper userspace tools.
*
@@ -623,4 +624,68 @@ int dm_snprintf(char *buf, size_t bufsiz
*/
char *dm_basename(const char *path);
+/*********************
+ * report function
+ *********************/
+
+struct dm_report_field;
+struct dm_report;
+
+/* Definition of reported object */
+struct dm_report_object_type {
+ uint32_t id; /* must be a power of 2 */
+ const char *desc; /* description of the object type */
+ const char *prefix; /* default prefix of id string (if any) */
+ void * (*get) (void *object); /* callback from report_object() */
+};
+
+/* Definition of field */
+#define DM_REPORT_FIELD_ALIGN_LEFT 0x00000001
+#define DM_REPORT_FIELD_ALIGN_RIGHT 0x00000002
+#define DM_REPORT_FIELD_STRING 0x00000004
+#define DM_REPORT_FIELD_NUMBER 0x00000008
+struct dm_report_field_type {
+ uint32_t type; /* object type id */
+ const char id[32]; /* string used to specify the field */
+ unsigned int offset; /* byte offset in the object */
+ const char heading[32]; /* string printed in header */
+ int width; /* default width */
+ uint32_t flags; /* string or number, alignment */
+ int (*report_fn) (struct dm_report * rh, struct dm_pool * mem,
+ struct dm_report_field * field, const void *data);
+};
+
+/*
+ * Report API
+ */
+struct dm_report *dm_report_init(const char *format, const char *keys,
+ uint32_t *report_types, const char *separator,
+ int aligned, int buffered, int headings,
+ const struct dm_report_field_type *fds,
+ int num_fds,
+ const struct dm_report_object_type *types,
+ int num_types,
+ void *private);
+void dm_report_free(struct dm_report *rh);
+int dm_report_object(struct dm_report *rh, void *object);
+int dm_report_output(struct dm_report *rh);
+void * dm_report_get_private(struct dm_report *rh);
+
+/* report functions for common types */
+int dm_report_field_string(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data);
+int dm_report_field_int32(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data);
+int dm_report_field_uint32(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data);
+int dm_report_field_int(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data);
+int dm_report_field_uint64(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data);
+
+/* helper functions for custom report functions */
+int dm_report_field_raw(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data);
+void dm_report_field_set_string(struct dm_report_field *field, const char *string);
+void dm_report_field_set_sort_value(struct dm_report_field *field, const void *value);
#endif /* LIB_DEVICE_MAPPER_H */
Index: device-mapper/lib/libdm-report.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ device-mapper/lib/libdm-report.c 2007-01-12 15:56:04.000000000 -0500
@@ -0,0 +1,1111 @@
+/*
+ * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2007 NEC Corporation
+ *
+ * This file is part of device-mapper userspace tools.
+ * The code is based on LVM2 report function.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "libdevmapper.h"
+#include "list.h"
+#include "log.h"
+
+/*
+ * 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 dm_report {
+ struct dm_pool *mem;
+
+ uint32_t report_types;
+ const 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;
+
+ /* Array of field definitions */
+ const struct dm_report_field_type *fields;
+ int num_fields;
+ const struct dm_report_object_type *types;
+ int num_types;
+
+ /* To store caller private data */
+ void *private;
+};
+
+void * dm_report_get_private(struct dm_report *rh)
+{
+ return rh->private;
+}
+
+/*
+ * 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
+
+#define FLD_CMP_EQUAL 0x00010000
+#define FLD_CMP_NOT 0x00020000
+#define FLD_CMP_GT 0x00040000
+#define FLD_CMP_LT 0x00080000
+#define FLD_CMP_SUBSTR 0x00100000
+#define FLD_CMP_PREFIX 0x00200000
+#define FLD_CMP_MASK 0x00ff0000
+
+struct field_properties {
+ struct list list;
+ uint32_t field_num;
+ uint32_t sort_posn;
+ int width;
+ const struct dm_report_object_type *type;
+ uint32_t flags;
+ char *cmp;
+};
+
+/*
+ * Report data field
+ */
+struct dm_report_field {
+ struct list list;
+ struct field_properties *props;
+
+ const char *report_string; /* Formatted ready for display */
+ const void *sort_value; /* Raw value for sorting */
+};
+
+struct row {
+ struct list list;
+ struct dm_report *rh;
+ struct list fields; /* Fields in display order */
+ struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
+};
+
+static const struct dm_report_object_type *_find_type(struct dm_report *rh,
+ uint32_t report_type)
+{
+ const struct dm_report_object_type *t;
+
+ for (t = rh->types; t < rh->types + rh->num_types; t++)
+ if (t->id == report_type)
+ return t;
+
+ return NULL;
+}
+
+/*
+ * Data-munging functions to prepare each data type for display and sorting
+ */
+
+int dm_report_field_string(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ char *repstr;
+
+ if (!(repstr = dm_pool_strdup(rh->mem, *(const char **) data))) {
+ log_error("dm_report_field_string: dm_pool_strdup failed");
+ return 0;
+ }
+
+ field->report_string = repstr;
+ field->sort_value = (const void *) field->report_string;
+
+ return 1;
+}
+
+int dm_report_field_uint32(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ const uint32_t value = *(const uint32_t *) data;
+ uint64_t *sortval;
+ char *repstr;
+
+ if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
+ log_error("dm_report_field_uint32: dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
+ log_error("dm_report_field_uint32: dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (dm_snprintf(repstr, 11, "%u", value) < 0) {
+ log_error("dm_report_field_uint32: uint32 too big: %u", value);
+ return 0;
+ }
+
+ *sortval = (const uint64_t) value;
+ field->sort_value = sortval;
+ field->report_string = repstr;
+
+ return 1;
+}
+
+int dm_report_field_int32(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ const int32_t value = *(const int32_t *) data;
+ uint64_t *sortval;
+ char *repstr;
+
+ if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
+ log_error("dm_report_field_int32: dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
+ log_error("dm_report_field_int32: dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (dm_snprintf(repstr, 12, "%d", value) < 0) {
+ log_error("dm_report_field_int32: int32 too big: %d", value);
+ return 0;
+ }
+
+ *sortval = (const uint64_t) value;
+ field->sort_value = sortval;
+ field->report_string = repstr;
+
+ return 1;
+}
+
+int dm_report_field_int(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ const int value = *(const int *) data;
+ uint64_t *sortval;
+ char *repstr;
+
+ if (!(repstr = dm_pool_zalloc(rh->mem, 23))) {
+ log_error("dm_report_field_int: dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
+ log_error("dm_report_field_int: dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (dm_snprintf(repstr, 22, "%d", value) < 0) {
+ log_error("dm_report_field_int: int too big: %d", value);
+ return 0;
+ }
+
+ *sortval = (const uint64_t) value;
+ field->sort_value = sortval;
+ field->report_string = repstr;
+
+ return 1;
+}
+
+int dm_report_field_uint64(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ const int value = *(const uint64_t *) data;
+ uint64_t *sortval;
+ char *repstr;
+
+ if (!(repstr = dm_pool_zalloc(rh->mem, 22))) {
+ log_error("dm_report_field_uint64: dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
+ log_error("dm_report_field_uint64: dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (dm_snprintf(repstr, 21, "%d", value) < 0) {
+ log_error("dm_report_field_uint64: uint64 too big: %d", value);
+ return 0;
+ }
+
+ *sortval = (const uint64_t) value;
+ field->sort_value = sortval;
+ field->report_string = repstr;
+
+ return 1;
+}
+
+/*
+ * Helper functions for custom report functions
+ */
+void dm_report_field_set_string(struct dm_report_field *field,
+ const char *string)
+{
+ field->report_string = string;
+}
+
+void dm_report_field_set_sort_value(struct dm_report_field *field,
+ const void *value)
+{
+ field->sort_value = value;
+}
+
+int dm_report_field_raw(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ field->report_string = (const char *) data;
+ field->sort_value = data;
+ return 1;
+}
+
+/*
+ * comparison operators to set a condition to display row
+ */
+static char _cmp_op_chars[] = "=!><~^";
+
+static struct {
+ const char *string;
+ uint32_t flags;
+} _cmp_op[] = {
+ { "=", FLD_CMP_EQUAL },
+ { "!=", FLD_CMP_NOT|FLD_CMP_EQUAL },
+ { ">", FLD_CMP_GT|FLD_NUMBER },
+ { ">=", FLD_CMP_GT|FLD_CMP_EQUAL|FLD_NUMBER },
+ { "<", FLD_CMP_LT|FLD_NUMBER },
+ { "<=", FLD_CMP_LT|FLD_CMP_EQUAL|FLD_NUMBER },
+ { "=~", FLD_CMP_SUBSTR|FLD_STRING },
+ { "!~", FLD_CMP_SUBSTR|FLD_CMP_NOT|FLD_STRING },
+ { "=~^", FLD_CMP_PREFIX|FLD_STRING },
+ { "!~^", FLD_CMP_PREFIX|FLD_CMP_NOT|FLD_STRING },
+ { NULL, 0 }
+};
+
+static int _cmp_op_char(const char c)
+{
+ char *p = _cmp_op_chars;
+
+ while (*p) {
+ if (*p == c)
+ return 1;
+ p++;
+ }
+
+ return 0;
+}
+
+static uint32_t _cmp_op_flags(struct dm_report *rh, const char *s, int len)
+{
+ int i;
+ char *buf;
+
+ for (i = 0; _cmp_op[i].string; i++)
+ if (!strncmp(s, _cmp_op[i].string, len))
+ return _cmp_op[i].flags;
+
+ if (!(buf = dm_pool_zalloc(rh->mem, len + 1))) {
+ log_error("dm_report: log message allocation failed");
+ return 0;
+ }
+ memcpy(buf, s, len);
+ log_error("dm_report: wrong comparison operator %s", buf);
+ dm_pool_free(rh->mem, buf);
+ return 0;
+}
+
+/*
+ * show help message
+ */
+static void _display_operators(void)
+{
+ int i;
+
+ log_print(" ");
+ log_print("Comparison operators");
+
+ for (i = 0; _cmp_op[i].string; i++)
+ log_print("- %s %s%s", _cmp_op[i].string,
+ _cmp_op[i].flags & FLD_NUMBER ? "(number only)" : "",
+ _cmp_op[i].flags & FLD_STRING ? "(string only)" : "");
+}
+
+static void _display_fields(struct dm_report *rh)
+{
+ uint32_t f;
+ const struct dm_report_object_type *type;
+ const char *desc, *last_desc = "";
+
+ for (f = 0; f < rh->num_fields; f++) {
+ if ((type = _find_type(rh, rh->fields[f].type)) && type->desc)
+ desc = type->desc;
+ else
+ desc = " ";
+ if (desc != last_desc) {
+ if (*last_desc)
+ log_print(" ");
+ log_print("%s Fields", desc);
+ }
+
+ log_print("- %s", rh->fields[f].id);
+ last_desc = desc;
+ }
+
+ _display_operators();
+}
+
+/*
+ * Initialise report handle
+ */
+
+static uint32_t _translate_flags(uint32_t flags)
+{
+ /* translate public flags (DM_REPORT_) to internal flags (FLD_) */
+ static uint32_t _map[] = {
+ DM_REPORT_FIELD_ALIGN_LEFT, FLD_ALIGN_LEFT,
+ DM_REPORT_FIELD_ALIGN_RIGHT, FLD_ALIGN_RIGHT,
+ DM_REPORT_FIELD_STRING, FLD_STRING,
+ DM_REPORT_FIELD_NUMBER, FLD_NUMBER,
+ 0, 0,
+ };
+ uint32_t f = 0, *m;
+
+ for (m = _map; *m; m += 2)
+ if (flags & *m)
+ f |= *(m + 1);
+
+ return f;
+}
+
+static int _copy_field(struct dm_report *rh, struct field_properties *dest,
+ uint32_t field_num)
+{
+ dest->field_num = field_num;
+ dest->width = rh->fields[field_num].width;
+ dest->flags = _translate_flags(rh->fields[field_num].flags);
+
+ /* set object type method */
+ dest->type = _find_type(rh, rh->fields[field_num].type);
+ if (!dest->type) {
+ log_error("dm_report: field not match: %s",
+ rh->fields[field_num].id);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _field_match(struct dm_report *rh,
+ const char *field, size_t flen,
+ const char *cmp, size_t clen, uint32_t cflags)
+{
+ uint32_t f, l;
+ struct field_properties *fp;
+
+ if (!flen)
+ return 0;
+
+ for (f = 0; f < rh->num_fields; f++) {
+ if ((!strncasecmp(rh->fields[f].id, field, flen) &&
+ strlen(rh->fields[f].id) == flen) ||
+ (l = strlen(rh->field_prefix),
+ !strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
+ !strncasecmp(rh->fields[f].id + l, field, flen) &&
+ strlen(rh->fields[f].id) == l + flen)) {
+ rh->report_types |= rh->fields[f].type;
+ if (!(fp = dm_pool_zalloc(rh->mem, sizeof(*fp)))) {
+ log_error("dm_report: "
+ "struct field_properties allocation "
+ "failed");
+ return 0;
+ }
+ if (!_copy_field(rh, fp, f))
+ return 0;
+
+ /* comparison operator */
+ fp->flags |= cflags;
+ if (fp->flags & FLD_NUMBER && fp->flags & FLD_STRING) {
+ log_error("dm_report: operator type conflict");
+ if (cflags & FLD_NUMBER)
+ log_error("for number only");
+ else /* FLD_STRING */
+ log_error("for string only");
+ }
+
+ if (!(fp->cmp = dm_pool_zalloc(rh->mem, clen + 1))) {
+ log_error("dm_report: "
+ "condition string allocation "
+ "failed");
+ return 0;
+ }
+ memcpy(fp->cmp, cmp, clen);
+
+ list_add(&rh->field_props, &fp->list);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
+ uint32_t flags)
+{
+ struct field_properties *fp, *found = NULL;
+
+ list_iterate_items(fp, &rh->field_props) {
+ if (fp->field_num == field_num) {
+ found = fp;
+ break;
+ }
+ }
+
+ if (!found) {
+ rh->report_types |= rh->fields[field_num].type;
+ if (!(found = dm_pool_zalloc(rh->mem, sizeof(*found)))) {
+ log_error("dm_report: "
+ "struct field_properties allocation failed");
+ return 0;
+ }
+ if (!_copy_field(rh, found, field_num))
+ return 0;
+
+ /* Add as a non-display field */
+ found->flags |= FLD_HIDDEN;
+
+ list_add(&rh->field_props, &found->list);
+ }
+
+ if (found->flags & FLD_SORT_KEY) {
+ log_error("dm_report: Ignoring duplicate sort field: %s",
+ rh->fields[field_num].id);
+ return 1;
+ }
+
+ found->flags |= FLD_SORT_KEY;
+ found->sort_posn = rh->keys_count++;
+ found->flags |= flags;
+
+ return 1;
+}
+
+static int _key_match(struct dm_report *rh, const char *key, size_t len)
+{
+ uint32_t f, l;
+ uint32_t flags;
+
+ 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("dm_report: Missing sort field name");
+ return 0;
+ }
+
+ for (f = 0; f < rh->num_fields; f++) {
+ if ((!strncasecmp(rh->fields[f].id, key, len) &&
+ strlen(rh->fields[f].id) == len) ||
+ (l = strlen(rh->field_prefix),
+ !strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
+ !strncasecmp(rh->fields[f].id + l, key, len) &&
+ strlen(rh->fields[f].id) == l + len)) {
+ return _add_sort_key(rh, f, flags);
+ }
+ }
+
+ return 0;
+}
+
+static int _parse_options(struct dm_report *rh, const char *format)
+{
+ const char *ws; /* Word start */
+ const char *we = format; /* Word end */
+ const char *cs, *ce; /* Comparison word start/end */
+ uint32_t flags;
+
+ while (*we) {
+ flags = 0;
+
+ /* Allow consecutive commas */
+ while (*we && *we == ',')
+ we++;
+
+ /* prefix of condition to mark the field hidden */
+ if (*we == '-') {
+ flags |= FLD_HIDDEN;
+ we++;
+ }
+
+ /* start of the field name */
+ ws = we;
+ while (*we && *we != ',' && !_cmp_op_char(*we))
+ we++;
+
+ /* comparison operator and string if any */
+ cs = ce = NULL;
+ if (_cmp_op_char(*we)) {
+ cs = ce = we;
+ while (*ce && *ce != ',' && _cmp_op_char(*ce))
+ ce++;
+ flags |= _cmp_op_flags(rh, cs, ce - cs);
+
+ cs = ce;
+ while (*ce && *ce != ',')
+ ce++;
+ }
+
+ if (!_field_match(rh, ws, (size_t) (we - ws),
+ cs, (size_t) (ce - cs), flags)) {
+ _display_fields(rh);
+ log_print(" ");
+ log_error("dm_report: Unrecognised field: %.*s",
+ (int) (we - ws), ws);
+ return 0;
+ }
+
+ if (ce)
+ we = ce;
+ }
+
+ return 1;
+}
+
+static int _parse_keys(struct dm_report *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, (size_t) (we - ws))) {
+ log_error("dm_report: Unrecognised field: %.*s",
+ (int) (we - ws), ws);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+#define ALIGN_MASK (DM_REPORT_FIELD_ALIGN_LEFT|DM_REPORT_FIELD_ALIGN_RIGHT)
+#define TYPE_MASK (DM_REPORT_FIELD_NUMBER|DM_REPORT_FIELD_STRING)
+
+/*
+ * Check the field/type definition as much as possible
+ * to omit checks in the later stage or avoid unexpected failures
+ */
+static int _check_definition(const struct dm_report_field_type *fds,
+ int num_fds,
+ const struct dm_report_object_type *types,
+ int num_types)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < num_fds; i++) {
+ if (!fds[i].report_fn) {
+ log_error("dm_report: report_fn isn't defined for %s",
+ fds[i].id);
+ ret = 1;
+ }
+
+ if (!(fds[i].flags & TYPE_MASK)) {
+ log_error("dm_report: field %s type unspecified",
+ fds[i].id);
+ ret = 1;
+ }
+ if ((fds[i].flags & TYPE_MASK) == TYPE_MASK) {
+ log_error("dm_report: field %s type conflict",
+ fds[i].id);
+ ret = 1;
+ }
+
+ if (!(fds[i].flags & ALIGN_MASK)) {
+ log_error("dm_report: field %s alignment unspecified",
+ fds[i].id);
+ ret = 1;
+ }
+ if ((fds[i].flags & ALIGN_MASK) == ALIGN_MASK) {
+ log_error("dm_report: field %s alignment conflict",
+ fds[i].id);
+ ret = 1;
+ }
+ }
+
+ for (i = 0; i < num_types; i++) {
+ if (hweight32(types[i].id) != 1) {
+ log_error("dm_report: object type %d isn't power of 2",
+ types[i].id);
+ ret = 1;
+ }
+ if (!types[i].get) {
+ log_error("dm_report: get isn't defined for object "
+ "type %d", types[i].id);
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+struct dm_report *dm_report_init(
+ const char *format, const char *keys,
+ uint32_t *report_types,
+ const char *separator,
+ int aligned, int buffered, int headings,
+ const struct dm_report_field_type *fds, int num_fds,
+ const struct dm_report_object_type *types, int num_types,
+ void *private)
+{
+ struct dm_report *rh;
+ const struct dm_report_object_type *type;
+
+ if (_check_definition(fds, num_fds, types, num_types))
+ return 0;
+
+ if (!(rh = dm_malloc(sizeof(*rh)))) {
+ log_error("dm_report_init: dm_malloc failed");
+ return 0;
+ }
+ memset(rh, 0, sizeof(*rh));
+
+ /*
+ * rh->report_types is updated in _parse_options() and _parse_keys()
+ * to contain all types corresponding to the fields specified by
+ * options or keys.
+ */
+ if (report_types)
+ rh->report_types = *report_types;
+
+ rh->separator = separator;
+ rh->fields = fds;
+ rh->num_fields = num_fds;
+ rh->types = types;
+ rh->num_types = num_types;
+ rh->private = private;
+
+ 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);
+
+ if ((type = _find_type(rh, rh->report_types)) && type->prefix)
+ rh->field_prefix = type->prefix;
+ else
+ rh->field_prefix = "";
+
+ if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
+ log_error("dm_report_init: allocation of memory pool 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;
+
+ /* Return updated types value for further compatility check by caller */
+ if (report_types)
+ *report_types = rh->report_types;
+
+ return rh;
+}
+
+void dm_report_free(struct dm_report *rh)
+{
+ dm_pool_destroy(rh->mem);
+
+ return;
+}
+
+/*
+ * Create a row of data for an object
+ */
+static int _compare_field_number(uint64_t a, uint64_t b, uint32_t flags)
+{
+ switch (flags & FLD_CMP_MASK) {
+ case FLD_CMP_EQUAL:
+ return a == b;
+ case FLD_CMP_NOT|FLD_CMP_EQUAL:
+ return a != b;
+ case FLD_CMP_GT:
+ return a > b;
+ case FLD_CMP_GT|FLD_CMP_EQUAL:
+ return a >= b;
+ case FLD_CMP_LT:
+ return a < b;
+ case FLD_CMP_LT|FLD_CMP_EQUAL:
+ return a <= b;
+ }
+ return 0;
+}
+
+static int _compare_field_string(const char *a, const char *b, uint32_t flags)
+{
+ switch (flags & FLD_CMP_MASK) {
+ case FLD_CMP_EQUAL:
+ return !strcmp(a, b);
+ case FLD_CMP_NOT|FLD_CMP_EQUAL:
+ return strcmp(a, b);
+ case FLD_CMP_PREFIX:
+ return !strncmp(b, a, strlen(b));
+ case FLD_CMP_PREFIX|FLD_CMP_NOT:
+ return strncmp(b, a, strlen(b));
+ case FLD_CMP_SUBSTR:
+ return strstr(a, b) != NULL;
+ case FLD_CMP_SUBSTR|FLD_CMP_NOT:
+ return strstr(a, b) == NULL;
+ }
+ return 0;
+}
+
+static int _compare_field(struct dm_report_field *field,
+ struct field_properties *fp)
+{
+ if (!field->sort_value) {
+ log_error("dm_report: field without value: %d",
+ field->props->field_num);
+ return 0;
+ }
+
+ if (field->props->flags & FLD_NUMBER) {
+ const uint64_t numa = *(const uint64_t *)field->sort_value;
+ const uint64_t numb = strtoul(fp->cmp, NULL, 0);
+ return _compare_field_number(numa, numb, fp->flags);
+ } else { /* FLD_STRING */
+ const char *stra = (const char *) field->sort_value;
+ const char *strb = fp->cmp;
+ return _compare_field_string(stra, strb, fp->flags);
+ }
+}
+
+static void * _report_get_field_data(struct dm_report *rh,
+ struct field_properties *fp, void *object)
+{
+ void *ret = fp->type->get(object);
+
+ if (!ret)
+ return NULL;
+
+ return ret + rh->fields[fp->field_num].offset;
+}
+
+int dm_report_object(struct dm_report *rh, void *object)
+{
+ struct field_properties *fp;
+ struct row *row;
+ struct dm_report_field *field;
+ void *data = NULL;
+
+ if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
+ log_error("dm_report_object: struct row allocation failed");
+ return 0;
+ }
+
+ row->rh = rh;
+
+ if ((rh->flags & RH_SORT_REQUIRED) &&
+ !(row->sort_fields =
+ dm_pool_zalloc(rh->mem, sizeof(struct dm_report_field *) *
+ rh->keys_count))) {
+ log_error("dm_report_object: "
+ "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_items(fp, &rh->field_props) {
+ if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
+ log_error("dm_report_object: "
+ "struct dm_report_field allocation failed");
+ return 0;
+ }
+ field->props = fp;
+
+ data = _report_get_field_data(rh, fp, object);
+ if (!data)
+ return 0;
+
+ if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
+ field, data)) {
+ log_error("dm_report_object: "
+ "report function failed for field %s",
+ rh->fields[fp->field_num].id);
+ return 0;
+ }
+
+ if ((fp->flags & FLD_CMP_MASK) && !_compare_field(field, fp)) {
+ list_del(&row->list);
+ 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))
+ return dm_report_output(rh);
+
+ return 1;
+}
+
+/*
+ * Print row of headings
+ */
+static int _report_headings(void *handle)
+{
+ struct dm_report *rh = handle;
+ struct field_properties *fp;
+ const char *heading;
+ char buf[1024];
+
+ if (rh->flags & RH_HEADINGS_PRINTED)
+ return 1;
+
+ rh->flags |= RH_HEADINGS_PRINTED;
+
+ if (!(rh->flags & RH_HEADINGS))
+ return 1;
+
+ if (!dm_pool_begin_object(rh->mem, 128)) {
+ log_error("dm_report: "
+ "dm_pool_begin_object failed for headings");
+ return 0;
+ }
+
+ /* First heading line */
+ list_iterate_items(fp, &rh->field_props) {
+ if (fp->flags & FLD_HIDDEN)
+ continue;
+
+ heading = rh->fields[fp->field_num].heading;
+ if (rh->flags & RH_ALIGNED) {
+ if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
+ fp->width, fp->width, heading) < 0)
+ goto bad_snprintf;
+ if (!dm_pool_grow_object(rh->mem, buf, fp->width))
+ goto bad_grow;
+ } else if (!dm_pool_grow_object(rh->mem, heading,
+ strlen(heading)))
+ goto bad_grow;
+
+ if (!list_end(&rh->field_props, &fp->list))
+ if (!dm_pool_grow_object(rh->mem, rh->separator,
+ strlen(rh->separator)))
+ goto bad_grow;
+ }
+ if (!dm_pool_grow_object(rh->mem, "\0", 1))
+ goto bad_grow;
+ log_print("%s", (char *) dm_pool_end_object(rh->mem));
+
+ return 1;
+
+ bad_snprintf:
+ log_error("dm_report: snprintf heading failed");
+ bad_grow:
+ log_error("dm_report: Failed to generate report headings for printing");
+ dm_pool_abandon_object(rh->mem);
+ return 0;
+}
+
+/*
+ * Sort rows of data
+ */
+static int _row_compare(const void *a, const void *b)
+{
+ const struct row *rowa = *(const struct row **) a;
+ const struct row *rowb = *(const struct row **) b;
+ const struct dm_report_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) {
+ const uint64_t numa =
+ *(const uint64_t *) sfa->sort_value;
+ const uint64_t numb =
+ *(const 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 */
+ const char *stra = (const char *) sfa->sort_value;
+ const char *strb = (const 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 dm_report *rh)
+{
+ struct row *(*rows)[];
+ uint32_t count = 0;
+ struct row *row;
+
+ if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
+ list_size(&rh->rows)))) {
+ log_error("dm_report: sort array allocation failed");
+ return 0;
+ }
+
+ list_iterate_items(row, &rh->rows)
+ (*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 dm_report_output(struct dm_report *rh)
+{
+ struct list *fh, *rowh, *ftmp, *rtmp;
+ struct row *row = NULL;
+ struct dm_report_field *field;
+ const char *repstr;
+ char buf[4096];
+ int width;
+
+ 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) {
+ if (!dm_pool_begin_object(rh->mem, 512)) {
+ log_error("dm_report: "
+ "dm_pool_begin_object failed for row");
+ return 0;
+ }
+ row = list_item(rowh, struct row);
+ list_iterate_safe(fh, ftmp, &row->fields) {
+ field = list_item(fh, struct dm_report_field);
+ if (field->props->flags & FLD_HIDDEN)
+ continue;
+
+ repstr = field->report_string;
+ width = field->props->width;
+ if (!(rh->flags & RH_ALIGNED)) {
+ if (!dm_pool_grow_object(rh->mem, repstr,
+ strlen(repstr)))
+ goto bad_grow;
+ } else if (field->props->flags & FLD_ALIGN_LEFT) {
+ if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
+ width, width, repstr) < 0)
+ goto bad_snprintf;
+ if (!dm_pool_grow_object(rh->mem, buf, width))
+ goto bad_grow;
+ } else if (field->props->flags & FLD_ALIGN_RIGHT) {
+ if (dm_snprintf(buf, sizeof(buf), "%*.*s",
+ width, width, repstr) < 0)
+ goto bad_snprintf;
+ if (!dm_pool_grow_object(rh->mem, buf, width))
+ goto bad_grow;
+ }
+
+ if (!list_end(&row->fields, fh))
+ if (!dm_pool_grow_object(rh->mem, rh->separator,
+ strlen(rh->separator)))
+ goto bad_grow;
+ list_del(&field->list);
+ }
+ if (!dm_pool_grow_object(rh->mem, "\0", 1))
+ goto bad_grow;
+ log_print("%s", (char *) dm_pool_end_object(rh->mem));
+ list_del(&row->list);
+ }
+
+ if (row)
+ dm_pool_free(rh->mem, row);
+
+ return 1;
+
+ bad_snprintf:
+ log_error("dm_report: snprintf row failed");
+ bad_grow:
+ log_error("dm_report: Failed to generate row for printing");
+ dm_pool_abandon_object(rh->mem);
+ return 0;
+}
Index: device-mapper/lib/Makefile.in
===================================================================
--- device-mapper.orig/lib/Makefile.in 2007-01-12 15:21:52.000000000 -0500
+++ device-mapper/lib/Makefile.in 2007-01-12 15:36:55.000000000 -0500
@@ -24,6 +24,7 @@ SOURCES =\
libdm-file.c \
libdm-deptree.c \
libdm-string.c \
+ libdm-report.c \
mm/dbg_malloc.c \
mm/pool.c \
$(interface)/libdm-iface.c
Index: device-mapper/lib/.exported_symbols
===================================================================
--- device-mapper.orig/lib/.exported_symbols 2007-01-12 15:21:52.000000000 -0500
+++ device-mapper/lib/.exported_symbols 2007-01-12 15:36:55.000000000 -0500
@@ -115,3 +115,16 @@ dm_split_lvm_name
dm_split_words
dm_snprintf
dm_basename
+dm_report_init
+dm_report_object
+dm_report_output
+dm_report_free
+dm_report_get_private
+dm_report_field_string
+dm_report_field_int32
+dm_report_field_uint32
+dm_report_field_int
+dm_report_field_uint64
+dm_report_field_raw
+dm_report_field_set_string
+dm_report_field_set_sort_value
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] (1/4) dm_report support in libdevmapper
@ 2007-01-12 23:13 ` Jun'ichi Nomura
0 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:13 UTC (permalink / raw)
To: lvm-devel
Hi,
Attached patch adds dm_report API to libdevmapper.
The code is based on LVM2 lib/report with a enhancement
to option format (e.g. "name=a" to report objects whose
"name" field is "a") and generalizations.
I would like to use this from dmsetup to make "dmsetup info -c"
more flexible like LVM2 lvs/pvs/vgs commands.
Also, LVM2 can use this API instead of its own lib/report.
(Patches for dmsetup and LVM2 will follow.)
Comments are welcome.
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 01-libdm-report.patch
Type: text/x-patch
Size: 33117 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/lvm-devel/attachments/20070112/6486edb7/attachment.bin>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] (2/4) dmsetup info to use dm_report
2007-01-12 23:13 ` Jun'ichi Nomura
@ 2007-01-12 23:31 ` Jun'ichi Nomura
-1 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:31 UTC (permalink / raw)
To: device-mapper development, LVM2 development
[-- Attachment #1: Type: text/plain, Size: 1504 bytes --]
Hi,
This patch makes "dmsetup info -c" to use dm_report
in libdevmapper.
For example, to see what maps are overlaying on each map,
# dmsetup info -c -o name,parents_count,parent_maps -O name
Name Parents Parent Maps
B8-root 0
B9-root 0
d1 2 testvg-m1_mimage_0,testvg-lvol2
d2 2 testvg-m1_mimage_1,testvg-lvol2
d3 1 testvg-lvol0-real
d4 2 testvg-lvol2,testvg-lvol0-real
d5 1 testvg-lvol1-cow
d6 1 testvg-lvol2
d7 1 testvg-m1_mlog
testvg-lvol0 0
testvg-lvol0-real 2 testvg-lvol1,testvg-lvol0
testvg-lvol1 0
testvg-lvol1-cow 1 testvg-lvol1
testvg-lvol2 0
testvg-m1 0
testvg-m1_mimage_0 1 testvg-m1
testvg-m1_mimage_1 1 testvg-m1
testvg-m1_mlog 1 testvg-m1
Then, to see the top level map names,
# dmsetup info -c -o name,-parents_count=0 --noheadings
B9-root
testvg-m1
testvg-lvol2
testvg-lvol1
testvg-lvol0
B8-root
Output of "dmsetup info -c" is basically same as the former version
except for a few spacing difference, which should be harmless.
- Field width is correctly aligned (e.g. in case of long map name)
- Trailing space is added to fill the width
(same behaviour as LVM2 lvs/pvs/vgs)
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: 02-dmsetup-report.patch --]
[-- Type: text/x-patch, Size: 17162 bytes --]
Extend "dmsetup info -c -o" using dm_report API.
New options "-O" and "--seprator" are also added.
Usage:
dmsetup info -c -o <field1>[,<field2>...] \
[-O <field>[,<field>...]
[--separator <string>]
Combination of the following field name is allowed:
name
device
major
minor
uuid
status
open_count
target_count
event_nr
deps
deps_count
parents
parents_count
parent_maps
Examples:
If you have the following dm tree:
# dmsetup ls --tree -o inverted
(7:0)
|-d4 (254:6)
| |-testvg-lvol2 (254:17)
| `-testvg-lvol0-real (254:15)
| |-testvg-lvol1 (254:14)
| `-testvg-lvol0 (254:13)
|-d1 (254:3)
| |-testvg-m1_mimage_0 (254:10)
| | `-testvg-m1 (254:12)
| `-testvg-lvol2 (254:17)
|-d3 (254:5)
| `-testvg-lvol0-real (254:15)
| |-testvg-lvol1 (254:14)
| `-testvg-lvol0 (254:13)
|-d2 (254:4)
| |-testvg-m1_mimage_1 (254:11)
| | `-testvg-m1 (254:12)
| `-testvg-lvol2 (254:17)
|-d7 (254:9)
| `-testvg-m1_mlog (254:0)
| `-testvg-m1 (254:12)
|-d6 (254:8)
| `-testvg-lvol2 (254:17)
`-d5 (254:7)
`-testvg-lvol1-cow (254:16)
`-testvg-lvol1 (254:14)
(8:48)
`-asr_HOSTRAID1 (254:18)
|-asr_HOSTRAID15 (254:22)
|-asr_HOSTRAID13 (254:21)
|-asr_HOSTRAID12 (254:20)
`-asr_HOSTRAID11 (254:19)
(8:32)
`-asr_HOSTRAID1 (254:18)
|-asr_HOSTRAID15 (254:22)
|-asr_HOSTRAID13 (254:21)
|-asr_HOSTRAID12 (254:20)
`-asr_HOSTRAID11 (254:19)
To obtain the sorted list of the maps which have no parent maps:
# dmsetup info -c -o 'name,-parents_count=0' --noheadings -O name
asr_HOSTRAID11
asr_HOSTRAID12
asr_HOSTRAID13
asr_HOSTRAID15
testvg-lvol0
testvg-lvol1
testvg-lvol2
testvg-m1
Output of "dmsetup info -c" is basically same as the former version
except for a few spacing difference, which should be harmless.
- Field width is correctly aligned (e.g. in case of long map name)
- Trailing space is added to fill the width
(same behaviour as LVM2 lvs/pvs/vgs)
Index: device-mapper/dmsetup/dmsetup.c
===================================================================
--- device-mapper.orig/dmsetup/dmsetup.c 2007-01-12 16:50:37.000000000 -0500
+++ device-mapper/dmsetup/dmsetup.c 2007-01-12 17:03:45.000000000 -0500
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2005 NEC Corperation
+ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2005-2007 NEC Corperation
*
* This file is part of the device-mapper userspace tools.
*
@@ -114,7 +114,9 @@ enum {
NOOPENCOUNT_ARG,
NOTABLE_ARG,
OPTIONS_ARG,
+ SEPARATOR_ARG,
SHOWKEYS_ARG,
+ SORTKEYS_ARG,
TABLE_ARG,
TARGET_ARG,
TREE_ARG,
@@ -129,11 +131,12 @@ static int _switches[NUM_SWITCHES];
static int _values[NUM_SWITCHES];
static int _num_devices;
static char *_uuid;
-static char *_fields;
+static char *_fields[NUM_SWITCHES];
static char *_table;
static char *_target;
static char *_command;
static struct dm_tree *_dtree;
+static struct dm_report *_rhandle;
/*
* Commands
@@ -322,6 +325,8 @@ static void _display_info_long(struct dm
printf("\n");
}
+static int _report(int argc, char **argv, void *data);
+
static int _display_info(struct dm_task *dmt)
{
struct dm_info info;
@@ -1056,6 +1061,12 @@ static int _info(int argc, char **argv,
struct dm_names *names = (struct dm_names *) data;
char *name = NULL;
+ /*
+ * Using reporter function
+ */
+ if (_switches[COLS_ARG])
+ return _report(argc, argv, data);
+
if (data)
name = names->name;
else {
@@ -1506,6 +1517,414 @@ static int _ls(int argc, char **argv, vo
return _process_all(argc, argv, 0, _display_name);
}
+
+/*
+ * Report device information
+ */
+
+/* dm specific display functions */
+
+static int _dm_name_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ const char *name = dm_task_get_name((struct dm_task *) data);
+
+ return dm_report_field_string(rh, mem, field, &name);
+}
+
+static int _dm_uuid_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const char *uuid = dm_task_get_uuid((struct dm_task *) data);
+
+ if (!uuid || !*uuid)
+ uuid = "";
+
+ return dm_report_field_string(rh, mem, field, &uuid);
+}
+
+static int _dm_info_status_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ char buf[5], *s = buf;
+ struct dm_info *info = (struct dm_info *) data;
+
+ buf[0] = info->live_table ? 'L' : '-';
+ buf[1] = info->inactive_table ? 'I' : '-';
+ buf[2] = info->suspended ? 's' : '-';
+ buf[3] = info->read_only ? 'r' : 'w';
+ buf[4] = 0;
+
+ return dm_report_field_string(rh, mem, field, &s);
+}
+
+#define MAJ_MIN_LEN 32
+
+static int _dm_info_device_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ char *repstr;
+ struct dm_info *info = (struct dm_info *) data;
+
+ if (!(repstr = dm_pool_zalloc(mem, MAJ_MIN_LEN))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (dm_snprintf(repstr, MAJ_MIN_LEN, "%d:%d",
+ info->major, info->minor) < 0) {
+ dm_pool_free(mem, repstr);
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _dm_tree_parent_maps_disp(struct dm_report *rh,
+ struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
+ void *t = NULL;
+ const char *name;
+ int first_node = 1;
+ char *repstr;
+
+ if (!dm_pool_begin_object(mem, 256)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ while ((parent = dm_tree_next_child(&t, node, 1))) {
+ name = dm_tree_node_get_name(parent);
+ if (!name || !*name)
+ continue;
+ if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (!dm_pool_grow_object(mem, name, strlen(name))) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (first_node)
+ first_node = 0;
+ }
+
+ if (!dm_pool_grow_object(mem, "\0", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+
+ repstr = dm_pool_end_object(mem);
+ return dm_report_field_raw(rh, mem, field, repstr);
+
+ return 1;
+
+ out_abandon:
+ dm_pool_abandon_object(mem);
+ return 0;
+}
+
+static int _dm_tree_parents_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
+ void *t = NULL;
+ const struct dm_info *info;
+ int first_node = 1;
+ char buf[MAJ_MIN_LEN], *repstr;
+
+ if (!dm_pool_begin_object(mem, 256)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ while ((parent = dm_tree_next_child(&t, node, 1))) {
+ info = dm_tree_node_get_info(parent);
+ if (!info->major && !info->minor)
+ continue;
+ if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (dm_snprintf(buf, MAJ_MIN_LEN, "%d:%d",
+ info->major, info->minor) < 0) {
+ log_error("dm_snprintf failed");
+ goto out_abandon;
+ }
+ if (!dm_pool_grow_object(mem, buf, strlen(buf))) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (first_node)
+ first_node = 0;
+ }
+
+ if (!dm_pool_grow_object(mem, "\0", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+
+ repstr = dm_pool_end_object(mem);
+ return dm_report_field_raw(rh, mem, field, repstr);
+
+ out_abandon:
+ dm_pool_abandon_object(mem);
+ return 0;
+}
+
+static int _dm_tree_parents_count_disp(struct dm_report *rh,
+ struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ struct dm_tree_node *node = (struct dm_tree_node *) data;
+ int num_parent = dm_tree_node_num_children(node, 1);
+
+ return dm_report_field_int(rh, mem, field, &num_parent);
+}
+
+static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ struct dm_deps *deps = (struct dm_deps *) data;
+ int i;
+ char buf[MAJ_MIN_LEN], *repstr;
+
+ if (!dm_pool_begin_object(mem, 256)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ for (i = 0; i < deps->count; i++) {
+ if (dm_snprintf(buf, sizeof(buf) - 1, "%d:%d",
+ (int) MAJOR(deps->device[i]),
+ (int) MINOR(deps->device[i])) < 0) {
+ log_error("dm_snprintf failed");
+ goto out_abandon;
+ }
+ if (!dm_pool_grow_object(mem, buf, strlen(buf))) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ }
+
+ if (!dm_pool_grow_object(mem, "\0", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+
+ repstr = dm_pool_end_object(mem);
+ return dm_report_field_raw(rh, mem, field, repstr);
+
+ out_abandon:
+ dm_pool_abandon_object(mem);
+ return 0;
+}
+
+/* Report object types */
+
+#define DESC1 "Device Mapper Device"
+#define DESC2 "Dependency"
+#define PREFIX "dm_"
+enum { DR_TASK = 1, DR_INFO = 2, DR_DEPS = 4, DR_TREE = 8 };
+
+struct dmsetup_report_obj {
+ struct dm_task *task;
+ struct dm_info *info;
+ struct dm_tree_node *tree;
+};
+
+static void *_task_get_obj(void *obj)
+{
+ return ((struct dmsetup_report_obj *)obj)->task;
+}
+
+static void *_info_get_obj(void *obj)
+{
+ return ((struct dmsetup_report_obj *)obj)->info;
+}
+
+static void *_tree_get_obj(void *obj)
+{
+ return ((struct dmsetup_report_obj *)obj)->tree;
+}
+
+static void *_deps_get_obj(void *obj)
+{
+ struct dm_task *dmt;
+
+ if (!(dmt = _task_get_obj((struct dmsetup_report_obj *)obj)))
+ return NULL;
+
+ return dm_task_get_deps(dmt);
+}
+
+static const struct dm_report_object_type _report_types[] = {
+ { DR_TASK, DESC1, PREFIX, _task_get_obj },
+ { DR_INFO, DESC1, PREFIX, _info_get_obj },
+ { DR_DEPS, DESC2, PREFIX, _deps_get_obj },
+ { DR_TREE, DESC2, PREFIX, _tree_get_obj },
+};
+
+/* Column definitions */
+static union {
+ struct dm_info _dm_info;
+ struct dm_deps _dm_deps;
+} _dummy;
+
+#define OFFSET_OF(struct, field) ((unsigned int) ((void *)&_dummy._ ## struct.field - (void *)&_dummy._ ## struct))
+#define STR (DM_REPORT_FIELD_STRING | DM_REPORT_FIELD_ALIGN_LEFT)
+#define NUM (DM_REPORT_FIELD_NUMBER | DM_REPORT_FIELD_ALIGN_RIGHT)
+#define FIELD_O(type, strct, sorttype, head, field, width, func, id) {DR_ ## type, id, OFFSET_OF(strct, field), head, width, sorttype, &dm_report_field_ ## func},
+#define FIELD_F(type, sorttype, head, width, func, id) {DR_ ## type, id, 0, head, width, sorttype, &_ ## func ## _disp},
+
+static const struct dm_report_field_type _report_fields[] = {
+/* *INDENT-OFF* */
+FIELD_F(TASK, STR, "Name", 16, dm_name, "name")
+FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid")
+FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "status")
+FIELD_F(INFO, STR, "Device", 6, dm_info_device, "device")
+FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major")
+FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor")
+FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open_count")
+FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "target_count")
+FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "event_nr")
+FIELD_O(DEPS, dm_deps, NUM, "Deps", count, 4, int32, "deps_count")
+FIELD_F(DEPS, STR, "Depend on", 10, dm_deps, "deps")
+FIELD_F(TREE, STR, "Parent Devices", 16, dm_tree_parents, "parents")
+FIELD_F(TREE, STR, "Parent Maps", 12, dm_tree_parent_maps, "parent_maps")
+FIELD_F(TREE, NUM, "Parents", 7, dm_tree_parents_count, "parents_count")
+/* *INDENT-ON* */
+};
+
+#undef STR
+#undef NUM
+#undef FIELD_O
+#undef FIELD_F
+
+static const char *default_report_options = "name,major,minor,status,open_count,target_count,event_nr,uuid";
+static unsigned int _num_report_fields = sizeof(_report_fields) / sizeof(_report_fields[0]);
+static unsigned int _num_report_types = sizeof(_report_types) / sizeof(_report_types[0]);
+
+static int _do_report(int argc, char **argv, void *data)
+{
+ const char *name = NULL;
+ struct dm_task *dmt;
+ struct dm_info info;
+ int r = 0;
+ struct dmsetup_report_obj obj;
+
+ if (data) {
+ if (argc == 0)
+ name = dm_task_get_name((struct dm_task *)data);
+ else
+ name = ((struct dm_names *)data)->name;
+ } else {
+ if (argc == 1)
+ return _process_all(argc, argv, 0, _report);
+ if (argc == 2)
+ name = argv[1];
+ }
+
+ if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
+ return 0;
+
+ if (!_set_task_device(dmt, name, 0))
+ goto out;
+
+ if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
+ goto out;
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ if (!dm_task_get_info(dmt, &info))
+ goto out;
+
+ obj.task = dmt;
+ obj.info = &info;
+ obj.tree = dm_tree_find_node(_dtree, info.major, info.minor);
+ dm_report_object(_rhandle, &obj);
+
+ r = 1;
+
+ out:
+ dm_task_destroy(dmt);
+ return r;
+}
+
+static int _report(int argc, char **argv, void *data)
+{
+ char *options = (char *) default_report_options;
+ const char *keys = "";
+ const char *separator = " ";
+ int aligned = 1, buffered = 1;
+ int headings = !_switches[NOHEADINGS_ARG];
+ uint32_t report_type = 0;
+
+ if (_rhandle)
+ return _do_report(argc, argv, data);
+
+ if (!(_dtree = dm_tree_create()))
+ return 0;
+ if (!_process_all(argc, argv, 0, _add_dep))
+ return 0;
+
+ if (_switches[OPTIONS_ARG] && _fields[OPTIONS_ARG]) {
+ if (*_fields[OPTIONS_ARG] == '+') {
+ int len = strlen(default_report_options) +
+ strlen(_fields[OPTIONS_ARG]);
+ if (!(options = dm_malloc(len))) {
+ err("Failed to malloc option string.");
+ return 0;
+ }
+ if (dm_snprintf(options, len, "%s,%s",
+ default_report_options,
+ &_fields[OPTIONS_ARG][1]) < 0) {
+ err("snprintf failed");
+ return 0;
+ }
+ } else
+ options = _fields[OPTIONS_ARG];
+ }
+ if (_switches[SORTKEYS_ARG] && _fields[SORTKEYS_ARG])
+ keys = _fields[SORTKEYS_ARG];
+ if (_switches[SEPARATOR_ARG] && _fields[SEPARATOR_ARG]) {
+ separator = _fields[SEPARATOR_ARG];
+ aligned = 0;
+ }
+
+ if (!(_rhandle = dm_report_init(options, keys, &report_type,
+ separator, aligned, buffered, headings,
+ _report_fields, _num_report_fields,
+ _report_types, _num_report_types,
+ NULL)))
+ return 0;
+
+ _do_report(argc, argv, data);
+
+ dm_report_output(_rhandle);
+ dm_report_free(_rhandle);
+ _rhandle = NULL;
+
+ if (_dtree) {
+ dm_tree_free(_dtree);
+ _dtree = NULL;
+ }
+
+ return 1;
+}
+
/*
* dispatch table
*/
@@ -1884,7 +2303,9 @@ static int _process_switches(int *argc,
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
{"notable", 0, &ind, NOTABLE_ARG},
{"options", 1, &ind, OPTIONS_ARG},
+ {"separator", 1, &ind, SEPARATOR_ARG},
{"showkeys", 0, &ind, SHOWKEYS_ARG},
+ {"sortkeys", 1, &ind, SORTKEYS_ARG},
{"table", 1, &ind, TABLE_ARG},
{"target", 1, &ind, TARGET_ARG},
{"tree", 0, &ind, TREE_ARG},
@@ -1914,7 +2335,7 @@ static int _process_switches(int *argc,
_switches[OPTIONS_ARG]++;
_switches[MAJOR_ARG]++;
_switches[MINOR_ARG]++;
- _fields = (char *) "name";
+ _fields[OPTIONS_ARG] = (char *) "name";
if (*argc == 3) {
_values[MAJOR_ARG] = atoi((*argv)[1]);
@@ -1946,7 +2367,7 @@ static int _process_switches(int *argc,
optarg = 0;
optind = OPTIND_INIT;
- while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfGj:m:Mno:ru:Uv",
+ while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfGj:m:Mno:O:ru:Uv",
long_options, NULL)) != -1) {
if (c == ':' || c == '?')
return 0;
@@ -1968,7 +2389,15 @@ static int _process_switches(int *argc,
_switches[NOTABLE_ARG]++;
if (c == 'o' || ind == OPTIONS_ARG) {
_switches[OPTIONS_ARG]++;
- _fields = optarg;
+ _fields[OPTIONS_ARG] = optarg;
+ }
+ if (ind == SEPARATOR_ARG) {
+ _switches[SEPARATOR_ARG]++;
+ _fields[SEPARATOR_ARG] = optarg;
+ }
+ if (c == 'O' || ind == SORTKEYS_ARG) {
+ _switches[SORTKEYS_ARG]++;
+ _fields[SORTKEYS_ARG] = optarg;
}
if (c == 'v' || ind == VERBOSE_ARG)
_switches[VERBOSE_ARG]++;
@@ -2027,13 +2456,7 @@ static int _process_switches(int *argc,
return 0;
}
- if (_switches[COLS_ARG] && _switches[OPTIONS_ARG] &&
- strcmp(_fields, "name")) {
- fprintf(stderr, "Only -o name is supported so far.\n");
- return 0;
- }
-
- if (_switches[TREE_ARG] && !_process_tree_options(_fields))
+ if (_switches[TREE_ARG] && !_process_tree_options(_fields[OPTIONS_ARG]))
return 0;
if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] (2/4) dmsetup info to use dm_report
@ 2007-01-12 23:31 ` Jun'ichi Nomura
0 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:31 UTC (permalink / raw)
To: lvm-devel
Hi,
This patch makes "dmsetup info -c" to use dm_report
in libdevmapper.
For example, to see what maps are overlaying on each map,
# dmsetup info -c -o name,parents_count,parent_maps -O name
Name Parents Parent Maps
B8-root 0
B9-root 0
d1 2 testvg-m1_mimage_0,testvg-lvol2
d2 2 testvg-m1_mimage_1,testvg-lvol2
d3 1 testvg-lvol0-real
d4 2 testvg-lvol2,testvg-lvol0-real
d5 1 testvg-lvol1-cow
d6 1 testvg-lvol2
d7 1 testvg-m1_mlog
testvg-lvol0 0
testvg-lvol0-real 2 testvg-lvol1,testvg-lvol0
testvg-lvol1 0
testvg-lvol1-cow 1 testvg-lvol1
testvg-lvol2 0
testvg-m1 0
testvg-m1_mimage_0 1 testvg-m1
testvg-m1_mimage_1 1 testvg-m1
testvg-m1_mlog 1 testvg-m1
Then, to see the top level map names,
# dmsetup info -c -o name,-parents_count=0 --noheadings
B9-root
testvg-m1
testvg-lvol2
testvg-lvol1
testvg-lvol0
B8-root
Output of "dmsetup info -c" is basically same as the former version
except for a few spacing difference, which should be harmless.
- Field width is correctly aligned (e.g. in case of long map name)
- Trailing space is added to fill the width
(same behaviour as LVM2 lvs/pvs/vgs)
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 02-dmsetup-report.patch
Type: text/x-patch
Size: 17162 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/lvm-devel/attachments/20070112/47367b4c/attachment.bin>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] (3/4) Remove old codes for "info -c" from dmsetup
2007-01-12 23:13 ` Jun'ichi Nomura
@ 2007-01-12 23:31 ` Jun'ichi Nomura
-1 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:31 UTC (permalink / raw)
To: device-mapper development, LVM2 development
[-- Attachment #1: Type: text/plain, Size: 210 bytes --]
Hi,
This patch removes _display_info_cols*() functions used
for "dmsetup info -c" implementation.
These can be replaced by the new code using dm_report.
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: 03-dmsetup-remove-old-info-cols.patch --]
[-- Type: text/x-patch, Size: 3171 bytes --]
Replace old _display_info_cols{_noheadings} by _report()
Slight incompatibility is introduced:
Output of verbose + column is changed.
e.g. dmsetup table -v -c
# dmsetup.old table -c -v
Name Maj Min Stat Open Targ Event UUID
d4 254 6 L--w 0 1 0
0 409600 linear 7:0 1638400
d3 254 5 L--w 0 1 0
0 409600 linear 7:0 1228800
...
# dmsetup.new table -c -v
Name Maj Min Stat Open Targ Event UUID
d4 254 6 L--w 0 1 0
0 409600 linear 7:0 1638400
Name Maj Min Stat Open Targ Event UUID
d3 254 5 L--w 0 1 0
0 409600 linear 7:0 1228800
...
Field head used to be displayed only once but now it's displayed
for every tables.
Index: device-mapper/dmsetup/dmsetup.c
===================================================================
--- device-mapper.orig/dmsetup/dmsetup.c 2007-01-12 16:54:45.000000000 -0500
+++ device-mapper/dmsetup/dmsetup.c 2007-01-12 16:55:14.000000000 -0500
@@ -225,68 +225,6 @@ static int _parse_file(struct dm_task *d
return r;
}
-static void _display_info_cols_noheadings(struct dm_task *dmt,
- struct dm_info *info)
-{
- const char *uuid;
-
- if (!info->exists)
- return;
-
- uuid = dm_task_get_uuid(dmt);
-
- if (_switches[OPTIONS_ARG])
- printf("%s\n", dm_task_get_name(dmt));
- else
- printf("%s:%d:%d:%s%s%s%s:%d:%d:%" PRIu32 ":%s\n",
- dm_task_get_name(dmt),
- info->major, info->minor,
- info->live_table ? "L" : "-",
- info->inactive_table ? "I" : "-",
- info->suspended ? "s" : "-",
- info->read_only ? "r" : "w",
- info->open_count, info->target_count, info->event_nr,
- uuid && *uuid ? uuid : "");
-}
-
-static void _display_info_cols(struct dm_task *dmt, struct dm_info *info)
-{
- static int _headings = 0;
- const char *uuid;
-
- if (!info->exists) {
- printf("Device does not exist.\n");
- return;
- }
-
- if (!_headings) {
- if (_switches[OPTIONS_ARG])
- printf("Name\n");
- else
- printf("Name Maj Min Stat Open Targ "
- "Event UUID\n");
- _headings = 1;
- }
-
- if (_switches[OPTIONS_ARG])
- printf("%s\n", dm_task_get_name(dmt));
- else {
- printf("%-16s %3d %3d %s%s%s%s %4d %4d %6" PRIu32 " ",
- dm_task_get_name(dmt),
- info->major, info->minor,
- info->live_table ? "L" : "-",
- info->inactive_table ? "I" : "-",
- info->suspended ? "s" : "-",
- info->read_only ? "r" : "w",
- info->open_count, info->target_count, info->event_nr);
-
- if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
- printf("%s", uuid);
-
- printf("\n");
- }
-}
-
static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
{
const char *uuid;
@@ -336,10 +274,8 @@ static int _display_info(struct dm_task
if (!_switches[COLS_ARG])
_display_info_long(dmt, &info);
- else if (_switches[NOHEADINGS_ARG])
- _display_info_cols_noheadings(dmt, &info);
else
- _display_info_cols(dmt, &info);
+ _report(0, NULL, dmt);
return info.exists ? 1 : 0;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] (3/4) Remove old codes for "info -c" from dmsetup
@ 2007-01-12 23:31 ` Jun'ichi Nomura
0 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:31 UTC (permalink / raw)
To: lvm-devel
Hi,
This patch removes _display_info_cols*() functions used
for "dmsetup info -c" implementation.
These can be replaced by the new code using dm_report.
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 03-dmsetup-remove-old-info-cols.patch
Type: text/x-patch
Size: 3171 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/lvm-devel/attachments/20070112/9672438d/attachment.bin>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] (4/4) LVM2 to use dm_report
2007-01-12 23:13 ` Jun'ichi Nomura
@ 2007-01-12 23:32 ` Jun'ichi Nomura
-1 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:32 UTC (permalink / raw)
To: device-mapper development, LVM2 development
[-- Attachment #1: Type: text/plain, Size: 725 bytes --]
Hi,
This patch makes LVM2 to use dm_report in libdevmapper
instead of its lib/report functions.
Tested following commands where LVs of linear, striped, mirrored
and snapshot exist and confirmed the output is same with the
original LVM2 2.02.17.
lvs
pvs
vgs
lvs -a
pvs -a
lvs -a -o +devices
lvs -o name,name,lv_name,vg_name
lvs -a -o name,name,lv_name,vg_name
lvs -a -o name,lv_name,vg_name -O name
lvs -a -o name,lv_name,vg_name -O -name
lvs -a -o name,lv_name,vg_name -O size
lvs -a -o name,lv_name,vg_name -O lv_size
lvs -a -o name,lv_name,vg_name -O -size
pvs -o +pe_alloc_count,used,dev_size
pvs -a -o +pe_alloc_count,used,dev_size
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: 04-lvm2-use-dm-report.patch --]
[-- Type: text/x-patch, Size: 74176 bytes --]
Replaces lib/report by dm_report API in libdevmapper.
Index: LVM2.02.17/lib/Makefile.in
===================================================================
--- LVM2.02.17.orig/lib/Makefile.in 2007-01-11 11:27:16.000000000 -0500
+++ LVM2.02.17/lib/Makefile.in 2007-01-12 03:46:15.000000000 -0500
@@ -84,7 +84,6 @@ SOURCES =\
regex/matcher.c \
regex/parse_rx.c \
regex/ttree.c \
- report/report.c \
striped/striped.c \
uuid/uuid.c \
zero/zero.c
Index: LVM2.02.17/lib/report/columns.h
===================================================================
--- LVM2.02.17.orig/lib/report/columns.h 2006-10-07 06:42:27.000000000 -0400
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* 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 */
-
-/* *INDENT-OFF* */
-FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
-FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
-FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
-FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
-FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
-FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major")
-FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_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(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
-FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
-FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
-FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
-FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
-
-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, "DevSize", dev, 7, devsize, "dev_size")
-FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start")
-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(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
-
-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", cmd, 5, 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(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
-
-FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
-FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
-FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
-FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
-FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
-FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
-FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
-FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
-FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
-FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
-FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
-FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
-
-FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
-FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
-/* *INDENT-ON* */
Index: LVM2.02.17/lib/report/report.c
===================================================================
--- LVM2.02.17.orig/lib/report/report.c 2007-01-11 11:27:16.000000000 -0500
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,1572 +0,0 @@
-/*
- * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; 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 "lvm-string.h"
-#include "display.h"
-#include "activate.h"
-#include "segtype.h"
-#include "str_list.h"
-
-/*
- * For macro use
- */
-static union {
- struct physical_volume _pv;
- struct logical_volume _lv;
- struct volume_group _vg;
- struct lv_segment _seg;
- struct pv_segment _pvseg;
-} _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 dm_pool *mem;
-
- report_type_t type;
- const 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;
-
- const char *report_string; /* Formatted ready for display */
- const 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 */
-};
-
-static char _alloc_policy_char(alloc_policy_t alloc)
-{
- switch (alloc) {
- case ALLOC_CONTIGUOUS:
- return 'c';
- case ALLOC_CLING:
- return 'C';
- case ALLOC_NORMAL:
- return 'n';
- case ALLOC_ANYWHERE:
- return 'a';
- default:
- return 'i';
- }
-}
-
-/*
- * 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 =
- dm_pool_strdup(rh->mem, *(const char **) data))) {
- log_error("dm_pool_strdup failed");
- return 0;
- }
-
- field->sort_value = (const 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(*(const struct device **) data);
-
- return _string_disp(rh, field, &name);
-}
-
-static int _devices_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct lv_segment *seg = (const struct lv_segment *) data;
- unsigned int s;
- const char *name = NULL;
- uint32_t extent = 0;
- char extent_str[32];
-
- if (!dm_pool_begin_object(rh->mem, 256)) {
- log_error("dm_pool_begin_object failed");
- return 0;
- }
-
- for (s = 0; s < seg->area_count; s++) {
- switch (seg_type(seg, s)) {
- case AREA_LV:
- name = seg_lv(seg, s)->name;
- extent = seg_le(seg, s);
- break;
- case AREA_PV:
- name = dev_name(seg_dev(seg, s));
- extent = seg_pe(seg, s);
- break;
- case AREA_UNASSIGNED:
- name = "unassigned";
- extent = 0;
- }
-
- if (!dm_pool_grow_object(rh->mem, name, strlen(name))) {
- log_error("dm_pool_grow_object failed");
- return 0;
- }
-
- if (dm_snprintf(extent_str, sizeof(extent_str), "(%" PRIu32
- ")", extent) < 0) {
- log_error("Extent number dm_snprintf failed");
- return 0;
- }
-
- if (!dm_pool_grow_object(rh->mem, extent_str, strlen(extent_str))) {
- log_error("dm_pool_grow_object failed");
- return 0;
- }
-
- if ((s != seg->area_count - 1) &&
- !dm_pool_grow_object(rh->mem, ",", 1)) {
- log_error("dm_pool_grow_object failed");
- return 0;
- }
- }
-
- if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
- log_error("dm_pool_grow_object failed");
- return 0;
- }
-
- field->report_string = dm_pool_end_object(rh->mem);
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _tags_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct list *tags = (const struct list *) data;
- struct str_list *sl;
-
- if (!dm_pool_begin_object(rh->mem, 256)) {
- log_error("dm_pool_begin_object failed");
- return 0;
- }
-
- list_iterate_items(sl, tags) {
- if (!dm_pool_grow_object(rh->mem, sl->str, strlen(sl->str)) ||
- (sl->list.n != tags && !dm_pool_grow_object(rh->mem, ",", 1))) {
- log_error("dm_pool_grow_object failed");
- return 0;
- }
- }
-
- if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
- log_error("dm_pool_grow_object failed");
- return 0;
- }
-
- field->report_string = dm_pool_end_object(rh->mem);
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _modules_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct logical_volume *lv = (const struct logical_volume *) data;
- struct list *modules;
-
- if (!(modules = str_list_create(rh->mem))) {
- log_error("modules str_list allocation failed");
- return 0;
- }
-
- if (!list_lv_modules(rh->mem, lv, modules))
- return_0;
-
- return _tags_disp(rh, field, modules);
-}
-
-static int _vgfmt_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct volume_group *vg = (const struct volume_group *) data;
-
- if (!vg->fid) {
- field->report_string = "";
- field->sort_value = (const 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)
-{
- const struct physical_volume *pv =
- (const struct physical_volume *) data;
-
- if (!pv->fmt) {
- field->report_string = "";
- field->sort_value = (const void *) field->report_string;
- return 1;
- }
-
- return _string_disp(rh, field, &pv->fmt->name);
-}
-
-static int _int_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const int value = *(const int *) data;
- uint64_t *sortval;
- char *repstr;
-
- if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (dm_snprintf(repstr, 12, "%d", value) < 0) {
- log_error("int too big: %d", value);
- return 0;
- }
-
- *sortval = (const uint64_t) value;
- field->sort_value = sortval;
- field->report_string = repstr;
-
- return 1;
-}
-
-static int _lvkmaj_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct logical_volume *lv = (const struct logical_volume *) data;
- struct lvinfo info;
- uint64_t minusone = UINT64_C(-1);
-
- if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
- return _int_disp(rh, field, &info.major);
- else
- return _int_disp(rh, field, &minusone);
-
- return 1;
-}
-
-static int _lvkmin_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct logical_volume *lv = (const struct logical_volume *) data;
- struct lvinfo info;
- uint64_t minusone = UINT64_C(-1);
-
- if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
- return _int_disp(rh, field, &info.minor);
- else
- return _int_disp(rh, field, &minusone);
-
- return 1;
-}
-
-static int _lvstatus_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct logical_volume *lv = (const struct logical_volume *) data;
- struct lvinfo info;
- char *repstr;
- float snap_percent;
-
- if (!(repstr = dm_pool_zalloc(rh->mem, 7))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (lv->status & PVMOVE)
- repstr[0] = 'p';
- else if (lv->status & MIRRORED) {
- if (lv->status & MIRROR_NOTSYNCED)
- repstr[0] = 'M';
- else
- repstr[0] = 'm';
- }else if (lv->status & MIRROR_IMAGE)
- repstr[0] = 'i';
- else if (lv->status & MIRROR_LOG)
- repstr[0] = 'l';
- else if (lv->status & VIRTUAL)
- repstr[0] = 'v';
- else if (lv_is_origin(lv))
- repstr[0] = 'o';
- else if (lv_is_cow(lv))
- repstr[0] = 's';
- else
- repstr[0] = '-';
-
- if (lv->status & PVMOVE)
- repstr[1] = '-';
- else if (lv->status & LVM_WRITE)
- repstr[1] = 'w';
- else
- repstr[1] = 'r';
-
- repstr[2] = _alloc_policy_char(lv->alloc);
-
- if (lv->status & LOCKED)
- repstr[2] = toupper(repstr[2]);
-
- if (lv->status & FIXED_MINOR)
- repstr[3] = 'm'; /* Fixed Minor */
- else
- repstr[3] = '-';
-
- if (lv_info(lv->vg->cmd, lv, &info, 1) && info.exists) {
- if (info.suspended)
- repstr[4] = 's'; /* Suspended */
- else if (info.live_table)
- repstr[4] = 'a'; /* Active */
- else if (info.inactive_table)
- repstr[4] = 'i'; /* Inactive with table */
- else
- repstr[4] = 'd'; /* Inactive without table */
-
- /* Snapshot dropped? */
- if (info.live_table && lv_is_cow(lv) &&
- (!lv_snapshot_percent(lv, &snap_percent) ||
- snap_percent < 0 || snap_percent >= 100)) {
- repstr[0] = toupper(repstr[0]);
- if (info.suspended)
- repstr[4] = 'S'; /* Susp Inv snapshot */
- else
- repstr[4] = 'I'; /* Invalid snapshot */
- }
-
- if (info.open_count)
- repstr[5] = 'o'; /* Open */
- else
- repstr[5] = '-';
- } else {
- repstr[4] = '-';
- repstr[5] = '-';
- }
-
- field->report_string = repstr;
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _pvstatus_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const uint32_t status = *(const uint32_t *) data;
- char *repstr;
-
- if (!(repstr = dm_pool_zalloc(rh->mem, 4))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (status & ALLOCATABLE_PV)
- repstr[0] = 'a';
- else
- repstr[0] = '-';
-
- if (status & EXPORTED_VG)
- repstr[1] = 'x';
- else
- repstr[1] = '-';
-
- field->report_string = repstr;
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _vgstatus_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct volume_group *vg = (const struct volume_group *) data;
- char *repstr;
-
- if (!(repstr = dm_pool_zalloc(rh->mem, 7))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (vg->status & LVM_WRITE)
- repstr[0] = 'w';
- else
- repstr[0] = 'r';
-
- if (vg->status & RESIZEABLE_VG)
- repstr[1] = 'z';
- else
- repstr[1] = '-';
-
- if (vg->status & EXPORTED_VG)
- repstr[2] = 'x';
- else
- repstr[2] = '-';
-
- if (vg->status & PARTIAL_VG)
- repstr[3] = 'p';
- else
- repstr[3] = '-';
-
- repstr[4] = _alloc_policy_char(vg->alloc);
-
- if (vg->status & CLUSTERED)
- repstr[5] = 'c';
- else
- repstr[5] = '-';
-
- field->report_string = repstr;
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _segtype_disp(struct report_handle *rh __attribute((unused)),
- struct field *field,
- const void *data)
-{
- const struct lv_segment *seg = (const struct lv_segment *) data;
-
- if (seg->area_count == 1)
- field->report_string = "linear";
- else
- field->report_string = seg->segtype->ops->name(seg);
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _origin_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct logical_volume *lv = (const struct logical_volume *) data;
-
- if (lv_is_cow(lv))
- return _string_disp(rh, field, &origin_from_cow(lv)->name);
-
- field->report_string = "";
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _loglv_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct logical_volume *lv = (const struct logical_volume *) data;
- struct lv_segment *seg;
-
- list_iterate_items(seg, &lv->segments) {
- if (!seg_is_mirrored(seg) || !seg->log_lv)
- continue;
- return _string_disp(rh, field, &seg->log_lv->name);
- }
-
- field->report_string = "";
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _lvname_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct logical_volume *lv = (const struct logical_volume *) data;
- char *repstr;
- size_t len;
-
- if (lv_is_visible(lv)) {
- repstr = lv->name;
- return _string_disp(rh, field, &repstr);
- }
-
- len = strlen(lv->name) + 3;
- if (!(repstr = dm_pool_zalloc(rh->mem, len))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
- log_error("lvname snprintf failed");
- return 0;
- }
-
- field->report_string = repstr;
-
- if (!(field->sort_value = dm_pool_strdup(rh->mem, lv->name))) {
- log_error("dm_pool_strdup failed");
- return 0;
- }
-
- return 1;
-}
-
-static int _movepv_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct logical_volume *lv = (const struct logical_volume *) data;
- const char *name;
- struct lv_segment *seg;
-
- list_iterate_items(seg, &lv->segments) {
- if (!(seg->status & PVMOVE))
- continue;
- name = dev_name(seg_dev(seg, 0));
- return _string_disp(rh, field, &name);
- }
-
- field->report_string = "";
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _size32_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const uint32_t size = *(const uint32_t *) data;
- const char *disp;
- uint64_t *sortval;
-
- if (!*(disp = display_size_units(rh->cmd, (uint64_t) size))) {
- stack;
- return 0;
- }
-
- if (!(field->report_string = dm_pool_strdup(rh->mem, disp))) {
- log_error("dm_pool_strdup failed");
- return 0;
- }
-
- if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- *sortval = (const uint64_t) size;
- field->sort_value = (const void *) sortval;
-
- return 1;
-}
-
-static int _size64_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const uint64_t size = *(const uint64_t *) data;
- const char *disp;
- uint64_t *sortval;
-
- if (!*(disp = display_size_units(rh->cmd, size))) {
- stack;
- return 0;
- }
-
- if (!(field->report_string = dm_pool_strdup(rh->mem, disp))) {
- log_error("dm_pool_strdup failed");
- return 0;
- }
-
- if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- *sortval = size;
- field->sort_value = sortval;
-
- return 1;
-}
-
-static int _vgsize_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct volume_group *vg = (const struct volume_group *) data;
- uint64_t size;
-
- size = (uint64_t) 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)
-{
- const struct lv_segment *seg = (const struct lv_segment *) data;
- uint64_t start;
-
- start = (uint64_t) 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)
-{
- const struct lv_segment *seg = (const struct lv_segment *) data;
- uint64_t size;
-
- size = (uint64_t) seg->len * seg->lv->vg->extent_size;
-
- return _size64_disp(rh, field, &size);
-}
-
-static int _chunksize_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct lv_segment *seg = (const struct lv_segment *) data;
- uint64_t size;
-
- if (lv_is_cow(seg->lv))
- size = (uint64_t) find_cow(seg->lv)->chunk_size;
- else
- size = 0;
-
- return _size64_disp(rh, field, &size);
-}
-
-static int _pvused_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct physical_volume *pv =
- (const struct physical_volume *) data;
- uint64_t used;
-
- if (!pv->pe_count)
- used = 0LL;
- else
- used = (uint64_t) 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)
-{
- const struct physical_volume *pv =
- (const struct physical_volume *) data;
- uint64_t freespace;
-
- if (!pv->pe_count)
- freespace = pv->size;
- else
- freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
-
- return _size64_disp(rh, field, &freespace);
-}
-
-static int _pvsize_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct physical_volume *pv =
- (const struct physical_volume *) data;
- uint64_t size;
-
- if (!pv->pe_count)
- size = pv->size;
- else
- size = (uint64_t) pv->pe_count * pv->pe_size;
-
- return _size64_disp(rh, field, &size);
-}
-
-static int _devsize_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct device *dev = *(const struct device **) data;
- uint64_t size;
-
- if (!dev_get_size(dev, &size))
- size = 0;
-
- return _size64_disp(rh, field, &size);
-}
-
-static int _vgfree_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct volume_group *vg = (const struct volume_group *) data;
- uint64_t freespace;
-
- freespace = (uint64_t) vg->free_count * vg->extent_size;
-
- return _size64_disp(rh, field, &freespace);
-}
-
-static int _uuid_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- char *repstr = NULL;
-
- if (!(repstr = dm_pool_alloc(rh->mem, 40))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (!id_write_format((const struct id *) data, repstr, 40)) {
- stack;
- return 0;
- }
-
- field->report_string = repstr;
- field->sort_value = (const void *) field->report_string;
-
- return 1;
-}
-
-static int _uint32_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const uint32_t value = *(const uint32_t *) data;
- uint64_t *sortval;
- char *repstr;
-
- if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (dm_snprintf(repstr, 11, "%u", value) < 0) {
- log_error("uint32 too big: %u", value);
- return 0;
- }
-
- *sortval = (const uint64_t) value;
- field->sort_value = sortval;
- field->report_string = repstr;
-
- return 1;
-}
-
-static int _int32_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const int32_t value = *(const int32_t *) data;
- uint64_t *sortval;
- char *repstr;
-
- if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (dm_snprintf(repstr, 12, "%d", value) < 0) {
- log_error("int32 too big: %d", value);
- return 0;
- }
-
- *sortval = (const uint64_t) value;
- field->sort_value = sortval;
- field->report_string = repstr;
-
- return 1;
-}
-
-static int _lvsegcount_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- const struct logical_volume *lv = (const 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)
-{
- const struct logical_volume *lv = (const struct logical_volume *) data;
- struct lvinfo info;
- float snap_percent;
- uint64_t *sortval;
- char *repstr;
-
- if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (!lv_is_cow(lv) ||
- (lv_info(lv->vg->cmd, lv, &info, 0) && !info.exists)) {
- field->report_string = "";
- *sortval = UINT64_C(0);
- field->sort_value = sortval;
- return 1;
- }
-
- if (!lv_snapshot_percent(lv, &snap_percent) || snap_percent < 0) {
- field->report_string = "100.00";
- *sortval = UINT64_C(100);
- field->sort_value = sortval;
- return 1;
- }
-
- if (!(repstr = dm_pool_zalloc(rh->mem, 8))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) {
- log_error("snapshot percentage too large");
- return 0;
- }
-
- *sortval = snap_percent * UINT64_C(1000);
- field->sort_value = sortval;
- field->report_string = repstr;
-
- return 1;
-}
-
-static int _copypercent_disp(struct report_handle *rh, struct field *field,
- const void *data)
-{
- struct logical_volume *lv = (struct logical_volume *) data;
- float percent;
- uint64_t *sortval;
- char *repstr;
-
- if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
- !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL)) {
- field->report_string = "";
- *sortval = UINT64_C(0);
- field->sort_value = sortval;
- return 1;
- }
-
- percent = copy_percent(lv);
-
- if (!(repstr = dm_pool_zalloc(rh->mem, 8))) {
- log_error("dm_pool_alloc failed");
- return 0;
- }
-
- if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) {
- log_error("copy percentage too large");
- return 0;
- }
-
- *sortval = percent * UINT64_C(1000);
- field->sort_value = sortval;
- field->report_string = repstr;
-
- 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[32];
- off_t offset;
- const char heading[32];
- int width;
- uint32_t flags;
- field_report_fn report_fn;
-} _fields[] = {
-#include "columns.h"
-};
-
-#undef STR
-#undef NUM
-#undef FIELD
-
-const unsigned int _num_fields = sizeof(_fields) / sizeof(_fields[0]);
-
-static void _display_fields(void)
-{
- uint32_t f;
- const char *type, *last_type = "";
-
- for (f = 0; f < _num_fields; f++) {
- switch (_fields[f].type) {
- case PVS:
- type = "Physical Volume";
- break;
- case LVS:
- type = "Logical Volume";
- break;
- case VGS:
- type = "Volume Group";
- break;
- case SEGS:
- type = "Logical Volume Segment";
- break;
- case PVSEGS:
- type = "Physical Volume Segment";
- break;
- default:
- type = " ";
- }
-
- if (type != last_type) {
- if (*last_type)
- log_print(" ");
- log_print("%s Fields", type);
- }
-
- log_print("- %s", _fields[f].id);
-
- last_type = type;
- }
-}
-
-/*
- * Initialise report handle
- */
-static int _field_match(struct report_handle *rh, const char *field, size_t 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 = dm_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 field_properties *fp, *found = NULL;
-
- list_iterate_items(fp, &rh->field_props) {
- if (fp->field_num == field_num) {
- found = fp;
- break;
- }
- }
-
- if (!found) {
- /* Add as a non-display field */
- if (!(found = dm_pool_zalloc(rh->mem, sizeof(*found)))) {
- log_error("struct field_properties allocation failed");
- return 0;
- }
-
- rh->type |= _fields[field_num].type;
- found->field_num = field_num;
- found->width = _fields[field_num].width;
- found->flags = _fields[field_num].flags | FLD_HIDDEN;
-
- list_add(&rh->field_props, &found->list);
- }
-
- if (found->flags & FLD_SORT_KEY) {
- log_error("Ignoring duplicate sort field: %s",
- _fields[field_num].id);
- return 1;
- }
-
- found->flags |= FLD_SORT_KEY;
- found->sort_posn = rh->keys_count++;
- found->flags |= flags;
-
- return 1;
-}
-
-static int _key_match(struct report_handle *rh, const char *key, size_t 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, (size_t) (we - ws))) {
- _display_fields();
- log_print(" ");
- log_error("Unrecognised field: %.*s", (int) (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, (size_t) (we - ws))) {
- log_error("Unrecognised field: %.*s", (int) (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 = dm_pool_zalloc(cmd->mem, sizeof(*rh)))) {
- log_error("report_handle dm_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;
- case PVSEGS:
- rh->field_prefix = "pvseg_";
- break;
- default:
- rh->field_prefix = "";
- }
-
- if (!(rh->mem = dm_pool_create("report", 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 & PVSEGS)
- rh->type |= PVS;
- 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 & PVSEGS)
- *report_type = PVSEGS;
- else if (rh->type & PVS)
- *report_type = PVS;
-
- return rh;
-}
-
-void report_free(void *handle)
-{
- struct report_handle *rh = handle;
-
- dm_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 pv_segment *pvseg)
-{
- struct report_handle *rh = handle;
- struct field_properties *fp;
- struct row *row;
- struct field *field;
- void *data = NULL;
- int skip;
-
- if (lv && pv) {
- log_error("report_object: One of *lv and *pv must be NULL!");
- return 0;
- }
-
- if (!(row = dm_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 = dm_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_items(fp, &rh->field_props) {
- skip = 0;
-
- if (!(field = dm_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:
- if (!vg) {
- skip = 1;
- break;
- }
- 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;
- break;
- case PVSEGS:
- data = (void *) pvseg + _fields[fp->field_num].offset;
- }
-
- if (skip) {
- field->report_string = "";
- field->sort_value = (const void *) field->report_string;
- } else 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
- */
-static int _report_headings(void *handle)
-{
- struct report_handle *rh = handle;
- struct field_properties *fp;
- const char *heading;
- char buf[1024];
-
- if (rh->flags & RH_HEADINGS_PRINTED)
- return 1;
-
- rh->flags |= RH_HEADINGS_PRINTED;
-
- if (!(rh->flags & RH_HEADINGS))
- return 1;
-
- if (!dm_pool_begin_object(rh->mem, 128)) {
- log_error("dm_pool_begin_object failed for headings");
- return 0;
- }
-
- /* First heading line */
- list_iterate_items(fp, &rh->field_props) {
- if (fp->flags & FLD_HIDDEN)
- continue;
-
- heading = _fields[fp->field_num].heading;
- if (rh->flags & RH_ALIGNED) {
- if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
- fp->width, fp->width, heading) < 0) {
- log_error("snprintf heading failed");
- dm_pool_end_object(rh->mem);
- return 0;
- }
- if (!dm_pool_grow_object(rh->mem, buf, fp->width))
- goto bad;
- } else if (!dm_pool_grow_object(rh->mem, heading, strlen(heading)))
- goto bad;
-
- if (!list_end(&rh->field_props, &fp->list))
- if (!dm_pool_grow_object(rh->mem, rh->separator,
- strlen(rh->separator)))
- goto bad;
- }
- if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
- log_error("dm_pool_grow_object failed");
- goto bad;
- }
- log_print("%s", (char *) dm_pool_end_object(rh->mem));
-
- return 1;
-
- bad:
- log_error("Failed to generate report headings for printing");
-
- return 0;
-}
-
-/*
- * Sort rows of data
- */
-static int _row_compare(const void *a, const void *b)
-{
- const struct row *rowa = *(const struct row **) a;
- const struct row *rowb = *(const struct row **) b;
- const 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) {
- const uint64_t numa =
- *(const uint64_t *) sfa->sort_value;
- const uint64_t numb =
- *(const 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 */
- const char *stra = (const char *) sfa->sort_value;
- const char *strb = (const 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)[];
- uint32_t count = 0;
- struct row *row;
-
- if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
- list_size(&rh->rows)))) {
- log_error("sort array allocation failed");
- return 0;
- }
-
- list_iterate_items(row, &rh->rows)
- (*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;
- const char *repstr;
- char buf[4096];
- int width;
-
- 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) {
- if (!dm_pool_begin_object(rh->mem, 512)) {
- log_error("dm_pool_begin_object failed for row");
- return 0;
- }
- 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;
-
- repstr = field->report_string;
- width = field->props->width;
- if (!(rh->flags & RH_ALIGNED)) {
- if (!dm_pool_grow_object(rh->mem, repstr,
- strlen(repstr)))
- goto bad;
- } else if (field->props->flags & FLD_ALIGN_LEFT) {
- if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
- width, width, repstr) < 0) {
- log_error("snprintf repstr failed");
- dm_pool_end_object(rh->mem);
- return 0;
- }
- if (!dm_pool_grow_object(rh->mem, buf, width))
- goto bad;
- } else if (field->props->flags & FLD_ALIGN_RIGHT) {
- if (dm_snprintf(buf, sizeof(buf), "%*.*s",
- width, width, repstr) < 0) {
- log_error("snprintf repstr failed");
- dm_pool_end_object(rh->mem);
- return 0;
- }
- if (!dm_pool_grow_object(rh->mem, buf, width))
- goto bad;
- }
-
- if (!list_end(&row->fields, fh))
- if (!dm_pool_grow_object(rh->mem, rh->separator,
- strlen(rh->separator)))
- goto bad;
- list_del(&field->list);
- }
- if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
- log_error("dm_pool_grow_object failed for row");
- return 0;
- }
- log_print("%s", (char *) dm_pool_end_object(rh->mem));
- list_del(&row->list);
- }
-
- if (row)
- dm_pool_free(rh->mem, row);
-
- return 1;
-
- bad:
- log_error("Failed to generate row for printing");
- return 0;
-}
Index: LVM2.02.17/lib/report/report.h
===================================================================
--- LVM2.02.17.orig/lib/report/report.h 2007-01-11 11:27:16.000000000 -0500
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; 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, PVSEGS = 16 } 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, struct pv_segment *pvseg);
-int report_output(void *handle);
-
-#endif
Index: LVM2.02.17/tools/columns.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ LVM2.02.17/tools/columns.h 2007-01-12 14:50:18.000000000 -0500
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 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 */
+
+/* *INDENT-OFF* */
+FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
+FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
+FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
+FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
+FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
+FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major")
+FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_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(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
+FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
+FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
+FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
+FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
+
+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, "DevSize", dev, 7, devsize, "dev_size")
+FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start")
+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(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
+
+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", cmd, 5, 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(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
+
+FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
+FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
+FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
+FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
+FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
+FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
+FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
+FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
+FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
+FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
+FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
+FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
+
+FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
+FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
+
+/* *INDENT-ON* */
Index: LVM2.02.17/tools/reporter.c
===================================================================
--- LVM2.02.17.orig/tools/reporter.c 2006-09-01 21:18:17.000000000 -0400
+++ LVM2.02.17/tools/reporter.c 2007-01-12 17:31:55.000000000 -0500
@@ -13,19 +13,882 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "libdevmapper.h"
#include "tools.h"
-#include "report.h"
+
+#include "lib.h"
+#include "metadata.h"
+#include "toolcontext.h"
+#include "lvm-string.h"
+#include "display.h"
+#include "activate.h"
+#include "segtype.h"
+#include "str_list.h"
+
+typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8, PVSEGS = 16 } report_type_t;
+
+struct lvm_report_object {
+ struct volume_group *pv;
+ struct logical_volume *lv;
+ struct physical_volume *vg;
+ struct lv_segment *seg;
+ struct pv_segment *pvseg;
+};
+
+/*
+ * For macro use
+ */
+static union {
+ struct physical_volume _pv;
+ struct logical_volume _lv;
+ struct volume_group _vg;
+ struct lv_segment _seg;
+ struct pv_segment _pvseg;
+} _dummy;
+
+static char _alloc_policy_char(alloc_policy_t alloc)
+{
+ switch (alloc) {
+ case ALLOC_CONTIGUOUS:
+ return 'c';
+ case ALLOC_CLING:
+ return 'C';
+ case ALLOC_NORMAL:
+ return 'n';
+ case ALLOC_ANYWHERE:
+ return 'a';
+ default:
+ return 'i';
+ }
+}
+
+/*
+ * Data-munging functions to prepare each data type for display and sorting
+ */
+static int _string_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ return dm_report_field_string(rh, mem, field, data);
+}
+
+static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const char *name = dev_name(*(const struct device **) data);
+
+ return dm_report_field_string(rh, mem, field, &name);
+}
+
+static int _devices_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct lv_segment *seg = (const struct lv_segment *) data;
+ unsigned int s;
+ const char *name = NULL;
+ uint32_t extent = 0;
+ char extent_str[32];
+
+ if (!dm_pool_begin_object(mem, 256)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ for (s = 0; s < seg->area_count; s++) {
+ switch (seg_type(seg, s)) {
+ case AREA_LV:
+ name = seg_lv(seg, s)->name;
+ extent = seg_le(seg, s);
+ break;
+ case AREA_PV:
+ name = dev_name(seg_dev(seg, s));
+ extent = seg_pe(seg, s);
+ break;
+ case AREA_UNASSIGNED:
+ name = "unassigned";
+ extent = 0;
+ }
+
+ if (!dm_pool_grow_object(mem, name, strlen(name))) {
+ log_error("dm_pool_grow_object failed");
+ return 0;
+ }
+
+ if (dm_snprintf(extent_str, sizeof(extent_str), "(%" PRIu32
+ ")", extent) < 0) {
+ log_error("Extent number dm_snprintf failed");
+ return 0;
+ }
+
+ if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
+ log_error("dm_pool_grow_object failed");
+ return 0;
+ }
+
+ if ((s != seg->area_count - 1) &&
+ !dm_pool_grow_object(mem, ",", 1)) {
+ log_error("dm_pool_grow_object failed");
+ return 0;
+ }
+ }
+
+ if (!dm_pool_grow_object(mem, "\0", 1)) {
+ log_error("dm_pool_grow_object failed");
+ return 0;
+ }
+
+ return dm_report_field_raw(rh, mem, field, dm_pool_end_object(mem));
+}
+
+static int _tags_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct list *tags = (const struct list *) data;
+ struct str_list *sl;
+
+ if (!dm_pool_begin_object(mem, 256)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ list_iterate_items(sl, tags) {
+ if (!dm_pool_grow_object(mem, sl->str, strlen(sl->str)) ||
+ (sl->list.n != tags && !dm_pool_grow_object(mem, ",", 1))) {
+ log_error("dm_pool_grow_object failed");
+ return 0;
+ }
+ }
+
+ if (!dm_pool_grow_object(mem, "\0", 1)) {
+ log_error("dm_pool_grow_object failed");
+ return 0;
+ }
+
+ return dm_report_field_raw(rh, mem, field, dm_pool_end_object(mem));
+}
+
+static int _modules_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+ struct list *modules;
+
+ if (!(modules = str_list_create(mem))) {
+ log_error("modules str_list allocation failed");
+ return 0;
+ }
+
+ if (!list_lv_modules(mem, lv, modules))
+ return_0;
+
+ return _tags_disp(rh, mem, field, modules);
+}
+
+static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct volume_group *vg = (const struct volume_group *) data;
+
+ if (!vg->fid)
+ return dm_report_field_raw(rh, mem, field, "");
+
+ return _string_disp(rh, mem, field, &vg->fid->fmt->name);
+}
+
+static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct physical_volume *pv =
+ (const struct physical_volume *) data;
+
+ if (!pv->fmt)
+ return dm_report_field_raw(rh, mem, field, "");
+
+ return _string_disp(rh, mem, field, &pv->fmt->name);
+}
+
+static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+ struct lvinfo info;
+ uint64_t minusone = UINT64_C(-1);
+
+ if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
+ return dm_report_field_int(rh, mem, field, &info.major);
+
+ return dm_report_field_int(rh, mem, field, &minusone);
+}
+
+static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+ struct lvinfo info;
+ uint64_t minusone = UINT64_C(-1);
+
+ if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
+ return dm_report_field_int(rh, mem, field, &info.minor);
+
+ return dm_report_field_int(rh, mem, field, &minusone);
+}
+
+static int _lvstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+ struct lvinfo info;
+ char *repstr;
+ float snap_percent;
+
+ if (!(repstr = dm_pool_zalloc(mem, 7))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (lv->status & PVMOVE)
+ repstr[0] = 'p';
+ else if (lv->status & MIRRORED) {
+ if (lv->status & MIRROR_NOTSYNCED)
+ repstr[0] = 'M';
+ else
+ repstr[0] = 'm';
+ }else if (lv->status & MIRROR_IMAGE)
+ repstr[0] = 'i';
+ else if (lv->status & MIRROR_LOG)
+ repstr[0] = 'l';
+ else if (lv->status & VIRTUAL)
+ repstr[0] = 'v';
+ else if (lv_is_origin(lv))
+ repstr[0] = 'o';
+ else if (lv_is_cow(lv))
+ repstr[0] = 's';
+ else
+ repstr[0] = '-';
+
+ if (lv->status & PVMOVE)
+ repstr[1] = '-';
+ else if (lv->status & LVM_WRITE)
+ repstr[1] = 'w';
+ else
+ repstr[1] = 'r';
+
+ repstr[2] = _alloc_policy_char(lv->alloc);
+
+ if (lv->status & LOCKED)
+ repstr[2] = toupper(repstr[2]);
+
+ if (lv->status & FIXED_MINOR)
+ repstr[3] = 'm'; /* Fixed Minor */
+ else
+ repstr[3] = '-';
+
+ if (lv_info(lv->vg->cmd, lv, &info, 1) && info.exists) {
+ if (info.suspended)
+ repstr[4] = 's'; /* Suspended */
+ else if (info.live_table)
+ repstr[4] = 'a'; /* Active */
+ else if (info.inactive_table)
+ repstr[4] = 'i'; /* Inactive with table */
+ else
+ repstr[4] = 'd'; /* Inactive without table */
+
+ /* Snapshot dropped? */
+ if (info.live_table && lv_is_cow(lv) &&
+ (!lv_snapshot_percent(lv, &snap_percent) ||
+ snap_percent < 0 || snap_percent >= 100)) {
+ repstr[0] = toupper(repstr[0]);
+ if (info.suspended)
+ repstr[4] = 'S'; /* Susp Inv snapshot */
+ else
+ repstr[4] = 'I'; /* Invalid snapshot */
+ }
+
+ if (info.open_count)
+ repstr[5] = 'o'; /* Open */
+ else
+ repstr[5] = '-';
+ } else {
+ repstr[4] = '-';
+ repstr[5] = '-';
+ }
+
+ return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _pvstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const uint32_t status = *(const uint32_t *) data;
+ char *repstr;
+
+ if (!(repstr = dm_pool_zalloc(mem, 4))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (status & ALLOCATABLE_PV)
+ repstr[0] = 'a';
+ else
+ repstr[0] = '-';
+
+ if (status & EXPORTED_VG)
+ repstr[1] = 'x';
+ else
+ repstr[1] = '-';
+
+ return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _vgstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct volume_group *vg = (const struct volume_group *) data;
+ char *repstr;
+
+ if (!(repstr = dm_pool_zalloc(mem, 7))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (vg->status & LVM_WRITE)
+ repstr[0] = 'w';
+ else
+ repstr[0] = 'r';
+
+ if (vg->status & RESIZEABLE_VG)
+ repstr[1] = 'z';
+ else
+ repstr[1] = '-';
+
+ if (vg->status & EXPORTED_VG)
+ repstr[2] = 'x';
+ else
+ repstr[2] = '-';
+
+ if (vg->status & PARTIAL_VG)
+ repstr[3] = 'p';
+ else
+ repstr[3] = '-';
+
+ repstr[4] = _alloc_policy_char(vg->alloc);
+
+ if (vg->status & CLUSTERED)
+ repstr[5] = 'c';
+ else
+ repstr[5] = '-';
+
+ return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _segtype_disp(struct dm_report *rh __attribute((unused)),
+ struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct lv_segment *seg = (const struct lv_segment *) data;
+
+ if (seg->area_count == 1)
+ return dm_report_field_raw(rh, mem, field, "linear");
+
+ return dm_report_field_raw(rh, mem, field,
+ seg->segtype->ops->name(seg));
+}
+
+static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+
+ if (lv_is_cow(lv))
+ return dm_report_field_string(rh, mem, field,
+ &origin_from_cow(lv)->name);
+
+ return dm_report_field_raw(rh, mem, field, "");
+}
+
+static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+ struct lv_segment *seg;
+
+ list_iterate_items(seg, &lv->segments) {
+ if (!seg_is_mirrored(seg) || !seg->log_lv)
+ continue;
+ return dm_report_field_string(rh, mem, field,
+ &seg->log_lv->name);
+ }
+
+ return dm_report_field_raw(rh, mem, field, "");
+}
+
+static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+ char *repstr, *lvname;
+ size_t len;
+
+ if (lv_is_visible(lv)) {
+ repstr = lv->name;
+ return dm_report_field_string(rh, mem, field, &repstr);
+ }
+
+ len = strlen(lv->name) + 3;
+ if (!(repstr = dm_pool_zalloc(mem, len))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
+ log_error("lvname snprintf failed");
+ return 0;
+ }
+
+ dm_report_field_set_string(field, repstr);
+
+ if (!(lvname = dm_pool_strdup(mem, lv->name))) {
+ log_error("dm_pool_strdup failed");
+ return 0;
+ }
+ dm_report_field_set_sort_value(field, lvname);
+
+ return 1;
+}
+
+static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+ const char *name;
+ struct lv_segment *seg;
+
+ list_iterate_items(seg, &lv->segments) {
+ if (!(seg->status & PVMOVE))
+ continue;
+ name = dev_name(seg_dev(seg, 0));
+ return dm_report_field_string(rh, mem, field, &name);
+ }
+
+ return dm_report_field_raw(rh, mem, field, "");
+}
+
+static int _size32_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const uint32_t size = *(const uint32_t *) data;
+ const char *disp, *repstr;
+ uint64_t *sortval;
+
+ if (!*(disp = display_size_units(dm_report_get_private(rh),
+ (uint64_t) size))) {
+ stack;
+ return 0;
+ }
+
+ if (!(repstr = dm_pool_strdup(mem, disp))) {
+ log_error("dm_pool_strdup failed");
+ return 0;
+ }
+
+ if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ *sortval = (const uint64_t) size;
+
+ dm_report_field_set_string(field, repstr);
+ dm_report_field_set_sort_value(field, sortval);
+
+ return 1;
+}
+
+static int _size64_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const uint64_t size = *(const uint64_t *) data;
+ const char *disp, *repstr;
+ uint64_t *sortval;
+
+ if (!*(disp = display_size_units(dm_report_get_private(rh), size))) {
+ stack;
+ return 0;
+ }
+
+ if (!(repstr = dm_pool_strdup(mem, disp))) {
+ log_error("dm_pool_strdup failed");
+ return 0;
+ }
+
+ if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ *sortval = size;
+ dm_report_field_set_string(field, repstr);
+ dm_report_field_set_sort_value(field, sortval);
+
+ return 1;
+}
+
+static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct volume_group *vg = (const struct volume_group *) data;
+ uint64_t size;
+
+ size = (uint64_t) vg->extent_count * vg->extent_size;
+
+ return _size64_disp(rh, mem, field, &size);
+}
+
+static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct lv_segment *seg = (const struct lv_segment *) data;
+ uint64_t start;
+
+ start = (uint64_t) seg->le * seg->lv->vg->extent_size;
+
+ return _size64_disp(rh, mem, field, &start);
+}
+
+static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct lv_segment *seg = (const struct lv_segment *) data;
+ uint64_t size;
+
+ size = (uint64_t) seg->len * seg->lv->vg->extent_size;
+
+ return _size64_disp(rh, mem, field, &size);
+}
+
+static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct lv_segment *seg = (const struct lv_segment *) data;
+ uint64_t size;
+
+ if (lv_is_cow(seg->lv))
+ size = (uint64_t) find_cow(seg->lv)->chunk_size;
+ else
+ size = 0;
+
+ return _size64_disp(rh, mem, field, &size);
+}
+
+static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct physical_volume *pv =
+ (const struct physical_volume *) data;
+ uint64_t used;
+
+ if (!pv->pe_count)
+ used = 0LL;
+ else
+ used = (uint64_t) pv->pe_alloc_count * pv->pe_size;
+
+ return _size64_disp(rh, mem, field, &used);
+}
+
+static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct physical_volume *pv =
+ (const struct physical_volume *) data;
+ uint64_t freespace;
+
+ if (!pv->pe_count)
+ freespace = pv->size;
+ else
+ freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
+
+ return _size64_disp(rh, mem, field, &freespace);
+}
+
+static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct physical_volume *pv =
+ (const struct physical_volume *) data;
+ uint64_t size;
+
+ if (!pv->pe_count)
+ size = pv->size;
+ else
+ size = (uint64_t) pv->pe_count * pv->pe_size;
+
+ return _size64_disp(rh, mem, field, &size);
+}
+
+static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct device *dev = *(const struct device **) data;
+ uint64_t size;
+
+ if (!dev_get_size(dev, &size))
+ size = 0;
+
+ return _size64_disp(rh, mem, field, &size);
+}
+
+static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct volume_group *vg = (const struct volume_group *) data;
+ uint64_t freespace;
+
+ freespace = (uint64_t) vg->free_count * vg->extent_size;
+
+ return _size64_disp(rh, mem, field, &freespace);
+}
+
+static int _uuid_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ char *repstr = NULL;
+
+ if (!(repstr = dm_pool_alloc(mem, 40))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (!id_write_format((const struct id *) data, repstr, 40)) {
+ stack;
+ return 0;
+ }
+
+ return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ return dm_report_field_uint32(rh, mem, field, data);
+}
+
+static int _int32_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ return dm_report_field_int32(rh, mem, field, data);
+}
+
+static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+ uint32_t count;
+
+ count = list_size(&lv->segments);
+
+ return _uint32_disp(rh, mem, field, &count);
+}
+
+static int _snpercent_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+ struct lvinfo info;
+ float snap_percent;
+ uint64_t *sortval;
+ char *repstr;
+
+ if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (!lv_is_cow(lv) ||
+ (lv_info(lv->vg->cmd, lv, &info, 0) && !info.exists)) {
+ dm_report_field_set_string(field, "");
+ *sortval = UINT64_C(0);
+ dm_report_field_set_sort_value(field, sortval);
+ return 1;
+ }
+
+ if (!lv_snapshot_percent(lv, &snap_percent) || snap_percent < 0) {
+ dm_report_field_set_string(field, "100.00");
+ *sortval = UINT64_C(100);
+ dm_report_field_set_sort_value(field, sortval);
+ return 1;
+ }
+
+ if (!(repstr = dm_pool_zalloc(mem, 8))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) {
+ log_error("snapshot percentage too large");
+ return 0;
+ }
+
+ *sortval = snap_percent * UINT64_C(1000);
+ dm_report_field_set_sort_value(field, sortval);
+ dm_report_field_set_string(field, repstr);
+
+ return 1;
+}
+
+static int _copypercent_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ struct logical_volume *lv = (struct logical_volume *) data;
+ float percent;
+ uint64_t *sortval;
+ char *repstr;
+
+ if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
+ !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL)) {
+ dm_report_field_set_string(field, "");
+ *sortval = UINT64_C(0);
+ dm_report_field_set_sort_value(field, sortval);
+ return 1;
+ }
+
+ percent = copy_percent(lv);
+
+ if (!(repstr = dm_pool_zalloc(mem, 8))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) {
+ log_error("copy percentage too large");
+ return 0;
+ }
+
+ *sortval = percent * UINT64_C(1000);
+ dm_report_field_set_sort_value(field, sortval);
+ dm_report_field_set_string(field, repstr);
+
+ return 1;
+}
+
+/* Report object types */
+
+/* necessary for displaying something for PVs not belonging to VG */
+static struct volume_group _dummy_vg = {
+ .name = "",
+};
+
+static void *_obj_get_vg(void *obj)
+{
+ struct volume_group *vg = ((struct lvm_report_object *)obj)->vg;
+
+ return vg ? vg : &_dummy_vg;
+}
+
+static void *_obj_get_lv(void *obj)
+{
+ return ((struct lvm_report_object *)obj)->lv;
+}
+
+static void *_obj_get_pv(void *obj)
+{
+ return ((struct lvm_report_object *)obj)->pv;
+}
+
+static void *_obj_get_seg(void *obj)
+{
+ return ((struct lvm_report_object *)obj)->seg;
+}
+
+static void *_obj_get_pvseg(void *obj)
+{
+ return ((struct lvm_report_object *)obj)->pvseg;
+}
+
+static const struct dm_report_object_type _report_types[] = {
+ { VGS, "Volume Group", "vg_", _obj_get_vg },
+ { LVS, "Logical Volume", "lv_", _obj_get_lv },
+ { PVS, "Physical Volume", "pv_", _obj_get_pv },
+ { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
+ { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
+};
+const unsigned int _num_report_types = sizeof(_report_types) / sizeof(_report_types[0]);
+
+/*
+ * Import column definitions
+ */
+
+#define STR (DM_REPORT_FIELD_STRING | DM_REPORT_FIELD_ALIGN_LEFT)
+#define NUM (DM_REPORT_FIELD_NUMBER | DM_REPORT_FIELD_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 dm_report_field_type _fields[] = {
+#include "columns.h"
+};
+
+#undef STR
+#undef NUM
+#undef FIELD
+
+const unsigned int _num_fields = sizeof(_fields) / sizeof(_fields[0]);
+
+#define PACKOBJ(o, v, l, p, s, ps) \
+ o.vg = v; \
+ o.lv = l; \
+ o.pv = p; \
+ o.seg = s; \
+ o.pvseg = ps;
static int _vgs_single(struct cmd_context *cmd __attribute((unused)),
const char *vg_name, struct volume_group *vg,
int consistent __attribute((unused)), void *handle)
{
+ struct lvm_report_object obj;
+
if (!vg) {
log_error("Volume group %s not found", vg_name);
return ECMD_FAILED;
}
- if (!report_object(handle, vg, NULL, NULL, NULL, NULL))
+ PACKOBJ(obj, vg, NULL, NULL, NULL, NULL);
+ if (!dm_report_object(handle, &obj))
return ECMD_FAILED;
check_current_backup(vg);
@@ -36,10 +899,13 @@ static int _vgs_single(struct cmd_contex
static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
+ struct lvm_report_object obj;
+
if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
return ECMD_PROCESSED;
- if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL))
+ PACKOBJ(obj, lv->vg, lv, NULL, NULL, NULL);
+ if (!dm_report_object(handle, &obj))
return ECMD_FAILED;
return ECMD_PROCESSED;
@@ -48,7 +914,10 @@ static int _lvs_single(struct cmd_contex
static int _segs_single(struct cmd_context *cmd __attribute((unused)),
struct lv_segment *seg, void *handle)
{
- if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL))
+ struct lvm_report_object obj;
+
+ PACKOBJ(obj, seg->lv->vg, seg->lv, NULL, seg, NULL);
+ if (!dm_report_object(handle, &obj))
return ECMD_FAILED;
return ECMD_PROCESSED;
@@ -60,6 +929,7 @@ static int _pvsegs_sub_single(struct cmd
int consistent = 0;
struct physical_volume *pv = pvseg->pv;
int ret = ECMD_PROCESSED;
+ struct lvm_report_object obj;
if (!lock_vol(cmd, pv->vg_name, LCK_VG_READ)) {
log_error("Can't lock %s: skipping", pv->vg_name);
@@ -78,7 +948,8 @@ static int _pvsegs_sub_single(struct cmd
goto out;
}
- if (!report_object(handle, vg, NULL, pv, NULL, pvseg))
+ PACKOBJ(obj, vg, NULL, pv, NULL, pvseg);
+ if (!dm_report_object(handle, &obj))
ret = ECMD_FAILED;
out:
@@ -107,6 +978,7 @@ static int _pvs_single(struct cmd_contex
{
int consistent = 0;
int ret = ECMD_PROCESSED;
+ struct lvm_report_object obj;
if (pv->vg_name) {
if (!lock_vol(cmd, pv->vg_name, LCK_VG_READ)) {
@@ -128,7 +1000,8 @@ static int _pvs_single(struct cmd_contex
}
}
- if (!report_object(handle, vg, NULL, pv, NULL, NULL))
+ PACKOBJ(obj, vg, NULL, pv, NULL, NULL);
+ if (!dm_report_object(handle, &obj))
ret = ECMD_FAILED;
out:
@@ -257,10 +1130,32 @@ static int _report(struct cmd_context *c
if (arg_count(cmd, noheadings_ARG))
headings = 0;
- if (!(report_handle = report_init(cmd, options, keys, &report_type,
+ if (!(report_handle = dm_report_init(options, keys, &report_type,
separator, aligned, buffered,
- headings)))
+ headings, _fields, _num_fields,
+ _report_types, _num_report_types,
+ cmd)))
+ return 0;
+
+ /* Ensure options selected are compatible */
+ if (report_type & SEGS)
+ report_type |= LVS;
+ if (report_type & PVSEGS)
+ report_type |= PVS;
+ if ((report_type & LVS) && (report_type & PVS)) {
+ log_error("Can't report LV and PV fields at the same time");
return 0;
+ }
+
+ /* Change report type if fields specified makes this necessary */
+ if (report_type & SEGS)
+ report_type = SEGS;
+ else if (report_type & LVS)
+ report_type = LVS;
+ else if (report_type & PVSEGS)
+ report_type = PVSEGS;
+ else if (report_type & PVS)
+ report_type = PVS;
switch (report_type) {
case LVS:
@@ -285,9 +1180,9 @@ static int _report(struct cmd_context *c
break;
}
- report_output(report_handle);
+ dm_report_output(report_handle);
- report_free(report_handle);
+ dm_report_free(report_handle);
return r;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] (4/4) LVM2 to use dm_report
@ 2007-01-12 23:32 ` Jun'ichi Nomura
0 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:32 UTC (permalink / raw)
To: lvm-devel
Hi,
This patch makes LVM2 to use dm_report in libdevmapper
instead of its lib/report functions.
Tested following commands where LVs of linear, striped, mirrored
and snapshot exist and confirmed the output is same with the
original LVM2 2.02.17.
lvs
pvs
vgs
lvs -a
pvs -a
lvs -a -o +devices
lvs -o name,name,lv_name,vg_name
lvs -a -o name,name,lv_name,vg_name
lvs -a -o name,lv_name,vg_name -O name
lvs -a -o name,lv_name,vg_name -O -name
lvs -a -o name,lv_name,vg_name -O size
lvs -a -o name,lv_name,vg_name -O lv_size
lvs -a -o name,lv_name,vg_name -O -size
pvs -o +pe_alloc_count,used,dev_size
pvs -a -o +pe_alloc_count,used,dev_size
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 04-lvm2-use-dm-report.patch
Type: text/x-patch
Size: 74176 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/lvm-devel/attachments/20070112/f4d39f00/attachment.bin>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-01-12 23:32 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-01-12 23:13 [PATCH] (1/4) dm_report support in libdevmapper Jun'ichi Nomura
2007-01-12 23:13 ` Jun'ichi Nomura
2007-01-12 23:31 ` [PATCH] (2/4) dmsetup info to use dm_report Jun'ichi Nomura
2007-01-12 23:31 ` Jun'ichi Nomura
2007-01-12 23:31 ` [PATCH] (3/4) Remove old codes for "info -c" from dmsetup Jun'ichi Nomura
2007-01-12 23:31 ` Jun'ichi Nomura
2007-01-12 23:32 ` [PATCH] (4/4) LVM2 to use dm_report Jun'ichi Nomura
2007-01-12 23:32 ` Jun'ichi Nomura
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.