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