* [PATCH] libdevmapper: (1/6) Tidy up _field_match() and _key_match()
2007-04-18 16:41 [PATCH] libdevmapper: (0/6) Filtering feature in dm_report Jun'ichi Nomura
@ 2007-04-18 16:47 ` Jun'ichi Nomura
2007-04-18 16:47 ` [PATCH] libdevmapper: (2/6) Fix trailing separator Jun'ichi Nomura
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Jun'ichi Nomura @ 2007-04-18 16:47 UTC (permalink / raw)
To: device-mapper development, Alasdair Kergon
[-- Attachment #1: Type: text/plain, Size: 181 bytes --]
Hi,
This patch cleans up _field_match() and _key_match() by separating
common operations out.
No effect on functionality.
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: libdm-report-tidy-add_field.patch --]
[-- Type: text/x-patch, Size: 4255 bytes --]
Tidy up _field_match() and _key_match()
* Add _add_field() function for flag setting, alloc, copy, and list_add of
struct field_properties
* Add _is_same_field() for lengthy test to check field name
abbreviation
---
lib/libdm-report.c | 101 +++++++++++++++++++++++++++++------------------------
1 file changed, 56 insertions(+), 45 deletions(-)
Index: device-mapper.work/lib/libdm-report.c
===================================================================
--- device-mapper.work.orig/lib/libdm-report.c
+++ device-mapper.work/lib/libdm-report.c
@@ -296,35 +296,62 @@ static int _copy_field(struct dm_report
return 1;
}
-static int _field_match(struct dm_report *rh, const char *field, size_t flen)
+static struct field_properties * _add_field(struct dm_report *rh,
+ uint32_t field_num, uint32_t flags)
{
- uint32_t f, l;
struct field_properties *fp;
+ rh->report_types |= rh->fields[field_num].type;
+ if (!(fp = dm_pool_zalloc(rh->mem, sizeof(struct field_properties)))) {
+ log_error("dm_report: "
+ "struct field_properties allocation failed");
+ return NULL;
+ }
+ if (!_copy_field(rh, fp, field_num)) {
+ dm_pool_free(rh->mem, fp);
+ return NULL;
+ }
+
+ /* Add additional flags */
+ fp->flags |= flags;
+
+ list_add(&rh->field_props, &fp->list);
+ return fp;
+}
+
+/*
+ * compare name1 and name2 (or prefix+name2)
+ * name2 is not \0 terminated. len is the length of name2.
+ */
+static int _is_same_field(const char *name1, const char *name2,
+ size_t len, const char *prefix)
+{
+ size_t l;
+
+ /* name1 == name2 */
+ if (!strncasecmp(name1, name2, len) && strlen(name1) == len)
+ return 1;
+
+ /* name1 == name2 */
+ l = strlen(prefix);
+ if (!strncasecmp(prefix, name1, l) &&
+ !strncasecmp(name1 + l, name2, len) && strlen(name1) == l + len)
+ return 1;
+
+ return 0;
+}
+
+static int _field_match(struct dm_report *rh, const char *field, size_t flen)
+{
+ uint32_t f;
+
if (!flen)
return 0;
- for (f = 0; rh->fields[f].report_fn; 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;
-
- list_add(&rh->field_props, &fp->list);
- return 1;
- }
- }
+ for (f = 0; rh->fields[f].report_fn; f++)
+ if (_is_same_field(rh->fields[f].id,
+ field, flen, rh->field_prefix))
+ return (_add_field(rh, f, 0) != NULL);
return 0;
}
@@ -342,19 +369,9 @@ static int _add_sort_key(struct dm_repor
}
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 = _add_field(rh, field_num, FLD_HIDDEN)))
+ return 0;
}
if (found->flags & FLD_SORT_KEY) {
@@ -372,7 +389,7 @@ static int _add_sort_key(struct dm_repor
static int _key_match(struct dm_report *rh, const char *key, size_t len)
{
- uint32_t f, l;
+ uint32_t f;
uint32_t flags;
if (!len)
@@ -394,16 +411,10 @@ static int _key_match(struct dm_report *
return 0;
}
- for (f = 0; rh->fields[f].report_fn; 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)) {
+ for (f = 0; rh->fields[f].report_fn; f++)
+ if (_is_same_field(rh->fields[f].id,
+ key, len, rh->field_prefix))
return _add_sort_key(rh, f, flags);
- }
- }
return 0;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH] libdevmapper: (2/6) Fix trailing separator
2007-04-18 16:41 [PATCH] libdevmapper: (0/6) Filtering feature in dm_report Jun'ichi Nomura
2007-04-18 16:47 ` [PATCH] libdevmapper: (1/6) Tidy up _field_match() and _key_match() Jun'ichi Nomura
@ 2007-04-18 16:47 ` Jun'ichi Nomura
2007-04-18 16:47 ` [PATCH] libdevmapper: (3/6) Move lib/regex from LVM2 Jun'ichi Nomura
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Jun'ichi Nomura @ 2007-04-18 16:47 UTC (permalink / raw)
To: device-mapper development, Alasdair Kergon
[-- Attachment #1: Type: text/plain, Size: 492 bytes --]
Hi,
This patch fixes dm_report_output() so that it can correctly check
the end of the row.
It uses list_end() but trailing fields may have HIDDEN flag and
not be printed.
For example,
# dmsetup info -c -o name -O minor VG0-lv0
Name
VG0-lv0
# dmsetup info -c -o name -O minor --noheadings VG0-lv0
VG0-lv0:
# dmsetup info -c -o name --noheadings VG0-lv0
VG0-lv0
The patch fixes it by inserting hidden fields at the head of the list.
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: libdm-report-fix-trailing-separator.patch --]
[-- Type: text/x-patch, Size: 989 bytes --]
Later, dm_report_output() loops through rh->field_props list
and checks the end of the list by list_end() whether to display the
separator or not.
The check doesn't work if hidden field is on the tail.
For example, try 'dmsetup info -c -o name -O minor' and
compare the results with and without '--noheadings'.
---
lib/libdm-report.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
Index: device-mapper.work/lib/libdm-report.c
===================================================================
--- device-mapper.work.orig/lib/libdm-report.c
+++ device-mapper.work/lib/libdm-report.c
@@ -315,7 +315,12 @@ static struct field_properties * _add_fi
/* Add additional flags */
fp->flags |= flags;
- list_add(&rh->field_props, &fp->list);
+ /* Hidden field must come first, otherwise list_end() doesn't work
+ as expected */
+ if (fp->flags & FLD_HIDDEN)
+ list_add_h(&rh->field_props, &fp->list);
+ else
+ list_add(&rh->field_props, &fp->list);
return fp;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH] libdevmapper: (3/6) Move lib/regex from LVM2
2007-04-18 16:41 [PATCH] libdevmapper: (0/6) Filtering feature in dm_report Jun'ichi Nomura
2007-04-18 16:47 ` [PATCH] libdevmapper: (1/6) Tidy up _field_match() and _key_match() Jun'ichi Nomura
2007-04-18 16:47 ` [PATCH] libdevmapper: (2/6) Fix trailing separator Jun'ichi Nomura
@ 2007-04-18 16:47 ` Jun'ichi Nomura
2007-04-18 19:23 ` [PATCH] LVM2: (1/2) Use dm_regex Jun'ichi Nomura
2007-04-18 16:47 ` [PATCH] libdevmapper: (4/6) Add filtering feature to dm_report Jun'ichi Nomura
` (3 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: Jun'ichi Nomura @ 2007-04-18 16:47 UTC (permalink / raw)
To: device-mapper development, Alasdair Kergon
[-- Attachment #1: Type: text/plain, Size: 306 bytes --]
Hi,
This patch just moves lib/regex from LVM2 as a preparation for
the filtering feature of dm_report.
Now, the following functions are exported:
- dm_regex_create()
- dm_regex_match()
Corresponding patch to LVM2 will be posted to lvm-devel.
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: libdm-regex.patch --]
[-- Type: text/x-patch, Size: 22489 bytes --]
Moved lib/regex from LVM2
Exported functions and a structure are renamed:
- matcher_create() -> dm_regex_create()
- matcher_run() -> dm_regex_match()
- struct matcher -> struct dm_regex
---
lib/.exported_symbols | 2
lib/Makefile.in | 3
lib/libdevmapper.h | 7
lib/regex/matcher.c | 366 ++++++++++++++++++++++++++++++++++++++++++++++++++
lib/regex/parse_rx.c | 360 +++++++++++++++++++++++++++++++++++++++++++++++++
lib/regex/parse_rx.h | 52 +++++++
lib/regex/ttree.c | 117 +++++++++++++++
lib/regex/ttree.h | 26 +++
8 files changed, 933 insertions(+)
Index: device-mapper.work/lib/.exported_symbols
===================================================================
--- device-mapper.work.orig/lib/.exported_symbols
+++ device-mapper.work/lib/.exported_symbols
@@ -127,3 +127,5 @@ dm_report_field_int32
dm_report_field_uint32
dm_report_field_uint64
dm_report_field_set_value
+dm_regex_create
+dm_regex_match
Index: device-mapper.work/lib/libdevmapper.h
===================================================================
--- device-mapper.work.orig/lib/libdevmapper.h
+++ device-mapper.work/lib/libdevmapper.h
@@ -711,4 +711,11 @@ int dm_report_field_uint64(struct dm_rep
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
const void *sortvalue);
+/*
+ * dm_regex
+ */
+struct dm_regex;
+struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
+ unsigned num);
+int dm_regex_match(struct dm_regex *regex, const char *s);
#endif /* LIB_DEVICE_MAPPER_H */
Index: device-mapper.work/lib/regex/matcher.c
===================================================================
--- /dev/null
+++ device-mapper.work/lib/regex/matcher.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * 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 "parse_rx.h"
+#include "ttree.h"
+
+#define assert(x) do { if (!(x)) log_error("assertion failed"); } while(0)
+
+struct dfa_state {
+ int final;
+ struct dfa_state *lookup[256];
+};
+
+struct state_queue {
+ struct dfa_state *s;
+ dm_bitset_t bits;
+ struct state_queue *next;
+};
+
+struct dm_regex { /* Instance variables for the lexer */
+ struct dfa_state *start;
+ unsigned num_nodes;
+ int nodes_entered;
+ struct rx_node **nodes;
+ struct dm_pool *scratch, *mem;
+};
+
+#define TARGET_TRANS '\0'
+
+static int _count_nodes(struct rx_node *rx)
+{
+ int r = 1;
+
+ if (rx->left)
+ r += _count_nodes(rx->left);
+
+ if (rx->right)
+ r += _count_nodes(rx->right);
+
+ return r;
+}
+
+static void _fill_table(struct dm_regex *m, struct rx_node *rx)
+{
+ assert((rx->type != OR) || (rx->left && rx->right));
+
+ if (rx->left)
+ _fill_table(m, rx->left);
+
+ if (rx->right)
+ _fill_table(m, rx->right);
+
+ m->nodes[m->nodes_entered++] = rx;
+}
+
+static void _create_bitsets(struct dm_regex *m)
+{
+ int i;
+
+ for (i = 0; i < m->num_nodes; i++) {
+ struct rx_node *n = m->nodes[i];
+ n->firstpos = dm_bitset_create(m->scratch, m->num_nodes);
+ n->lastpos = dm_bitset_create(m->scratch, m->num_nodes);
+ n->followpos = dm_bitset_create(m->scratch, m->num_nodes);
+ }
+}
+
+static void _calc_functions(struct dm_regex *m)
+{
+ int i, j, final = 1;
+ struct rx_node *rx, *c1, *c2;
+
+ for (i = 0; i < m->num_nodes; i++) {
+ rx = m->nodes[i];
+ c1 = rx->left;
+ c2 = rx->right;
+
+ if (dm_bit(rx->charset, TARGET_TRANS))
+ rx->final = final++;
+
+ switch (rx->type) {
+ case CAT:
+ if (c1->nullable)
+ dm_bit_union(rx->firstpos,
+ c1->firstpos, c2->firstpos);
+ else
+ dm_bit_copy(rx->firstpos, c1->firstpos);
+
+ if (c2->nullable)
+ dm_bit_union(rx->lastpos,
+ c1->lastpos, c2->lastpos);
+ else
+ dm_bit_copy(rx->lastpos, c2->lastpos);
+
+ rx->nullable = c1->nullable && c2->nullable;
+ break;
+
+ case PLUS:
+ dm_bit_copy(rx->firstpos, c1->firstpos);
+ dm_bit_copy(rx->lastpos, c1->lastpos);
+ rx->nullable = c1->nullable;
+ break;
+
+ case OR:
+ dm_bit_union(rx->firstpos, c1->firstpos, c2->firstpos);
+ dm_bit_union(rx->lastpos, c1->lastpos, c2->lastpos);
+ rx->nullable = c1->nullable || c2->nullable;
+ break;
+
+ case QUEST:
+ case STAR:
+ dm_bit_copy(rx->firstpos, c1->firstpos);
+ dm_bit_copy(rx->lastpos, c1->lastpos);
+ rx->nullable = 1;
+ break;
+
+ case CHARSET:
+ dm_bit_set(rx->firstpos, i);
+ dm_bit_set(rx->lastpos, i);
+ rx->nullable = 0;
+ break;
+
+ default:
+ log_error("Internal error: Unknown calc node type");
+ }
+
+ /*
+ * followpos has it's own switch
+ * because PLUS and STAR do the
+ * same thing.
+ */
+ switch (rx->type) {
+ case CAT:
+ for (j = 0; j < m->num_nodes; j++) {
+ if (dm_bit(c1->lastpos, j)) {
+ struct rx_node *n = m->nodes[j];
+ dm_bit_union(n->followpos,
+ n->followpos, c2->firstpos);
+ }
+ }
+ break;
+
+ case PLUS:
+ case STAR:
+ for (j = 0; j < m->num_nodes; j++) {
+ if (dm_bit(rx->lastpos, j)) {
+ struct rx_node *n = m->nodes[j];
+ dm_bit_union(n->followpos,
+ n->followpos, rx->firstpos);
+ }
+ }
+ break;
+ }
+ }
+}
+
+static struct dfa_state *_create_dfa_state(struct dm_pool *mem)
+{
+ return dm_pool_zalloc(mem, sizeof(struct dfa_state));
+}
+
+static struct state_queue *_create_state_queue(struct dm_pool *mem,
+ struct dfa_state *dfa,
+ dm_bitset_t bits)
+{
+ struct state_queue *r = dm_pool_alloc(mem, sizeof(*r));
+
+ if (!r) {
+ stack;
+ return NULL;
+ }
+
+ r->s = dfa;
+ r->bits = dm_bitset_create(mem, bits[0]); /* first element is the size */
+ dm_bit_copy(r->bits, bits);
+ r->next = 0;
+ return r;
+}
+
+static int _calc_states(struct dm_regex *m, struct rx_node *rx)
+{
+ unsigned iwidth = (m->num_nodes / DM_BITS_PER_INT) + 1;
+ struct ttree *tt = ttree_create(m->scratch, iwidth);
+ struct state_queue *h, *t, *tmp;
+ struct dfa_state *dfa, *ldfa;
+ int i, a, set_bits = 0, count = 0;
+ dm_bitset_t bs, dfa_bits;
+
+ if (!tt)
+ return_0;
+
+ if (!(bs = dm_bitset_create(m->scratch, m->num_nodes)))
+ return_0;
+
+ /* create first state */
+ dfa = _create_dfa_state(m->mem);
+ m->start = dfa;
+ ttree_insert(tt, rx->firstpos + 1, dfa);
+
+ /* prime the queue */
+ h = t = _create_state_queue(m->scratch, dfa, rx->firstpos);
+ while (h) {
+ /* pop state off front of the queue */
+ dfa = h->s;
+ dfa_bits = h->bits;
+ h = h->next;
+
+ /* iterate through all the inputs for this state */
+ dm_bit_clear_all(bs);
+ for (a = 0; a < 256; a++) {
+ /* iterate through all the states in firstpos */
+ for (i = dm_bit_get_first(dfa_bits);
+ i >= 0; i = dm_bit_get_next(dfa_bits, i)) {
+ if (dm_bit(m->nodes[i]->charset, a)) {
+ if (a == TARGET_TRANS)
+ dfa->final = m->nodes[i]->final;
+
+ dm_bit_union(bs, bs,
+ m->nodes[i]->followpos);
+ set_bits = 1;
+ }
+ }
+
+ if (set_bits) {
+ ldfa = ttree_lookup(tt, bs + 1);
+ if (!ldfa) {
+ /* push */
+ ldfa = _create_dfa_state(m->mem);
+ ttree_insert(tt, bs + 1, ldfa);
+ tmp =
+ _create_state_queue(m->scratch,
+ ldfa, bs);
+ if (!h)
+ h = t = tmp;
+ else {
+ t->next = tmp;
+ t = tmp;
+ }
+
+ count++;
+ }
+
+ dfa->lookup[a] = ldfa;
+ set_bits = 0;
+ dm_bit_clear_all(bs);
+ }
+ }
+ }
+
+ log_debug("Matcher built with %d dfa states", count);
+ return 1;
+}
+
+struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
+ unsigned num)
+{
+ char *all, *ptr;
+ int i;
+ size_t len = 0;
+ struct rx_node *rx;
+ struct dm_pool *scratch = dm_pool_create("regex matcher", 10 * 1024);
+ struct dm_regex *m;
+
+ if (!scratch) {
+ stack;
+ return NULL;
+ }
+
+ if (!(m = dm_pool_alloc(mem, sizeof(*m)))) {
+ stack;
+ dm_pool_destroy(scratch);
+ return NULL;
+ }
+
+ memset(m, 0, sizeof(*m));
+
+ /* join the regexps together, delimiting with zero */
+ for (i = 0; i < num; i++)
+ len += strlen(patterns[i]) + 8;
+
+ ptr = all = dm_pool_alloc(scratch, len + 1);
+
+ if (!all) {
+ stack;
+ goto bad;
+ }
+
+ for (i = 0; i < num; i++) {
+ ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
+ if (i < (num - 1))
+ *ptr++ = '|';
+ }
+
+ /* parse this expression */
+ if (!(rx = rx_parse_tok(scratch, all, ptr))) {
+ log_error("Couldn't parse regex");
+ goto bad;
+ }
+
+ m->mem = mem;
+ m->scratch = scratch;
+ m->num_nodes = _count_nodes(rx);
+ m->nodes = dm_pool_alloc(scratch, sizeof(*m->nodes) * m->num_nodes);
+
+ if (!m->nodes) {
+ stack;
+ goto bad;
+ }
+
+ _fill_table(m, rx);
+ _create_bitsets(m);
+ _calc_functions(m);
+ _calc_states(m, rx);
+ dm_pool_destroy(scratch);
+ m->scratch = NULL;
+
+ return m;
+
+ bad:
+ dm_pool_destroy(scratch);
+ dm_pool_destroy(mem);
+ return NULL;
+}
+
+static struct dfa_state *_step_matcher(int c, struct dfa_state *cs, int *r)
+{
+ if (!(cs = cs->lookup[(unsigned char) c]))
+ return NULL;
+
+ if (cs->final && (cs->final > *r))
+ *r = cs->final;
+
+ return cs;
+}
+
+int dm_regex_match(struct dm_regex *m, const char *b)
+{
+ struct dfa_state *cs = m->start;
+ int r = 0;
+
+ if (!(cs = _step_matcher(HAT_CHAR, cs, &r)))
+ goto out;
+
+ for (; *b; b++)
+ if (!(cs = _step_matcher(*b, cs, &r)))
+ goto out;
+
+ _step_matcher(DOLLAR_CHAR, cs, &r);
+
+ out:
+ /* subtract 1 to get back to zero index */
+ return r - 1;
+}
Index: device-mapper.work/lib/regex/parse_rx.c
===================================================================
--- /dev/null
+++ device-mapper.work/lib/regex/parse_rx.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * 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 "parse_rx.h"
+
+struct parse_sp { /* scratch pad for the parsing process */
+ struct dm_pool *mem;
+ int type; /* token type, 0 indicates a charset */
+ dm_bitset_t charset; /* The current charset */
+ const char *cursor; /* where we are in the regex */
+ const char *rx_end; /* 1pte for the expression being parsed */
+};
+
+static struct rx_node *_or_term(struct parse_sp *ps);
+
+static void _single_char(struct parse_sp *ps, unsigned int c, const char *ptr)
+{
+ ps->type = 0;
+ ps->cursor = ptr + 1;
+ dm_bit_clear_all(ps->charset);
+ dm_bit_set(ps->charset, c);
+}
+
+/*
+ * Get the next token from the regular expression.
+ * Returns: 1 success, 0 end of input, -1 error.
+ */
+static int _rx_get_token(struct parse_sp *ps)
+{
+ int neg = 0, range = 0;
+ char c, lc = 0;
+ const char *ptr = ps->cursor;
+ if (ptr == ps->rx_end) { /* end of input ? */
+ ps->type = -1;
+ return 0;
+ }
+
+ switch (*ptr) {
+ /* charsets and ncharsets */
+ case '[':
+ ptr++;
+ if (*ptr == '^') {
+ dm_bit_set_all(ps->charset);
+
+ /* never transition on zero */
+ dm_bit_clear(ps->charset, 0);
+ neg = 1;
+ ptr++;
+
+ } else
+ dm_bit_clear_all(ps->charset);
+
+ while ((ptr < ps->rx_end) && (*ptr != ']')) {
+ if (*ptr == '\\') {
+ /* an escaped character */
+ ptr++;
+ switch (*ptr) {
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ default:
+ c = *ptr;
+ }
+ } else if (*ptr == '-' && lc) {
+ /* we've got a range on our hands */
+ range = 1;
+ ptr++;
+ if (ptr == ps->rx_end) {
+ log_error("Incomplete range"
+ "specification");
+ return -1;
+ }
+ c = *ptr;
+ } else
+ c = *ptr;
+
+ if (range) {
+ /* add lc - c into the bitset */
+ if (lc > c) {
+ char tmp = c;
+ c = lc;
+ lc = tmp;
+ }
+
+ for (; lc <= c; lc++) {
+ if (neg)
+ dm_bit_clear(ps->charset, lc);
+ else
+ dm_bit_set(ps->charset, lc);
+ }
+ range = 0;
+ } else {
+ /* add c into the bitset */
+ if (neg)
+ dm_bit_clear(ps->charset, c);
+ else
+ dm_bit_set(ps->charset, c);
+ }
+ ptr++;
+ lc = c;
+ }
+
+ if (ptr >= ps->rx_end) {
+ ps->type = -1;
+ return -1;
+ }
+
+ ps->type = 0;
+ ps->cursor = ptr + 1;
+ break;
+
+ /* These characters are special, we just return their ASCII
+ codes as the type. Sorted into ascending order to help the
+ compiler */
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case '?':
+ case '|':
+ ps->type = (int) *ptr;
+ ps->cursor = ptr + 1;
+ break;
+
+ case '^':
+ _single_char(ps, HAT_CHAR, ptr);
+ break;
+
+ case '$':
+ _single_char(ps, DOLLAR_CHAR, ptr);
+ break;
+
+ case '.':
+ /* The 'all but newline' character set */
+ ps->type = 0;
+ ps->cursor = ptr + 1;
+ dm_bit_set_all(ps->charset);
+ dm_bit_clear(ps->charset, (int) '\n');
+ dm_bit_clear(ps->charset, (int) '\r');
+ dm_bit_clear(ps->charset, 0);
+ break;
+
+ case '\\':
+ /* escaped character */
+ ptr++;
+ if (ptr >= ps->rx_end) {
+ log_error("Badly quoted character at end "
+ "of expression");
+ ps->type = -1;
+ return -1;
+ }
+
+ ps->type = 0;
+ ps->cursor = ptr + 1;
+ dm_bit_clear_all(ps->charset);
+ switch (*ptr) {
+ case 'n':
+ dm_bit_set(ps->charset, (int) '\n');
+ break;
+ case 'r':
+ dm_bit_set(ps->charset, (int) '\r');
+ break;
+ case 't':
+ dm_bit_set(ps->charset, (int) '\t');
+ break;
+ default:
+ dm_bit_set(ps->charset, (int) *ptr);
+ }
+ break;
+
+ default:
+ /* add a single character to the bitset */
+ ps->type = 0;
+ ps->cursor = ptr + 1;
+ dm_bit_clear_all(ps->charset);
+ dm_bit_set(ps->charset, (int) *ptr);
+ break;
+ }
+
+ return 1;
+}
+
+static struct rx_node *_node(struct dm_pool *mem, int type,
+ struct rx_node *l, struct rx_node *r)
+{
+ struct rx_node *n = dm_pool_zalloc(mem, sizeof(*n));
+
+ if (n) {
+ if (!(n->charset = dm_bitset_create(mem, 256))) {
+ dm_pool_free(mem, n);
+ return NULL;
+ }
+
+ n->type = type;
+ n->left = l;
+ n->right = r;
+ }
+
+ return n;
+}
+
+static struct rx_node *_term(struct parse_sp *ps)
+{
+ struct rx_node *n;
+
+ switch (ps->type) {
+ case 0:
+ if (!(n = _node(ps->mem, CHARSET, NULL, NULL))) {
+ stack;
+ return NULL;
+ }
+
+ dm_bit_copy(n->charset, ps->charset);
+ _rx_get_token(ps); /* match charset */
+ break;
+
+ case '(':
+ _rx_get_token(ps); /* match '(' */
+ n = _or_term(ps);
+ if (ps->type != ')') {
+ log_error("missing ')' in regular expression");
+ return 0;
+ }
+ _rx_get_token(ps); /* match ')' */
+ break;
+
+ default:
+ n = 0;
+ }
+
+ return n;
+}
+
+static struct rx_node *_closure_term(struct parse_sp *ps)
+{
+ struct rx_node *l, *n;
+
+ if (!(l = _term(ps)))
+ return NULL;
+
+ for (;;) {
+ switch (ps->type) {
+ case '*':
+ n = _node(ps->mem, STAR, l, NULL);
+ break;
+
+ case '+':
+ n = _node(ps->mem, PLUS, l, NULL);
+ break;
+
+ case '?':
+ n = _node(ps->mem, QUEST, l, NULL);
+ break;
+
+ default:
+ return l;
+ }
+
+ if (!n) {
+ stack;
+ return NULL;
+ }
+
+ _rx_get_token(ps);
+ l = n;
+ }
+
+ return n;
+}
+
+static struct rx_node *_cat_term(struct parse_sp *ps)
+{
+ struct rx_node *l, *r, *n;
+
+ if (!(l = _closure_term(ps)))
+ return NULL;
+
+ if (ps->type == '|')
+ return l;
+
+ if (!(r = _cat_term(ps)))
+ return l;
+
+ if (!(n = _node(ps->mem, CAT, l, r)))
+ stack;
+
+ return n;
+}
+
+static struct rx_node *_or_term(struct parse_sp *ps)
+{
+ struct rx_node *l, *r, *n;
+
+ if (!(l = _cat_term(ps)))
+ return NULL;
+
+ if (ps->type != '|')
+ return l;
+
+ _rx_get_token(ps); /* match '|' */
+
+ if (!(r = _or_term(ps))) {
+ log_error("Badly formed 'or' expression");
+ return NULL;
+ }
+
+ if (!(n = _node(ps->mem, OR, l, r)))
+ stack;
+
+ return n;
+}
+
+struct rx_node *rx_parse_tok(struct dm_pool *mem,
+ const char *begin, const char *end)
+{
+ struct rx_node *r;
+ struct parse_sp *ps = dm_pool_zalloc(mem, sizeof(*ps));
+
+ if (!ps) {
+ stack;
+ return NULL;
+ }
+
+ ps->mem = mem;
+ ps->charset = dm_bitset_create(mem, 256);
+ ps->cursor = begin;
+ ps->rx_end = end;
+ _rx_get_token(ps); /* load the first token */
+
+ if (!(r = _or_term(ps))) {
+ log_error("Parse error in regex");
+ dm_pool_free(mem, ps);
+ }
+
+ return r;
+}
+
+struct rx_node *rx_parse_str(struct dm_pool *mem, const char *str)
+{
+ return rx_parse_tok(mem, str, str + strlen(str));
+}
Index: device-mapper.work/lib/regex/parse_rx.h
===================================================================
--- /dev/null
+++ device-mapper.work/lib/regex/parse_rx.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * 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_PARSE_REGEX_H
+#define _LVM_PARSE_REGEX_H
+
+enum {
+ CAT,
+ STAR,
+ PLUS,
+ OR,
+ QUEST,
+ CHARSET
+};
+
+/*
+ * We're never going to be running the regex on non-printable
+ * chars, so we can use a couple of these chars to represent the
+ * start and end of a string.
+ */
+#define HAT_CHAR 0x2
+#define DOLLAR_CHAR 0x3
+
+struct rx_node {
+ int type;
+ dm_bitset_t charset;
+ struct rx_node *left, *right;
+
+ /* used to build the dfa for the toker */
+ int nullable, final;
+ dm_bitset_t firstpos;
+ dm_bitset_t lastpos;
+ dm_bitset_t followpos;
+};
+
+struct rx_node *rx_parse_str(struct dm_pool *mem, const char *str);
+struct rx_node *rx_parse_tok(struct dm_pool *mem,
+ const char *begin, const char *end);
+
+#endif
Index: device-mapper.work/lib/regex/ttree.c
===================================================================
--- /dev/null
+++ device-mapper.work/lib/regex/ttree.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * 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 "ttree.h"
+
+struct node {
+ unsigned k;
+ struct node *l, *m, *r;
+ void *data;
+};
+
+struct ttree {
+ int klen;
+ struct dm_pool *mem;
+ struct node *root;
+};
+
+static struct node **_lookup_single(struct node **c, unsigned int k)
+{
+ while (*c) {
+ if (k < (*c)->k)
+ c = &((*c)->l);
+
+ else if (k > (*c)->k)
+ c = &((*c)->r);
+
+ else {
+ c = &((*c)->m);
+ break;
+ }
+ }
+
+ return c;
+}
+
+void *ttree_lookup(struct ttree *tt, unsigned *key)
+{
+ struct node **c = &tt->root;
+ int count = tt->klen;
+
+ while (*c && count) {
+ c = _lookup_single(c, *key++);
+ count--;
+ }
+
+ return *c ? (*c)->data : NULL;
+}
+
+static struct node *_tree_node(struct dm_pool *mem, unsigned int k)
+{
+ struct node *n = dm_pool_zalloc(mem, sizeof(*n));
+
+ if (n)
+ n->k = k;
+
+ return n;
+}
+
+int ttree_insert(struct ttree *tt, unsigned int *key, void *data)
+{
+ struct node **c = &tt->root;
+ int count = tt->klen;
+ unsigned int k;
+
+ do {
+ k = *key++;
+ c = _lookup_single(c, k);
+ count--;
+
+ } while (*c && count);
+
+ if (!*c) {
+ count++;
+
+ while (count--) {
+ if (!(*c = _tree_node(tt->mem, k))) {
+ stack;
+ return 0;
+ }
+
+ k = *key++;
+
+ if (count)
+ c = &((*c)->m);
+ }
+ }
+ (*c)->data = data;
+
+ return 1;
+}
+
+struct ttree *ttree_create(struct dm_pool *mem, unsigned int klen)
+{
+ struct ttree *tt;
+
+ if (!(tt = dm_pool_zalloc(mem, sizeof(*tt)))) {
+ stack;
+ return NULL;
+ }
+
+ tt->klen = klen;
+ tt->mem = mem;
+ return tt;
+}
Index: device-mapper.work/lib/regex/ttree.h
===================================================================
--- /dev/null
+++ device-mapper.work/lib/regex/ttree.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * 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_TTREE_H
+#define _LVM_TTREE_H
+
+struct ttree;
+
+struct ttree *ttree_create(struct dm_pool *mem, unsigned int klen);
+
+void *ttree_lookup(struct ttree *tt, unsigned *key);
+int ttree_insert(struct ttree *tt, unsigned *key, void *data);
+
+#endif
Index: device-mapper.work/lib/Makefile.in
===================================================================
--- device-mapper.work.orig/lib/Makefile.in
+++ device-mapper.work/lib/Makefile.in
@@ -25,6 +25,9 @@ SOURCES =\
libdm-deptree.c \
libdm-string.c \
libdm-report.c \
+ regex/matcher.c \
+ regex/parse_rx.c \
+ regex/ttree.c \
mm/dbg_malloc.c \
mm/pool.c \
$(interface)/libdm-iface.c
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH] libdevmapper: (4/6) Add filtering feature to dm_report
2007-04-18 16:41 [PATCH] libdevmapper: (0/6) Filtering feature in dm_report Jun'ichi Nomura
` (2 preceding siblings ...)
2007-04-18 16:47 ` [PATCH] libdevmapper: (3/6) Move lib/regex from LVM2 Jun'ichi Nomura
@ 2007-04-18 16:47 ` Jun'ichi Nomura
2007-04-18 19:32 ` [PATCH] LVM2: (2/2) Use dm_report filter Jun'ichi Nomura
2007-04-18 16:47 ` [PATCH] libdevmapper: (5/6) Add '--filter' option to dmsetup Jun'ichi Nomura
` (2 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: Jun'ichi Nomura @ 2007-04-18 16:47 UTC (permalink / raw)
To: device-mapper development, Alasdair Kergon
[-- Attachment #1: Type: text/plain, Size: 758 bytes --]
Hi,
This patch adds a filtering feature to dm_report.
- Add dm_report_set_filter() API.
By calling this, dm_report_object() omits rows which doesn't
match the condition specified by the filter.
- Fitlers can be composed with the following components:
* Simple comparison of field value
'==', '!=', '>', '>=', '<', '<='
Strings should be quoted by either ' or ".
Only decimal, non-negative integers are currently allowed.
* Regular expression
'=~', '!~'
Regular expression can be quoted by '/', '|', '#', or any
other characters.
* Logical combinations of the expressions
'and', 'or', '!', '(', ')'
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: libdm-report-add-filter.patch --]
[-- Type: text/x-patch, Size: 22659 bytes --]
Add filtering feature to dm_report.
Filter is set by dm_report_set_filters()
---
lib/.exported_symbols | 1
lib/libdevmapper.h | 4
lib/libdm-report.c | 783 +++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 781 insertions(+), 7 deletions(-)
Index: device-mapper.work/lib/.exported_symbols
===================================================================
--- device-mapper.work.orig/lib/.exported_symbols
+++ device-mapper.work/lib/.exported_symbols
@@ -127,5 +127,6 @@ dm_report_field_int32
dm_report_field_uint32
dm_report_field_uint64
dm_report_field_set_value
+dm_report_set_filter
dm_regex_create
dm_regex_match
Index: device-mapper.work/lib/libdevmapper.h
===================================================================
--- device-mapper.work.orig/lib/libdevmapper.h
+++ device-mapper.work/lib/libdevmapper.h
@@ -688,6 +688,10 @@ int dm_report_object(struct dm_report *r
int dm_report_output(struct dm_report *rh);
void dm_report_free(struct dm_report *rh);
+/* Set filter */
+int dm_report_set_filter(struct dm_report *rh,
+ const char *filter, uint32_t flags);
+
/*
* Report functions are provided for simple data types.
* They take care of allocating copies of the data.
Index: device-mapper.work/lib/libdm-report.c
===================================================================
--- device-mapper.work.orig/lib/libdm-report.c
+++ device-mapper.work/lib/libdm-report.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004 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 device-mapper userspace tools.
* The code is based on LVM2 report function.
@@ -14,6 +15,7 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <ctype.h>
#include "libdevmapper.h"
#include "list.h"
#include "log.h"
@@ -24,6 +26,7 @@
#define RH_SORT_REQUIRED 0x00000100
#define RH_HEADINGS_PRINTED 0x00000200
+struct filter_node;
struct dm_report {
struct dm_pool *mem;
@@ -46,6 +49,8 @@ struct dm_report {
/* To store caller private data */
void *private;
+
+ struct filter_node *filter_root;
};
/*
@@ -474,6 +479,653 @@ static int _parse_keys(struct dm_report
return 1;
}
+/*
+ * Filter tokens
+ */
+
+/*
+ * Comparison and logical operation tokens
+ * OP_CMP := '==' | '!=' | '>' | '>=' | '<' | '<=' | '=~' | '!~'
+ * OP_LOG := '!' | '(' | ')' | ',' | 'and' | 'or' | '&&' | '||'
+ */
+
+struct op_def {
+ const char *string;
+ uint32_t flags;
+ const char *desc;
+};
+
+static const char * _skip_space(const char *s)
+{
+ while (*s && isspace(*s))
+ s++;
+ return s;
+}
+
+static const char * _token_match(const char *s, const char *token)
+{
+ s = _skip_space(s);
+
+ if (!strncmp(s, token, strlen(token)))
+ return s + strlen(token);
+
+ return NULL;
+}
+
+static int _tok_op(struct op_def *t, const char *s, const char **end,
+ uint32_t expect)
+{
+ const char *next;
+
+ for (; t->string; t++) {
+ if (expect && !(t->flags & expect))
+ continue;
+
+ if ((next = _token_match(s, t->string))) {
+ *end = next;
+ return t->flags;
+ }
+ }
+
+ *end = s;
+ return 0;
+}
+
+/* OP_CMP definition and matcher function */
+
+#define FLD_CMP_MASK 0x000FF000
+#define FLD_CMP_EQUAL 0x00001000
+#define FLD_CMP_NOT 0x00002000
+#define FLD_CMP_GT 0x00004000
+#define FLD_CMP_LT 0x00008000
+#define FLD_CMP_REGEX 0x00010000
+
+/* _tok_op() tries to match from the first of this list.
+ * So longer one should come first.
+ * e.g. ">=" should appear earlier in the list than ">". */
+static struct op_def _op_cmp[] = {
+ { "==", FLD_CMP_EQUAL, "Equal to" },
+ { "!=", FLD_CMP_NOT|FLD_CMP_EQUAL, "Not equal" },
+ { ">=", FLD_CMP_GT|FLD_CMP_EQUAL|DM_REPORT_FIELD_TYPE_NUMBER,
+ "Greater than or equal to" },
+ { ">", FLD_CMP_GT|DM_REPORT_FIELD_TYPE_NUMBER, "Greater than" },
+ { "<=", FLD_CMP_LT|FLD_CMP_EQUAL|DM_REPORT_FIELD_TYPE_NUMBER,
+ "Lesser than or equal to" },
+ { "<", FLD_CMP_LT|DM_REPORT_FIELD_TYPE_NUMBER, "Lesser than" },
+ { "=~", FLD_CMP_REGEX|DM_REPORT_FIELD_TYPE_STRING,
+ "Matching regular expression" },
+ { "!~", FLD_CMP_REGEX|FLD_CMP_NOT|DM_REPORT_FIELD_TYPE_STRING,
+ "Not matching regular expression" },
+ { NULL, 0, NULL }
+};
+
+static uint32_t _tok_op_cmp(const char *s, const char **end)
+{
+ return _tok_op(_op_cmp, s, end, 0);
+}
+
+/* OP_LOG definitions and matcher functions */
+
+#define FILTER_TYPE_MASK 0x00FF
+#define FILTER_COND 0x0001
+#define FILTER_AND 0x0002
+#define FILTER_OR 0x0004
+#define FILTER_MODIFIER_MASK 0x0F00
+#define FILTER_NOT 0x0100
+#define FILTER_DELIMITER_MASK 0xF000
+#define FILTER_PS 0x1000
+#define FILTER_PE 0x2000
+
+static struct op_def _op_log[] = {
+ { "&&", FILTER_AND, NULL },
+ { "and", FILTER_AND, NULL },
+ { ",", FILTER_AND, NULL },
+ { "||", FILTER_OR, NULL },
+ { "or", FILTER_OR, NULL },
+ { "!", FILTER_NOT, NULL },
+ { "(", FILTER_PS, NULL },
+ { ")", FILTER_PE, NULL },
+ { NULL, 0, NULL},
+};
+
+static int _tok_op_log(const char *s, const char **end, uint32_t expect)
+{
+ return _tok_op(_op_log, s, end, expect);
+}
+
+/*
+ * Other tokens (FIELD, VALUE, STRING, NUMBER, REGEX)
+ * FIELD := <strings of alphabet, number and '_'>
+ * VALUE := NUMBER | STRING
+ * REGEX := <strings quoted by any character>
+ * NUMBER := <strings of [0-9]> (because sort_value is unsigned)
+ * STRING := <strings quoted by '"' or '\''>
+ *
+ * _tok_* functions
+ *
+ * Input:
+ * s - a pointer to the parsed string
+ * Output:
+ * begin - a pointer to the beginning of the token
+ * end - a pointer to the end of the token + 1
+ * or undefined if return value is NULL
+ * return value - a starting point of the next parsing
+ * NULL if s doesn't match with token type
+ * (the parsing should be terminated)
+ */
+
+static const char * _tok_number(const char *s,
+ const char **begin, const char **end)
+{
+ *begin = s;
+ while (*s && isdigit(*s))
+ s++;
+ *end = s;
+
+ return s;
+}
+
+static const char * _tok_string(const char *s,
+ const char **begin, const char **end,
+ const char endchar)
+{
+ *begin = s;
+ while (*s && *s != endchar)
+ s++;
+ *end = s;
+
+ return s;
+}
+
+static const char * _tok_regex(const char *s,
+ const char **begin, const char **end,
+ char *quote)
+{
+ s = _skip_space(s);
+
+ if (!*s) {
+ log_error("Regular expression expected");
+ return NULL;
+ }
+
+ switch (*s) {
+ case '(': *quote = ')'; break;
+ case '{': *quote = '}'; break;
+ case '[': *quote = ']'; break;
+ default: *quote = *s;
+ }
+
+ s = _tok_string(s + 1, begin, end, *quote);
+ if (!*s) {
+ log_error("Missing end quote of regex");
+ return NULL;
+ }
+ s++;
+
+ return s;
+}
+
+static const char * _tok_value(const char *s,
+ const char **begin, const char **end,
+ char *quote)
+{
+ s = _skip_space(s);
+
+ if (*s == '"' || *s == '\'') { /* quoted string */
+ *quote = *s;
+ s = _tok_string(s + 1, begin, end, *quote);
+ if (!*s) {
+ log_error("Missing end quote of string");
+ return NULL;
+ }
+ s++;
+ } else { /* number */
+ *quote = 0;
+ s = _tok_number(s, begin, end);
+ if (*begin == *end) {
+ log_error("Empty value or unquoted string");
+ return NULL;
+ }
+ }
+
+ return s;
+}
+
+static int _field_name_char(const char c)
+{
+ return (isalnum(c) || c == '_' || c == '-');
+}
+
+static const char * _tok_field_name(const char *s,
+ const char **begin, const char **end)
+{
+ s = _skip_space(s);
+
+ *begin = s;
+ while (*s && _field_name_char(*s))
+ s++;
+ *end = s;
+
+ if (*begin == *end)
+ return NULL;
+
+ return s;
+}
+
+static void _display_operators(void)
+{
+ int i;
+
+ log_print(" ");
+ log_print("Comparison operators");
+ log_print("--------------------");
+
+ for (i = 0; _op_cmp[i].string; i++)
+ log_print(" %-4s - %s%s%s", _op_cmp[i].string, _op_cmp[i].desc,
+ _op_cmp[i].flags & DM_REPORT_FIELD_TYPE_NUMBER ?
+ " (numeric field only)" : "",
+ _op_cmp[i].flags & DM_REPORT_FIELD_TYPE_STRING ?
+ " (string field only)" : "");
+
+ log_print(" ");
+ log_print("Comparison operands");
+ log_print("-------------------");
+ log_print(" numbers - decimal, non-negative, integer only");
+ log_print(" strings - characters quoted by ' or \"");
+ log_print(" regular expression - characters quoted by any character");
+
+ log_print(" ");
+ log_print("Combining comparison");
+ log_print("--------------------");
+ log_print(" and, && - logical AND");
+ log_print(" or, || - logical OR");
+ log_print(" () - grouping expressions");
+ log_print(" ! - logical NOT");
+}
+
+/*
+ * Filter components
+ */
+
+/* a comparison condition */
+struct field_filter {
+ struct field_properties *fp;
+ uint32_t flags; /* see _op_cmp[] */
+ union {
+ const char *string;
+ uint64_t number;
+ struct dm_regex *regex;
+ } v;
+};
+
+/* an expression: either comparison condition, and-clause or or-clause */
+struct filter_node {
+ uint32_t type; /* FILTER_* */
+ struct list list;
+ union {
+ struct field_filter * f; /* type is COND */
+ struct list l; /* type is AND or OR */
+ } e;
+};
+
+static struct field_filter *_create_field_filter(struct dm_report *rh,
+ uint32_t field_num,
+ const char *v, size_t len,
+ uint32_t flags)
+{
+ struct field_properties *fp, *found = NULL;
+ struct field_filter *filter;
+ char *s;
+
+ list_iterate_items(fp, &rh->field_props) {
+ if (fp->field_num == field_num) {
+ found = fp;
+ break;
+ }
+ }
+
+ /* The field is neither used in display options nor sort keys. */
+ if (!found) {
+ if (!(found = _add_field(rh, field_num, FLD_HIDDEN)))
+ return NULL;
+ }
+
+ if (!(found->flags & flags & DM_REPORT_FIELD_TYPE_MASK)) {
+ log_error("dm_report: Incompatible comparison type");
+ return NULL;
+ }
+
+ /* set up filter */
+ if (!(filter = dm_pool_zalloc(rh->mem, sizeof(struct field_filter)))) {
+ log_error("dm_report: struct field_filter allocation failed");
+ return NULL;
+ }
+ filter->fp = found;
+ filter->flags = flags;
+
+ /* store comparison operand */
+ if (flags & FLD_CMP_REGEX) {
+ if (!(s = dm_malloc(len + 1))) {
+ log_error("dm_report: dm_malloc failed");
+ goto out_free_filter;
+ }
+ memcpy(s, v, len);
+ s[len] = '\0';
+
+ filter->v.regex = dm_regex_create(rh->mem,
+ (const char **) &s, 1);
+ dm_free(s);
+ if (!filter->v.regex) {
+ log_error("dm_report: failed to create matcher");
+ goto out_free_filter;
+ }
+ } else {
+ if (!(s = dm_pool_alloc(rh->mem, len + 1))) {
+ log_error("dm_report: dm_pool_alloc failed");
+ goto out_free_filter;
+ }
+ memcpy(s, v, len);
+ s[len] = '\0';
+
+ if (flags & DM_REPORT_FIELD_TYPE_STRING) {
+ filter->v.string = s;
+ } else {
+ filter->v.number = strtoul(s, NULL, 0);
+ dm_pool_free(rh->mem, s);
+ }
+ }
+
+ return filter;
+
+ out_free_filter:
+ dm_pool_free(rh->mem, filter);
+ return NULL;
+}
+
+static struct field_filter * _filter_match(struct dm_report *rh,
+ const char *field, size_t flen,
+ const char *value, size_t vlen,
+ uint32_t flags)
+{
+ uint32_t f;
+
+ if (!flen)
+ return NULL;
+
+ for (f = 0; rh->fields[f].report_fn; f++)
+ if (_is_same_field(rh->fields[f].id,
+ field, flen, rh->field_prefix))
+ return _create_field_filter(rh, f, value, vlen, flags);
+
+ log_print("Undefined field name");
+ return NULL;
+}
+
+static struct filter_node * _alloc_filter_node(struct dm_pool *mem,
+ uint32_t type)
+{
+ struct filter_node *n;
+
+ if (!(n = dm_pool_zalloc(mem, sizeof(struct filter_node)))) {
+ log_error("dm_report: struct filter_node allocation failed");
+ return NULL;
+ }
+
+ list_init(&n->list);
+
+ n->type = type;
+ if (!(type & FILTER_COND))
+ list_init(&n->e.l);
+ return n;
+}
+
+/*
+ * Filter parser
+ *
+ * _parse_* functions
+ *
+ * Input:
+ * s - a pointer to the parsed string
+ * Output:
+ * next - a pointer used for next _parse_*'s input,
+ * next == s if return value is NULL
+ * return value - a filter node pointer,
+ * NULL if s doesn't match
+ */
+
+/*
+ * CONDITION := FIELD_NAME OP_CMP STRING |
+ * FIELD_NAME OP_CMP NUMBER |
+ * FIELD_NAME OP_REGEX REGEX
+ */
+static struct filter_node * _parse_condition(struct dm_report *rh,
+ const char *s, const char **next)
+{
+ struct field_filter *f;
+ struct filter_node *n;
+ const char *ws, *we; /* field name */
+ const char *vs, *ve; /* value */
+ const char *last;
+ uint32_t flags;
+ char quote;
+
+ /* field name */
+ if (!(last = _tok_field_name(s, &ws, &we))) {
+ log_error("Expecting field name");
+ goto syntax_error;
+ }
+ if (!last) {
+ log_error("Missing operator after the field name");
+ goto syntax_error;
+ }
+
+ /* comparison operator */
+ if (!(flags = _tok_op_cmp(we, &last))) {
+ log_error("Unrecognized comparison operator: %s", s);
+ goto syntax_error;
+ }
+ if (!last) {
+ log_error("Missing value after operator");
+ goto syntax_error;
+ }
+
+ /* comparison value */
+ if (flags & FLD_CMP_REGEX) {
+ if (!(last = _tok_regex(last, &vs, &ve, "e)))
+ goto syntax_error;
+ } else {
+ if (!(last = _tok_value(last, &vs, &ve, "e)))
+ goto syntax_error;
+
+ if (quote) {
+ /* the token is strings */
+ if (flags & DM_REPORT_FIELD_TYPE_NUMBER) {
+ log_print("The operator requires number");
+ goto syntax_error;
+ }
+ flags |= DM_REPORT_FIELD_TYPE_STRING;
+ } else {
+ /* the token is number */
+ if (flags & DM_REPORT_FIELD_TYPE_STRING) {
+ log_print("The operator requires string");
+ goto syntax_error;
+ }
+ flags |= DM_REPORT_FIELD_TYPE_NUMBER;
+ }
+ }
+ *next = _skip_space(last);
+
+ /* store condition */
+ f = _filter_match(rh, ws, (size_t) (we - ws),
+ vs, (size_t) (ve - vs), flags);
+ if (!f)
+ goto syntax_error;
+
+ if (!(n = _alloc_filter_node(rh->mem, FILTER_COND)))
+ return NULL;
+ n->e.f = f;
+ return n;
+
+ syntax_error:
+ log_error("Filter syntax error at %s", s);
+ *next = s;
+ return NULL;
+}
+
+/* EX := CONDITION | '!'? '(' EXPRESSION ')' */
+static struct filter_node * _parse_or_ex(struct dm_report *,
+ const char *, const char **,
+ struct filter_node *);
+
+static struct filter_node * _parse_ex(struct dm_report *rh,
+ const char *s, const char **next)
+{
+ struct filter_node *n = NULL;
+ uint32_t t;
+ const char *tmp;
+
+ t = _tok_op_log(s, next, FILTER_NOT|FILTER_PS);
+ if (t == FILTER_NOT) {
+ /* '!' '(' EXPRESSION ')' */
+ if (!_tok_op_log(*next, &tmp, FILTER_PS)) {
+ log_error("Syntax error: '(' expected");
+ goto out_error;
+ }
+ if (!(n = _parse_or_ex(rh, tmp, next, NULL)))
+ goto out_error;
+ n->type |= FILTER_NOT;
+ if (!_tok_op_log(*next, &tmp, FILTER_PE)) {
+ log_error("Syntax error: ')' expected");
+ goto out_error;
+ }
+ *next = tmp;
+ } else if (t == FILTER_PS) {
+ /* '(' EXPRESSION ')' */
+ if (!(n = _parse_or_ex(rh, *next, &tmp, NULL)))
+ goto out_error;
+ if (!_tok_op_log(tmp, next, FILTER_PE)) {
+ log_error("Syntax error: ')' expected");
+ goto out_error;
+ }
+ } else if ((s = _skip_space(s))) {
+ /* CONDITION */
+ n = _parse_condition(rh, s, next);
+ } else {
+ n = NULL;
+ *next = s;
+ }
+
+ return n;
+
+ out_error:
+ *next = s;
+ return NULL;
+}
+
+/* AND_EXPRESSION := EX (AND_OP AND_EXPRSSION) */
+static struct filter_node * _parse_and_ex(struct dm_report *rh,
+ const char *s, const char **next,
+ struct filter_node *and_n)
+{
+ struct filter_node *n;
+ const char *tmp;
+
+ n = _parse_ex(rh, s, next);
+ if (!n)
+ goto out_error;
+
+ if (!_tok_op_log(*next, &tmp, FILTER_AND)) {
+ if (!and_n)
+ return n;
+ list_add(&and_n->e.l, &n->list);
+ return and_n;
+ }
+
+ if (!and_n) {
+ if (!(and_n = _alloc_filter_node(rh->mem, FILTER_AND)))
+ goto out_error;
+ }
+ list_add(&and_n->e.l, &n->list);
+
+ return _parse_and_ex(rh, tmp, next, and_n);
+
+ out_error:
+ *next = s;
+ return NULL;
+}
+
+/* OR_EXPRESSION := AND_EXPRESSION (OR_OP OR_EXPRESSION) */
+static struct filter_node * _parse_or_ex(struct dm_report *rh,
+ const char *s, const char **next,
+ struct filter_node *or_n)
+{
+ struct filter_node *n;
+ const char *tmp;
+
+ n = _parse_and_ex(rh, s, next, NULL);
+ if (!n)
+ goto out_error;
+
+ if (!_tok_op_log(*next, &tmp, FILTER_OR)) {
+ if (!or_n)
+ return n;
+ list_add(&or_n->e.l, &n->list);
+ return or_n;
+ }
+
+ if (!or_n) {
+ if (!(or_n = _alloc_filter_node(rh->mem, FILTER_OR)))
+ goto out_error;
+ }
+ list_add(&or_n->e.l, &n->list);
+
+ return _parse_or_ex(rh, tmp, next, or_n);
+
+ out_error:
+ *next = s;
+ return NULL;
+}
+
+
+int dm_report_set_filter(struct dm_report *rh, const char *string,
+ uint32_t flags)
+{
+ const char *fin;
+ struct filter_node *root;
+
+ if (flags) {
+ log_error("dm_report_set_filter: flags not supported");
+ return 0;
+ }
+
+ if (rh->filter_root) {
+ log_error("dm_report_set_filter: filter already set");
+ return 0;
+ }
+
+ /* null string means no filter */
+ if (!string || !string[0])
+ return 1;
+
+ if (!(root = _alloc_filter_node(rh->mem, FILTER_OR)))
+ goto out_error;
+
+ if (!_parse_or_ex(rh, string, &fin, root) || *_skip_space(fin)) {
+ dm_pool_free(rh->mem, root);
+ goto out_error;
+ }
+
+ rh->filter_root = root;
+ return 1;
+
+ out_error:
+ _display_operators();
+ log_print(" ");
+ _display_fields(rh);
+ log_print(" ");
+ return 0;
+}
+
struct dm_report *dm_report_init(uint32_t *report_types,
const struct dm_report_object_type *types,
const struct dm_report_field_type *fields,
@@ -551,6 +1203,65 @@ void dm_report_free(struct dm_report *rh
/*
* Create a row of data for an object
*/
+static int _cmp_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;
+ default:
+ log_error("Unsupported comparison type for number");
+ }
+ return 0;
+}
+
+static int _cmp_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);
+ default:
+ log_error("Unsupported comparison type for string");
+ }
+ return 0;
+}
+
+static int _cmp_field_regex(const char *s, struct dm_regex *r, uint32_t flags)
+{
+ return (dm_regex_match(r, s) >= 0) ^ ((flags & FLD_CMP_NOT) != 0);
+}
+
+static int _compare_field(struct dm_report_field *field,
+ struct field_filter *filter)
+{
+ if (!field->sort_value) {
+ log_error("dm_report: field without value: %d",
+ field->props->field_num);
+ return 0;
+ }
+
+ if (filter->flags & FLD_CMP_REGEX)
+ return _cmp_field_regex((const char *) field->sort_value,
+ filter->v.regex, filter->flags);
+ else if (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER)
+ return _cmp_field_number(*(const uint64_t *)field->sort_value,
+ filter->v.number, filter->flags);
+ else /* DM_REPORT_FIELD_TYPE_STRING */
+ return _cmp_field_string((const char *) field->sort_value,
+ filter->v.string, filter->flags);
+}
+
static void * _report_get_field_data(struct dm_report *rh,
struct field_properties *fp, void *object)
{
@@ -562,6 +1273,51 @@ static void * _report_get_field_data(str
return ret + rh->fields[fp->field_num].offset;
}
+static int _filter(struct filter_node *n, struct list *fields)
+{
+ int r;
+ struct filter_node *f;
+ struct dm_report_field *field;
+
+ switch (n->type & FILTER_TYPE_MASK) {
+ case FILTER_COND:
+ r = 1;
+ list_iterate_items(field, fields) {
+ if (n->e.f->fp != field->props)
+ continue;
+ if (!_compare_field(field, n->e.f))
+ r = 0;
+ }
+ break;
+ case FILTER_OR:
+ r = 0;
+ list_iterate_items(f, &n->e.l)
+ if ((r |= _filter(f, fields)))
+ break;
+ break;
+ case FILTER_AND:
+ r = 1;
+ list_iterate_items(f, &n->e.l)
+ if (!(r &= _filter(f, fields)))
+ break;
+ break;
+ default:
+ log_error("Unsupported filter type");
+ return 0;
+ }
+
+ return (n->type & FILTER_NOT) ? !r : r;
+}
+
+/* the object is given as a list of "struct field"s */
+static int _filter_object(struct dm_report *rh, struct list *fields)
+{
+ if (!rh->filter_root)
+ return 1;
+
+ return _filter(rh->filter_root, fields);
+}
+
int dm_report_object(struct dm_report *rh, void *object)
{
struct field_properties *fp;
@@ -582,24 +1338,23 @@ int dm_report_object(struct dm_report *r
rh->keys_count))) {
log_error("dm_report_object: "
"row sort value structure allocation failed");
- return 0;
+ goto out_free_row;
}
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;
+ goto out_free_row;
}
field->props = fp;
data = _report_get_field_data(rh, fp, object);
if (!data)
- return 0;
+ goto out_free_row;
if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
field, data,
@@ -607,9 +1362,20 @@ int dm_report_object(struct dm_report *r
log_error("dm_report_object: "
"report function failed for field %s",
rh->fields[fp->field_num].id);
- return 0;
+ goto out_free_row;
}
+ list_add(&row->fields, &field->list);
+ }
+
+ /* Check filter and decide whether to display or not */
+ if (!_filter_object(rh, &row->fields))
+ goto out_free_row;
+
+ list_add(&rh->rows, &row->list);
+
+ /* For the object to be displayed, udpate width and record sort value */
+ list_iterate_items(field, &row->fields) {
if ((strlen(field->report_string) > field->props->width))
field->props->width = strlen(field->report_string);
@@ -617,13 +1383,16 @@ int dm_report_object(struct dm_report *r
(field->props->flags & FLD_SORT_KEY)) {
(*row->sort_fields)[field->props->sort_posn] = field;
}
- list_add(&row->fields, &field->list);
}
if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
return dm_report_output(rh);
return 1;
+
+ out_free_row:
+ dm_pool_free(rh->mem, row);
+ return 0;
}
/*
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH] libdevmapper: (5/6) Add '--filter' option to dmsetup
2007-04-18 16:41 [PATCH] libdevmapper: (0/6) Filtering feature in dm_report Jun'ichi Nomura
` (3 preceding siblings ...)
2007-04-18 16:47 ` [PATCH] libdevmapper: (4/6) Add filtering feature to dm_report Jun'ichi Nomura
@ 2007-04-18 16:47 ` Jun'ichi Nomura
2007-04-18 16:47 ` [PATCH] libdevmapper: (6/6) Add deps and treenode fields for dmsetup info -c Jun'ichi Nomura
2007-04-18 19:23 ` [PATCH] libdevmapper: (7/6) Add dm_report_get_report_types() Jun'ichi Nomura
6 siblings, 0 replies; 10+ messages in thread
From: Jun'ichi Nomura @ 2007-04-18 16:47 UTC (permalink / raw)
To: device-mapper development, Alasdair Kergon
[-- Attachment #1: Type: text/plain, Size: 163 bytes --]
Hi,
This patch adds '--filter' option to dmsetup, so that it can
use the filtering feature of dm_report.
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: dmsetup-info-add-filter-option.patch --]
[-- Type: text/x-patch, Size: 2289 bytes --]
Add --filter (-F) option to dmsetup for filtering report output.
---
dmsetup/dmsetup.c | 15 ++++++++++++++-
man/dmsetup.8 | 2 +-
2 files changed, 15 insertions(+), 2 deletions(-)
Index: device-mapper.work/dmsetup/dmsetup.c
===================================================================
--- device-mapper.work.orig/dmsetup/dmsetup.c
+++ device-mapper.work/dmsetup/dmsetup.c
@@ -104,6 +104,7 @@ enum {
COLS_ARG,
EXEC_ARG,
FORCE_ARG,
+ FILTER_ARG,
GID_ARG,
MAJOR_ARG,
MINOR_ARG,
@@ -1650,6 +1651,13 @@ static int _report_init(struct command *
options, separator, flags, keys, NULL)))
goto out;
+ if (_string_args[FILTER_ARG] &&
+ !dm_report_set_filter(_report, _string_args[FILTER_ARG], 0)) {
+ dm_report_free(_report);
+ _report = NULL;
+ goto out;
+ }
+
r = 1;
out:
@@ -2059,6 +2067,7 @@ static int _process_switches(int *argc,
{"columns", 0, &ind, COLS_ARG},
{"exec", 1, &ind, EXEC_ARG},
{"force", 0, &ind, FORCE_ARG},
+ {"filter", 1, &ind, FILTER_ARG},
{"gid", 1, &ind, GID_ARG},
{"major", 1, &ind, MAJOR_ARG},
{"minor", 1, &ind, MINOR_ARG},
@@ -2133,7 +2142,7 @@ static int _process_switches(int *argc,
optarg = 0;
optind = OPTIND_INIT;
- while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfGj:m:Mno:O:ru:Uv",
+ while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfF:Gj:m:Mno:O:ru:Uv",
long_options, NULL)) != -1) {
if (c == ':' || c == '?')
return 0;
@@ -2141,6 +2150,10 @@ static int _process_switches(int *argc,
_switches[COLS_ARG]++;
if (c == 'f' || ind == FORCE_ARG)
_switches[FORCE_ARG]++;
+ if (c == 'F' || ind == FILTER_ARG) {
+ _switches[FILTER_ARG]++;
+ _string_args[FILTER_ARG] = optarg;
+ }
if (c == 'r' || ind == READ_ONLY)
_switches[READ_ONLY]++;
if (c == 'j' || ind == MAJOR_ARG) {
Index: device-mapper.work/man/dmsetup.8
===================================================================
--- device-mapper.work.orig/man/dmsetup.8
+++ device-mapper.work/man/dmsetup.8
@@ -44,7 +44,7 @@ dmsetup \- low level logical volume mana
.br
.B dmsetup info -c|-C|--columns
.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
-.I [device_name]
+.I [--filter expression] [device_name]
.br
.B dmsetup deps
.I [device_name]
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH] libdevmapper: (6/6) Add deps and treenode fields for dmsetup info -c
2007-04-18 16:41 [PATCH] libdevmapper: (0/6) Filtering feature in dm_report Jun'ichi Nomura
` (4 preceding siblings ...)
2007-04-18 16:47 ` [PATCH] libdevmapper: (5/6) Add '--filter' option to dmsetup Jun'ichi Nomura
@ 2007-04-18 16:47 ` Jun'ichi Nomura
2007-04-18 19:23 ` [PATCH] libdevmapper: (7/6) Add dm_report_get_report_types() Jun'ichi Nomura
6 siblings, 0 replies; 10+ messages in thread
From: Jun'ichi Nomura @ 2007-04-18 16:47 UTC (permalink / raw)
To: device-mapper development, Alasdair Kergon
[-- Attachment #1: Type: text/plain, Size: 359 bytes --]
Hi,
This patch adds optional fields to 'dmsetup info -c'.
You can specify the following fields with '-o', '-O' and filtering option.
- deps
- deps_count
- parents
- parents_count
For example, you can find the top-level dm devices by:
# dmsetup info -c -o name --filter 'parents_count == 0'
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: dmsetup-info-add-deps-columns.patch --]
[-- Type: text/x-patch, Size: 10148 bytes --]
Add fields of deps and treenode to dmsetup
---
dmsetup/dmsetup.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 276 insertions(+), 7 deletions(-)
Index: device-mapper.work/dmsetup/dmsetup.c
===================================================================
--- device-mapper.work.orig/dmsetup/dmsetup.c
+++ device-mapper.work/dmsetup/dmsetup.c
@@ -241,11 +241,14 @@ static int _parse_file(struct dm_task *d
struct dmsetup_report_obj {
struct dm_task *task;
struct dm_info *info;
+ struct dm_task *deps;
+ struct dm_tree_node *tree;
};
static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
{
struct dmsetup_report_obj obj;
+ int r = 0;
if (!info->exists) {
fprintf(stderr, "Device does not exist.\n");
@@ -254,11 +257,18 @@ static int _display_info_cols(struct dm_
obj.task = dmt;
obj.info = info;
+ obj.deps = NULL; /* task is created later on demand */
+ obj.tree = NULL; /* deptree is created later on demand */
if (!dm_report_object(_report, &obj))
- return 0;
+ goto out;
- return 1;
+ r = 1;
+
+ out:
+ if (obj.deps)
+ dm_task_destroy(obj.deps);
+ return r;
}
static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
@@ -1457,17 +1467,26 @@ static int _add_dep(int argc __attribute
/*
* Create and walk dependency tree
*/
-static int _tree(int argc, char **argv, void *data __attribute((unused)))
+static int _build_whole_deptree(void)
{
+ if (_dtree)
+ return 1;
+
if (!(_dtree = dm_tree_create()))
return 0;
- if (!_process_all(argc, argv, 0, _add_dep))
+ if (!_process_all(0, NULL, 0, _add_dep))
return 0;
- _tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
+ return 1;
+}
+
+static int _tree(int argc, char **argv, void *data __attribute((unused)))
+{
+ if (!_build_whole_deptree())
+ return 0;
- dm_tree_free(_dtree);
+ _tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
return 1;
}
@@ -1539,8 +1558,193 @@ static int _dm_info_status_disp(struct d
return dm_report_field_string(rh, 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,
+ void *private)
+{
+ char buf[MAJ_MIN_LEN], *repstr;
+ struct dm_info *info = (struct dm_info *) data;
+
+ if (!dm_pool_begin_object(mem, 8)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ if (dm_snprintf(buf, sizeof(buf), "%d:%d",
+ info->major, info->minor) < 0) {
+ log_error("dm_pool_alloc failed");
+ goto out_abandon;
+ }
+
+ if (!dm_pool_grow_object(mem, buf, strlen(buf))) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+
+ repstr = dm_pool_end_object(mem);
+ dm_report_field_set_value(field, repstr, repstr);
+ return 1;
+
+ out_abandon:
+ dm_pool_abandon_object(mem);
+ return 0;
+}
+
+static int _dm_tree_parent_maps_disp(struct dm_report *rh,
+ struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data, void *private)
+{
+ 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, 16)) {
+ 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);
+ dm_report_field_set_value(field, repstr, 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, void *private)
+{
+ 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, 16)) {
+ 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, sizeof(buf), "%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);
+ dm_report_field_set_value(field, repstr, repstr);
+ return 1;
+
+ 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, void *private)
+{
+ 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, field, &num_parent);
+}
+
+static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data,
+ void *private)
+{
+ struct dm_deps *deps = (struct dm_deps *) data;
+ int i;
+ char buf[MAJ_MIN_LEN], *repstr;
+
+ if (!dm_pool_begin_object(mem, 16)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ for (i = 0; i < deps->count; i++) {
+ if (dm_snprintf(buf, sizeof(buf), "%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);
+ dm_report_field_set_value(field, repstr, repstr);
+ return 1;
+
+ out_abandon:
+ dm_pool_abandon_object(mem);
+ return 0;
+}
+
/* Report types */
-enum { DR_TASK = 1, DR_INFO = 2 };
+enum { DR_TASK = 1, DR_INFO = 2, DR_DEPS = 4, DR_TREE = 8 };
static void *_task_get_obj(void *obj)
{
@@ -1552,9 +1756,65 @@ static void *_info_get_obj(void *obj)
return ((struct dmsetup_report_obj *)obj)->info;
}
+static void *_tree_get_obj(void *obj)
+{
+ struct dmsetup_report_obj *o = (struct dmsetup_report_obj *) obj;
+ struct dm_info *info;
+
+ if (o->tree)
+ return o->tree;
+
+ if (!_build_whole_deptree())
+ return NULL;
+
+ if (!(info = _info_get_obj(o)))
+ return NULL;
+
+ o->tree = dm_tree_find_node(_dtree, info->major, info->minor);
+ return o->tree;
+}
+
+static void *_deps_get_obj(void *obj)
+{
+ struct dmsetup_report_obj *o = (struct dmsetup_report_obj *) obj;
+ struct dm_task *dmt;
+ const char *name;
+
+ if (o->deps)
+ return dm_task_get_deps(o->deps);
+
+ /* name */
+ if (!(dmt = _task_get_obj(o)))
+ return NULL;
+ if (!(name = dm_task_get_name(dmt)))
+ return NULL;
+
+ /* deps */
+ if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
+ return NULL;
+
+ if (!dm_task_set_name(dmt, name))
+ goto out;
+
+ if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
+ goto out;
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ o->deps = dmt;
+ return dm_task_get_deps(dmt);
+
+ out:
+ dm_task_destroy(dmt);
+ return NULL;
+}
+
static const struct dm_report_object_type _report_types[] = {
{ DR_TASK, "Mapped Device Name", "", _task_get_obj },
{ DR_INFO, "Mapped Device Information", "", _info_get_obj },
+ { DR_DEPS, "Mapped Device Dependency", "", _deps_get_obj },
+ { DR_TREE, "Mapped Device Dependency", "", _tree_get_obj },
{ 0, "", "", NULL },
};
@@ -1570,11 +1830,17 @@ static const struct dm_report_field_type
FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
+FIELD_F(INFO, STR, "Device", 6, dm_info_device, "device", "Device major and minor numbers")
FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")
FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")
FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")
FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")
FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
+FIELD_O(DEPS, dm_deps, NUM, "Deps", count, 4, int32, "deps_count", "Number of underlying devices")
+FIELD_F(DEPS, STR, "Depend on", 10, dm_deps, "deps", "List of underlying devic es")
+FIELD_F(TREE, STR, "Parent Devices", 16, dm_tree_parents, "parents", "List of overlaying devices")
+FIELD_F(TREE, STR, "Parent Maps", 12, dm_tree_parent_maps, "parent_maps", "List of overlaying maps")
+FIELD_F(TREE, NUM, "Parents", 7, dm_tree_parents_count, "parents_count", "Number of overlaying devices")
{0, 0, 0, 0, "", "", NULL, NULL},
/* *INDENT-ON* */
};
@@ -2300,5 +2566,8 @@ out:
dm_report_free(_report);
}
+ if (_dtree)
+ dm_tree_free(_dtree);
+
return r;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH] libdevmapper: (7/6) Add dm_report_get_report_types()
2007-04-18 16:41 [PATCH] libdevmapper: (0/6) Filtering feature in dm_report Jun'ichi Nomura
` (5 preceding siblings ...)
2007-04-18 16:47 ` [PATCH] libdevmapper: (6/6) Add deps and treenode fields for dmsetup info -c Jun'ichi Nomura
@ 2007-04-18 19:23 ` Jun'ichi Nomura
6 siblings, 0 replies; 10+ messages in thread
From: Jun'ichi Nomura @ 2007-04-18 19:23 UTC (permalink / raw)
To: device-mapper development, Alasdair Kergon
[-- Attachment #1: Type: text/plain, Size: 211 bytes --]
Hi,
This patch was missing from the last post...
Since rh->report_types can be updated after dm_report_init(),
we need an interface to obtain it later.
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: libdm-report-get-types.patch --]
[-- Type: text/x-patch, Size: 2075 bytes --]
Add dm_report_get_report_types() to obtain updated report_types field
after dm_report_set_filter() call.
---
dmsetup/dmsetup.c | 1 +
lib/.exported_symbols | 1 +
lib/libdevmapper.h | 1 +
lib/libdm-report.c | 5 +++++
4 files changed, 8 insertions(+)
Index: device-mapper.work/lib/.exported_symbols
===================================================================
--- device-mapper.work.orig/lib/.exported_symbols
+++ device-mapper.work/lib/.exported_symbols
@@ -128,5 +128,6 @@ dm_report_field_uint32
dm_report_field_uint64
dm_report_field_set_value
dm_report_set_filter
+dm_report_get_report_types
dm_regex_create
dm_regex_match
Index: device-mapper.work/lib/libdm-report.c
===================================================================
--- device-mapper.work.orig/lib/libdm-report.c
+++ device-mapper.work/lib/libdm-report.c
@@ -88,6 +88,11 @@ struct row {
struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
};
+uint32_t dm_report_get_report_types(struct dm_report *rh)
+{
+ return rh->report_types;
+}
+
static const struct dm_report_object_type *_find_type(struct dm_report *rh,
uint32_t report_type)
{
Index: device-mapper.work/lib/libdevmapper.h
===================================================================
--- device-mapper.work.orig/lib/libdevmapper.h
+++ device-mapper.work/lib/libdevmapper.h
@@ -687,6 +687,7 @@ struct dm_report *dm_report_init(uint32_
int dm_report_object(struct dm_report *rh, void *object);
int dm_report_output(struct dm_report *rh);
void dm_report_free(struct dm_report *rh);
+uint32_t dm_report_get_report_types(struct dm_report *rh);
/* Set filter */
int dm_report_set_filter(struct dm_report *rh,
Index: device-mapper.work/dmsetup/dmsetup.c
===================================================================
--- device-mapper.work.orig/dmsetup/dmsetup.c
+++ device-mapper.work/dmsetup/dmsetup.c
@@ -1924,6 +1924,7 @@ static int _report_init(struct command *
goto out;
}
+ report_type = dm_report_get_report_types(_report);
r = 1;
out:
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread