Home | History | Annotate | Line # | Download | only in filters
      1 /*	$NetBSD: filter-regex.c,v 1.1.1.1 2008/12/22 00:17:58 haad Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
      5  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
      6  *
      7  * This file is part of LVM2.
      8  *
      9  * This copyrighted material is made available to anyone wishing to use,
     10  * modify, copy, or redistribute it subject to the terms and conditions
     11  * of the GNU Lesser General Public License v.2.1.
     12  *
     13  * You should have received a copy of the GNU Lesser General Public License
     14  * along with this program; if not, write to the Free Software Foundation,
     15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     16  */
     17 
     18 #include "lib.h"
     19 #include "filter-regex.h"
     20 #include "device.h"
     21 
     22 struct rfilter {
     23 	struct dm_pool *mem;
     24 	dm_bitset_t accept;
     25 	struct dm_regex *engine;
     26 };
     27 
     28 static int _extract_pattern(struct dm_pool *mem, const char *pat,
     29 			    char **regex, dm_bitset_t accept, int ix)
     30 {
     31 	char sep, *r, *ptr;
     32 
     33 	/*
     34 	 * is this an accept or reject pattern
     35 	 */
     36 	switch (*pat) {
     37 	case 'a':
     38 		dm_bit_set(accept, ix);
     39 		break;
     40 
     41 	case 'r':
     42 		dm_bit_clear(accept, ix);
     43 		break;
     44 
     45 	default:
     46 		log_info("pattern must begin with 'a' or 'r'");
     47 		return 0;
     48 	}
     49 	pat++;
     50 
     51 	/*
     52 	 * get the separator
     53 	 */
     54 	switch (*pat) {
     55 	case '(':
     56 		sep = ')';
     57 		break;
     58 
     59 	case '[':
     60 		sep = ']';
     61 		break;
     62 
     63 	case '{':
     64 		sep = '}';
     65 		break;
     66 
     67 	default:
     68 		sep = *pat;
     69 	}
     70 	pat++;
     71 
     72 	/*
     73 	 * copy the regex
     74 	 */
     75 	if (!(r = dm_pool_strdup(mem, pat)))
     76 		return_0;
     77 
     78 	/*
     79 	 * trim the trailing character, having checked it's sep.
     80 	 */
     81 	ptr = r + strlen(r) - 1;
     82 	if (*ptr != sep) {
     83 		log_info("invalid separator at end of regex");
     84 		return 0;
     85 	}
     86 	*ptr = '\0';
     87 
     88 	regex[ix] = r;
     89 	return 1;
     90 }
     91 
     92 static int _build_matcher(struct rfilter *rf, struct config_value *val)
     93 {
     94 	struct dm_pool *scratch;
     95 	struct config_value *v;
     96 	char **regex;
     97 	unsigned count = 0;
     98 	int i, r = 0;
     99 
    100 	if (!(scratch = dm_pool_create("filter dm_regex", 1024)))
    101 		return_0;
    102 
    103 	/*
    104 	 * count how many patterns we have.
    105 	 */
    106 	for (v = val; v; v = v->next) {
    107 		if (v->type != CFG_STRING) {
    108 			log_error("filter patterns must be enclosed in quotes");
    109 			goto out;
    110 		}
    111 
    112 		count++;
    113 	}
    114 
    115 	/*
    116 	 * allocate space for them
    117 	 */
    118 	if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count)))
    119 		goto_out;
    120 
    121 	/*
    122 	 * create the accept/reject bitset
    123 	 */
    124 	rf->accept = dm_bitset_create(rf->mem, count);
    125 
    126 	/*
    127 	 * fill the array back to front because we
    128 	 * want the opposite precedence to what
    129 	 * the matcher gives.
    130 	 */
    131 	for (v = val, i = count - 1; v; v = v->next, i--)
    132 		if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
    133 			log_error("invalid filter pattern");
    134 			goto out;
    135 		}
    136 
    137 	/*
    138 	 * build the matcher.
    139 	 */
    140 	if (!(rf->engine = dm_regex_create(rf->mem, (const char **) regex,
    141 					   count)))
    142 		stack;
    143 	r = 1;
    144 
    145       out:
    146 	dm_pool_destroy(scratch);
    147 	return r;
    148 }
    149 
    150 static int _accept_p(struct dev_filter *f, struct device *dev)
    151 {
    152 	int m, first = 1, rejected = 0;
    153 	struct rfilter *rf = (struct rfilter *) f->private;
    154 	struct str_list *sl;
    155 
    156 	dm_list_iterate_items(sl, &dev->aliases) {
    157 		m = dm_regex_match(rf->engine, sl->str);
    158 
    159 		if (m >= 0) {
    160 			if (dm_bit(rf->accept, m)) {
    161 				if (!first)
    162 					dev_set_preferred_name(sl, dev);
    163 
    164 				return 1;
    165 			}
    166 
    167 			rejected = 1;
    168 		}
    169 
    170 		first = 0;
    171 	}
    172 
    173 	if (rejected)
    174 		log_debug("%s: Skipping (regex)", dev_name(dev));
    175 
    176 	/*
    177 	 * pass everything that doesn't match
    178 	 * anything.
    179 	 */
    180 	return !rejected;
    181 }
    182 
    183 static void _regex_destroy(struct dev_filter *f)
    184 {
    185 	struct rfilter *rf = (struct rfilter *) f->private;
    186 	dm_pool_destroy(rf->mem);
    187 }
    188 
    189 struct dev_filter *regex_filter_create(struct config_value *patterns)
    190 {
    191 	struct dm_pool *mem = dm_pool_create("filter regex", 10 * 1024);
    192 	struct rfilter *rf;
    193 	struct dev_filter *f;
    194 
    195 	if (!mem)
    196 		return_NULL;
    197 
    198 	if (!(rf = dm_pool_alloc(mem, sizeof(*rf))))
    199 		goto_bad;
    200 
    201 	rf->mem = mem;
    202 
    203 	if (!_build_matcher(rf, patterns))
    204 		goto_bad;
    205 
    206 	if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
    207 		goto_bad;
    208 
    209 	f->passes_filter = _accept_p;
    210 	f->destroy = _regex_destroy;
    211 	f->private = rf;
    212 	return f;
    213 
    214       bad:
    215 	dm_pool_destroy(mem);
    216 	return NULL;
    217 }
    218