mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-10 05:18:36 +03:00
o Filter for the dev cache that takes values from config file:
devices { # first match is final, eg. /dev/ide/cdrom # get's rejected due to the first pattern filter=["r/cdrom/", # don't touch the music ! "a/hd[a-d][0-9]+/", "a/ide/", "a/sd/", "a/md/", "a|loop/[0-9]+|", # accept devfs style loop back "r/loop/", # and reject old style "a/dasd/", "a/dac960/", "a/nbd/", "a/ida/", "a/cciss/", "a/ubd/", "r/.*/"] # reject all others } Alasdair this is ready to roll into the tools now.
This commit is contained in:
parent
5370eeecea
commit
4ab20322fe
2
configure
vendored
2
configure
vendored
@ -2163,6 +2163,7 @@ test/mm/Makefile \
|
||||
test/device/Makefile \
|
||||
test/format1/Makefile \
|
||||
test/regex/Makefile \
|
||||
test/filters/Makefile \
|
||||
" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
|
||||
EOF
|
||||
cat >> $CONFIG_STATUS <<EOF
|
||||
@ -2262,6 +2263,7 @@ test/mm/Makefile \
|
||||
test/device/Makefile \
|
||||
test/format1/Makefile \
|
||||
test/regex/Makefile \
|
||||
test/filters/Makefile \
|
||||
"}
|
||||
EOF
|
||||
cat >> $CONFIG_STATUS <<\EOF
|
||||
|
@ -139,4 +139,5 @@ test/mm/Makefile \
|
||||
test/device/Makefile \
|
||||
test/format1/Makefile \
|
||||
test/regex/Makefile \
|
||||
test/filters/Makefile \
|
||||
)
|
||||
|
@ -8,6 +8,7 @@
|
||||
../lib/device/device.h
|
||||
../lib/display/display.h
|
||||
../lib/filters/filter.h
|
||||
../lib/filters/filter-regex.h
|
||||
../lib/format1/format1.h
|
||||
../lib/log/log.h
|
||||
../lib/metadata/metadata.h
|
||||
|
@ -17,6 +17,7 @@ SOURCES=\
|
||||
device/dev-io.c \
|
||||
device/device.c \
|
||||
filters/filter.c \
|
||||
filters/filter-regex.c \
|
||||
format1/disk-rep.c \
|
||||
format1/format1.c \
|
||||
format1/import-export.c \
|
||||
|
@ -123,7 +123,7 @@ static int _insert(const char *path, int recurse)
|
||||
struct stat info;
|
||||
struct device *dev;
|
||||
|
||||
log_very_verbose("dev-cache adding %s", path);
|
||||
//log_very_verbose("dev-cache adding %s", path);
|
||||
|
||||
if (stat(path, &info) < 0) {
|
||||
log_sys_very_verbose("stat", path);
|
||||
@ -138,7 +138,7 @@ static int _insert(const char *path, int recurse)
|
||||
}
|
||||
|
||||
if (S_ISLNK(info.st_mode)) {
|
||||
log_debug("%s is a symbolic link, following", path);
|
||||
//log_debug("%s is a symbolic link, following", path);
|
||||
if (!(path = _follow_link(path, &info))) {
|
||||
stack;
|
||||
return 0;
|
||||
@ -146,7 +146,7 @@ static int _insert(const char *path, int recurse)
|
||||
}
|
||||
|
||||
if (!S_ISBLK(info.st_mode)) {
|
||||
log_debug("%s is not a block device", path);
|
||||
//log_debug("%s is not a block device", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
struct dev_filter {
|
||||
int (*passes_filter)(struct dev_filter *f, struct device *dev);
|
||||
void (*destroy)(struct dev_filter *f);
|
||||
void *private;
|
||||
};
|
||||
|
||||
|
207
lib/filters/filter-regex.c
Normal file
207
lib/filters/filter-regex.c
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#include "pool.h"
|
||||
#include "filter-regex.h"
|
||||
#include "matcher.h"
|
||||
#include "device.h"
|
||||
#include "bitset.h"
|
||||
#include "log.h"
|
||||
|
||||
struct rfilter {
|
||||
struct pool *mem;
|
||||
bitset_t accept;
|
||||
struct matcher *engine;
|
||||
};
|
||||
|
||||
int _extract_pattern(struct pool *mem, const char *pat,
|
||||
char **regex, bitset_t accept, int index)
|
||||
{
|
||||
char sep, *r, *ptr;
|
||||
|
||||
/*
|
||||
* is this an accept or reject pattern
|
||||
*/
|
||||
switch (*pat) {
|
||||
case 'a':
|
||||
bit_set(accept, index);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
bit_clear(accept, index);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_info("pattern must begin with 'a' or 'r'");
|
||||
return 0;
|
||||
}
|
||||
pat++;
|
||||
|
||||
/*
|
||||
* get the seperator
|
||||
*/
|
||||
switch (*pat) {
|
||||
case '(':
|
||||
sep = ')';
|
||||
break;
|
||||
|
||||
case '[':
|
||||
sep = ']';
|
||||
break;
|
||||
|
||||
case '{':
|
||||
sep = '}';
|
||||
break;
|
||||
|
||||
default:
|
||||
sep = *pat;
|
||||
}
|
||||
pat++;
|
||||
|
||||
/*
|
||||
* copy the regex
|
||||
*/
|
||||
if (!(r = pool_strdup(mem, pat))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* trim the trailing character, having checked it's sep.
|
||||
*/
|
||||
ptr = r + strlen(r) - 1;
|
||||
if (*ptr != sep) {
|
||||
log_info("invalid seperator at end of regex");
|
||||
return 0;
|
||||
}
|
||||
*ptr = '\0';
|
||||
|
||||
regex[index] = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
{
|
||||
struct pool *scratch;
|
||||
struct config_value *v;
|
||||
char **regex;
|
||||
int count = 0, i, r = 0;
|
||||
|
||||
if (!(scratch = pool_create(1024))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* count how many patterns we have.
|
||||
*/
|
||||
for (v = val; v; v = v->next) {
|
||||
|
||||
if (v->type != CFG_STRING) {
|
||||
log_info("filter patterns must be enclosed in quotes");
|
||||
goto out;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate space for them
|
||||
*/
|
||||
if (!(regex = pool_alloc(scratch, sizeof(*regex) * count))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* create the accept/reject bitset
|
||||
*/
|
||||
rf->accept = bitset_create(rf->mem, count);
|
||||
|
||||
/*
|
||||
* fill the array back to front because we
|
||||
* want the opposite precedence to what
|
||||
* the matcher gives.
|
||||
*/
|
||||
for (v = val, i = count - 1; v; v = v->next, i--)
|
||||
if (!_extract_pattern(scratch, v->v.str,
|
||||
regex, rf->accept, i)) {
|
||||
log_info("invalid filter pattern");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* build the matcher.
|
||||
*/
|
||||
if (!(rf->engine = matcher_create(rf->mem,
|
||||
(const char **) regex, count)))
|
||||
stack;
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
pool_destroy(scratch);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _accept_p(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
int m;
|
||||
struct rfilter *rf = (struct rfilter *) f->private;
|
||||
|
||||
m = matcher_run(rf->engine, dev->name);
|
||||
|
||||
/*
|
||||
* pass everything that doesn't match,
|
||||
* otherwise look it up in the accepts
|
||||
* bitset.
|
||||
*/
|
||||
return (m < 0) ? 1 : bit(rf->accept, m);
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
struct rfilter *rf = (struct rfilter *) f->private;
|
||||
pool_destroy(rf->mem);
|
||||
}
|
||||
|
||||
struct dev_filter *regex_filter_create(struct config_value *patterns)
|
||||
{
|
||||
struct pool *mem = pool_create(256);
|
||||
struct rfilter *rf;
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!mem) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(rf = pool_alloc(mem, sizeof(*rf)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
rf->mem = mem;
|
||||
|
||||
if (!_build_matcher(rf, patterns)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
f->passes_filter = _accept_p;
|
||||
f->destroy = _destroy;
|
||||
f->private = rf;
|
||||
return f;
|
||||
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
23
lib/filters/filter-regex.h
Normal file
23
lib/filters/filter-regex.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_FILTER_REGEX_H
|
||||
#define _LVM_FILTER_REGEX_H
|
||||
|
||||
#include "config.h"
|
||||
#include "dev-cache.h"
|
||||
|
||||
/*
|
||||
* patterns must be an array of strings of the form:
|
||||
* [ra]<sep><regex><sep>, eg,
|
||||
* r/cdrom/ - reject cdroms
|
||||
* a|loop/[0-4]| - accept loops 0 to 4
|
||||
* r|.*| - reject everything else
|
||||
*/
|
||||
|
||||
struct dev_filter *regex_filter_create(struct config_value *patterns);
|
||||
|
||||
#endif
|
@ -206,11 +206,11 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
|
||||
/* create first state */
|
||||
dfa = _create_dfa_state(m->mem);
|
||||
m->start = dfa;
|
||||
ttree_insert(tt, rx->firstpos, dfa);
|
||||
ttree_insert(tt, rx->firstpos + 1, dfa);
|
||||
|
||||
/* prime the queue */
|
||||
h = t = _create_state_queue(m->scratch, dfa, rx->firstpos);
|
||||
while(h) {
|
||||
while (h) {
|
||||
/* pop state off front of the queue */
|
||||
dfa = h->s;
|
||||
dfa_bits = h->bits;
|
||||
@ -256,7 +256,7 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("Lexer built with %d dfa states", count);
|
||||
log_debug("Matcher built with %d dfa states", count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -330,20 +330,20 @@ struct matcher *matcher_create(struct pool *mem,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int matcher_run(struct matcher *m, const char *b, const char *e)
|
||||
int matcher_run(struct matcher *m, const char *b)
|
||||
{
|
||||
struct dfa_state *cs = m->start;
|
||||
int r = -1;
|
||||
int r = 0;
|
||||
|
||||
for (; b != e; b++) {
|
||||
for (; *b; b++) {
|
||||
|
||||
if (!(cs = cs->lookup[(int) (unsigned char) *b]))
|
||||
break;
|
||||
|
||||
if (cs->final)
|
||||
if (cs->final && (!r || cs->final > r))
|
||||
r = cs->final;
|
||||
}
|
||||
|
||||
/* subtract 1 to get back to zero index */
|
||||
return (r < 0) ? r : (r - 1);
|
||||
return r - 1;
|
||||
}
|
||||
|
@ -13,6 +13,6 @@ struct matcher;
|
||||
struct matcher *matcher_create(struct pool *mem,
|
||||
const char **patterns, int num);
|
||||
|
||||
int matcher_run(struct matcher *m, const char *begin, const char *end);
|
||||
int matcher_run(struct matcher *m, const char *begin);
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,83 @@ struct ttree {
|
||||
struct node *root;
|
||||
};
|
||||
|
||||
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;
|
||||
unsigned int k;
|
||||
|
||||
while (*c && count) {
|
||||
k = *key++;
|
||||
count--;
|
||||
|
||||
c = _lookup_single(c, k);
|
||||
}
|
||||
|
||||
return *c ? (*c)->data : NULL;
|
||||
}
|
||||
|
||||
static struct node *_create_node(struct pool *mem, unsigned int k)
|
||||
{
|
||||
struct node *n = 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;
|
||||
|
||||
while (*c && count) {
|
||||
k = *key++;
|
||||
count--;
|
||||
|
||||
c = _lookup_single(c, k);
|
||||
}
|
||||
|
||||
if (!*c) {
|
||||
count++;
|
||||
|
||||
while (count--) {
|
||||
if (!(*c = _create_node(tt->mem, k))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
k = *key++;
|
||||
|
||||
if (count)
|
||||
c = &((*c)->m);
|
||||
}
|
||||
}
|
||||
(*c)->data = data;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ttree *ttree_create(struct pool *mem, unsigned int klen)
|
||||
{
|
||||
struct ttree *tt;
|
||||
@ -35,95 +112,3 @@ struct ttree *ttree_create(struct pool *mem, unsigned int klen)
|
||||
tt->mem = mem;
|
||||
return tt;
|
||||
}
|
||||
|
||||
void *ttree_lookup(struct ttree *tt, unsigned *key)
|
||||
{
|
||||
struct node *c = tt->root;
|
||||
int count = tt->klen;
|
||||
unsigned k = *key++;
|
||||
|
||||
while (c) {
|
||||
if (k < c->k)
|
||||
c = c->l;
|
||||
|
||||
else if (k > c->k)
|
||||
c = c->r;
|
||||
|
||||
else {
|
||||
if (!--count)
|
||||
break;
|
||||
|
||||
c = c->m;
|
||||
k = *key++;
|
||||
}
|
||||
}
|
||||
|
||||
return c ? c->data : 0;
|
||||
}
|
||||
|
||||
void *ttree_insert(struct ttree *tt, unsigned *key, void *data)
|
||||
{
|
||||
struct node *c = tt->root, *p = 0;
|
||||
int count = tt->klen, first = 1;
|
||||
unsigned k = *key;
|
||||
void *r = NULL;
|
||||
|
||||
while (c) {
|
||||
p = c;
|
||||
if (k < c->k)
|
||||
c = c->l;
|
||||
|
||||
else if (k > c->k)
|
||||
c = c->r;
|
||||
|
||||
else {
|
||||
c = c->m;
|
||||
if (!--count)
|
||||
break;
|
||||
|
||||
k = *++key;
|
||||
}
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
/* key is already in the tree */
|
||||
r = p->data;
|
||||
p->data = data;
|
||||
|
||||
} else {
|
||||
/* FIXME: put this in seperate function */
|
||||
/* insert new chain of nodes */
|
||||
while (count--) {
|
||||
k = *key++;
|
||||
c = pool_alloc(tt->mem, sizeof(*c));
|
||||
|
||||
if (!c) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c->k = k;
|
||||
c->l = c->m = c->r = c->data = 0;
|
||||
if (!p)
|
||||
tt->root = c;
|
||||
|
||||
else if (first) {
|
||||
if (k < p->k)
|
||||
p->l = c;
|
||||
|
||||
else if (k > p->k)
|
||||
p->r = c;
|
||||
|
||||
else
|
||||
p->m = c;
|
||||
|
||||
first = 0;
|
||||
} else
|
||||
p->m = c;
|
||||
p = c;
|
||||
}
|
||||
c->data = data;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -14,6 +14,6 @@ struct ttree;
|
||||
struct ttree *ttree_create(struct pool *mem, unsigned int klen);
|
||||
|
||||
void *ttree_lookup(struct ttree *tt, unsigned *key);
|
||||
void *ttree_insert(struct ttree *tt, unsigned *key, void *data);
|
||||
int ttree_insert(struct ttree *tt, unsigned *key, void *data);
|
||||
|
||||
#endif
|
||||
|
21
old-tests/filters/Makefile.in
Normal file
21
old-tests/filters/Makefile.in
Normal file
@ -0,0 +1,21 @@
|
||||
#
|
||||
# Copyright (C) 2001 Sistina Software (UK) Limited
|
||||
#
|
||||
# This file is released under the GPL.
|
||||
#
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SOURCES=\
|
||||
rfilter_t.c
|
||||
|
||||
TARGETS=\
|
||||
rfilter_t
|
||||
|
||||
include ../../make.tmpl
|
||||
|
||||
rfilter_t: rfilter_t.o $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o rfilter_t rfilter_t.o -L$(top_srcdir)/lib -llvm
|
||||
|
84
old-tests/filters/rfilter_t.c
Normal file
84
old-tests/filters/rfilter_t.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#include "filter-regex.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "dbg_malloc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct config_file *cf;
|
||||
struct config_node *cn;
|
||||
struct dev_filter *filter;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage : %s <config_file>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
init_log(stderr);
|
||||
init_debug(_LOG_DEBUG);
|
||||
|
||||
if (!(cf = create_config_file())) {
|
||||
fprintf(stderr, "couldn't create config file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!read_config(cf, argv[1])) {
|
||||
fprintf(stderr, "couldn't read config file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(cf->root, "/devices/filter", '/'))) {
|
||||
fprintf(stderr, "couldn't find filter section\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!dev_cache_init()) {
|
||||
fprintf(stderr, "couldn't initialise dev_cache_init failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!dev_cache_add_dir("/dev")) {
|
||||
fprintf(stderr, "couldn't add '/dev' to dev_cache\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!(filter = regex_filter_create(cn->v))) {
|
||||
fprintf(stderr, "couldn't build filter\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!(iter = dev_iter_create(filter))) {
|
||||
log_err("couldn't create iterator");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((dev = dev_iter_get(iter)))
|
||||
printf("%s\n", dev->name);
|
||||
|
||||
dev_iter_destroy(iter);
|
||||
filter->destroy(filter);
|
||||
dev_cache_exit();
|
||||
destroy_config_file(cf);
|
||||
|
||||
dump_memory();
|
||||
fin_log();
|
||||
return 0;
|
||||
}
|
||||
|
21
old-tests/filters/sample.cfg
Normal file
21
old-tests/filters/sample.cfg
Normal file
@ -0,0 +1,21 @@
|
||||
devices {
|
||||
|
||||
# first match is final, eg. /dev/ide/cdrom
|
||||
# get's rejected due to the first pattern
|
||||
|
||||
filter=["r/cdrom/", # don't touch the music !
|
||||
"a/hd[a-d][0-9]+/",
|
||||
"a/ide/",
|
||||
"a/sd/",
|
||||
"a/md/",
|
||||
"a|loop/[0-9]+|", # accept devfs style loop back
|
||||
"r/loop/", # and reject old style
|
||||
"a/dasd/",
|
||||
"a/dac960/",
|
||||
"a/nbd/",
|
||||
"a/ida/",
|
||||
"a/cciss/",
|
||||
"a/ubd/",
|
||||
"r/.*/"] # reject all others
|
||||
|
||||
}
|
@ -87,7 +87,7 @@ static void _scan_input(struct matcher *m, char **regex)
|
||||
if ((ptr = strchr(buffer, '\n')))
|
||||
*ptr = '\0';
|
||||
|
||||
r = matcher_run(m, buffer, buffer + strlen(buffer));
|
||||
r = matcher_run(m, buffer);
|
||||
|
||||
if (r >= 0)
|
||||
printf("%s : %s\n", buffer, regex[r]);
|
||||
|
Loading…
Reference in New Issue
Block a user