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