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