| /* | |
| * Copyright (C) 2019 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <functional> | |
| #include <android-base/file.h> | |
| #include <android-base/macros.h> | |
| #include <android-base/unique_fd.h> | |
| #include <gtest/gtest.h> | |
| #include <modprobe/modprobe.h> | |
| #include "libmodprobe_test.h" | |
| // Used by libmodprobe_ext_test to check if requested modules are present. | |
| std::vector<std::string> test_modules; | |
| // Used by libmodprobe_ext_test to report which modules would have been loaded. | |
| std::vector<std::string> modules_loaded; | |
| // Used by libmodprobe_ext_test to fake a kernel commandline | |
| std::string kernel_cmdline; | |
| TEST(libmodprobe, Test) { | |
| kernel_cmdline = | |
| "flag1 flag2 test1.option1=50 test4.option3=\"set x\" test1.option2=60 " | |
| "test8. test5.option1= test10.option1=1"; | |
| test_modules = { | |
| "/test1.ko", "/test2.ko", "/test3.ko", "/test4.ko", "/test5.ko", | |
| "/test6.ko", "/test7.ko", "/test8.ko", "/test9.ko", "/test10.ko", | |
| "/test11.ko", "/test12.ko", "/test13.ko", "/test14.ko", "/test15.ko", | |
| }; | |
| std::vector<std::string> expected_modules_loaded = { | |
| "/test14.ko", | |
| "/test15.ko", | |
| "/test3.ko", | |
| "/test4.ko option3=\"set x\"", | |
| "/test1.ko option1=50 option2=60", | |
| "/test6.ko", | |
| "/test2.ko", | |
| "/test5.ko option1=", | |
| "/test8.ko", | |
| "/test7.ko param1=4", | |
| "/test9.ko param_x=1 param_y=2 param_z=3", | |
| "/test10.ko option1=1", | |
| "/test12.ko", | |
| "/test11.ko", | |
| "/test13.ko", | |
| }; | |
| std::vector<std::string> expected_after_remove = { | |
| "/test14.ko", | |
| "/test15.ko", | |
| "/test1.ko option1=50 option2=60", | |
| "/test6.ko", | |
| "/test2.ko", | |
| "/test5.ko option1=", | |
| "/test8.ko", | |
| "/test7.ko param1=4", | |
| "/test9.ko param_x=1 param_y=2 param_z=3", | |
| "/test10.ko option1=1", | |
| "/test12.ko", | |
| "/test11.ko", | |
| "/test13.ko", | |
| }; | |
| std::vector<std::string> expected_modules_blocklist_enabled = { | |
| "/test1.ko option1=50 option2=60", | |
| "/test6.ko", | |
| "/test2.ko", | |
| "/test5.ko option1=", | |
| "/test8.ko", | |
| "/test7.ko param1=4", | |
| "/test12.ko", | |
| "/test11.ko", | |
| "/test13.ko", | |
| }; | |
| const std::string modules_dep = | |
| "test1.ko:\n" | |
| "test2.ko:\n" | |
| "test3.ko:\n" | |
| "test4.ko: test3.ko\n" | |
| "test5.ko: test2.ko test6.ko\n" | |
| "test6.ko:\n" | |
| "test7.ko:\n" | |
| "test8.ko:\n" | |
| "test9.ko:\n" | |
| "test10.ko:\n" | |
| "test11.ko:\n" | |
| "test12.ko:\n" | |
| "test13.ko:\n" | |
| "test14.ko:\n" | |
| "test15.ko:\n"; | |
| const std::string modules_softdep = | |
| "softdep test7 pre: test8\n" | |
| "softdep test9 post: test10\n" | |
| "softdep test11 pre: test12 post: test13\n" | |
| "softdep test3 pre: test141516\n"; | |
| const std::string modules_alias = | |
| "# Aliases extracted from modules themselves.\n" | |
| "\n" | |
| "alias test141516 test14\n" | |
| "alias test141516 test15\n" | |
| "alias test141516 test16\n"; | |
| const std::string modules_options = | |
| "options test7.ko param1=4\n" | |
| "options test9.ko param_x=1 param_y=2 param_z=3\n" | |
| "options test100.ko param_1=1\n"; | |
| const std::string modules_blocklist = | |
| "blocklist test9.ko\n" | |
| "blocklist test3.ko\n"; | |
| const std::string modules_load = | |
| "test4.ko\n" | |
| "test1.ko\n" | |
| "test3.ko\n" | |
| "test5.ko\n" | |
| "test7.ko\n" | |
| "test9.ko\n" | |
| "test11.ko\n"; | |
| TemporaryDir dir; | |
| auto dir_path = std::string(dir.path); | |
| ASSERT_TRUE(android::base::WriteStringToFile(modules_alias, dir_path + "/modules.alias", 0600, | |
| getuid(), getgid())); | |
| ASSERT_TRUE(android::base::WriteStringToFile(modules_dep, dir_path + "/modules.dep", 0600, | |
| getuid(), getgid())); | |
| ASSERT_TRUE(android::base::WriteStringToFile(modules_softdep, dir_path + "/modules.softdep", | |
| 0600, getuid(), getgid())); | |
| ASSERT_TRUE(android::base::WriteStringToFile(modules_options, dir_path + "/modules.options", | |
| 0600, getuid(), getgid())); | |
| ASSERT_TRUE(android::base::WriteStringToFile(modules_load, dir_path + "/modules.load", 0600, | |
| getuid(), getgid())); | |
| ASSERT_TRUE(android::base::WriteStringToFile(modules_blocklist, dir_path + "/modules.blocklist", | |
| 0600, getuid(), getgid())); | |
| for (auto i = test_modules.begin(); i != test_modules.end(); ++i) { | |
| *i = dir.path + *i; | |
| } | |
| Modprobe m({dir.path}, "modules.load", false); | |
| EXPECT_TRUE(m.LoadListedModules()); | |
| GTEST_LOG_(INFO) << "Expected modules loaded (in order):"; | |
| for (auto i = expected_modules_loaded.begin(); i != expected_modules_loaded.end(); ++i) { | |
| *i = dir.path + *i; | |
| GTEST_LOG_(INFO) << "\"" << *i << "\""; | |
| } | |
| GTEST_LOG_(INFO) << "Actual modules loaded (in order):"; | |
| for (auto i = modules_loaded.begin(); i != modules_loaded.end(); ++i) { | |
| GTEST_LOG_(INFO) << "\"" << *i << "\""; | |
| } | |
| EXPECT_TRUE(modules_loaded == expected_modules_loaded); | |
| EXPECT_TRUE(m.GetModuleCount() == 15); | |
| EXPECT_TRUE(m.Remove("test4")); | |
| GTEST_LOG_(INFO) << "Expected modules loaded after removing test4 (in order):"; | |
| for (auto i = expected_after_remove.begin(); i != expected_after_remove.end(); ++i) { | |
| *i = dir.path + *i; | |
| GTEST_LOG_(INFO) << "\"" << *i << "\""; | |
| } | |
| GTEST_LOG_(INFO) << "Actual modules loaded after removing test4 (in order):"; | |
| for (auto i = modules_loaded.begin(); i != modules_loaded.end(); ++i) { | |
| GTEST_LOG_(INFO) << "\"" << *i << "\""; | |
| } | |
| EXPECT_TRUE(modules_loaded == expected_after_remove); | |
| Modprobe m2({dir.path}); | |
| EXPECT_FALSE(m2.LoadWithAliases("test4", true)); | |
| while (modules_loaded.size() > 0) EXPECT_TRUE(m2.Remove(modules_loaded.front())); | |
| EXPECT_TRUE(m2.LoadListedModules()); | |
| GTEST_LOG_(INFO) << "Expected modules loaded after enabling blocklist (in order):"; | |
| for (auto i = expected_modules_blocklist_enabled.begin(); | |
| i != expected_modules_blocklist_enabled.end(); ++i) { | |
| *i = dir.path + *i; | |
| GTEST_LOG_(INFO) << "\"" << *i << "\""; | |
| } | |
| GTEST_LOG_(INFO) << "Actual modules loaded with blocklist enabled (in order):"; | |
| for (auto i = modules_loaded.begin(); i != modules_loaded.end(); ++i) { | |
| GTEST_LOG_(INFO) << "\"" << *i << "\""; | |
| } | |
| EXPECT_TRUE(modules_loaded == expected_modules_blocklist_enabled); | |
| } | |
| TEST(libmodprobe, ModuleDepLineWithoutColonIsSkipped) { | |
| TemporaryDir dir; | |
| auto dir_path = std::string(dir.path); | |
| ASSERT_TRUE(android::base::WriteStringToFile( | |
| "no_colon.ko no_colon.ko\n", dir_path + "/modules.dep", 0600, getuid(), getgid())); | |
| kernel_cmdline = ""; | |
| test_modules = {dir_path + "/no_colon.ko"}; | |
| Modprobe m({dir.path}); | |
| EXPECT_FALSE(m.LoadWithAliases("no_colon", true)); | |
| } |