1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/lib/filters/filter-regex.c

229 lines
3.5 KiB
C

/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "pool.h"
#include "filter-regex.h"
#include "matcher.h"
#include "device.h"
#include "bitset.h"
#include "log.h"
#include "list.h"
struct rfilter {
struct pool *mem;
bitset_t accept;
struct matcher *engine;
};
static 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;
}
static 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)
{
struct list *ah;
int m, first = 1, rejected = 0;
struct rfilter *rf = (struct rfilter *) f->private;
struct str_list *sl;
list_iterate(ah, &dev->aliases) {
sl = list_item(ah, struct str_list);
m = matcher_run(rf->engine, sl->str);
if (m >= 0) {
if (bit(rf->accept, m)) {
if (!first) {
list_del(&sl->list);
list_add_h(&dev->aliases, &sl->list);
}
return 1;
}
rejected = 1;
}
first = 0;
}
/*
* pass everything that doesn't match
* anything.
*/
return !rejected;
}
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(10 * 1024);
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;
}