diff options
-rw-r--r-- | init/Android.bp | 1 | ||||
-rw-r--r-- | init/devices.h | 27 | ||||
-rw-r--r-- | init/ueventd_parser.cpp | 4 | ||||
-rw-r--r-- | init/ueventd_parser_test.cpp | 224 |
4 files changed, 244 insertions, 12 deletions
diff --git a/init/Android.bp b/init/Android.bp index 625fb949a..5bbb7a09c 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -180,6 +180,7 @@ cc_test { "service_test.cpp", "subcontext_test.cpp", "tokenizer_test.cpp", + "ueventd_parser_test.cpp", "ueventd_test.cpp", "util_test.cpp", ], diff --git a/init/devices.h b/init/devices.h index 9224fcd82..0be660f80 100644 --- a/init/devices.h +++ b/init/devices.h @@ -35,6 +35,8 @@ namespace init { class Permissions { public: + friend void TestPermissions(const Permissions& expected, const Permissions& test); + Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid); bool Match(const std::string& path) const; @@ -57,6 +59,8 @@ class Permissions { class SysfsPermissions : public Permissions { public: + friend void TestSysfsPermissions(const SysfsPermissions& expected, const SysfsPermissions& test); + SysfsPermissions(const std::string& name, const std::string& attribute, mode_t perm, uid_t uid, gid_t gid) : Permissions(name, perm, uid, gid), attribute_(attribute) {} @@ -71,16 +75,24 @@ class SysfsPermissions : public Permissions { class Subsystem { public: friend class SubsystemParser; + friend void TestSubsystems(const Subsystem& expected, const Subsystem& test); + + enum DevnameSource { + DEVNAME_UEVENT_DEVNAME, + DEVNAME_UEVENT_DEVPATH, + }; Subsystem() {} - Subsystem(std::string name) : name_(std::move(name)) {} + Subsystem(const std::string& name) : name_(name) {} + Subsystem(const std::string& name, DevnameSource source, const std::string& dir_name) + : name_(name), devname_source_(source), dir_name_(dir_name) {} // Returns the full path for a uevent of a device that is a member of this subsystem, // according to the rules parsed from ueventd.rc std::string ParseDevPath(const Uevent& uevent) const { - std::string devname = devname_source_ == DevnameSource::DEVNAME_UEVENT_DEVNAME - ? uevent.device_name - : android::base::Basename(uevent.path); + std::string devname = devname_source_ == DEVNAME_UEVENT_DEVNAME + ? uevent.device_name + : android::base::Basename(uevent.path); return dir_name_ + "/" + devname; } @@ -88,14 +100,9 @@ class Subsystem { bool operator==(const std::string& string_name) const { return name_ == string_name; } private: - enum class DevnameSource { - DEVNAME_UEVENT_DEVNAME, - DEVNAME_UEVENT_DEVPATH, - }; - std::string name_; + DevnameSource devname_source_ = DEVNAME_UEVENT_DEVNAME; std::string dir_name_ = "/dev"; - DevnameSource devname_source_; }; class DeviceHandler { diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp index c114ec704..54b0d16aa 100644 --- a/init/ueventd_parser.cpp +++ b/init/ueventd_parser.cpp @@ -117,11 +117,11 @@ Result<Success> SubsystemParser::ParseSection(std::vector<std::string>&& args, Result<Success> SubsystemParser::ParseDevName(std::vector<std::string>&& args) { if (args[1] == "uevent_devname") { - subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME; + subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVNAME; return Success(); } if (args[1] == "uevent_devpath") { - subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH; + subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVPATH; return Success(); } diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp new file mode 100644 index 000000000..31208b926 --- /dev/null +++ b/init/ueventd_parser_test.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2018 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 "ueventd_parser.h" + +#include <android-base/test_utils.h> +#include <gtest/gtest.h> +#include <private/android_filesystem_config.h> + +namespace android { +namespace init { + +void TestSubsystems(const Subsystem& expected, const Subsystem& test) { + EXPECT_EQ(expected.name_, test.name_); + EXPECT_EQ(expected.devname_source_, test.devname_source_) << expected.name_; + EXPECT_EQ(expected.dir_name_, test.dir_name_) << expected.name_; +} + +void TestPermissions(const Permissions& expected, const Permissions& test) { + EXPECT_EQ(expected.name_, test.name_); + EXPECT_EQ(expected.perm_, test.perm_) << expected.name_; + EXPECT_EQ(expected.uid_, test.uid_) << expected.name_; + EXPECT_EQ(expected.gid_, test.gid_) << expected.name_; + EXPECT_EQ(expected.prefix_, test.prefix_) << expected.name_; + EXPECT_EQ(expected.wildcard_, test.wildcard_) << expected.name_; +} + +void TestSysfsPermissions(const SysfsPermissions& expected, const SysfsPermissions& test) { + TestPermissions(expected, test); + EXPECT_EQ(expected.attribute_, test.attribute_); +} + +template <typename T, typename F> +void TestVector(const T& expected, const T& test, F function) { + ASSERT_EQ(expected.size(), test.size()); + auto expected_it = expected.begin(); + auto test_it = test.begin(); + + for (; expected_it != expected.end(); ++expected_it, ++test_it) { + function(*expected_it, *test_it); + } +} + +void TestUeventdFile(const std::string& content, const UeventdConfiguration& expected) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + ASSERT_TRUE(android::base::WriteStringToFd(content, tf.fd)); + + auto result = ParseConfig({tf.path}); + + TestVector(expected.subsystems, result.subsystems, TestSubsystems); + TestVector(expected.sysfs_permissions, result.sysfs_permissions, TestSysfsPermissions); + TestVector(expected.dev_permissions, result.dev_permissions, TestPermissions); + EXPECT_EQ(expected.firmware_directories, result.firmware_directories); +} + +TEST(ueventd_parser, EmptyFile) { + TestUeventdFile("", {}); +} + +TEST(ueventd_parser, Subsystems) { + auto ueventd_file = R"( +subsystem test_devname + devname uevent_devname + +subsystem test_devpath_no_dirname + devname uevent_devpath + +subsystem test_devname2 + devname uevent_devname + +subsystem test_devpath_dirname + devname uevent_devpath + dirname /dev/graphics +)"; + + auto subsystems = std::vector<Subsystem>{ + {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, + {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"}, + {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, + {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}}; + + TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}}); +} + +TEST(ueventd_parser, Permissions) { + auto ueventd_file = R"( +/dev/rtc0 0640 system system +/dev/graphics/* 0660 root graphics +/dev/*/test 0660 root system + +/sys/devices/platform/trusty.* trusty_version 0440 root log +/sys/devices/virtual/input/input enable 0660 root input +/sys/devices/virtual/*/input poll_delay 0660 root input +)"; + + auto permissions = std::vector<Permissions>{ + {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM}, + {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS}, + {"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM}, + }; + + auto sysfs_permissions = std::vector<SysfsPermissions>{ + {"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG}, + {"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT}, + {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT}, + }; + + TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}}); +} + +TEST(ueventd_parser, FirmwareDirectories) { + auto ueventd_file = R"( +firmware_directories /first/ /second /third +firmware_directories /more +)"; + + auto firmware_directories = std::vector<std::string>{ + "/first/", + "/second", + "/third", + "/more", + }; + + TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories}); +} + +TEST(ueventd_parser, AllTogether) { + auto ueventd_file = R"( + +/dev/rtc0 0640 system system +firmware_directories /first/ /second /third +/sys/devices/platform/trusty.* trusty_version 0440 root log + +subsystem test_devname + devname uevent_devname + +/dev/graphics/* 0660 root graphics + +subsystem test_devpath_no_dirname + devname uevent_devpath + +/sys/devices/virtual/input/input enable 0660 root input + +## this is a comment + +subsystem test_devname2 +## another comment + devname uevent_devname + +subsystem test_devpath_dirname + devname uevent_devpath + dirname /dev/graphics + +/dev/*/test 0660 root system +/sys/devices/virtual/*/input poll_delay 0660 root input +firmware_directories /more + +#ending comment +)"; + + auto subsystems = std::vector<Subsystem>{ + {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, + {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"}, + {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, + {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}}; + + auto permissions = std::vector<Permissions>{ + {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM}, + {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS}, + {"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM}, + }; + + auto sysfs_permissions = std::vector<SysfsPermissions>{ + {"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG}, + {"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT}, + {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT}, + }; + + auto firmware_directories = std::vector<std::string>{ + "/first/", + "/second", + "/third", + "/more", + }; + + TestUeventdFile(ueventd_file, + {subsystems, sysfs_permissions, permissions, firmware_directories}); +} + +// All of these lines are ill-formed, so test that there is 0 output. +TEST(ueventd_parser, ParseErrors) { + auto ueventd_file = R"( + +/dev/rtc0 badmode baduidbad system +/dev/rtc0 0640 baduidbad system +/dev/rtc0 0640 system baduidbad +firmware_directories #no directory listed +/sys/devices/platform/trusty.* trusty_version badmode root log +/sys/devices/platform/trusty.* trusty_version 0440 baduidbad log +/sys/devices/platform/trusty.* trusty_version 0440 root baduidbad + +subsystem #no name + +)"; + + TestUeventdFile(ueventd_file, {}); +} + +} // namespace init +} // namespace android |