Merge changes I1f70f2c4,I698ca962,Idbbf2682
* changes: init: remove unused parts of parser.cpp ueventd: replace ueventd_parser.cpp with init_parser.cpp init: add Parser::AddSingleLineParser()
This commit is contained in:
commit
960ed3ce1b
|
@ -93,7 +93,6 @@ LOCAL_SRC_FILES:= \
|
|||
reboot.cpp \
|
||||
signal_handler.cpp \
|
||||
ueventd.cpp \
|
||||
ueventd_parser.cpp \
|
||||
watchdogd.cpp \
|
||||
|
||||
LOCAL_MODULE:= init
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
169
init/devices.cpp
169
init/devices.cpp
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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...
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
|
|
@ -57,24 +57,26 @@ class SectionParser {
|
|||
|
||||
class Parser {
|
||||
public:
|
||||
// LineCallback is the type for callbacks that can parse a line starting with a given prefix.
|
||||
//
|
||||
// They take the form of bool Callback(std::vector<std::string>&& args, std::string* err)
|
||||
//
|
||||
// Similar to ParseSection() and ParseLineSection(), this function returns bool with false
|
||||
// indicating a failure and has an std::string* err parameter into which an error string can
|
||||
// be written.
|
||||
using LineCallback = std::function<bool(std::vector<std::string>&&, std::string*)>;
|
||||
|
||||
static Parser& GetInstance();
|
||||
|
||||
// Exposed for testing
|
||||
Parser();
|
||||
|
||||
bool ParseConfig(const std::string& path);
|
||||
void AddSectionParser(const std::string& name,
|
||||
std::unique_ptr<SectionParser> parser);
|
||||
|
||||
void set_is_system_etc_init_loaded(bool loaded) {
|
||||
is_system_etc_init_loaded_ = loaded;
|
||||
}
|
||||
void set_is_vendor_etc_init_loaded(bool loaded) {
|
||||
is_vendor_etc_init_loaded_ = loaded;
|
||||
}
|
||||
void set_is_odm_etc_init_loaded(bool loaded) {
|
||||
is_odm_etc_init_loaded_ = loaded;
|
||||
}
|
||||
void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
|
||||
void AddSingleLineParser(const std::string& prefix, LineCallback callback);
|
||||
void set_is_system_etc_init_loaded(bool loaded) { is_system_etc_init_loaded_ = loaded; }
|
||||
void set_is_vendor_etc_init_loaded(bool loaded) { is_vendor_etc_init_loaded_ = loaded; }
|
||||
void set_is_odm_etc_init_loaded(bool loaded) { is_odm_etc_init_loaded_ = loaded; }
|
||||
bool is_system_etc_init_loaded() { return is_system_etc_init_loaded_; }
|
||||
bool is_vendor_etc_init_loaded() { return is_vendor_etc_init_loaded_; }
|
||||
bool is_odm_etc_init_loaded() { return is_odm_etc_init_loaded_; }
|
||||
|
@ -85,6 +87,7 @@ class Parser {
|
|||
bool ParseConfigDir(const std::string& path);
|
||||
|
||||
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
|
||||
std::vector<std::pair<std::string, LineCallback>> line_callbacks_;
|
||||
bool is_system_etc_init_loaded_ = false;
|
||||
bool is_vendor_etc_init_loaded_ = false;
|
||||
bool is_odm_etc_init_loaded_ = false;
|
||||
|
|
|
@ -31,11 +31,16 @@ class KeywordMap {
|
|||
virtual ~KeywordMap() {
|
||||
}
|
||||
|
||||
const Function FindFunction(const std::string& keyword,
|
||||
size_t num_args,
|
||||
std::string* err) const {
|
||||
const Function FindFunction(const std::vector<std::string>& args, std::string* err) const {
|
||||
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);
|
||||
if (function_info_it == map().end()) {
|
||||
*err = StringPrintf("invalid keyword '%s'", keyword.c_str());
|
||||
|
|
|
@ -1,28 +1,5 @@
|
|||
#include "parser.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
void parse_error(struct parse_state *state, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[128];
|
||||
int off;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s: %d: ", state->filename, state->line);
|
||||
buf[127] = 0;
|
||||
off = strlen(buf);
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf + off, 128 - off, fmt, ap);
|
||||
va_end(ap);
|
||||
buf[127] = 0;
|
||||
LOG(ERROR) << buf;
|
||||
}
|
||||
|
||||
int next_token(struct parse_state *state)
|
||||
{
|
||||
char *x = state->ptr;
|
||||
|
|
|
@ -27,14 +27,8 @@ struct parse_state
|
|||
char *text;
|
||||
int line;
|
||||
int nexttoken;
|
||||
void *context;
|
||||
void (*parse_line)(struct parse_state *state, int nargs, char **args);
|
||||
const char *filename;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
void dump_parser_state(void);
|
||||
int next_token(struct parse_state *state);
|
||||
void parse_error(struct parse_state *state, const char *fmt, ...);
|
||||
|
||||
#endif /* PARSER_H_ */
|
||||
|
|
|
@ -572,13 +572,8 @@ const Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
|
|||
}
|
||||
|
||||
bool Service::ParseLine(const std::vector<std::string>& args, std::string* err) {
|
||||
if (args.empty()) {
|
||||
*err = "option needed, but not provided";
|
||||
return false;
|
||||
}
|
||||
|
||||
static const OptionParserMap parser_map;
|
||||
auto parser = parser_map.FindFunction(args[0], args.size() - 1, err);
|
||||
auto parser = parser_map.FindFunction(args, err);
|
||||
|
||||
if (!parser) {
|
||||
return false;
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <poll.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -33,9 +31,11 @@
|
|||
|
||||
#include "devices.h"
|
||||
#include "log.h"
|
||||
#include "ueventd_parser.h"
|
||||
#include "util.h"
|
||||
|
||||
template <bool sysfs>
|
||||
static bool ParseSingleLine(std::vector<std::string>&& line, std::string* err);
|
||||
|
||||
int ueventd_main(int argc, char **argv)
|
||||
{
|
||||
/*
|
||||
|
@ -60,9 +60,14 @@ int ueventd_main(int argc, char **argv)
|
|||
cb.func_log = selinux_klog_callback;
|
||||
selinux_set_callback(SELINUX_CB_LOG, cb);
|
||||
|
||||
ueventd_parse_config_file("/ueventd.rc");
|
||||
ueventd_parse_config_file("/vendor/ueventd.rc");
|
||||
ueventd_parse_config_file("/odm/ueventd.rc");
|
||||
Parser& parser = Parser::GetInstance();
|
||||
parser.AddSectionParser("subsystem", std::make_unique<SubsystemParser>());
|
||||
using namespace std::placeholders;
|
||||
parser.AddSingleLineParser("/sys/", std::bind(ParsePermissionsLine, _1, _2, true));
|
||||
parser.AddSingleLineParser("/dev/", std::bind(ParsePermissionsLine, _1, _2, false));
|
||||
parser.ParseConfig("/ueventd.rc");
|
||||
parser.ParseConfig("/vendor/ueventd.rc");
|
||||
parser.ParseConfig("/odm/ueventd.rc");
|
||||
|
||||
/*
|
||||
* keep the current product name base configuration so
|
||||
|
@ -72,7 +77,7 @@ int ueventd_main(int argc, char **argv)
|
|||
* device node entries (b/34968103)
|
||||
*/
|
||||
std::string hardware = android::base::GetProperty("ro.hardware", "");
|
||||
ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str());
|
||||
parser.ParseConfig("/ueventd." + hardware + ".rc");
|
||||
|
||||
device_init();
|
||||
|
||||
|
@ -93,59 +98,3 @@ int ueventd_main(int argc, char **argv)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_device_permission(const char* fn, int line, int nargs, char **args)
|
||||
{
|
||||
char *name;
|
||||
char *attr = 0;
|
||||
mode_t perm;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
char *endptr;
|
||||
|
||||
if (nargs == 0)
|
||||
return;
|
||||
|
||||
if (args[0][0] == '#')
|
||||
return;
|
||||
|
||||
name = args[0];
|
||||
|
||||
if (!strncmp(name,"/sys/", 5) && (nargs == 5)) {
|
||||
LOG(INFO) << "/sys/ rule " << args[0] << " " << args[1];
|
||||
attr = args[1];
|
||||
args++;
|
||||
nargs--;
|
||||
}
|
||||
|
||||
if (nargs != 4) {
|
||||
LOG(ERROR) << "invalid line (" << fn << ":" << line << ") line for '" << args[0] << "'";
|
||||
return;
|
||||
}
|
||||
|
||||
perm = strtol(args[1], &endptr, 8);
|
||||
if (!endptr || *endptr != '\0') {
|
||||
LOG(ERROR) << "invalid mode (" << fn << ":" << line << ") '" << args[1] << "'";
|
||||
return;
|
||||
}
|
||||
|
||||
struct passwd* pwd = getpwnam(args[2]);
|
||||
if (!pwd) {
|
||||
LOG(ERROR) << "invalid uid (" << fn << ":" << line << ") '" << args[2] << "'";
|
||||
return;
|
||||
}
|
||||
uid = pwd->pw_uid;
|
||||
|
||||
struct group* grp = getgrnam(args[3]);
|
||||
if (!grp) {
|
||||
LOG(ERROR) << "invalid gid (" << fn << ":" << line << ") '" << args[3] << "'";
|
||||
return;
|
||||
}
|
||||
gid = grp->gr_gid;
|
||||
|
||||
if (attr) {
|
||||
sysfs_permissions.emplace_back(name, attr, perm, uid, gid);
|
||||
} else {
|
||||
dev_permissions.emplace_back(name, perm, uid, gid);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,24 +17,6 @@
|
|||
#ifndef _INIT_UEVENTD_H_
|
||||
#define _INIT_UEVENTD_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cutils/list.h>
|
||||
|
||||
enum devname_src_t {
|
||||
DEVNAME_UNKNOWN = 0,
|
||||
DEVNAME_UEVENT_DEVNAME,
|
||||
DEVNAME_UEVENT_DEVPATH,
|
||||
};
|
||||
|
||||
struct ueventd_subsystem {
|
||||
struct listnode slist;
|
||||
|
||||
const char *name;
|
||||
const char *dirname;
|
||||
devname_src_t devname_src;
|
||||
};
|
||||
|
||||
int ueventd_main(int argc, char **argv);
|
||||
int ueventd_main(int argc, char** argv);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef KEYWORD
|
||||
#define __MAKE_KEYWORD_ENUM__
|
||||
#define KEYWORD(symbol, flags, nargs) K_##symbol,
|
||||
enum {
|
||||
K_UNKNOWN,
|
||||
#endif
|
||||
KEYWORD(subsystem, SECTION, 1)
|
||||
KEYWORD(devname, OPTION, 1)
|
||||
KEYWORD(dirname, OPTION, 1)
|
||||
#ifdef __MAKE_KEYWORD_ENUM__
|
||||
KEYWORD_COUNT,
|
||||
};
|
||||
#undef __MAKE_KEYWORD_ENUM__
|
||||
#undef KEYWORD
|
||||
#endif
|
|
@ -1,241 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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 <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "util.h"
|
||||
|
||||
static list_declare(subsystem_list);
|
||||
|
||||
static void parse_line_device(struct parse_state *state, int nargs, char **args);
|
||||
|
||||
#define SECTION 0x01
|
||||
#define OPTION 0x02
|
||||
|
||||
#include "ueventd_keywords.h"
|
||||
|
||||
#define KEYWORD(symbol, flags, nargs) \
|
||||
[ K_##symbol ] = { #symbol, (nargs) + 1, flags, },
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
unsigned char nargs;
|
||||
unsigned char flags;
|
||||
} keyword_info[KEYWORD_COUNT] = {
|
||||
[ K_UNKNOWN ] = { "unknown", 0, 0 },
|
||||
#include "ueventd_keywords.h"
|
||||
};
|
||||
#undef KEYWORD
|
||||
|
||||
#define kw_is(kw, type) (keyword_info[kw].flags & (type))
|
||||
#define kw_nargs(kw) (keyword_info[kw].nargs)
|
||||
|
||||
static int lookup_keyword(const char *s)
|
||||
{
|
||||
switch (*s++) {
|
||||
case 'd':
|
||||
if (!strcmp(s, "evname")) return K_devname;
|
||||
if (!strcmp(s, "irname")) return K_dirname;
|
||||
break;
|
||||
case 's':
|
||||
if (!strcmp(s, "ubsystem")) return K_subsystem;
|
||||
break;
|
||||
}
|
||||
return K_UNKNOWN;
|
||||
}
|
||||
|
||||
static void parse_line_no_op(struct parse_state*, int, char**) {
|
||||
}
|
||||
|
||||
static int valid_name(const char *name)
|
||||
{
|
||||
while (*name) {
|
||||
if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
|
||||
return 0;
|
||||
}
|
||||
name++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct ueventd_subsystem *s;
|
||||
|
||||
list_for_each(node, &subsystem_list) {
|
||||
s = node_to_item(node, struct ueventd_subsystem, slist);
|
||||
if (!strcmp(s->name, name)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *parse_subsystem(parse_state* state, int /*nargs*/, char** args) {
|
||||
if (!valid_name(args[1])) {
|
||||
parse_error(state, "invalid subsystem name '%s'\n", args[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ueventd_subsystem* s = ueventd_subsystem_find_by_name(args[1]);
|
||||
if (s) {
|
||||
parse_error(state, "ignored duplicate definition of subsystem '%s'\n",
|
||||
args[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s = (ueventd_subsystem*) calloc(1, sizeof(*s));
|
||||
if (!s) {
|
||||
parse_error(state, "out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
s->name = args[1];
|
||||
s->dirname = "/dev";
|
||||
list_add_tail(&subsystem_list, &s->slist);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void parse_line_subsystem(struct parse_state *state, int nargs,
|
||||
char **args)
|
||||
{
|
||||
struct ueventd_subsystem *s = (ueventd_subsystem*) state->context;
|
||||
int kw;
|
||||
|
||||
if (nargs == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
kw = lookup_keyword(args[0]);
|
||||
switch (kw) {
|
||||
case K_devname:
|
||||
if (!strcmp(args[1], "uevent_devname"))
|
||||
s->devname_src = DEVNAME_UEVENT_DEVNAME;
|
||||
else if (!strcmp(args[1], "uevent_devpath"))
|
||||
s->devname_src = DEVNAME_UEVENT_DEVPATH;
|
||||
else
|
||||
parse_error(state, "invalid devname '%s'\n", args[1]);
|
||||
break;
|
||||
|
||||
case K_dirname:
|
||||
if (args[1][0] == '/')
|
||||
s->dirname = args[1];
|
||||
else
|
||||
parse_error(state, "dirname '%s' does not start with '/'\n",
|
||||
args[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
parse_error(state, "invalid option '%s'\n", args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_new_section(struct parse_state *state, int kw,
|
||||
int nargs, char **args)
|
||||
{
|
||||
printf("[ %s %s ]\n", args[0],
|
||||
nargs > 1 ? args[1] : "");
|
||||
|
||||
switch(kw) {
|
||||
case K_subsystem:
|
||||
state->context = parse_subsystem(state, nargs, args);
|
||||
if (state->context) {
|
||||
state->parse_line = parse_line_subsystem;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
state->parse_line = parse_line_no_op;
|
||||
}
|
||||
|
||||
static void parse_line(struct parse_state *state, char **args, int nargs)
|
||||
{
|
||||
int kw = lookup_keyword(args[0]);
|
||||
int kw_nargs = kw_nargs(kw);
|
||||
|
||||
if (nargs < kw_nargs) {
|
||||
parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
|
||||
kw_nargs > 2 ? "arguments" : "argument");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kw_is(kw, SECTION)) {
|
||||
parse_new_section(state, kw, nargs, args);
|
||||
} else if (kw_is(kw, OPTION)) {
|
||||
state->parse_line(state, nargs, args);
|
||||
} else {
|
||||
parse_line_device(state, nargs, args);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_config(const char *fn, const std::string& data)
|
||||
{
|
||||
char *args[UEVENTD_PARSER_MAXARGS];
|
||||
|
||||
int nargs = 0;
|
||||
parse_state state;
|
||||
state.filename = fn;
|
||||
state.line = 1;
|
||||
state.ptr = strdup(data.c_str()); // TODO: fix this code!
|
||||
state.nexttoken = 0;
|
||||
state.parse_line = parse_line_no_op;
|
||||
for (;;) {
|
||||
int token = next_token(&state);
|
||||
switch (token) {
|
||||
case T_EOF:
|
||||
parse_line(&state, args, nargs);
|
||||
return;
|
||||
case T_NEWLINE:
|
||||
if (nargs) {
|
||||
parse_line(&state, args, nargs);
|
||||
nargs = 0;
|
||||
}
|
||||
state.line++;
|
||||
break;
|
||||
case T_TEXT:
|
||||
if (nargs < UEVENTD_PARSER_MAXARGS) {
|
||||
args[nargs++] = state.text;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ueventd_parse_config_file(const char *fn)
|
||||
{
|
||||
std::string data;
|
||||
if (!read_file(fn, &data)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data.push_back('\n'); // TODO: fix parse_config.
|
||||
parse_config(fn, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_line_device(parse_state* state, int nargs, char** args) {
|
||||
set_device_permission(state->filename, state->line, nargs, args);
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#ifndef _INIT_UEVENTD_PARSER_H_
|
||||
#define _INIT_UEVENTD_PARSER_H_
|
||||
|
||||
#include "ueventd.h"
|
||||
|
||||
#define UEVENTD_PARSER_MAXARGS 5
|
||||
|
||||
int ueventd_parse_config_file(const char *fn);
|
||||
void set_device_permission(const char* fn, int line, int nargs, char **args);
|
||||
struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue