[libmultipath] blacklist exceptions issues
[multipath-tools/.git] / libmultipath / blacklist.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  */
4 #include <stdio.h>
5 #include <checkers.h>
6
7 #include "memory.h"
8 #include "vector.h"
9 #include "util.h"
10 #include "debug.h"
11 #include "structs.h"
12 #include "config.h"
13 #include "blacklist.h"
14
15 extern int
16 store_ble (vector blist, char * str, int origin)
17 {
18         struct blentry * ble;
19         
20         if (!str)
21                 return 0;
22
23         if (!blist)
24                 goto out;
25
26         ble = MALLOC(sizeof(struct blentry));
27
28         if (!ble)
29                 goto out;
30
31         if (regcomp(&ble->regex, str, REG_EXTENDED|REG_NOSUB))
32                 goto out1;
33
34         if (!vector_alloc_slot(blist))
35                 goto out1;
36
37         ble->str = str;
38         ble->origin = origin;
39         vector_set_slot(blist, ble);
40         return 0;
41 out1:
42         FREE(ble);
43 out:
44         FREE(str);
45         return 1;
46 }
47
48
49 extern int
50 alloc_ble_device (vector blist)
51 {
52         struct blentry_device * ble = MALLOC(sizeof(struct blentry_device));
53
54         if (!ble || !blist)
55                 return 1;
56
57         if (!vector_alloc_slot(blist)) {
58                 FREE(ble);
59                 return 1;
60         }
61         vector_set_slot(blist, ble);
62         return 0;
63 }
64         
65 extern int
66 set_ble_device (vector blist, char * vendor, char * product, int origin)
67 {
68         struct blentry_device * ble;
69         
70         if (!blist)
71                 return 1;
72
73         ble = VECTOR_SLOT(blist, VECTOR_SIZE(blist) - 1);
74
75         if (!ble)
76                 return 1;
77
78         if (vendor) {
79                 if (regcomp(&ble->vendor_reg, vendor,
80                             REG_EXTENDED|REG_NOSUB)) {
81                         FREE(vendor);
82                         return 1;
83                 }
84                 ble->vendor = vendor;
85         }
86         if (product) {
87                 if (regcomp(&ble->product_reg, product,
88                             REG_EXTENDED|REG_NOSUB)) {
89                         FREE(product);
90                         return 1;
91                 }
92                 ble->product = product;
93         }
94         ble->origin = origin;
95         return 0;
96 }
97
98 int
99 setup_default_blist (struct config * conf)
100 {
101         struct blentry * ble;
102         struct hwentry *hwe;
103         char * str;
104         int i;
105
106         str = STRDUP("^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*");
107         if (!str)
108                 return 1;
109         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
110                 return 1;
111
112         str = STRDUP("^hd[a-z]");
113         if (!str)
114                 return 1;
115         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
116                 return 1;
117
118         str = STRDUP("^dcssblk[0-9]*");
119         if (!str)
120                 return 1;
121         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
122                 return 1;
123
124         vector_foreach_slot (conf->hwtable, hwe, i) {
125                 if (hwe->bl_product) {
126                         if (alloc_ble_device(conf->blist_device))
127                                 return 1;
128                         ble = VECTOR_SLOT(conf->blist_device,
129                                           VECTOR_SIZE(conf->blist_device) -1);
130                         if (set_ble_device(conf->blist_device,
131                                            STRDUP(hwe->vendor),
132                                            STRDUP(hwe->bl_product),
133                                            ORIGIN_DEFAULT)) {
134                                 FREE(ble);
135                                 return 1;
136                         }
137                 }
138         }
139         return 0;
140 }
141
142 int
143 _blacklist_exceptions (vector elist, char * str)
144 {
145         int i;
146         struct blentry * ele;
147
148         vector_foreach_slot (elist, ele, i) {
149                 if (!regexec(&ele->regex, str, 0, NULL, 0))
150                         return 1;
151         }
152         return 0;
153 }
154
155 int
156 _blacklist (vector blist, char * str)
157 {
158         int i;
159         struct blentry * ble;
160
161         vector_foreach_slot (blist, ble, i) {
162                 if (!regexec(&ble->regex, str, 0, NULL, 0))
163                         return 1;
164         }
165         return 0;
166 }
167
168 int
169 _blacklist_exceptions_device(vector elist, char * vendor, char * product)
170 {
171         int i;
172         struct blentry_device * ble;
173
174         vector_foreach_slot (elist, ble, i) {
175                 if (!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) &&
176                     !regexec(&ble->product_reg, product, 0, NULL, 0))
177                         return 1;
178         }
179         return 0;
180 }
181
182 int
183 _blacklist_device (vector blist, char * vendor, char * product)
184 {
185         int i;
186         struct blentry_device * ble;
187
188         vector_foreach_slot (blist, ble, i) {
189                 if (!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) &&
190                     !regexec(&ble->product_reg, product, 0, NULL, 0))
191                         return 1;
192         }
193         return 0;
194 }
195
196 #define LOG_BLIST(M) \
197         if (vendor && product)                                           \
198                 condlog(3, "%s: (%s:%s) %s", dev, vendor, product, (M)); \
199         else if (wwid)                                                   \
200                 condlog(3, "%s: (%s) %s", dev, wwid, (M));               \
201         else                                                             \
202                 condlog(3, "%s: %s", dev, (M))
203
204 void
205 log_filter (char *dev, char *vendor, char *product, char *wwid, int r)
206 {
207         /*
208          * Try to sort from most likely to least.
209          */
210         switch (r) {
211         case MATCH_NOTHING:
212                 break;
213         case MATCH_DEVICE_BLIST:
214                 LOG_BLIST("vendor/product blacklisted");
215                 break;
216         case MATCH_WWID_BLIST:
217                 LOG_BLIST("wwid blacklisted");
218                 break;
219         case MATCH_DEVNODE_BLIST:
220                 LOG_BLIST("device node name blacklisted");
221                 break;
222         case MATCH_DEVICE_BLIST_EXCEPT:
223                 LOG_BLIST("vendor/product whitelisted");
224                 break;
225         case MATCH_WWID_BLIST_EXCEPT:
226                 LOG_BLIST("wwid whitelisted");
227                 break;
228         case MATCH_DEVNODE_BLIST_EXCEPT:
229                 LOG_BLIST("device node name whitelisted");
230                 break;
231         }
232 }
233
234 int
235 _filter_device (vector blist, vector elist, char * vendor, char * product)
236 {
237         if (!vendor || !product)
238                 return 0;
239         if (_blacklist_exceptions_device(elist, vendor, product))
240                 return MATCH_DEVICE_BLIST_EXCEPT;
241         if (_blacklist_device(blist, vendor, product))
242                 return MATCH_DEVICE_BLIST;
243         return 0;
244 }
245
246 int
247 filter_device (vector blist, vector elist, char * vendor, char * product)
248 {
249         int r = _filter_device(blist, elist, vendor, product);
250         log_filter(NULL, vendor, product, NULL, r);
251         return r;
252 }
253
254 int
255 _filter_devnode (vector blist, vector elist, char * dev)
256 {
257         if (!dev)
258                 return 0;
259         if (_blacklist_exceptions(elist, dev))
260                 return MATCH_DEVNODE_BLIST_EXCEPT;
261         if (_blacklist(blist, dev))
262                 return MATCH_DEVNODE_BLIST;
263         return 0;
264 }
265
266 int
267 filter_devnode (vector blist, vector elist, char * dev)
268 {
269         int r = _filter_devnode(blist, elist, dev);
270         log_filter(dev, NULL, NULL, NULL, r);
271         return r;
272 }
273
274 int
275 _filter_wwid (vector blist, vector elist, char * wwid)
276 {
277         if (!wwid)
278                 return 0;
279         if (_blacklist_exceptions(elist, wwid))
280                 return MATCH_WWID_BLIST_EXCEPT;
281         if (_blacklist(blist, wwid))
282                 return MATCH_WWID_BLIST;
283         return 0;
284 }
285
286 int
287 filter_wwid (vector blist, vector elist, char * wwid)
288 {
289         int r = _filter_wwid(blist, elist, wwid);
290         log_filter(NULL, NULL, NULL, wwid, r);
291         return r;
292 }
293
294 int
295 _filter_path (struct config * conf, struct path * pp)
296 {
297         int r;
298
299         r = _filter_devnode(conf->blist_devnode, conf->elist_devnode,pp->dev);
300         if (r > 0)
301                 return r;
302         r = _filter_device(conf->blist_device, conf->elist_device,
303                            pp->vendor_id, pp->product_id);
304         if (r > 0)
305                 return r;
306         r = _filter_wwid(conf->blist_wwid, conf->elist_wwid, pp->wwid);
307         return r;
308 }
309
310 int
311 filter_path (struct config * conf, struct path * pp)
312 {
313         int r=_filter_path(conf, pp);
314         log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, r);
315         return r;
316 }
317
318 void
319 free_blacklist (vector blist)
320 {
321         struct blentry * ble;
322         int i;
323
324         if (!blist)
325                 return;
326
327         vector_foreach_slot (blist, ble, i) {
328                 if (ble) {
329                         regfree(&ble->regex);
330                         FREE(ble->str);
331                         FREE(ble);
332                 }
333         }
334         vector_free(blist);
335 }
336
337 void
338 free_blacklist_device (vector blist)
339 {
340         struct blentry_device * ble;
341         int i;
342
343         if (!blist)
344                 return;
345
346         vector_foreach_slot (blist, ble, i) {
347                 if (ble) {
348                         regfree(&ble->vendor_reg);
349                         regfree(&ble->product_reg);
350                         FREE(ble->vendor);
351                         FREE(ble->product);
352                         FREE(ble);
353                 }
354         }
355         vector_free(blist);
356 }