/* * Copyright (c) 2018 Benjamin Marzinski, Redhat * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include #include #include #include "globals.c" #include "blacklist.h" #include "test-log.h" struct udev_device { const char *sysname; char *property_list[]; }; const char * __wrap_udev_device_get_sysname(struct udev_device *udev_device) { assert_non_null(udev_device); assert_non_null(udev_device->sysname); return udev_device->sysname; } struct udev_list_entry * __wrap_udev_device_get_properties_list_entry(struct udev_device *udev_device) { assert_non_null(udev_device); if (!*udev_device->property_list) return NULL; return (struct udev_list_entry *)udev_device->property_list; } struct udev_list_entry * __wrap_udev_list_entry_get_next(struct udev_list_entry *list_entry) { assert_non_null(list_entry); if (!*((char **)list_entry + 1)) return NULL; return (struct udev_list_entry *)(((char **)list_entry) + 1); } const char * __wrap_udev_list_entry_get_name(struct udev_list_entry *list_entry) { return *(const char **)list_entry; } vector blist_devnode_sdb; vector blist_all; vector blist_device_foo_bar; vector blist_device_all; vector blist_wwid_xyzzy; vector blist_protocol_fcp; vector blist_property_wwn; static int setup(void **state) { blist_devnode_sdb = vector_alloc(); if (!blist_devnode_sdb || store_ble(blist_devnode_sdb, strdup("sdb"), ORIGIN_CONFIG)) return -1; blist_all = vector_alloc(); if (!blist_all || store_ble(blist_all, strdup(".*"), ORIGIN_CONFIG)) return -1; blist_device_foo_bar = vector_alloc(); if (!blist_device_foo_bar || alloc_ble_device(blist_device_foo_bar) || set_ble_device(blist_device_foo_bar, strdup("foo"), strdup("bar"), ORIGIN_CONFIG)) return -1; blist_device_all = vector_alloc(); if (!blist_device_all || alloc_ble_device(blist_device_all) || set_ble_device(blist_device_all, strdup(".*"), strdup(".*"), ORIGIN_CONFIG)) return -1; blist_wwid_xyzzy = vector_alloc(); if (!blist_wwid_xyzzy || store_ble(blist_wwid_xyzzy, strdup("xyzzy"), ORIGIN_CONFIG)) return -1; blist_protocol_fcp = vector_alloc(); if (!blist_protocol_fcp || store_ble(blist_protocol_fcp, strdup("scsi:fcp"), ORIGIN_CONFIG)) return -1; blist_property_wwn = vector_alloc(); if (!blist_property_wwn || store_ble(blist_property_wwn, strdup("ID_WWN"), ORIGIN_CONFIG)) return -1; return 0; } static int teardown(void **state) { free_blacklist(blist_devnode_sdb); free_blacklist(blist_all); free_blacklist_device(blist_device_foo_bar); free_blacklist_device(blist_device_all); free_blacklist(blist_wwid_xyzzy); free_blacklist(blist_protocol_fcp); free_blacklist(blist_property_wwn); return 0; } static int reset_blists(void **state) { conf.blist_devnode = NULL; conf.blist_wwid = NULL; conf.blist_property = NULL; conf.blist_protocol = NULL; conf.blist_device = NULL; conf.elist_devnode = NULL; conf.elist_wwid = NULL; conf.elist_property = NULL; conf.elist_protocol = NULL; conf.elist_device = NULL; return 0; } static void test_devnode_blacklist(void **state) { expect_condlog(3, "sdb: device node name blacklisted\n"); assert_int_equal(filter_devnode(blist_devnode_sdb, NULL, "sdb"), MATCH_DEVNODE_BLIST); } static void test_devnode_whitelist(void **state) { expect_condlog(3, "sdb: device node name whitelisted\n"); assert_int_equal(filter_devnode(blist_all, blist_devnode_sdb, "sdb"), MATCH_DEVNODE_BLIST_EXCEPT); expect_condlog(3, "sdc: device node name blacklisted\n"); assert_int_equal(filter_devnode(blist_all, blist_devnode_sdb, "sdc"), MATCH_DEVNODE_BLIST); } static void test_devnode_missing(void **state) { assert_int_equal(filter_devnode(blist_devnode_sdb, NULL, "sdc"), MATCH_NOTHING); } static void test_device_blacklist(void **state) { expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n"); assert_int_equal(filter_device(blist_device_foo_bar, NULL, "foo", "bar", "sdb"), MATCH_DEVICE_BLIST); } static void test_device_whitelist(void **state) { expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n"); assert_int_equal(filter_device(blist_device_all, blist_device_foo_bar, "foo", "bar", "sdb"), MATCH_DEVICE_BLIST_EXCEPT); expect_condlog(3, "sdb: (foo:baz) vendor/product blacklisted\n"); assert_int_equal(filter_device(blist_device_all, blist_device_foo_bar, "foo", "baz", "sdb"), MATCH_DEVICE_BLIST); } static void test_device_missing(void **state) { assert_int_equal(filter_device(blist_device_foo_bar, NULL, "foo", "baz", "sdb"), MATCH_NOTHING); } static void test_wwid_blacklist(void **state) { expect_condlog(3, "sdb: wwid xyzzy blacklisted\n"); assert_int_equal(filter_wwid(blist_wwid_xyzzy, NULL, "xyzzy", "sdb"), MATCH_WWID_BLIST); } static void test_wwid_whitelist(void **state) { expect_condlog(3, "sdb: wwid xyzzy whitelisted\n"); assert_int_equal(filter_wwid(blist_all, blist_wwid_xyzzy, "xyzzy", "sdb"), MATCH_WWID_BLIST_EXCEPT); expect_condlog(3, "sdb: wwid plugh blacklisted\n"); assert_int_equal(filter_wwid(blist_all, blist_wwid_xyzzy, "plugh", "sdb"), MATCH_WWID_BLIST); } static void test_wwid_missing(void **state) { assert_int_equal(filter_wwid(blist_wwid_xyzzy, NULL, "plugh", "sdb"), MATCH_NOTHING); } static void test_protocol_blacklist(void **state) { struct path pp = { .dev = "sdb", .bus = SYSFS_BUS_SCSI, .sg_id.proto_id = SCSI_PROTOCOL_FCP }; expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n"); assert_int_equal(filter_protocol(blist_protocol_fcp, NULL, &pp), MATCH_PROTOCOL_BLIST); } static void test_protocol_whitelist(void **state) { struct path pp1 = { .dev = "sdb", .bus = SYSFS_BUS_SCSI, .sg_id.proto_id = SCSI_PROTOCOL_FCP }; struct path pp2 = { .dev = "sdb", .bus = SYSFS_BUS_SCSI, .sg_id.proto_id = SCSI_PROTOCOL_ISCSI }; expect_condlog(3, "sdb: protocol scsi:fcp whitelisted\n"); assert_int_equal(filter_protocol(blist_all, blist_protocol_fcp, &pp1), MATCH_PROTOCOL_BLIST_EXCEPT); expect_condlog(3, "sdb: protocol scsi:iscsi blacklisted\n"); assert_int_equal(filter_protocol(blist_all, blist_protocol_fcp, &pp2), MATCH_PROTOCOL_BLIST); } static void test_protocol_missing(void **state) { struct path pp = { .dev = "sdb", .bus = SYSFS_BUS_SCSI, .sg_id.proto_id = SCSI_PROTOCOL_ISCSI }; assert_int_equal(filter_protocol(blist_protocol_fcp, NULL, &pp), MATCH_NOTHING); } static void test_property_blacklist(void **state) { static struct udev_device udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } }; conf.blist_property = blist_property_wwn; expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n"); assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"), MATCH_PROPERTY_BLIST); } /* the property check works different in that you check all the property * names, so setting a blacklist value will blacklist the device if any * of the property on the blacklist are found before the property names * in the whitelist. This might be worth changing. although it would * force multipath to go through the properties twice */ static void test_property_whitelist(void **state) { static struct udev_device udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } }; conf.elist_property = blist_property_wwn; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"), MATCH_PROPERTY_BLIST_EXCEPT); } static void test_property_missing(void **state) { static struct udev_device udev = { "sdb", { "ID_FOO", "ID_BAZ", "ID_BAR", "ID_SERIAL", NULL } }; conf.blist_property = blist_property_wwn; expect_condlog(3, "sdb: blacklisted, udev property missing\n"); assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"), MATCH_PROPERTY_BLIST_MISSING); assert_int_equal(filter_property(&conf, &udev, 3, "ID_BLAH"), MATCH_NOTHING); assert_int_equal(filter_property(&conf, &udev, 3, ""), MATCH_NOTHING); assert_int_equal(filter_property(&conf, &udev, 3, NULL), MATCH_NOTHING); } struct udev_device test_udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } }; struct path test_pp = { .dev = "sdb", .bus = SYSFS_BUS_SCSI, .udev = &test_udev, .sg_id.proto_id = SCSI_PROTOCOL_FCP, .vendor_id = "foo", .product_id = "bar", .wwid = "xyzzy" }; static void test_filter_path_property(void **state) { conf.blist_property = blist_property_wwn; expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROPERTY_BLIST); } static void test_filter_path_devnode(void **state) { /* always must include property elist, to avoid "missing property" * blacklisting */ conf.elist_property = blist_property_wwn; conf.blist_devnode = blist_devnode_sdb; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); expect_condlog(3, "sdb: device node name blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVNODE_BLIST); } static void test_filter_path_device(void **state) { /* always must include property elist, to avoid "missing property" * blacklisting */ conf.elist_property = blist_property_wwn; conf.blist_device = blist_device_foo_bar; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVICE_BLIST); } static void test_filter_path_protocol(void **state) { conf.elist_property = blist_property_wwn; conf.blist_protocol = blist_protocol_fcp; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROTOCOL_BLIST); } static void test_filter_path_wwid(void **state) { conf.elist_property = blist_property_wwn; conf.blist_wwid = blist_wwid_xyzzy; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); expect_condlog(3, "sdb: wwid xyzzy blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_WWID_BLIST); } struct udev_device miss_udev = { "sdb", { "ID_FOO", "ID_BAZ", "ID_BAR", "ID_SERIAL", NULL } }; struct path miss1_pp = { .dev = "sdc", .bus = SYSFS_BUS_SCSI, .udev = &miss_udev, .uid_attribute = "ID_SERIAL", .sg_id.proto_id = SCSI_PROTOCOL_ISCSI, .vendor_id = "foo", .product_id = "baz", .wwid = "plugh" }; struct path miss2_pp = { .dev = "sdc", .bus = SYSFS_BUS_SCSI, .udev = &test_udev, .uid_attribute = "ID_SERIAL", .sg_id.proto_id = SCSI_PROTOCOL_ISCSI, .vendor_id = "foo", .product_id = "baz", .wwid = "plugh" }; struct path miss3_pp = { .dev = "sdc", .bus = SYSFS_BUS_SCSI, .udev = &miss_udev, .uid_attribute = "ID_EGGS", .sg_id.proto_id = SCSI_PROTOCOL_ISCSI, .vendor_id = "foo", .product_id = "baz", .wwid = "plugh" }; static void test_filter_path_missing1(void **state) { conf.blist_property = blist_property_wwn; conf.blist_devnode = blist_devnode_sdb; conf.blist_device = blist_device_foo_bar; conf.blist_protocol = blist_protocol_fcp; conf.blist_wwid = blist_wwid_xyzzy; expect_condlog(3, "sdb: blacklisted, udev property missing\n"); assert_int_equal(filter_path(&conf, &miss1_pp), MATCH_PROPERTY_BLIST_MISSING); } /* This one matches the property whitelist, to test the other missing * functions */ static void test_filter_path_missing2(void **state) { conf.elist_property = blist_property_wwn; conf.blist_devnode = blist_devnode_sdb; conf.blist_device = blist_device_foo_bar; conf.blist_protocol = blist_protocol_fcp; conf.blist_wwid = blist_wwid_xyzzy; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); assert_int_equal(filter_path(&conf, &miss2_pp), MATCH_NOTHING); } /* Here we use a different uid_attribute which is also missing, thus the path is not blacklisted */ static void test_filter_path_missing3(void **state) { conf.blist_property = blist_property_wwn; conf.blist_devnode = blist_devnode_sdb; conf.blist_device = blist_device_foo_bar; conf.blist_protocol = blist_protocol_fcp; conf.blist_wwid = blist_wwid_xyzzy; assert_int_equal(filter_path(&conf, &miss3_pp), MATCH_NOTHING); } static void test_filter_path_whitelist(void **state) { conf.elist_property = blist_property_wwn; conf.elist_devnode = blist_devnode_sdb; conf.elist_device = blist_device_foo_bar; conf.elist_protocol = blist_protocol_fcp; conf.elist_wwid = blist_wwid_xyzzy; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); expect_condlog(3, "sdb: device node name whitelisted\n"); expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n"); expect_condlog(3, "sdb: protocol scsi:fcp whitelisted\n"); expect_condlog(3, "sdb: wwid xyzzy whitelisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_WWID_BLIST_EXCEPT); } static void test_filter_path_whitelist_property(void **state) { conf.blist_property = blist_property_wwn; conf.elist_devnode = blist_devnode_sdb; conf.elist_device = blist_device_foo_bar; conf.elist_protocol = blist_protocol_fcp; conf.elist_wwid = blist_wwid_xyzzy; expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROPERTY_BLIST); } static void test_filter_path_whitelist_devnode(void **state) { conf.elist_property = blist_property_wwn; conf.blist_devnode = blist_devnode_sdb; conf.elist_device = blist_device_foo_bar; conf.elist_protocol = blist_protocol_fcp; conf.elist_wwid = blist_wwid_xyzzy; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); expect_condlog(3, "sdb: device node name blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVNODE_BLIST); } static void test_filter_path_whitelist_device(void **state) { conf.elist_property = blist_property_wwn; conf.elist_devnode = blist_devnode_sdb; conf.blist_device = blist_device_foo_bar; conf.elist_protocol = blist_protocol_fcp; conf.elist_wwid = blist_wwid_xyzzy; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); expect_condlog(3, "sdb: device node name whitelisted\n"); expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVICE_BLIST); } static void test_filter_path_whitelist_protocol(void **state) { conf.elist_property = blist_property_wwn; conf.elist_devnode = blist_devnode_sdb; conf.elist_device = blist_device_foo_bar; conf.blist_protocol = blist_protocol_fcp; conf.elist_wwid = blist_wwid_xyzzy; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); expect_condlog(3, "sdb: device node name whitelisted\n"); expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n"); expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROTOCOL_BLIST); } static void test_filter_path_whitelist_wwid(void **state) { conf.elist_property = blist_property_wwn; conf.elist_devnode = blist_devnode_sdb; conf.elist_device = blist_device_foo_bar; conf.elist_protocol = blist_protocol_fcp; conf.blist_wwid = blist_wwid_xyzzy; expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n"); expect_condlog(3, "sdb: device node name whitelisted\n"); expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n"); expect_condlog(3, "sdb: protocol scsi:fcp whitelisted\n"); expect_condlog(3, "sdb: wwid xyzzy blacklisted\n"); assert_int_equal(filter_path(&conf, &test_pp), MATCH_WWID_BLIST); } #define test_and_reset(x) cmocka_unit_test_teardown((x), reset_blists) int test_blacklist(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_devnode_blacklist), cmocka_unit_test(test_devnode_whitelist), cmocka_unit_test(test_devnode_missing), cmocka_unit_test(test_device_blacklist), cmocka_unit_test(test_device_whitelist), cmocka_unit_test(test_device_missing), cmocka_unit_test(test_wwid_blacklist), cmocka_unit_test(test_wwid_whitelist), cmocka_unit_test(test_wwid_missing), cmocka_unit_test(test_protocol_blacklist), cmocka_unit_test(test_protocol_whitelist), cmocka_unit_test(test_protocol_missing), test_and_reset(test_property_blacklist), test_and_reset(test_property_whitelist), test_and_reset(test_property_missing), test_and_reset(test_filter_path_property), test_and_reset(test_filter_path_devnode), test_and_reset(test_filter_path_device), test_and_reset(test_filter_path_protocol), test_and_reset(test_filter_path_wwid), test_and_reset(test_filter_path_missing1), test_and_reset(test_filter_path_missing2), test_and_reset(test_filter_path_missing3), test_and_reset(test_filter_path_whitelist), test_and_reset(test_filter_path_whitelist_property), test_and_reset(test_filter_path_whitelist_devnode), test_and_reset(test_filter_path_whitelist_device), test_and_reset(test_filter_path_whitelist_protocol), test_and_reset(test_filter_path_whitelist_wwid), }; return cmocka_run_group_tests(tests, setup, teardown); } int main(void) { int ret = 0; ret += test_blacklist(); return ret; }