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
_extract_pattern(struct dm_pool * mem,const char * pat,char ** regex,dm_bitset_t accept,int ix)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
_build_matcher(struct rfilter * rf,struct config_value * val)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
_accept_p(struct dev_filter * f,struct device * dev)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
_regex_destroy(struct dev_filter * f)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
regex_filter_create(struct config_value * patterns)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