2 * Copyright (c) 2018 Benjamin Marzinski, Redhat
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 #include "blacklist.h"
28 char *property_list[];
32 __wrap_udev_device_get_sysname(struct udev_device *udev_device)
34 assert_non_null(udev_device);
35 assert_non_null(udev_device->sysname);
36 return udev_device->sysname;
39 struct udev_list_entry *
40 __wrap_udev_device_get_properties_list_entry(struct udev_device *udev_device)
42 assert_non_null(udev_device);
43 if (!*udev_device->property_list)
45 return (struct udev_list_entry *)udev_device->property_list;
48 struct udev_list_entry *
49 __wrap_udev_list_entry_get_next(struct udev_list_entry *list_entry)
51 assert_non_null(list_entry);
52 if (!*((char **)list_entry + 1))
54 return (struct udev_list_entry *)(((char **)list_entry) + 1);
58 __wrap_udev_list_entry_get_name(struct udev_list_entry *list_entry)
60 return *(const char **)list_entry;
63 vector blist_devnode_sdb;
65 vector blist_device_foo_bar;
66 vector blist_device_all;
67 vector blist_wwid_xyzzy;
68 vector blist_protocol_fcp;
69 vector blist_property_wwn;
71 static int setup(void **state)
73 blist_devnode_sdb = vector_alloc();
74 if (!blist_devnode_sdb ||
75 store_ble(blist_devnode_sdb, strdup("sdb"), ORIGIN_CONFIG))
78 blist_all = vector_alloc();
79 if (!blist_all || store_ble(blist_all, strdup(".*"), ORIGIN_CONFIG))
82 blist_device_foo_bar = vector_alloc();
83 if (!blist_device_foo_bar || alloc_ble_device(blist_device_foo_bar) ||
84 set_ble_device(blist_device_foo_bar, strdup("foo"), strdup("bar"),
88 blist_device_all = vector_alloc();
89 if (!blist_device_all || alloc_ble_device(blist_device_all) ||
90 set_ble_device(blist_device_all, strdup(".*"), strdup(".*"),
94 blist_wwid_xyzzy = vector_alloc();
95 if (!blist_wwid_xyzzy ||
96 store_ble(blist_wwid_xyzzy, strdup("xyzzy"), ORIGIN_CONFIG))
99 blist_protocol_fcp = vector_alloc();
100 if (!blist_protocol_fcp ||
101 store_ble(blist_protocol_fcp, strdup("scsi:fcp"), ORIGIN_CONFIG))
104 blist_property_wwn = vector_alloc();
105 if (!blist_property_wwn ||
106 store_ble(blist_property_wwn, strdup("ID_WWN"), ORIGIN_CONFIG))
112 static int teardown(void **state)
114 free_blacklist(blist_devnode_sdb);
115 free_blacklist(blist_all);
116 free_blacklist_device(blist_device_foo_bar);
117 free_blacklist_device(blist_device_all);
118 free_blacklist(blist_wwid_xyzzy);
119 free_blacklist(blist_protocol_fcp);
120 free_blacklist(blist_property_wwn);
124 static int reset_blists(void **state)
126 conf.blist_devnode = NULL;
127 conf.blist_wwid = NULL;
128 conf.blist_property = NULL;
129 conf.blist_protocol = NULL;
130 conf.blist_device = NULL;
131 conf.elist_devnode = NULL;
132 conf.elist_wwid = NULL;
133 conf.elist_property = NULL;
134 conf.elist_protocol = NULL;
135 conf.elist_device = NULL;
139 static void test_devnode_blacklist(void **state)
141 expect_condlog(3, "sdb: device node name blacklisted\n");
142 assert_int_equal(filter_devnode(blist_devnode_sdb, NULL, "sdb"),
143 MATCH_DEVNODE_BLIST);
146 static void test_devnode_whitelist(void **state)
148 expect_condlog(3, "sdb: device node name whitelisted\n");
149 assert_int_equal(filter_devnode(blist_all, blist_devnode_sdb, "sdb"),
150 MATCH_DEVNODE_BLIST_EXCEPT);
151 expect_condlog(3, "sdc: device node name blacklisted\n");
152 assert_int_equal(filter_devnode(blist_all, blist_devnode_sdb, "sdc"),
153 MATCH_DEVNODE_BLIST);
156 static void test_devnode_missing(void **state)
158 assert_int_equal(filter_devnode(blist_devnode_sdb, NULL, "sdc"),
162 static void test_device_blacklist(void **state)
164 expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n");
165 assert_int_equal(filter_device(blist_device_foo_bar, NULL, "foo",
170 static void test_device_whitelist(void **state)
172 expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n");
173 assert_int_equal(filter_device(blist_device_all, blist_device_foo_bar,
174 "foo", "bar", "sdb"),
175 MATCH_DEVICE_BLIST_EXCEPT);
176 expect_condlog(3, "sdb: (foo:baz) vendor/product blacklisted\n");
177 assert_int_equal(filter_device(blist_device_all, blist_device_foo_bar,
178 "foo", "baz", "sdb"),
182 static void test_device_missing(void **state)
184 assert_int_equal(filter_device(blist_device_foo_bar, NULL, "foo",
189 static void test_wwid_blacklist(void **state)
191 expect_condlog(3, "sdb: wwid xyzzy blacklisted\n");
192 assert_int_equal(filter_wwid(blist_wwid_xyzzy, NULL, "xyzzy", "sdb"),
196 static void test_wwid_whitelist(void **state)
198 expect_condlog(3, "sdb: wwid xyzzy whitelisted\n");
199 assert_int_equal(filter_wwid(blist_all, blist_wwid_xyzzy,
201 MATCH_WWID_BLIST_EXCEPT);
202 expect_condlog(3, "sdb: wwid plugh blacklisted\n");
203 assert_int_equal(filter_wwid(blist_all, blist_wwid_xyzzy,
208 static void test_wwid_missing(void **state)
210 assert_int_equal(filter_wwid(blist_wwid_xyzzy, NULL, "plugh", "sdb"),
214 static void test_protocol_blacklist(void **state)
216 struct path pp = { .dev = "sdb", .bus = SYSFS_BUS_SCSI,
217 .sg_id.proto_id = SCSI_PROTOCOL_FCP };
218 expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n");
219 assert_int_equal(filter_protocol(blist_protocol_fcp, NULL, &pp),
220 MATCH_PROTOCOL_BLIST);
223 static void test_protocol_whitelist(void **state)
225 struct path pp1 = { .dev = "sdb", .bus = SYSFS_BUS_SCSI,
226 .sg_id.proto_id = SCSI_PROTOCOL_FCP };
227 struct path pp2 = { .dev = "sdb", .bus = SYSFS_BUS_SCSI,
228 .sg_id.proto_id = SCSI_PROTOCOL_ISCSI };
229 expect_condlog(3, "sdb: protocol scsi:fcp whitelisted\n");
230 assert_int_equal(filter_protocol(blist_all, blist_protocol_fcp, &pp1),
231 MATCH_PROTOCOL_BLIST_EXCEPT);
232 expect_condlog(3, "sdb: protocol scsi:iscsi blacklisted\n");
233 assert_int_equal(filter_protocol(blist_all, blist_protocol_fcp, &pp2),
234 MATCH_PROTOCOL_BLIST);
237 static void test_protocol_missing(void **state)
239 struct path pp = { .dev = "sdb", .bus = SYSFS_BUS_SCSI,
240 .sg_id.proto_id = SCSI_PROTOCOL_ISCSI };
241 assert_int_equal(filter_protocol(blist_protocol_fcp, NULL, &pp),
245 static void test_property_blacklist(void **state)
247 static struct udev_device udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } };
248 conf.blist_property = blist_property_wwn;
249 expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n");
250 assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
251 MATCH_PROPERTY_BLIST);
254 /* the property check works different in that you check all the property
255 * names, so setting a blacklist value will blacklist the device if any
256 * of the property on the blacklist are found before the property names
257 * in the whitelist. This might be worth changing. although it would
258 * force multipath to go through the properties twice */
259 static void test_property_whitelist(void **state)
261 static struct udev_device udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } };
262 conf.elist_property = blist_property_wwn;
263 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
264 assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
265 MATCH_PROPERTY_BLIST_EXCEPT);
268 static void test_property_missing(void **state)
270 static struct udev_device udev = { "sdb", { "ID_FOO", "ID_BAZ", "ID_BAR", "ID_SERIAL", NULL } };
271 conf.blist_property = blist_property_wwn;
272 expect_condlog(3, "sdb: blacklisted, udev property missing\n");
273 assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
274 MATCH_PROPERTY_BLIST_MISSING);
275 assert_int_equal(filter_property(&conf, &udev, 3, "ID_BLAH"),
277 assert_int_equal(filter_property(&conf, &udev, 3, ""),
279 assert_int_equal(filter_property(&conf, &udev, 3, NULL),
283 struct udev_device test_udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } };
285 struct path test_pp = { .dev = "sdb", .bus = SYSFS_BUS_SCSI, .udev = &test_udev,
286 .sg_id.proto_id = SCSI_PROTOCOL_FCP, .vendor_id = "foo",
287 .product_id = "bar", .wwid = "xyzzy" };
289 static void test_filter_path_property(void **state)
291 conf.blist_property = blist_property_wwn;
292 expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n");
293 assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROPERTY_BLIST);
296 static void test_filter_path_devnode(void **state)
298 /* always must include property elist, to avoid "missing property"
300 conf.elist_property = blist_property_wwn;
301 conf.blist_devnode = blist_devnode_sdb;
302 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
303 expect_condlog(3, "sdb: device node name blacklisted\n");
304 assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVNODE_BLIST);
307 static void test_filter_path_device(void **state)
309 /* always must include property elist, to avoid "missing property"
311 conf.elist_property = blist_property_wwn;
312 conf.blist_device = blist_device_foo_bar;
313 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
314 expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n");
315 assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVICE_BLIST);
318 static void test_filter_path_protocol(void **state)
320 conf.elist_property = blist_property_wwn;
321 conf.blist_protocol = blist_protocol_fcp;
322 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
323 expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n");
324 assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROTOCOL_BLIST);
327 static void test_filter_path_wwid(void **state)
329 conf.elist_property = blist_property_wwn;
330 conf.blist_wwid = blist_wwid_xyzzy;
331 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
332 expect_condlog(3, "sdb: wwid xyzzy blacklisted\n");
333 assert_int_equal(filter_path(&conf, &test_pp), MATCH_WWID_BLIST);
336 struct udev_device miss_udev = { "sdb", { "ID_FOO", "ID_BAZ", "ID_BAR", "ID_SERIAL", NULL } };
338 struct path miss1_pp = { .dev = "sdc", .bus = SYSFS_BUS_SCSI,
340 .uid_attribute = "ID_SERIAL",
341 .sg_id.proto_id = SCSI_PROTOCOL_ISCSI,
342 .vendor_id = "foo", .product_id = "baz",
345 struct path miss2_pp = { .dev = "sdc", .bus = SYSFS_BUS_SCSI,
347 .uid_attribute = "ID_SERIAL",
348 .sg_id.proto_id = SCSI_PROTOCOL_ISCSI,
349 .vendor_id = "foo", .product_id = "baz",
352 struct path miss3_pp = { .dev = "sdc", .bus = SYSFS_BUS_SCSI,
354 .uid_attribute = "ID_EGGS",
355 .sg_id.proto_id = SCSI_PROTOCOL_ISCSI,
356 .vendor_id = "foo", .product_id = "baz",
359 static void test_filter_path_missing1(void **state)
361 conf.blist_property = blist_property_wwn;
362 conf.blist_devnode = blist_devnode_sdb;
363 conf.blist_device = blist_device_foo_bar;
364 conf.blist_protocol = blist_protocol_fcp;
365 conf.blist_wwid = blist_wwid_xyzzy;
366 expect_condlog(3, "sdb: blacklisted, udev property missing\n");
367 assert_int_equal(filter_path(&conf, &miss1_pp),
368 MATCH_PROPERTY_BLIST_MISSING);
371 /* This one matches the property whitelist, to test the other missing
373 static void test_filter_path_missing2(void **state)
375 conf.elist_property = blist_property_wwn;
376 conf.blist_devnode = blist_devnode_sdb;
377 conf.blist_device = blist_device_foo_bar;
378 conf.blist_protocol = blist_protocol_fcp;
379 conf.blist_wwid = blist_wwid_xyzzy;
380 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
381 assert_int_equal(filter_path(&conf, &miss2_pp),
385 /* Here we use a different uid_attribute which is also missing, thus
386 the path is not blacklisted */
387 static void test_filter_path_missing3(void **state)
389 conf.blist_property = blist_property_wwn;
390 conf.blist_devnode = blist_devnode_sdb;
391 conf.blist_device = blist_device_foo_bar;
392 conf.blist_protocol = blist_protocol_fcp;
393 conf.blist_wwid = blist_wwid_xyzzy;
394 assert_int_equal(filter_path(&conf, &miss3_pp),
398 static void test_filter_path_whitelist(void **state)
400 conf.elist_property = blist_property_wwn;
401 conf.elist_devnode = blist_devnode_sdb;
402 conf.elist_device = blist_device_foo_bar;
403 conf.elist_protocol = blist_protocol_fcp;
404 conf.elist_wwid = blist_wwid_xyzzy;
405 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
406 expect_condlog(3, "sdb: device node name whitelisted\n");
407 expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n");
408 expect_condlog(3, "sdb: protocol scsi:fcp whitelisted\n");
409 expect_condlog(3, "sdb: wwid xyzzy whitelisted\n");
410 assert_int_equal(filter_path(&conf, &test_pp),
411 MATCH_WWID_BLIST_EXCEPT);
414 static void test_filter_path_whitelist_property(void **state)
416 conf.blist_property = blist_property_wwn;
417 conf.elist_devnode = blist_devnode_sdb;
418 conf.elist_device = blist_device_foo_bar;
419 conf.elist_protocol = blist_protocol_fcp;
420 conf.elist_wwid = blist_wwid_xyzzy;
421 expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n");
422 assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROPERTY_BLIST);
425 static void test_filter_path_whitelist_devnode(void **state)
427 conf.elist_property = blist_property_wwn;
428 conf.blist_devnode = blist_devnode_sdb;
429 conf.elist_device = blist_device_foo_bar;
430 conf.elist_protocol = blist_protocol_fcp;
431 conf.elist_wwid = blist_wwid_xyzzy;
432 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
433 expect_condlog(3, "sdb: device node name blacklisted\n");
434 assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVNODE_BLIST);
437 static void test_filter_path_whitelist_device(void **state)
439 conf.elist_property = blist_property_wwn;
440 conf.elist_devnode = blist_devnode_sdb;
441 conf.blist_device = blist_device_foo_bar;
442 conf.elist_protocol = blist_protocol_fcp;
443 conf.elist_wwid = blist_wwid_xyzzy;
444 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
445 expect_condlog(3, "sdb: device node name whitelisted\n");
446 expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n");
447 assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVICE_BLIST);
450 static void test_filter_path_whitelist_protocol(void **state)
452 conf.elist_property = blist_property_wwn;
453 conf.elist_devnode = blist_devnode_sdb;
454 conf.elist_device = blist_device_foo_bar;
455 conf.blist_protocol = blist_protocol_fcp;
456 conf.elist_wwid = blist_wwid_xyzzy;
457 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
458 expect_condlog(3, "sdb: device node name whitelisted\n");
459 expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n");
460 expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n");
461 assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROTOCOL_BLIST);
464 static void test_filter_path_whitelist_wwid(void **state)
466 conf.elist_property = blist_property_wwn;
467 conf.elist_devnode = blist_devnode_sdb;
468 conf.elist_device = blist_device_foo_bar;
469 conf.elist_protocol = blist_protocol_fcp;
470 conf.blist_wwid = blist_wwid_xyzzy;
471 expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
472 expect_condlog(3, "sdb: device node name whitelisted\n");
473 expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n");
474 expect_condlog(3, "sdb: protocol scsi:fcp whitelisted\n");
475 expect_condlog(3, "sdb: wwid xyzzy blacklisted\n");
476 assert_int_equal(filter_path(&conf, &test_pp), MATCH_WWID_BLIST);
479 #define test_and_reset(x) cmocka_unit_test_teardown((x), reset_blists)
481 int test_blacklist(void)
483 const struct CMUnitTest tests[] = {
484 cmocka_unit_test(test_devnode_blacklist),
485 cmocka_unit_test(test_devnode_whitelist),
486 cmocka_unit_test(test_devnode_missing),
487 cmocka_unit_test(test_device_blacklist),
488 cmocka_unit_test(test_device_whitelist),
489 cmocka_unit_test(test_device_missing),
490 cmocka_unit_test(test_wwid_blacklist),
491 cmocka_unit_test(test_wwid_whitelist),
492 cmocka_unit_test(test_wwid_missing),
493 cmocka_unit_test(test_protocol_blacklist),
494 cmocka_unit_test(test_protocol_whitelist),
495 cmocka_unit_test(test_protocol_missing),
496 test_and_reset(test_property_blacklist),
497 test_and_reset(test_property_whitelist),
498 test_and_reset(test_property_missing),
499 test_and_reset(test_filter_path_property),
500 test_and_reset(test_filter_path_devnode),
501 test_and_reset(test_filter_path_device),
502 test_and_reset(test_filter_path_protocol),
503 test_and_reset(test_filter_path_wwid),
504 test_and_reset(test_filter_path_missing1),
505 test_and_reset(test_filter_path_missing2),
506 test_and_reset(test_filter_path_missing3),
507 test_and_reset(test_filter_path_whitelist),
508 test_and_reset(test_filter_path_whitelist_property),
509 test_and_reset(test_filter_path_whitelist_devnode),
510 test_and_reset(test_filter_path_whitelist_device),
511 test_and_reset(test_filter_path_whitelist_protocol),
512 test_and_reset(test_filter_path_whitelist_wwid),
514 return cmocka_run_group_tests(tests, setup, teardown);
520 ret += test_blacklist();