multipath-tools: merge dcssblk in similar blacklist regex
[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
16 extern int
17 store_ble (vector blist, char * str, int origin)
18 {
19         struct blentry * ble;
20
21         if (!str)
22                 return 0;
23
24         if (!blist)
25                 goto out;
26
27         ble = MALLOC(sizeof(struct blentry));
28
29         if (!ble)
30                 goto out;
31
32         if (regcomp(&ble->regex, str, REG_EXTENDED|REG_NOSUB))
33                 goto out1;
34
35         if (!vector_alloc_slot(blist))
36                 goto out1;
37
38         ble->str = str;
39         ble->origin = origin;
40         vector_set_slot(blist, ble);
41         return 0;
42 out1:
43         FREE(ble);
44 out:
45         FREE(str);
46         return 1;
47 }
48
49
50 extern int
51 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 extern int
67 set_ble_device (vector blist, char * vendor, char * product, int origin)
68 {
69         struct blentry_device * ble;
70
71         if (!blist)
72                 return 1;
73
74         ble = VECTOR_LAST_SLOT(blist);
75
76         if (!ble)
77                 return 1;
78
79         if (vendor) {
80                 if (regcomp(&ble->vendor_reg, vendor,
81                             REG_EXTENDED|REG_NOSUB)) {
82                         FREE(vendor);
83                         if (product)
84                                 FREE(product);
85                         return 1;
86                 }
87                 ble->vendor = vendor;
88         }
89         if (product) {
90                 if (regcomp(&ble->product_reg, product,
91                             REG_EXTENDED|REG_NOSUB)) {
92                         FREE(product);
93                         if (vendor) {
94                                 ble->vendor = NULL;
95                                 FREE(vendor);
96                         }
97                         return 1;
98                 }
99                 ble->product = product;
100         }
101         ble->origin = origin;
102         return 0;
103 }
104
105 int
106 _blacklist_exceptions (vector elist, const char * str)
107 {
108         int i;
109         struct blentry * ele;
110
111         vector_foreach_slot (elist, ele, i) {
112                 if (!regexec(&ele->regex, str, 0, NULL, 0))
113                         return 1;
114         }
115         return 0;
116 }
117
118 int
119 _blacklist (vector blist, const char * str)
120 {
121         int i;
122         struct blentry * ble;
123
124         vector_foreach_slot (blist, ble, i) {
125                 if (!regexec(&ble->regex, str, 0, NULL, 0))
126                         return 1;
127         }
128         return 0;
129 }
130
131 int
132 _blacklist_exceptions_device(vector elist, char * vendor, 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 (vector blist, char * vendor, char * product)
151 {
152         int i;
153         struct blentry_device * ble;
154
155         vector_foreach_slot (blist, ble, i) {
156                 if (!ble->vendor && !ble->product)
157                         continue;
158                 if ((!ble->vendor ||
159                      !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
160                     (!ble->product ||
161                      !regexec(&ble->product_reg, product, 0, NULL, 0)))
162                         return 1;
163         }
164         return 0;
165 }
166
167 int
168 setup_default_blist (struct config * conf)
169 {
170         struct blentry * ble;
171         struct hwentry *hwe;
172         char * str;
173         int i;
174
175         str = STRDUP("^(ram|raw|loop|fd|md|dm-|sr|scd|st|dcssblk)[0-9]");
176         if (!str)
177                 return 1;
178         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
179                 return 1;
180
181         str = STRDUP("^(td|hd|vd)[a-z]");
182         if (!str)
183                 return 1;
184         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
185                 return 1;
186
187         str = STRDUP("^nvme");
188         if (!str)
189                 return 1;
190         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
191                 return 1;
192
193         str = STRDUP("(SCSI_IDENT_|ID_WWN)");
194         if (!str)
195                 return 1;
196         if (store_ble(conf->elist_property, str, ORIGIN_DEFAULT))
197                 return 1;
198
199         vector_foreach_slot (conf->hwtable, hwe, i) {
200                 if (hwe->bl_product) {
201                         if (_blacklist_device(conf->blist_device, hwe->vendor,
202                                               hwe->bl_product))
203                                 continue;
204                         if (alloc_ble_device(conf->blist_device))
205                                 return 1;
206                         ble = VECTOR_SLOT(conf->blist_device,
207                                           VECTOR_SIZE(conf->blist_device) - 1);
208                         if (set_ble_device(conf->blist_device,
209                                            STRDUP(hwe->vendor),
210                                            STRDUP(hwe->bl_product),
211                                            ORIGIN_DEFAULT)) {
212                                 FREE(ble);
213                                 vector_del_slot(conf->blist_device, VECTOR_SIZE(conf->blist_device) - 1);
214                                 return 1;
215                         }
216                 }
217         }
218         return 0;
219 }
220
221 #define LOG_BLIST(M,S)                                                  \
222         if (vendor && product)                                          \
223                 condlog(3, "%s: (%s:%s) %s %s",                         \
224                         dev, vendor, product, (M), (S));                \
225         else if (wwid && !dev)                                          \
226                 condlog(3, "%s: %s %s", wwid, (M), (S));                \
227         else if (wwid)                                                  \
228                 condlog(3, "%s: %s %s %s", dev, (M), wwid, (S));        \
229         else if (env)                                                   \
230                 condlog(3, "%s: %s %s %s", dev, (M), env, (S));         \
231         else                                                            \
232                 condlog(3, "%s: %s %s", dev, (M), (S))
233
234 void
235 log_filter (const char *dev, char *vendor, char *product, char *wwid,
236             const char *env, int r)
237 {
238         /*
239          * Try to sort from most likely to least.
240          */
241         switch (r) {
242         case MATCH_NOTHING:
243                 break;
244         case MATCH_DEVICE_BLIST:
245                 LOG_BLIST("vendor/product", "blacklisted");
246                 break;
247         case MATCH_WWID_BLIST:
248                 LOG_BLIST("wwid", "blacklisted");
249                 break;
250         case MATCH_DEVNODE_BLIST:
251                 LOG_BLIST("device node name", "blacklisted");
252                 break;
253         case MATCH_PROPERTY_BLIST:
254                 LOG_BLIST("udev property", "blacklisted");
255                 break;
256         case MATCH_DEVICE_BLIST_EXCEPT:
257                 LOG_BLIST("vendor/product", "whitelisted");
258                 break;
259         case MATCH_WWID_BLIST_EXCEPT:
260                 LOG_BLIST("wwid", "whitelisted");
261                 break;
262         case MATCH_DEVNODE_BLIST_EXCEPT:
263                 LOG_BLIST("device node name", "whitelisted");
264                 break;
265         case MATCH_PROPERTY_BLIST_EXCEPT:
266                 LOG_BLIST("udev property", "whitelisted");
267                 break;
268         case MATCH_PROPERTY_BLIST_MISSING:
269                 LOG_BLIST("blacklisted,", "udev property missing");
270                 break;
271         }
272 }
273
274 int
275 _filter_device (vector blist, vector elist, char * vendor, char * product)
276 {
277         if (!vendor || !product)
278                 return 0;
279         if (_blacklist_exceptions_device(elist, vendor, product))
280                 return MATCH_DEVICE_BLIST_EXCEPT;
281         if (_blacklist_device(blist, vendor, product))
282                 return MATCH_DEVICE_BLIST;
283         return 0;
284 }
285
286 int
287 filter_device (vector blist, vector elist, char * vendor, char * product)
288 {
289         int r = _filter_device(blist, elist, vendor, product);
290         log_filter(NULL, vendor, product, NULL, NULL, r);
291         return r;
292 }
293
294 int
295 _filter_devnode (vector blist, vector elist, char * dev)
296 {
297         if (!dev)
298                 return 0;
299         if (_blacklist_exceptions(elist, dev))
300                 return MATCH_DEVNODE_BLIST_EXCEPT;
301         if (_blacklist(blist, dev))
302                 return MATCH_DEVNODE_BLIST;
303         return 0;
304 }
305
306 int
307 filter_devnode (vector blist, vector elist, char * dev)
308 {
309         int r = _filter_devnode(blist, elist, dev);
310         log_filter(dev, NULL, NULL, NULL, NULL, r);
311         return r;
312 }
313
314 int
315 _filter_wwid (vector blist, vector elist, char * wwid)
316 {
317         if (!wwid)
318                 return 0;
319         if (_blacklist_exceptions(elist, wwid))
320                 return MATCH_WWID_BLIST_EXCEPT;
321         if (_blacklist(blist, wwid))
322                 return MATCH_WWID_BLIST;
323         return 0;
324 }
325
326 int
327 filter_wwid (vector blist, vector elist, char * wwid, char * dev)
328 {
329         int r = _filter_wwid(blist, elist, wwid);
330         log_filter(dev, NULL, NULL, wwid, NULL, r);
331         return r;
332 }
333
334 int
335 _filter_path (struct config * conf, struct path * pp)
336 {
337         int r;
338
339         r = _filter_devnode(conf->blist_devnode, conf->elist_devnode,pp->dev);
340         if (r > 0)
341                 return r;
342         r = _filter_device(conf->blist_device, conf->elist_device,
343                            pp->vendor_id, pp->product_id);
344         if (r > 0)
345                 return r;
346         r = _filter_wwid(conf->blist_wwid, conf->elist_wwid, pp->wwid);
347         return r;
348 }
349
350 int
351 filter_path (struct config * conf, struct path * pp)
352 {
353         int r=_filter_path(conf, pp);
354         log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, NULL, r);
355         return r;
356 }
357
358 int
359 _filter_property (struct config *conf, const char *env)
360 {
361         if (_blacklist_exceptions(conf->elist_property, env))
362                 return MATCH_PROPERTY_BLIST_EXCEPT;
363         if (_blacklist(conf->blist_property, env))
364                 return MATCH_PROPERTY_BLIST;
365
366         return 0;
367 }
368
369 int
370 filter_property(struct config * conf, struct udev_device * udev)
371 {
372         const char *devname = udev_device_get_sysname(udev);
373         struct udev_list_entry *list_entry;
374         int r;
375
376         if (!udev)
377                 return 0;
378
379         udev_list_entry_foreach(list_entry,
380                                 udev_device_get_properties_list_entry(udev)) {
381                 const char *env;
382
383                 env = udev_list_entry_get_name(list_entry);
384                 if (!env)
385                         continue;
386
387                 r = _filter_property(conf, env);
388                 if (r) {
389                         log_filter(devname, NULL, NULL, NULL, env, r);
390                         return r;
391                 }
392         }
393
394         /*
395          * This is the inverse of the 'normal' matching;
396          * the environment variable _has_ to match.
397          */
398         log_filter(devname, NULL, NULL, NULL, NULL,
399                    MATCH_PROPERTY_BLIST_MISSING);
400         return MATCH_PROPERTY_BLIST_MISSING;
401 }
402
403 void
404 free_blacklist (vector blist)
405 {
406         struct blentry * ble;
407         int i;
408
409         if (!blist)
410                 return;
411
412         vector_foreach_slot (blist, ble, i) {
413                 if (ble) {
414                         regfree(&ble->regex);
415                         FREE(ble->str);
416                         FREE(ble);
417                 }
418         }
419         vector_free(blist);
420 }
421
422 void
423 free_blacklist_device (vector blist)
424 {
425         struct blentry_device * ble;
426         int i;
427
428         if (!blist)
429                 return;
430
431         vector_foreach_slot (blist, ble, i) {
432                 if (ble) {
433                         if (ble->vendor) {
434                                 regfree(&ble->vendor_reg);
435                                 FREE(ble->vendor);
436                         }
437                         if (ble->product) {
438                                 regfree(&ble->product_reg);
439                                 FREE(ble->product);
440                         }
441                         FREE(ble);
442                 }
443         }
444         vector_free(blist);
445 }