Tizen 2.1 base
[external/device-mapper.git] / lib / filters / filter-regex.c
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 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         switch (*pat) {
35         case 'a':
36                 dm_bit_set(accept, ix);
37                 break;
38
39         case 'r':
40                 dm_bit_clear(accept, ix);
41                 break;
42
43         default:
44                 log_info("pattern must begin with 'a' or 'r'");
45                 return 0;
46         }
47         pat++;
48
49         /*
50          * get the separator
51          */
52         switch (*pat) {
53         case '(':
54                 sep = ')';
55                 break;
56
57         case '[':
58                 sep = ']';
59                 break;
60
61         case '{':
62                 sep = '}';
63                 break;
64
65         default:
66                 sep = *pat;
67         }
68         pat++;
69
70         /*
71          * copy the regex
72          */
73         if (!(r = dm_pool_strdup(mem, pat)))
74                 return_0;
75
76         /*
77          * trim the trailing character, having checked it's sep.
78          */
79         ptr = r + strlen(r) - 1;
80         if (*ptr != sep) {
81                 log_info("invalid separator at end of regex");
82                 return 0;
83         }
84         *ptr = '\0';
85
86         regex[ix] = r;
87         return 1;
88 }
89
90 static int _build_matcher(struct rfilter *rf, const struct config_value *val)
91 {
92         struct dm_pool *scratch;
93         const struct config_value *v;
94         char **regex;
95         unsigned count = 0;
96         int i, r = 0;
97
98         if (!(scratch = dm_pool_create("filter dm_regex", 1024)))
99                 return_0;
100
101         /*
102          * count how many patterns we have.
103          */
104         for (v = val; v; v = v->next) {
105                 if (v->type != CFG_STRING) {
106                         log_error("Filter patterns must be enclosed in quotes.");
107                         goto out;
108                 }
109
110                 count++;
111         }
112
113         /*
114          * allocate space for them
115          */
116         if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count)))
117                 goto_out;
118
119         /*
120          * create the accept/reject bitset
121          */
122         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         for (v = val, i = count - 1; v; v = v->next, i--)
130                 if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
131                         log_error("Invalid filter pattern \"%s\".", v->v.str);
132                         goto out;
133                 }
134
135         /*
136          * build the matcher.
137          */
138         if (!(rf->engine = dm_regex_create(rf->mem, (const char **) regex,
139                                            count)))
140                 goto_out;
141         r = 1;
142
143       out:
144         dm_pool_destroy(scratch);
145         return r;
146 }
147
148 static int _accept_p(struct dev_filter *f, struct device *dev)
149 {
150         int m, first = 1, rejected = 0;
151         struct rfilter *rf = (struct rfilter *) f->private;
152         struct str_list *sl;
153
154         dm_list_iterate_items(sl, &dev->aliases) {
155                 m = dm_regex_match(rf->engine, sl->str);
156
157                 if (m >= 0) {
158                         if (dm_bit(rf->accept, m)) {
159                                 if (!first)
160                                         dev_set_preferred_name(sl, dev);
161
162                                 return 1;
163                         }
164
165                         rejected = 1;
166                 }
167
168                 first = 0;
169         }
170
171         if (rejected)
172                 log_debug("%s: Skipping (regex)", dev_name(dev));
173
174         /*
175          * pass everything that doesn't match
176          * anything.
177          */
178         return !rejected;
179 }
180
181 static void _regex_destroy(struct dev_filter *f)
182 {
183         struct rfilter *rf = (struct rfilter *) f->private;
184
185         if (f->use_count)
186                 log_error(INTERNAL_ERROR "Destroying regex filter while in use %u times.", f->use_count);
187
188         dm_pool_destroy(rf->mem);
189 }
190
191 struct dev_filter *regex_filter_create(const struct config_value *patterns)
192 {
193         struct dm_pool *mem = dm_pool_create("filter regex", 10 * 1024);
194         struct rfilter *rf;
195         struct dev_filter *f;
196
197         if (!mem)
198                 return_NULL;
199
200         if (!(rf = dm_pool_alloc(mem, sizeof(*rf))))
201                 goto_bad;
202
203         rf->mem = mem;
204
205         if (!_build_matcher(rf, patterns))
206                 goto_bad;
207
208         if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
209                 goto_bad;
210
211         f->passes_filter = _accept_p;
212         f->destroy = _regex_destroy;
213         f->use_count = 0;
214         f->private = rf;
215         return f;
216
217       bad:
218         dm_pool_destroy(mem);
219         return NULL;
220 }