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