libmultipath: avoid frequent messages from filter_property()
[multipath-tools/.git] / libmultipath / blacklist.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  */
4 #include <stdio.h>
5 #include <libudev.h>
6
7 #include "checkers.h"
8 #include "memory.h"
9 #include "vector.h"
10 #include "util.h"
11 #include "debug.h"
12 #include "structs.h"
13 #include "config.h"
14 #include "blacklist.h"
15 #include "structs_vec.h"
16 #include "print.h"
17
18 int store_ble(vector blist, char * str, int origin)
19 {
20         struct blentry * ble;
21
22         if (!str)
23                 return 0;
24
25         if (!blist)
26                 goto out;
27
28         ble = MALLOC(sizeof(struct blentry));
29
30         if (!ble)
31                 goto out;
32
33         if (regcomp(&ble->regex, str, REG_EXTENDED|REG_NOSUB))
34                 goto out1;
35
36         if (!vector_alloc_slot(blist))
37                 goto out1;
38
39         ble->str = str;
40         ble->origin = origin;
41         vector_set_slot(blist, ble);
42         return 0;
43 out1:
44         FREE(ble);
45 out:
46         FREE(str);
47         return 1;
48 }
49
50
51 int alloc_ble_device(vector blist)
52 {
53         struct blentry_device * ble = MALLOC(sizeof(struct blentry_device));
54
55         if (!ble)
56                 return 1;
57
58         if (!blist || !vector_alloc_slot(blist)) {
59                 FREE(ble);
60                 return 1;
61         }
62         vector_set_slot(blist, ble);
63         return 0;
64 }
65
66 int 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_LAST_SLOT(blist);
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                         if (product)
83                                 FREE(product);
84                         return 1;
85                 }
86                 ble->vendor = vendor;
87         }
88         if (product) {
89                 if (regcomp(&ble->product_reg, product,
90                             REG_EXTENDED|REG_NOSUB)) {
91                         FREE(product);
92                         if (vendor) {
93                                 ble->vendor = NULL;
94                                 FREE(vendor);
95                         }
96                         return 1;
97                 }
98                 ble->product = product;
99         }
100         ble->origin = origin;
101         return 0;
102 }
103
104 int
105 _blacklist_exceptions (vector elist, const char * str)
106 {
107         int i;
108         struct blentry * ele;
109
110         vector_foreach_slot (elist, ele, i) {
111                 if (!regexec(&ele->regex, str, 0, NULL, 0))
112                         return 1;
113         }
114         return 0;
115 }
116
117 int
118 _blacklist (vector blist, const char * str)
119 {
120         int i;
121         struct blentry * ble;
122
123         vector_foreach_slot (blist, ble, i) {
124                 if (!regexec(&ble->regex, str, 0, NULL, 0))
125                         return 1;
126         }
127         return 0;
128 }
129
130 int
131 _blacklist_exceptions_device(const struct _vector *elist, const char * vendor,
132                              const char * product)
133 {
134         int i;
135         struct blentry_device * ble;
136
137         vector_foreach_slot (elist, ble, i) {
138                 if (!ble->vendor && !ble->product)
139                         continue;
140                 if ((!ble->vendor ||
141                      !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
142                     (!ble->product ||
143                      !regexec(&ble->product_reg, product, 0, NULL, 0)))
144                         return 1;
145         }
146         return 0;
147 }
148
149 int
150 _blacklist_device (const struct _vector *blist, const char * vendor,
151                    const char * product)
152 {
153         int i;
154         struct blentry_device * ble;
155
156         vector_foreach_slot (blist, ble, i) {
157                 if (!ble->vendor && !ble->product)
158                         continue;
159                 if ((!ble->vendor ||
160                      !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
161                     (!ble->product ||
162                      !regexec(&ble->product_reg, product, 0, NULL, 0)))
163                         return 1;
164         }
165         return 0;
166 }
167
168 static int
169 find_blacklist_device (const struct _vector *blist, const char * vendor,
170                        const char * product)
171 {
172         int i;
173         struct blentry_device * ble;
174
175         vector_foreach_slot (blist, ble, i) {
176                 if (((!vendor && !ble->vendor) ||
177                      (vendor && ble->vendor &&
178                       !strcmp(vendor, ble->vendor))) &&
179                     ((!product && !ble->product) ||
180                      (product && ble->product &&
181                       !strcmp(product, ble->product))))
182                         return 1;
183         }
184         return 0;
185 }
186
187 int
188 setup_default_blist (struct config * conf)
189 {
190         struct blentry * ble;
191         struct hwentry *hwe;
192         char * str;
193         int i;
194
195         str = STRDUP("^(ram|raw|loop|fd|md|dm-|sr|scd|st|dcssblk)[0-9]");
196         if (!str)
197                 return 1;
198         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
199                 return 1;
200
201         str = STRDUP("^(td|hd|vd)[a-z]");
202         if (!str)
203                 return 1;
204         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
205                 return 1;
206
207         str = STRDUP("(SCSI_IDENT_|ID_WWN)");
208         if (!str)
209                 return 1;
210         if (store_ble(conf->elist_property, str, ORIGIN_DEFAULT))
211                 return 1;
212
213         vector_foreach_slot (conf->hwtable, hwe, i) {
214                 if (hwe->bl_product) {
215                         if (find_blacklist_device(conf->blist_device,
216                                                   hwe->vendor, hwe->bl_product))
217                                 continue;
218                         if (alloc_ble_device(conf->blist_device))
219                                 return 1;
220                         ble = VECTOR_SLOT(conf->blist_device,
221                                           VECTOR_SIZE(conf->blist_device) - 1);
222                         if (set_ble_device(conf->blist_device,
223                                            STRDUP(hwe->vendor),
224                                            STRDUP(hwe->bl_product),
225                                            ORIGIN_DEFAULT)) {
226                                 FREE(ble);
227                                 vector_del_slot(conf->blist_device, VECTOR_SIZE(conf->blist_device) - 1);
228                                 return 1;
229                         }
230                 }
231         }
232         return 0;
233 }
234
235 #define LOG_BLIST(M, S, lvl)                                            \
236         if (vendor && product)                                          \
237                 condlog(lvl, "%s: (%s:%s) %s %s",                       \
238                         dev, vendor, product, (M), (S));                \
239         else if (wwid && !dev)                                          \
240                 condlog(lvl, "%s: %s %s", wwid, (M), (S));              \
241         else if (wwid)                                                  \
242                 condlog(lvl, "%s: %s %s %s", dev, (M), wwid, (S));      \
243         else if (env)                                                   \
244                 condlog(lvl, "%s: %s %s %s", dev, (M), env, (S));       \
245         else if (protocol)                                              \
246                 condlog(lvl, "%s: %s %s %s", dev, (M), protocol, (S));  \
247         else                                                            \
248                 condlog(lvl, "%s: %s %s", dev, (M), (S))
249
250 static void
251 log_filter (const char *dev, char *vendor, char *product, char *wwid,
252             const char *env, const char *protocol, int r, int lvl)
253 {
254         /*
255          * Try to sort from most likely to least.
256          */
257         switch (r) {
258         case MATCH_NOTHING:
259                 break;
260         case MATCH_DEVICE_BLIST:
261                 LOG_BLIST("vendor/product", "blacklisted", lvl);
262                 break;
263         case MATCH_WWID_BLIST:
264                 LOG_BLIST("wwid", "blacklisted", lvl);
265                 break;
266         case MATCH_DEVNODE_BLIST:
267                 LOG_BLIST("device node name", "blacklisted", lvl);
268                 break;
269         case MATCH_PROPERTY_BLIST:
270                 LOG_BLIST("udev property", "blacklisted", lvl);
271                 break;
272         case MATCH_PROTOCOL_BLIST:
273                 LOG_BLIST("protocol", "blacklisted", lvl);
274                 break;
275         case MATCH_DEVICE_BLIST_EXCEPT:
276                 LOG_BLIST("vendor/product", "whitelisted", lvl);
277                 break;
278         case MATCH_WWID_BLIST_EXCEPT:
279                 LOG_BLIST("wwid", "whitelisted", lvl);
280                 break;
281         case MATCH_DEVNODE_BLIST_EXCEPT:
282                 LOG_BLIST("device node name", "whitelisted", lvl);
283                 break;
284         case MATCH_PROPERTY_BLIST_EXCEPT:
285                 LOG_BLIST("udev property", "whitelisted", lvl);
286                 break;
287         case MATCH_PROPERTY_BLIST_MISSING:
288                 LOG_BLIST("blacklisted,", "udev property missing", lvl);
289                 break;
290         case MATCH_PROTOCOL_BLIST_EXCEPT:
291                 LOG_BLIST("protocol", "whitelisted", lvl);
292                 break;
293         }
294 }
295
296 int
297 filter_device (vector blist, vector elist, char * vendor, char * product,
298                char * dev)
299 {
300         int r = MATCH_NOTHING;
301
302         if (vendor && product) {
303                 if (_blacklist_exceptions_device(elist, vendor, product))
304                         r = MATCH_DEVICE_BLIST_EXCEPT;
305                 else if (_blacklist_device(blist, vendor, product))
306                         r = MATCH_DEVICE_BLIST;
307         }
308
309         log_filter(dev, vendor, product, NULL, NULL, NULL, r, 3);
310         return r;
311 }
312
313 int
314 filter_devnode (vector blist, vector elist, char * dev)
315 {
316         int r = MATCH_NOTHING;
317
318         if (dev) {
319                 if (_blacklist_exceptions(elist, dev))
320                         r = MATCH_DEVNODE_BLIST_EXCEPT;
321                 else if (_blacklist(blist, dev))
322                         r = MATCH_DEVNODE_BLIST;
323         }
324
325         log_filter(dev, NULL, NULL, NULL, NULL, NULL, r, 3);
326         return r;
327 }
328
329 int
330 filter_wwid (vector blist, vector elist, char * wwid, char * dev)
331 {
332         int r = MATCH_NOTHING;
333
334         if (wwid) {
335                 if (_blacklist_exceptions(elist, wwid))
336                         r = MATCH_WWID_BLIST_EXCEPT;
337                 else if (_blacklist(blist, wwid))
338                         r = MATCH_WWID_BLIST;
339         }
340
341         log_filter(dev, NULL, NULL, wwid, NULL, NULL, r, 3);
342         return r;
343 }
344
345 int
346 filter_protocol(vector blist, vector elist, struct path * pp)
347 {
348         char buf[PROTOCOL_BUF_SIZE];
349         int r = MATCH_NOTHING;
350
351         if (pp) {
352                 snprint_path_protocol(buf, sizeof(buf), pp);
353
354                 if (_blacklist_exceptions(elist, buf))
355                         r = MATCH_PROTOCOL_BLIST_EXCEPT;
356                 else if (_blacklist(blist, buf))
357                         r = MATCH_PROTOCOL_BLIST;
358         }
359
360         log_filter(pp->dev, NULL, NULL, NULL, NULL, buf, r, 3);
361         return r;
362 }
363
364 int
365 filter_path (struct config * conf, struct path * pp)
366 {
367         int r;
368
369         r = filter_property(conf, pp->udev, 3);
370         if (r > 0)
371                 return r;
372         r = filter_devnode(conf->blist_devnode, conf->elist_devnode, pp->dev);
373         if (r > 0)
374                 return r;
375         r = filter_device(conf->blist_device, conf->elist_device,
376                            pp->vendor_id, pp->product_id, pp->dev);
377         if (r > 0)
378                 return r;
379         r = filter_protocol(conf->blist_protocol, conf->elist_protocol, pp);
380         if (r > 0)
381                 return r;
382         r = filter_wwid(conf->blist_wwid, conf->elist_wwid, pp->wwid, pp->dev);
383         return r;
384 }
385
386 int
387 filter_property(struct config *conf, struct udev_device *udev, int lvl)
388 {
389         const char *devname = udev_device_get_sysname(udev);
390         struct udev_list_entry *list_entry;
391         const char *env = NULL;
392         int r = MATCH_NOTHING;
393
394         if (udev) {
395                 /*
396                  * This is the inverse of the 'normal' matching;
397                  * the environment variable _has_ to match.
398                  */
399                 r = MATCH_PROPERTY_BLIST_MISSING;
400                 udev_list_entry_foreach(list_entry,
401                                 udev_device_get_properties_list_entry(udev)) {
402
403                         env = udev_list_entry_get_name(list_entry);
404                         if (!env)
405                                 continue;
406                         if (_blacklist_exceptions(conf->elist_property, env)) {
407                                 r = MATCH_PROPERTY_BLIST_EXCEPT;
408                                 break;
409                         }
410                         if (_blacklist(conf->blist_property, env)) {
411                                 r = MATCH_PROPERTY_BLIST;
412                                 break;
413                         }
414                         env = NULL;
415                 }
416         }
417
418         log_filter(devname, NULL, NULL, NULL, env, NULL, r, lvl);
419         return r;
420 }
421
422 static void free_ble(struct blentry *ble)
423 {
424         if (!ble)
425                 return;
426         regfree(&ble->regex);
427         FREE(ble->str);
428         FREE(ble);
429 }
430
431 void
432 free_blacklist (vector blist)
433 {
434         struct blentry * ble;
435         int i;
436
437         if (!blist)
438                 return;
439
440         vector_foreach_slot (blist, ble, i) {
441                 free_ble(ble);
442         }
443         vector_free(blist);
444 }
445
446 void merge_blacklist(vector blist)
447 {
448         struct blentry *bl1, *bl2;
449         int i, j;
450
451         vector_foreach_slot(blist, bl1, i) {
452                 j = i + 1;
453                 vector_foreach_slot_after(blist, bl2, j) {
454                         if (!bl1->str || !bl2->str || strcmp(bl1->str, bl2->str))
455                                 continue;
456                         condlog(3, "%s: duplicate blist entry section for %s",
457                                 __func__, bl1->str);
458                         free_ble(bl2);
459                         vector_del_slot(blist, j);
460                         j--;
461                 }
462         }
463 }
464
465 static void free_ble_device(struct blentry_device *ble)
466 {
467         if (ble) {
468                 if (ble->vendor) {
469                         regfree(&ble->vendor_reg);
470                         FREE(ble->vendor);
471                 }
472                 if (ble->product) {
473                         regfree(&ble->product_reg);
474                         FREE(ble->product);
475                 }
476                 FREE(ble);
477         }
478 }
479
480 void
481 free_blacklist_device (vector blist)
482 {
483         struct blentry_device * ble;
484         int i;
485
486         if (!blist)
487                 return;
488
489         vector_foreach_slot (blist, ble, i) {
490                 free_ble_device(ble);
491         }
492         vector_free(blist);
493 }
494
495 void merge_blacklist_device(vector blist)
496 {
497         struct blentry_device *bl1, *bl2;
498         int i, j;
499
500         vector_foreach_slot(blist, bl1, i) {
501                 if (!bl1->vendor && !bl1->product) {
502                         free_ble_device(bl1);
503                         vector_del_slot(blist, i);
504                         i--;
505                 }
506         }
507
508         vector_foreach_slot(blist, bl1, i) {
509                 j = i + 1;
510                 vector_foreach_slot_after(blist, bl2, j) {
511                         if ((!bl1->vendor && bl2->vendor) ||
512                             (bl1->vendor && !bl2->vendor) ||
513                             (bl1->vendor && bl2->vendor &&
514                              strcmp(bl1->vendor, bl2->vendor)))
515                                 continue;
516                         if ((!bl1->product && bl2->product) ||
517                             (bl1->product && !bl2->product) ||
518                             (bl1->product && bl2->product &&
519                              strcmp(bl1->product, bl2->product)))
520                                 continue;
521                         condlog(3, "%s: duplicate blist entry section for %s:%s",
522                                 __func__, bl1->vendor, bl1->product);
523                         free_ble_device(bl2);
524                         vector_del_slot(blist, j);
525                         j--;
526                 }
527         }
528 }