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