Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe062055 authored by Tom Cherry's avatar Tom Cherry
Browse files

ueventd: replace ueventd_parser.cpp with init_parser.cpp

Previously init_parser.cpp was made generic and capable of parsing any
number of differently named 'sections' or prefixed lines.  We now use
these capabilities to do the parsing for ueventd.

Bug: 36250207
Bug: 33785894

Test: boot bullhead and ensure the right /dev nodes exist
      with the right permissions set
Test: verify no boot time difference
Change-Id: I698ca962d414f8135af32f6c9cd778841b2b8b53
parent 35c5bcc8
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -92,7 +92,6 @@ LOCAL_SRC_FILES:= \
    reboot.cpp \
    reboot.cpp \
    signal_handler.cpp \
    signal_handler.cpp \
    ueventd.cpp \
    ueventd.cpp \
    ueventd_parser.cpp \
    watchdogd.cpp \
    watchdogd.cpp \


LOCAL_MODULE:= init
LOCAL_MODULE:= init
+1 −6
Original line number Original line Diff line number Diff line
@@ -58,12 +58,7 @@ bool Action::AddCommand(const std::vector<std::string>& args, int line, std::str
        return false;
        return false;
    }
    }


    if (args.empty()) {
    auto function = function_map_->FindFunction(args, err);
        *err = "command needed, but not provided";
        return false;
    }

    auto function = function_map_->FindFunction(args[0], args.size() - 1, err);
    if (!function) {
    if (!function) {
        return false;
        return false;
    }
    }
+142 −27
Original line number Original line Diff line number Diff line
@@ -20,8 +20,10 @@
#include <errno.h>
#include <errno.h>
#include <fcntl.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <fnmatch.h>
#include <grp.h>
#include <libgen.h>
#include <libgen.h>
#include <linux/netlink.h>
#include <linux/netlink.h>
#include <pwd.h>
#include <stddef.h>
#include <stddef.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
@@ -49,7 +51,8 @@
#include <selinux/label.h>
#include <selinux/label.h>
#include <selinux/selinux.h>
#include <selinux/selinux.h>


#include "ueventd_parser.h"
#include "keyword_map.h"
#include "ueventd.h"
#include "util.h"
#include "util.h"


extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle;
@@ -103,6 +106,137 @@ void SysfsPermissions::SetPermissions(const std::string& path) const {
std::vector<Permissions> dev_permissions;
std::vector<Permissions> dev_permissions;
std::vector<SysfsPermissions> sysfs_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) {
static void fixup_sys_permissions(const std::string& upath, const std::string& subsystem) {
    // upaths omit the "/sys" that paths in this list
    // upaths omit the "/sys" that paths in this list
    // contain, so we prepend it...
    // contain, so we prepend it...
@@ -483,32 +617,9 @@ static void handle_generic_device_event(uevent* uevent) {
    // if it's not a /dev device, nothing to do
    // if it's not a /dev device, nothing to do
    if (uevent->major < 0 || uevent->minor < 0) return;
    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;
    std::string devpath;


    if (subsystem) {
    if (android::base::StartsWith(uevent->subsystem, "usb")) {
        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 (uevent->subsystem == "usb") {
        if (uevent->subsystem == "usb") {
            if (!uevent->device_name.empty()) {
            if (!uevent->device_name.empty()) {
                devpath = "/dev/" + uevent->device_name;
                devpath = "/dev/" + uevent->device_name;
@@ -520,15 +631,19 @@ static void handle_generic_device_event(uevent* uevent) {
                int device_id = uevent->minor % 128 + 1;
                int device_id = uevent->minor % 128 + 1;
                devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
                devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
            }
            }
            mkdir_recursive(android::base::Dirname(devpath), 0755);
        } else {
        } else {
            // ignore other USB events
            // ignore other USB events
            return;
            return;
        }
        }
    } else if (auto subsystem = std::find(subsystems.begin(), subsystems.end(), uevent->subsystem);
               subsystem != subsystems.end()) {
        devpath = subsystem->ParseDevPath(uevent);
    } else {
    } 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);
    auto links = get_character_device_symlinks(uevent);


    handle_device(uevent->action, devpath, 0, uevent->major, uevent->minor, links);
    handle_device(uevent->action, devpath, 0, uevent->major, uevent->minor, links);
+40 −2
Original line number Original line Diff line number Diff line
@@ -24,6 +24,8 @@
#include <string>
#include <string>
#include <vector>
#include <vector>


#include "init_parser.h"

enum coldboot_action_t {
enum coldboot_action_t {
    // coldboot continues without creating the device for the uevent
    // coldboot continues without creating the device for the uevent
    COLDBOOT_CONTINUE = 0,
    COLDBOOT_CONTINUE = 0,
@@ -83,9 +85,45 @@ class SysfsPermissions : public Permissions {
    const std::string attribute_;
    const std::string attribute_;
};
};


extern std::vector<Permissions> dev_permissions;
class Subsystem {
extern std::vector<SysfsPermissions> sysfs_permissions;
  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;
typedef std::function<coldboot_action_t(struct uevent* uevent)> coldboot_callback;
extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr);
extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr);
extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr);
extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr);
+8 −3
Original line number Original line Diff line number Diff line
@@ -31,11 +31,16 @@ class KeywordMap {
    virtual ~KeywordMap() {
    virtual ~KeywordMap() {
    }
    }


    const Function FindFunction(const std::string& keyword,
    const Function FindFunction(const std::vector<std::string>& args, std::string* err) const {
                                size_t num_args,
                                std::string* err) const {
        using android::base::StringPrintf;
        using android::base::StringPrintf;


        if (args.empty()) {
            *err = "keyword needed, but not provided";
            return nullptr;
        }
        auto& keyword = args[0];
        auto num_args = args.size() - 1;

        auto function_info_it = map().find(keyword);
        auto function_info_it = map().find(keyword);
        if (function_info_it == map().end()) {
        if (function_info_it == map().end()) {
            *err = StringPrintf("invalid keyword '%s'", keyword.c_str());
            *err = StringPrintf("invalid keyword '%s'", keyword.c_str());
Loading