multipath-tools: use internal drd.h file
[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)[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("^dcssblk[0-9]");
188         if (!str)
189                 return 1;
190         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
191                 return 1;
192
193         str = STRDUP("^nvme");
194         if (!str)
195                 return 1;
196         if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
197                 return 1;
198
199         str = STRDUP("(SCSI_IDENT_|ID_WWN)");
200         if (!str)
201                 return 1;
202         if (store_ble(conf->elist_property, str, ORIGIN_DEFAULT))
203                 return 1;
204
205         vector_foreach_slot (conf->hwtable, hwe, i) {
206                 if (hwe->bl_product) {
207                         if (_blacklist_device(conf->blist_device, hwe->vendor,
208                                               hwe->bl_product))
209                                 continue;
210                         if (alloc_ble_device(conf->blist_device))
211                                 return 1;
212                         ble = VECTOR_SLOT(conf->blist_device,
213                                           VECTOR_SIZE(conf->blist_device) - 1);
214                         if (set_ble_device(conf->blist_device,
215                                            STRDUP(hwe->vendor),
216                                            STRDUP(hwe->bl_product),
217                                            ORIGIN_DEFAULT)) {
218                                 FREE(ble);
219                                 vector_del_slot(conf->blist_device, VECTOR_SIZE(conf->blist_device) - 1);
220                                 return 1;
221                         }
222                 }
223         }
224         return 0;
225 }
226
227 #define LOG_BLIST(M,S)                                                  \
228         if (vendor && product)                                          \
229                 condlog(3, "%s: (%s:%s) %s %s",                         \
230                         dev, vendor, product, (M), (S));                \
231         else if (wwid && !dev)                                          \
232                 condlog(3, "%s: %s %s", wwid, (M), (S));                \
233         else if (wwid)                                                  \
234                 condlog(3, "%s: %s %s %s", dev, (M), wwid, (S));        \
235         else if (env)                                                   \
236                 condlog(3, "%s: %s %s %s", dev, (M), env, (S));         \
237         else                                                            \
238                 condlog(3, "%s: %s %s", dev, (M), (S))
239
240 void
241 log_filter (const char *dev, char *vendor, char *product, char *wwid,
242             const char *env, int r)
243 {
244         /*
245          * Try to sort from most likely to least.
246          */
247         switch (r) {
248         case MATCH_NOTHING:
249                 break;
250         case MATCH_DEVICE_BLIST:
251                 LOG_BLIST("vendor/product", "blacklisted");
252                 break;
253         case MATCH_WWID_BLIST:
254                 LOG_BLIST("wwid", "blacklisted");
255                 break;
256         case MATCH_DEVNODE_BLIST:
257                 LOG_BLIST("device node name", "blacklisted");
258                 break;
259         case MATCH_PROPERTY_BLIST:
260                 LOG_BLIST("udev property", "blacklisted");
261                 break;
262         case MATCH_DEVICE_BLIST_EXCEPT:
263                 LOG_BLIST("vendor/product", "whitelisted");
264                 break;
265         case MATCH_WWID_BLIST_EXCEPT:
266                 LOG_BLIST("wwid", "whitelisted");
267                 break;
268         case MATCH_DEVNODE_BLIST_EXCEPT:
269                 LOG_BLIST("device node name", "whitelisted");
270                 break;
271         case MATCH_PROPERTY_BLIST_EXCEPT:
272                 LOG_BLIST("udev property", "whitelisted");
273                 break;
274         case MATCH_PROPERTY_BLIST_MISSING:
275                 LOG_BLIST("blacklisted,", "udev property missing");
276                 break;
277         }
278 }
279
280 int
281 _filter_device (vector blist, vector elist, char * vendor, char * product)
282 {
283         if (!vendor || !product)
284                 return 0;
285         if (_blacklist_exceptions_device(elist, vendor, product))
286                 return MATCH_DEVICE_BLIST_EXCEPT;
287         if (_blacklist_device(blist, vendor, product))
288                 return MATCH_DEVICE_BLIST;
289         return 0;
290 }
291
292 int
293 filter_device (vector blist, vector elist, char * vendor, char * product)
294 {
295         int r = _filter_device(blist, elist, vendor, product);
296         log_filter(NULL, vendor, product, NULL, NULL, r);
297         return r;
298 }
299
300 int
301 _filter_devnode (vector blist, vector elist, char * dev)
302 {
303         if (!dev)
304                 return 0;
305         if (_blacklist_exceptions(elist, dev))
306                 return MATCH_DEVNODE_BLIST_EXCEPT;
307         if (_blacklist(blist, dev))
308                 return MATCH_DEVNODE_BLIST;
309         return 0;
310 }
311
312 int
313 filter_devnode (vector blist, vector elist, char * dev)
314 {
315         int r = _filter_devnode(blist, elist, dev);
316         log_filter(dev, NULL, NULL, NULL, NULL, r);
317         return r;
318 }
319
320 int
321 _filter_wwid (vector blist, vector elist, char * wwid)
322 {
323         if (!wwid)
324                 return 0;
325         if (_blacklist_exceptions(elist, wwid))
326                 return MATCH_WWID_BLIST_EXCEPT;
327         if (_blacklist(blist, wwid))
328                 return MATCH_WWID_BLIST;
329         return 0;
330 }
331
332 int
333 filter_wwid (vector blist, vector elist, char * wwid, char * dev)
334 {
335         int r = _filter_wwid(blist, elist, wwid);
336         log_filter(dev, NULL, NULL, wwid, NULL, r);
337         return r;
338 }
339
340 int
341 _filter_path (struct config * conf, struct path * pp)
342 {
343         int r;
344
345         r = _filter_devnode(conf->blist_devnode, conf->elist_devnode,pp->dev);
346         if (r > 0)
347                 return r;
348         r = _filter_device(conf->blist_device, conf->elist_device,
349                            pp->vendor_id, pp->product_id);
350         if (r > 0)
351                 return r;
352         r = _filter_wwid(conf->blist_wwid, conf->elist_wwid, pp->wwid);
353         return r;
354 }
355
356 int
357 filter_path (struct config * conf, struct path * pp)
358 {
359         int r=_filter_path(conf, pp);
360         log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, NULL, r);
361         return r;
362 }
363
364 int
365 _filter_property (struct config *conf, const char *env)
366 {
367         if (_blacklist_exceptions(conf->elist_property, env))
368                 return MATCH_PROPERTY_BLIST_EXCEPT;
369         if (_blacklist(conf->blist_property, env))
370                 return MATCH_PROPERTY_BLIST;
371
372         return 0;
373 }
374
375 int
376 filter_property(struct config * conf, struct udev_device * udev)
377 {
378         const char *devname = udev_device_get_sysname(udev);
379         struct udev_list_entry *list_entry;
380         int r;
381
382         if (!udev)
383                 return 0;
384
385         udev_list_entry_foreach(list_entry,
386                                 udev_device_get_properties_list_entry(udev)) {
387                 const char *env;
388
389                 env = udev_list_entry_get_name(list_entry);
390                 if (!env)
391                         continue;
392
393                 r = _filter_property(conf, env);
394                 if (r) {
395                         log_filter(devname, NULL, NULL, NULL, env, r);
396                         return r;
397                 }
398         }
399
400         /*
401          * This is the inverse of the 'normal' matching;
402          * the environment variable _has_ to match.
403          */
404         log_filter(devname, NULL, NULL, NULL, NULL,
405                    MATCH_PROPERTY_BLIST_MISSING);
406         return MATCH_PROPERTY_BLIST_MISSING;
407 }
408
409 void
410 free_blacklist (vector blist)
411 {
412         struct blentry * ble;
413         int i;
414
415         if (!blist)
416                 return;
417
418         vector_foreach_slot (blist, ble, i) {
419                 if (ble) {
420                         regfree(&ble->regex);
421                         FREE(ble->str);
422                         FREE(ble);
423                 }
424         }
425         vector_free(blist);
426 }
427
428 void
429 free_blacklist_device (vector blist)
430 {
431         struct blentry_device * ble;
432         int i;
433
434         if (!blist)
435                 return;
436
437         vector_foreach_slot (blist, ble, i) {
438                 if (ble) {
439                         if (ble->vendor) {
440                                 regfree(&ble->vendor_reg);
441                                 FREE(ble->vendor);
442                         }
443                         if (ble->product) {
444                                 regfree(&ble->product_reg);
445                                 FREE(ble->product);
446                         }
447                         FREE(ble);
448                 }
449         }
450         vector_free(blist);
451 }