Loading init/Android.mk +0 −1 Original line number Diff line number Diff line Loading @@ -93,7 +93,6 @@ LOCAL_SRC_FILES:= \ reboot.cpp \ signal_handler.cpp \ ueventd.cpp \ ueventd_parser.cpp \ watchdogd.cpp \ LOCAL_MODULE:= init Loading init/action.cpp +1 −6 Original line number Diff line number Diff line Loading @@ -58,12 +58,7 @@ bool Action::AddCommand(const std::vector<std::string>& args, int line, std::str return false; } if (args.empty()) { *err = "command needed, but not provided"; return false; } auto function = function_map_->FindFunction(args[0], args.size() - 1, err); auto function = function_map_->FindFunction(args, err); if (!function) { return false; } Loading init/devices.cpp +142 −27 Original line number Diff line number Diff line Loading @@ -20,8 +20,10 @@ #include <errno.h> #include <fcntl.h> #include <fnmatch.h> #include <grp.h> #include <libgen.h> #include <linux/netlink.h> #include <pwd.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> Loading Loading @@ -49,7 +51,8 @@ #include <selinux/label.h> #include <selinux/selinux.h> #include "ueventd_parser.h" #include "keyword_map.h" #include "ueventd.h" #include "util.h" extern struct selabel_handle *sehandle; Loading Loading @@ -103,6 +106,137 @@ void SysfsPermissions::SetPermissions(const std::string& path) const { std::vector<Permissions> dev_permissions; std::vector<SysfsPermissions> sysfs_permissions; bool ParsePermissionsLine(std::vector<std::string>&& args, std::string* err, bool is_sysfs) { if (is_sysfs && args.size() != 5) { *err = "/sys/ lines must have 5 entries"; return false; } if (!is_sysfs && args.size() != 4) { *err = "/dev/ lines must have 4 entries"; return false; } auto it = args.begin(); const std::string& name = *it++; std::string sysfs_attribute; if (is_sysfs) sysfs_attribute = *it++; // args is now common to both sys and dev entries and contains: <perm> <uid> <gid> std::string& perm_string = *it++; char* end_pointer = 0; mode_t perm = strtol(perm_string.c_str(), &end_pointer, 8); if (end_pointer == nullptr || *end_pointer != '\0') { *err = "invalid mode '" + perm_string + "'"; return false; } std::string& uid_string = *it++; passwd* pwd = getpwnam(uid_string.c_str()); if (!pwd) { *err = "invalid uid '" + uid_string + "'"; return false; } uid_t uid = pwd->pw_uid; std::string& gid_string = *it++; struct group* grp = getgrnam(gid_string.c_str()); if (!grp) { *err = "invalid gid '" + gid_string + "'"; return false; } gid_t gid = grp->gr_gid; if (is_sysfs) { sysfs_permissions.emplace_back(name, sysfs_attribute, perm, uid, gid); } else { dev_permissions.emplace_back(name, perm, uid, gid); } return true; } // TODO: Move this to be a member variable of a future devices class. static std::vector<Subsystem> subsystems; std::string Subsystem::ParseDevPath(uevent* uevent) const { std::string devname = devname_source_ == DevnameSource::DEVNAME_UEVENT_DEVNAME ? uevent->device_name : android::base::Basename(uevent->path); return dir_name_ + "/" + devname; } bool SubsystemParser::ParseSection(std::vector<std::string>&& args, const std::string& filename, int line, std::string* err) { if (args.size() != 2) { *err = "subsystems must have exactly one name"; return false; } if (std::find(subsystems.begin(), subsystems.end(), args[1]) != subsystems.end()) { *err = "ignoring duplicate subsystem entry"; return false; } subsystem_.name_ = args[1]; return true; } bool SubsystemParser::ParseDevName(std::vector<std::string>&& args, std::string* err) { if (args[1] == "uevent_devname") { subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME; return true; } if (args[1] == "uevent_devpath") { subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH; return true; } *err = "invalid devname '" + args[1] + "'"; return false; } bool SubsystemParser::ParseDirName(std::vector<std::string>&& args, std::string* err) { if (args[1].front() != '/') { *err = "dirname '" + args[1] + " ' does not start with '/'"; return false; } subsystem_.dir_name_ = args[1]; return true; } bool SubsystemParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) { using OptionParser = bool (SubsystemParser::*)(std::vector<std::string> && args, std::string * err); static class OptionParserMap : public KeywordMap<OptionParser> { private: const Map& map() const override { // clang-format off static const Map option_parsers = { {"devname", {1, 1, &SubsystemParser::ParseDevName}}, {"dirname", {1, 1, &SubsystemParser::ParseDirName}}, }; // clang-format on return option_parsers; } } parser_map; auto parser = parser_map.FindFunction(args, err); if (!parser) { return false; } return (this->*parser)(std::move(args), err); } void SubsystemParser::EndSection() { subsystems.emplace_back(std::move(subsystem_)); } static void fixup_sys_permissions(const std::string& upath, const std::string& subsystem) { // upaths omit the "/sys" that paths in this list // contain, so we prepend it... Loading Loading @@ -483,32 +617,9 @@ static void handle_generic_device_event(uevent* uevent) { // if it's not a /dev device, nothing to do if (uevent->major < 0 || uevent->minor < 0) return; std::string name = android::base::Basename(uevent->path); ueventd_subsystem* subsystem = ueventd_subsystem_find_by_name(uevent->subsystem.c_str()); std::string devpath; if (subsystem) { std::string devname; switch (subsystem->devname_src) { case DEVNAME_UEVENT_DEVNAME: devname = uevent->device_name; break; case DEVNAME_UEVENT_DEVPATH: devname = name; break; default: LOG(ERROR) << uevent->subsystem << " subsystem's devpath option is not set; ignoring event"; return; } // TODO: Remove std::string() devpath = std::string(subsystem->dirname) + "/" + devname; mkdir_recursive(android::base::Dirname(devpath), 0755); } else if (android::base::StartsWith(uevent->subsystem, "usb")) { if (android::base::StartsWith(uevent->subsystem, "usb")) { if (uevent->subsystem == "usb") { if (!uevent->device_name.empty()) { devpath = "/dev/" + uevent->device_name; Loading @@ -520,15 +631,19 @@ static void handle_generic_device_event(uevent* uevent) { int device_id = uevent->minor % 128 + 1; devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id); } mkdir_recursive(android::base::Dirname(devpath), 0755); } else { // ignore other USB events return; } } else if (auto subsystem = std::find(subsystems.begin(), subsystems.end(), uevent->subsystem); subsystem != subsystems.end()) { devpath = subsystem->ParseDevPath(uevent); } else { devpath = "/dev/" + name; devpath = "/dev/" + android::base::Basename(uevent->path); } mkdir_recursive(android::base::Dirname(devpath), 0755); auto links = get_character_device_symlinks(uevent); handle_device(uevent->action, devpath, 0, uevent->major, uevent->minor, links); Loading init/devices.h +40 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ #include <string> #include <vector> #include "init_parser.h" enum coldboot_action_t { // coldboot continues without creating the device for the uevent COLDBOOT_CONTINUE = 0, Loading Loading @@ -83,9 +85,45 @@ class SysfsPermissions : public Permissions { const std::string attribute_; }; extern std::vector<Permissions> dev_permissions; extern std::vector<SysfsPermissions> sysfs_permissions; class Subsystem { public: friend class SubsystemParser; Subsystem() {} // 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(uevent* uevent) const; bool operator==(const std::string& string_name) { return name_ == string_name; } private: enum class DevnameSource { DEVNAME_UEVENT_DEVNAME, DEVNAME_UEVENT_DEVPATH, }; std::string name_; std::string dir_name_ = "/dev"; DevnameSource devname_source_; }; class SubsystemParser : public SectionParser { public: SubsystemParser() {} bool ParseSection(std::vector<std::string>&& args, const std::string& filename, int line, std::string* err) override; bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) override; void EndSection() override; private: bool ParseDevName(std::vector<std::string>&& args, std::string* err); bool ParseDirName(std::vector<std::string>&& args, std::string* err); Subsystem subsystem_; }; bool ParsePermissionsLine(std::vector<std::string>&& args, std::string* err, bool is_sysfs); typedef std::function<coldboot_action_t(struct uevent* uevent)> coldboot_callback; extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr); extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr); Loading init/init_parser.cpp +22 −5 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> #include "parser.h" #include "util.h" Loading @@ -37,13 +38,16 @@ void Parser::AddSectionParser(const std::string& name, section_parsers_[name] = std::move(parser); } void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) { line_callbacks_.emplace_back(prefix, callback); } void Parser::ParseData(const std::string& filename, const std::string& data) { //TODO: Use a parser with const input and remove this copy std::vector<char> data_copy(data.begin(), data.end()); data_copy.push_back('\0'); parse_state state; state.filename = filename.c_str(); state.line = 0; state.ptr = &data_copy[0]; state.nexttoken = 0; Loading @@ -63,21 +67,34 @@ void Parser::ParseData(const std::string& filename, const std::string& data) { if (args.empty()) { break; } // If we have a line matching a prefix we recognize, call its callback and unset any // current section parsers. This is meant for /sys/ and /dev/ line entries for uevent. for (const auto& [prefix, callback] : line_callbacks_) { if (android::base::StartsWith(args[0], prefix.c_str())) { if (section_parser) section_parser->EndSection(); std::string ret_err; if (!callback(std::move(args), &ret_err)) { LOG(ERROR) << filename << ": " << state.line << ": " << ret_err; } section_parser = nullptr; break; } } if (section_parsers_.count(args[0])) { if (section_parser) { section_parser->EndSection(); } section_parser = section_parsers_[args[0]].get(); std::string ret_err; if (!section_parser->ParseSection(std::move(args), state.filename, state.line, &ret_err)) { parse_error(&state, "%s\n", ret_err.c_str()); if (!section_parser->ParseSection(std::move(args), filename, state.line, &ret_err)) { LOG(ERROR) << filename << ": " << state.line << ": " << ret_err; section_parser = nullptr; } } else if (section_parser) { std::string ret_err; if (!section_parser->ParseLineSection(std::move(args), state.line, &ret_err)) { parse_error(&state, "%s\n", ret_err.c_str()); LOG(ERROR) << filename << ": " << state.line << ": " << ret_err; } } args.clear(); Loading Loading
init/Android.mk +0 −1 Original line number Diff line number Diff line Loading @@ -93,7 +93,6 @@ LOCAL_SRC_FILES:= \ reboot.cpp \ signal_handler.cpp \ ueventd.cpp \ ueventd_parser.cpp \ watchdogd.cpp \ LOCAL_MODULE:= init Loading
init/action.cpp +1 −6 Original line number Diff line number Diff line Loading @@ -58,12 +58,7 @@ bool Action::AddCommand(const std::vector<std::string>& args, int line, std::str return false; } if (args.empty()) { *err = "command needed, but not provided"; return false; } auto function = function_map_->FindFunction(args[0], args.size() - 1, err); auto function = function_map_->FindFunction(args, err); if (!function) { return false; } Loading
init/devices.cpp +142 −27 Original line number Diff line number Diff line Loading @@ -20,8 +20,10 @@ #include <errno.h> #include <fcntl.h> #include <fnmatch.h> #include <grp.h> #include <libgen.h> #include <linux/netlink.h> #include <pwd.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> Loading Loading @@ -49,7 +51,8 @@ #include <selinux/label.h> #include <selinux/selinux.h> #include "ueventd_parser.h" #include "keyword_map.h" #include "ueventd.h" #include "util.h" extern struct selabel_handle *sehandle; Loading Loading @@ -103,6 +106,137 @@ void SysfsPermissions::SetPermissions(const std::string& path) const { std::vector<Permissions> dev_permissions; std::vector<SysfsPermissions> sysfs_permissions; bool ParsePermissionsLine(std::vector<std::string>&& args, std::string* err, bool is_sysfs) { if (is_sysfs && args.size() != 5) { *err = "/sys/ lines must have 5 entries"; return false; } if (!is_sysfs && args.size() != 4) { *err = "/dev/ lines must have 4 entries"; return false; } auto it = args.begin(); const std::string& name = *it++; std::string sysfs_attribute; if (is_sysfs) sysfs_attribute = *it++; // args is now common to both sys and dev entries and contains: <perm> <uid> <gid> std::string& perm_string = *it++; char* end_pointer = 0; mode_t perm = strtol(perm_string.c_str(), &end_pointer, 8); if (end_pointer == nullptr || *end_pointer != '\0') { *err = "invalid mode '" + perm_string + "'"; return false; } std::string& uid_string = *it++; passwd* pwd = getpwnam(uid_string.c_str()); if (!pwd) { *err = "invalid uid '" + uid_string + "'"; return false; } uid_t uid = pwd->pw_uid; std::string& gid_string = *it++; struct group* grp = getgrnam(gid_string.c_str()); if (!grp) { *err = "invalid gid '" + gid_string + "'"; return false; } gid_t gid = grp->gr_gid; if (is_sysfs) { sysfs_permissions.emplace_back(name, sysfs_attribute, perm, uid, gid); } else { dev_permissions.emplace_back(name, perm, uid, gid); } return true; } // TODO: Move this to be a member variable of a future devices class. static std::vector<Subsystem> subsystems; std::string Subsystem::ParseDevPath(uevent* uevent) const { std::string devname = devname_source_ == DevnameSource::DEVNAME_UEVENT_DEVNAME ? uevent->device_name : android::base::Basename(uevent->path); return dir_name_ + "/" + devname; } bool SubsystemParser::ParseSection(std::vector<std::string>&& args, const std::string& filename, int line, std::string* err) { if (args.size() != 2) { *err = "subsystems must have exactly one name"; return false; } if (std::find(subsystems.begin(), subsystems.end(), args[1]) != subsystems.end()) { *err = "ignoring duplicate subsystem entry"; return false; } subsystem_.name_ = args[1]; return true; } bool SubsystemParser::ParseDevName(std::vector<std::string>&& args, std::string* err) { if (args[1] == "uevent_devname") { subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME; return true; } if (args[1] == "uevent_devpath") { subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH; return true; } *err = "invalid devname '" + args[1] + "'"; return false; } bool SubsystemParser::ParseDirName(std::vector<std::string>&& args, std::string* err) { if (args[1].front() != '/') { *err = "dirname '" + args[1] + " ' does not start with '/'"; return false; } subsystem_.dir_name_ = args[1]; return true; } bool SubsystemParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) { using OptionParser = bool (SubsystemParser::*)(std::vector<std::string> && args, std::string * err); static class OptionParserMap : public KeywordMap<OptionParser> { private: const Map& map() const override { // clang-format off static const Map option_parsers = { {"devname", {1, 1, &SubsystemParser::ParseDevName}}, {"dirname", {1, 1, &SubsystemParser::ParseDirName}}, }; // clang-format on return option_parsers; } } parser_map; auto parser = parser_map.FindFunction(args, err); if (!parser) { return false; } return (this->*parser)(std::move(args), err); } void SubsystemParser::EndSection() { subsystems.emplace_back(std::move(subsystem_)); } static void fixup_sys_permissions(const std::string& upath, const std::string& subsystem) { // upaths omit the "/sys" that paths in this list // contain, so we prepend it... Loading Loading @@ -483,32 +617,9 @@ static void handle_generic_device_event(uevent* uevent) { // if it's not a /dev device, nothing to do if (uevent->major < 0 || uevent->minor < 0) return; std::string name = android::base::Basename(uevent->path); ueventd_subsystem* subsystem = ueventd_subsystem_find_by_name(uevent->subsystem.c_str()); std::string devpath; if (subsystem) { std::string devname; switch (subsystem->devname_src) { case DEVNAME_UEVENT_DEVNAME: devname = uevent->device_name; break; case DEVNAME_UEVENT_DEVPATH: devname = name; break; default: LOG(ERROR) << uevent->subsystem << " subsystem's devpath option is not set; ignoring event"; return; } // TODO: Remove std::string() devpath = std::string(subsystem->dirname) + "/" + devname; mkdir_recursive(android::base::Dirname(devpath), 0755); } else if (android::base::StartsWith(uevent->subsystem, "usb")) { if (android::base::StartsWith(uevent->subsystem, "usb")) { if (uevent->subsystem == "usb") { if (!uevent->device_name.empty()) { devpath = "/dev/" + uevent->device_name; Loading @@ -520,15 +631,19 @@ static void handle_generic_device_event(uevent* uevent) { int device_id = uevent->minor % 128 + 1; devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id); } mkdir_recursive(android::base::Dirname(devpath), 0755); } else { // ignore other USB events return; } } else if (auto subsystem = std::find(subsystems.begin(), subsystems.end(), uevent->subsystem); subsystem != subsystems.end()) { devpath = subsystem->ParseDevPath(uevent); } else { devpath = "/dev/" + name; devpath = "/dev/" + android::base::Basename(uevent->path); } mkdir_recursive(android::base::Dirname(devpath), 0755); auto links = get_character_device_symlinks(uevent); handle_device(uevent->action, devpath, 0, uevent->major, uevent->minor, links); Loading
init/devices.h +40 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ #include <string> #include <vector> #include "init_parser.h" enum coldboot_action_t { // coldboot continues without creating the device for the uevent COLDBOOT_CONTINUE = 0, Loading Loading @@ -83,9 +85,45 @@ class SysfsPermissions : public Permissions { const std::string attribute_; }; extern std::vector<Permissions> dev_permissions; extern std::vector<SysfsPermissions> sysfs_permissions; class Subsystem { public: friend class SubsystemParser; Subsystem() {} // 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(uevent* uevent) const; bool operator==(const std::string& string_name) { return name_ == string_name; } private: enum class DevnameSource { DEVNAME_UEVENT_DEVNAME, DEVNAME_UEVENT_DEVPATH, }; std::string name_; std::string dir_name_ = "/dev"; DevnameSource devname_source_; }; class SubsystemParser : public SectionParser { public: SubsystemParser() {} bool ParseSection(std::vector<std::string>&& args, const std::string& filename, int line, std::string* err) override; bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) override; void EndSection() override; private: bool ParseDevName(std::vector<std::string>&& args, std::string* err); bool ParseDirName(std::vector<std::string>&& args, std::string* err); Subsystem subsystem_; }; bool ParsePermissionsLine(std::vector<std::string>&& args, std::string* err, bool is_sysfs); typedef std::function<coldboot_action_t(struct uevent* uevent)> coldboot_callback; extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr); extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr); Loading
init/init_parser.cpp +22 −5 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> #include "parser.h" #include "util.h" Loading @@ -37,13 +38,16 @@ void Parser::AddSectionParser(const std::string& name, section_parsers_[name] = std::move(parser); } void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) { line_callbacks_.emplace_back(prefix, callback); } void Parser::ParseData(const std::string& filename, const std::string& data) { //TODO: Use a parser with const input and remove this copy std::vector<char> data_copy(data.begin(), data.end()); data_copy.push_back('\0'); parse_state state; state.filename = filename.c_str(); state.line = 0; state.ptr = &data_copy[0]; state.nexttoken = 0; Loading @@ -63,21 +67,34 @@ void Parser::ParseData(const std::string& filename, const std::string& data) { if (args.empty()) { break; } // If we have a line matching a prefix we recognize, call its callback and unset any // current section parsers. This is meant for /sys/ and /dev/ line entries for uevent. for (const auto& [prefix, callback] : line_callbacks_) { if (android::base::StartsWith(args[0], prefix.c_str())) { if (section_parser) section_parser->EndSection(); std::string ret_err; if (!callback(std::move(args), &ret_err)) { LOG(ERROR) << filename << ": " << state.line << ": " << ret_err; } section_parser = nullptr; break; } } if (section_parsers_.count(args[0])) { if (section_parser) { section_parser->EndSection(); } section_parser = section_parsers_[args[0]].get(); std::string ret_err; if (!section_parser->ParseSection(std::move(args), state.filename, state.line, &ret_err)) { parse_error(&state, "%s\n", ret_err.c_str()); if (!section_parser->ParseSection(std::move(args), filename, state.line, &ret_err)) { LOG(ERROR) << filename << ": " << state.line << ": " << ret_err; section_parser = nullptr; } } else if (section_parser) { std::string ret_err; if (!section_parser->ParseLineSection(std::move(args), state.line, &ret_err)) { parse_error(&state, "%s\n", ret_err.c_str()); LOG(ERROR) << filename << ": " << state.line << ": " << ret_err; } } args.clear(); Loading