Merge "init: Use classes for parsing and clean up memory allocations"

This commit is contained in:
Tom Cherry 2015-09-01 21:35:45 +00:00 committed by Gerrit Code Review
commit 54c70ca156
19 changed files with 944 additions and 984 deletions

View File

@ -45,6 +45,7 @@ include $(CLEAR_VARS)
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
action.cpp \
import_parser.cpp \
init_parser.cpp \
log.cpp \
parser.cpp \

View File

@ -21,46 +21,27 @@
#include <base/strings.h>
#include <base/stringprintf.h>
#include "builtins.h"
#include "error.h"
#include "init_parser.h"
#include "log.h"
#include "property_service.h"
#include "util.h"
class Action::Command
{
public:
Command(int (*f)(const std::vector<std::string>& args),
const std::vector<std::string>& args,
const std::string& filename,
int line);
using android::base::Join;
using android::base::StringPrintf;
int InvokeFunc() const;
std::string BuildCommandString() const;
std::string BuildSourceString() const;
private:
int (*func_)(const std::vector<std::string>& args);
const std::vector<std::string> args_;
const std::string filename_;
int line_;
};
Action::Command::Command(int (*f)(const std::vector<std::string>& args),
const std::vector<std::string>& args,
const std::string& filename,
int line) :
func_(f), args_(args), filename_(filename), line_(line)
{
Command::Command(BuiltinFunction f, const std::vector<std::string>& args,
const std::string& filename, int line)
: func_(f), args_(args), filename_(filename), line_(line) {
}
int Action::Command::InvokeFunc() const
{
int Command::InvokeFunc() const {
std::vector<std::string> expanded_args;
expanded_args.resize(args_.size());
expanded_args[0] = args_[0];
for (std::size_t i = 1; i < args_.size(); ++i) {
if (expand_props(args_[i], &expanded_args[i]) == -1) {
if (!expand_props(args_[i], &expanded_args[i])) {
ERROR("%s: cannot expand '%s'\n", args_[0].c_str(), args_[i].c_str());
return -EINVAL;
}
@ -69,51 +50,71 @@ int Action::Command::InvokeFunc() const
return func_(expanded_args);
}
std::string Action::Command::BuildCommandString() const
{
return android::base::Join(args_, ' ');
std::string Command::BuildCommandString() const {
return Join(args_, ' ');
}
std::string Action::Command::BuildSourceString() const
{
std::string Command::BuildSourceString() const {
if (!filename_.empty()) {
return android::base::StringPrintf(" (%s:%d)", filename_.c_str(), line_);
return StringPrintf(" (%s:%d)", filename_.c_str(), line_);
} else {
return std::string();
}
}
Action::Action()
{
Action::Action(bool oneshot) : oneshot_(oneshot) {
}
void Action::AddCommand(int (*f)(const std::vector<std::string>& args),
const KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr;
bool Action::AddCommand(const std::vector<std::string>& args,
const std::string& filename, int line, std::string* err) {
if (!function_map_) {
*err = "no function map available";
return false;
}
if (args.empty()) {
*err = "command needed, but not provided";
return false;
}
auto function = function_map_->FindFunction(args[0], args.size() - 1, err);
if (!function) {
return false;
}
AddCommand(function, args, filename, line);
return true;
}
void Action::AddCommand(BuiltinFunction f,
const std::vector<std::string>& args,
const std::string& filename, int line)
{
Action::Command* cmd = new Action::Command(f, args, filename, line);
commands_.push_back(cmd);
const std::string& filename, int line) {
commands_.emplace_back(f, args, filename, line);
}
std::size_t Action::NumCommands() const
{
return commands_.size();
}
void Action::ExecuteOneCommand(std::size_t command) const
{
ExecuteCommand(*commands_[command]);
}
void Action::ExecuteAllCommands() const
{
for (const auto& c : commands_) {
ExecuteCommand(*c);
void Action::CombineAction(const Action& action) {
for (const auto& c : action.commands_) {
commands_.emplace_back(c);
}
}
void Action::ExecuteCommand(const Command& command) const
{
std::size_t Action::NumCommands() const {
return commands_.size();
}
void Action::ExecuteOneCommand(std::size_t command) const {
ExecuteCommand(commands_[command]);
}
void Action::ExecuteAllCommands() const {
for (const auto& c : commands_) {
ExecuteCommand(c);
}
}
void Action::ExecuteCommand(const Command& command) const {
Timer t;
int result = command.InvokeFunc();
@ -128,8 +129,7 @@ void Action::ExecuteCommand(const Command& command) const
}
}
bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err)
{
bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err) {
const static std::string prop_str("property:");
std::string prop_name(trigger.substr(prop_str.length()));
size_t equal_pos = prop_name.find('=');
@ -149,8 +149,7 @@ bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err)
return true;
}
bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err)
{
bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err) {
const static std::string prop_str("property:");
for (std::size_t i = 0; i < args.size(); ++i) {
if (i % 2) {
@ -179,21 +178,26 @@ bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err
return true;
}
bool Action::InitSingleTrigger(const std::string& trigger)
{
bool Action::InitSingleTrigger(const std::string& trigger) {
std::vector<std::string> name_vector{trigger};
std::string err;
return InitTriggers(name_vector, &err);
}
// This function checks that all property triggers are satisfied, that is
// for each (name, value) in property_triggers_, check that the current
// value of the property 'name' == value.
//
// It takes an optional (name, value) pair, which if provided must
// be present in property_triggers_; it skips the check of the current
// property value for this pair.
bool Action::CheckPropertyTriggers(const std::string& name,
const std::string& value) const
{
bool found = name.empty();
const std::string& value) const {
if (property_triggers_.empty()) {
return true;
}
bool found = name.empty();
for (const auto& t : property_triggers_) {
const auto& trigger_name = t.first;
const auto& trigger_value = t.second;
@ -214,27 +218,23 @@ bool Action::CheckPropertyTriggers(const std::string& name,
return found;
}
bool Action::CheckEventTrigger(const std::string& trigger) const
{
bool Action::CheckEventTrigger(const std::string& trigger) const {
return !event_trigger_.empty() &&
trigger == event_trigger_ &&
CheckPropertyTriggers();
}
bool Action::CheckPropertyTrigger(const std::string& name,
const std::string& value) const
{
const std::string& value) const {
return event_trigger_.empty() && CheckPropertyTriggers(name, value);
}
bool Action::TriggersEqual(const class Action& other) const
{
bool Action::TriggersEqual(const Action& other) const {
return property_triggers_ == other.property_triggers_ &&
event_trigger_ == other.event_trigger_;
}
std::string Action::BuildTriggersString() const
{
std::string Action::BuildTriggersString() const {
std::string result;
for (const auto& t : property_triggers_) {
@ -251,28 +251,26 @@ std::string Action::BuildTriggersString() const
return result;
}
void Action::DumpState() const
{
void Action::DumpState() const {
std::string trigger_name = BuildTriggersString();
INFO("on %s\n", trigger_name.c_str());
for (const auto& c : commands_) {
std::string cmd_str = c->BuildCommandString();
std::string cmd_str = c.BuildCommandString();
INFO(" %s\n", cmd_str.c_str());
}
INFO("\n");
}
class EventTrigger : public Trigger {
public:
EventTrigger(const std::string& trigger) : trigger_(trigger) {
}
bool CheckTriggers(const Action* action) override {
return action->CheckEventTrigger(trigger_);
bool CheckTriggers(const Action& action) const override {
return action.CheckEventTrigger(trigger_);
}
private:
std::string trigger_;
const std::string trigger_;
};
class PropertyTrigger : public Trigger {
@ -280,27 +278,26 @@ public:
PropertyTrigger(const std::string& name, const std::string& value)
: name_(name), value_(value) {
}
bool CheckTriggers(const Action* action) override {
return action->CheckPropertyTrigger(name_, value_);
bool CheckTriggers(const Action& action) const override {
return action.CheckPropertyTrigger(name_, value_);
}
private:
std::string name_;
std::string value_;
const std::string name_;
const std::string value_;
};
class BuiltinTrigger : public Trigger {
public:
BuiltinTrigger(Action* action) : action_(action) {
}
bool CheckTriggers(const Action* action) override {
return action == action_;
bool CheckTriggers(const Action& action) const override {
return action_ == &action;
}
private:
Action* action_;
const Action* action_;
};
ActionManager::ActionManager() : current_command_(0)
{
ActionManager::ActionManager() : current_command_(0) {
}
ActionManager& ActionManager::GetInstance() {
@ -308,45 +305,56 @@ ActionManager& ActionManager::GetInstance() {
return instance;
}
void ActionManager::QueueEventTrigger(const std::string& trigger)
{
void ActionManager::AddAction(std::unique_ptr<Action> action) {
auto old_action_it =
std::find_if(actions_.begin(), actions_.end(),
[&action] (std::unique_ptr<Action>& a) {
return action->TriggersEqual(*a);
});
if (old_action_it != actions_.end()) {
(*old_action_it)->CombineAction(*action);
} else {
actions_.emplace_back(std::move(action));
}
}
void ActionManager::QueueEventTrigger(const std::string& trigger) {
trigger_queue_.push(std::make_unique<EventTrigger>(trigger));
}
void ActionManager::QueuePropertyTrigger(const std::string& name,
const std::string& value)
{
const std::string& value) {
trigger_queue_.push(std::make_unique<PropertyTrigger>(name, value));
}
void ActionManager::QueueAllPropertyTriggers()
{
void ActionManager::QueueAllPropertyTriggers() {
QueuePropertyTrigger("", "");
}
void ActionManager::QueueBuiltinAction(int (*func)(const std::vector<std::string>& args),
const std::string& name)
{
Action* act = new Action();
void ActionManager::QueueBuiltinAction(BuiltinFunction func,
const std::string& name) {
auto action = std::make_unique<Action>(true);
std::vector<std::string> name_vector{name};
if (!act->InitSingleTrigger(name)) {
if (!action->InitSingleTrigger(name)) {
return;
}
act->AddCommand(func, name_vector);
action->AddCommand(func, name_vector);
actions_.push_back(act);
trigger_queue_.push(std::make_unique<BuiltinTrigger>(act));
trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get()));
actions_.emplace_back(std::move(action));
}
void ActionManager::ExecuteOneCommand() {
// Loop through the trigger queue until we have an action to execute
while (current_executing_actions_.empty() && !trigger_queue_.empty()) {
std::copy_if(actions_.begin(), actions_.end(),
std::back_inserter(current_executing_actions_),
[this] (Action* act) {
return trigger_queue_.front()->CheckTriggers(act);
});
for (const auto& action : actions_) {
if (trigger_queue_.front()->CheckTriggers(*action)) {
current_executing_actions_.emplace(action.get());
}
}
trigger_queue_.pop();
}
@ -354,59 +362,67 @@ void ActionManager::ExecuteOneCommand() {
return;
}
Action* action = current_executing_actions_.back();
if (!action->NumCommands()) {
current_executing_actions_.pop_back();
return;
}
auto action = current_executing_actions_.front();
if (current_command_ == 0) {
std::string trigger_name = action->BuildTriggersString();
INFO("processing action %p (%s)\n", action, trigger_name.c_str());
INFO("processing action (%s)\n", trigger_name.c_str());
}
action->ExecuteOneCommand(current_command_++);
action->ExecuteOneCommand(current_command_);
// If this was the last command in the current action, then remove
// the action from the executing list.
// If this action was oneshot, then also remove it from actions_.
++current_command_;
if (current_command_ == action->NumCommands()) {
current_executing_actions_.pop();
current_command_ = 0;
current_executing_actions_.pop_back();
if (action->oneshot()) {
auto eraser = [&action] (std::unique_ptr<Action>& a) {
return a.get() == action;
};
actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
}
}
}
bool ActionManager::HasMoreCommands() const
{
bool ActionManager::HasMoreCommands() const {
return !current_executing_actions_.empty() || !trigger_queue_.empty();
}
Action* ActionManager::AddNewAction(const std::vector<std::string>& triggers,
std::string* err)
{
if (triggers.size() < 1) {
*err = "actions must have a trigger\n";
return nullptr;
}
Action* act = new Action();
if (!act->InitTriggers(triggers, err)) {
return nullptr;
}
auto old_act_it =
std::find_if(actions_.begin(), actions_.end(),
[&act] (Action* a) { return act->TriggersEqual(*a); });
if (old_act_it != actions_.end()) {
delete act;
return *old_act_it;
}
actions_.push_back(act);
return act;
}
void ActionManager::DumpState() const
{
void ActionManager::DumpState() const {
for (const auto& a : actions_) {
a->DumpState();
}
INFO("\n");
}
bool ActionParser::ParseSection(const std::vector<std::string>& args,
std::string* err) {
std::vector<std::string> triggers(args.begin() + 1, args.end());
if (triggers.size() < 1) {
*err = "actions must have a trigger";
return false;
}
auto action = std::make_unique<Action>(false);
if (!action->InitTriggers(triggers, err)) {
return false;
}
action_ = std::move(action);
return true;
}
bool ActionParser::ParseLineSection(const std::vector<std::string>& args,
const std::string& filename, int line,
std::string* err) const {
return action_ ? action_->AddCommand(args, filename, line, err) : false;
}
void ActionParser::EndSection() {
if (action_ && action_->NumCommands() > 0) {
ActionManager::GetInstance().AddAction(std::move(action_));
}
}

View File

@ -22,13 +22,36 @@
#include <string>
#include <vector>
#include "builtins.h"
#include "init_parser.h"
#include "keyword_map.h"
class Command {
public:
Command(BuiltinFunction f, const std::vector<std::string>& args,
const std::string& filename, int line);
int InvokeFunc() const;
std::string BuildCommandString() const;
std::string BuildSourceString() const;
private:
BuiltinFunction func_;
std::vector<std::string> args_;
std::string filename_;
int line_;
};
class Action {
public:
Action();
Action(bool oneshot = false);
void AddCommand(int (*f)(const std::vector<std::string>& args),
bool AddCommand(const std::vector<std::string>& args,
const std::string& filename, int line, std::string* err);
void AddCommand(BuiltinFunction f,
const std::vector<std::string>& args,
const std::string& filename = "", int line = 0);
void CombineAction(const Action& action);
bool InitTriggers(const std::vector<std::string>& args, std::string* err);
bool InitSingleTrigger(const std::string& trigger);
std::size_t NumCommands() const;
@ -37,13 +60,17 @@ public:
bool CheckEventTrigger(const std::string& trigger) const;
bool CheckPropertyTrigger(const std::string& name,
const std::string& value) const;
bool TriggersEqual(const class Action& other) const;
bool TriggersEqual(const Action& other) const;
std::string BuildTriggersString() const;
void DumpState() const;
private:
class Command;
bool oneshot() const { return oneshot_; }
static void set_function_map(const KeywordMap<BuiltinFunction>* function_map) {
function_map_ = function_map;
}
private:
void ExecuteCommand(const Command& command) const;
bool CheckPropertyTriggers(const std::string& name = "",
const std::string& value = "") const;
@ -51,27 +78,28 @@ private:
std::map<std::string, std::string> property_triggers_;
std::string event_trigger_;
std::vector<Command*> commands_;
std::vector<Command> commands_;
bool oneshot_;
static const KeywordMap<BuiltinFunction>* function_map_;
};
class Trigger {
public:
virtual ~Trigger() { }
virtual bool CheckTriggers(const Action* action) = 0;
virtual bool CheckTriggers(const Action& action) const = 0;
};
class ActionManager {
public:
static ActionManager& GetInstance();
void AddAction(std::unique_ptr<Action> action);
void QueueEventTrigger(const std::string& trigger);
void QueuePropertyTrigger(const std::string& name, const std::string& value);
void QueueAllPropertyTriggers();
void QueueBuiltinAction(int (*func)(const std::vector<std::string>& args),
const std::string& name);
void QueueBuiltinAction(BuiltinFunction func, const std::string& name);
void ExecuteOneCommand();
bool HasMoreCommands() const;
Action* AddNewAction(const std::vector<std::string>& triggers,
std::string* err);
void DumpState() const;
private:
@ -80,10 +108,26 @@ private:
ActionManager(ActionManager const&) = delete;
void operator=(ActionManager const&) = delete;
std::vector<Action*> actions_;
std::vector<std::unique_ptr<Action>> actions_;
std::queue<std::unique_ptr<Trigger>> trigger_queue_;
std::vector<Action*> current_executing_actions_;
std::queue<const Action*> current_executing_actions_;
std::size_t current_command_;
};
class ActionParser : public SectionParser {
public:
ActionParser() : action_(nullptr) {
}
bool ParseSection(const std::vector<std::string>& args,
std::string* err) override;
bool ParseLineSection(const std::vector<std::string>& args,
const std::string& filename, int line,
std::string* err) const override;
void EndSection() override;
void EndFile(const std::string&) override {
}
private:
std::unique_ptr<Action> action_;
};
#endif

View File

@ -15,7 +15,6 @@
*/
#include "bootchart.h"
#include "keywords.h"
#include "log.h"
#include "property_service.h"
@ -32,6 +31,7 @@
#include <memory>
#include <string>
#include <vector>
#include <base/file.h>

View File

@ -17,6 +17,10 @@
#ifndef _BOOTCHART_H
#define _BOOTCHART_H
#include <string>
#include <vector>
int do_bootchart_init(const std::vector<std::string>& args);
void bootchart_sample(int* timeout);
#endif /* _BOOTCHART_H */

View File

@ -14,6 +14,8 @@
* limitations under the License.
*/
#include "builtins.h"
#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
@ -44,10 +46,10 @@
#include <private/android_filesystem_config.h>
#include "action.h"
#include "bootchart.h"
#include "devices.h"
#include "init.h"
#include "init_parser.h"
#include "keywords.h"
#include "log.h"
#include "property_service.h"
#include "service.h"
@ -60,8 +62,7 @@
// System call provided by bionic but not in any header file.
extern "C" int init_module(void *, unsigned long, const char *);
static int insmod(const char *filename, const char *options)
{
static int insmod(const char *filename, const char *options) {
std::string module;
if (!read_file(filename, &module)) {
return -1;
@ -71,8 +72,7 @@ static int insmod(const char *filename, const char *options)
return init_module(&module[0], module.size(), options);
}
static int __ifupdown(const char *interface, int up)
{
static int __ifupdown(const char *interface, int up) {
struct ifreq ifr;
int s, ret;
@ -99,8 +99,7 @@ done:
return ret;
}
static void unmount_and_fsck(const struct mntent *entry)
{
static void unmount_and_fsck(const struct mntent *entry) {
if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4"))
return;
@ -160,8 +159,7 @@ static void unmount_and_fsck(const struct mntent *entry)
}
}
int do_class_start(const std::vector<std::string>& args)
{
static int do_class_start(const std::vector<std::string>& args) {
/* Starting a class does not start services
* which are explicitly disabled. They must
* be started individually.
@ -171,27 +169,23 @@ int do_class_start(const std::vector<std::string>& args)
return 0;
}
int do_class_stop(const std::vector<std::string>& args)
{
static int do_class_stop(const std::vector<std::string>& args) {
ServiceManager::GetInstance().
ForEachServiceInClass(args[1], [] (Service* s) { s->Stop(); });
return 0;
}
int do_class_reset(const std::vector<std::string>& args)
{
static int do_class_reset(const std::vector<std::string>& args) {
ServiceManager::GetInstance().
ForEachServiceInClass(args[1], [] (Service* s) { s->Reset(); });
return 0;
}
int do_domainname(const std::vector<std::string>& args)
{
static int do_domainname(const std::vector<std::string>& args) {
return write_file("/proc/sys/kernel/domainname", args[1].c_str());
}
int do_enable(const std::vector<std::string>& args)
{
static int do_enable(const std::vector<std::string>& args) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
if (!svc) {
return -1;
@ -199,7 +193,7 @@ int do_enable(const std::vector<std::string>& args)
return svc->Enable();
}
int do_exec(const std::vector<std::string>& args) {
static int do_exec(const std::vector<std::string>& args) {
Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args);
if (!svc) {
return -1;
@ -211,23 +205,19 @@ int do_exec(const std::vector<std::string>& args) {
return 0;
}
int do_export(const std::vector<std::string>& args)
{
static int do_export(const std::vector<std::string>& args) {
return add_environment(args[1].c_str(), args[2].c_str());
}
int do_hostname(const std::vector<std::string>& args)
{
static int do_hostname(const std::vector<std::string>& args) {
return write_file("/proc/sys/kernel/hostname", args[1].c_str());
}
int do_ifup(const std::vector<std::string>& args)
{
static int do_ifup(const std::vector<std::string>& args) {
return __ifupdown(args[1].c_str(), 1);
}
int do_insmod(const std::vector<std::string>& args)
{
static int do_insmod(const std::vector<std::string>& args) {
std::string options;
if (args.size() > 2) {
@ -241,8 +231,7 @@ int do_insmod(const std::vector<std::string>& args)
return insmod(args[1].c_str(), options.c_str());
}
int do_mkdir(const std::vector<std::string>& args)
{
static int do_mkdir(const std::vector<std::string>& args) {
mode_t mode = 0755;
int ret;
@ -310,8 +299,7 @@ static struct {
#define DATA_MNT_POINT "/data"
/* mount <type> <device> <path> <flags ...> <options> */
int do_mount(const std::vector<std::string>& args)
{
static int do_mount(const std::vector<std::string>& args) {
char tmp[64];
const char *source, *target, *system;
const char *options = NULL;
@ -411,8 +399,7 @@ exit_success:
}
static int wipe_data_via_recovery()
{
static int wipe_data_via_recovery() {
mkdir("/cache/recovery", 0700);
int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0600);
if (fd >= 0) {
@ -427,16 +414,16 @@ static int wipe_data_via_recovery()
while (1) { pause(); } // never reached
}
void import_late()
{
static void import_late() {
static const std::vector<std::string> init_directories = {
"/system/etc/init",
"/vendor/etc/init",
"/odm/etc/init"
};
Parser& parser = Parser::GetInstance();
for (const auto& dir : init_directories) {
init_parse_config(dir.c_str());
parser.ParseConfig(dir.c_str());
}
}
@ -444,17 +431,13 @@ void import_late()
* This function might request a reboot, in which case it will
* not return.
*/
int do_mount_all(const std::vector<std::string>& args)
{
static int do_mount_all(const std::vector<std::string>& args) {
pid_t pid;
int ret = -1;
int child_ret = -1;
int status;
struct fstab *fstab;
if (args.size() != 2) {
return -1;
}
const char* fstabfile = args[1].c_str();
/*
* Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and
@ -535,8 +518,7 @@ int do_mount_all(const std::vector<std::string>& args)
return ret;
}
int do_swapon_all(const std::vector<std::string>& args)
{
static int do_swapon_all(const std::vector<std::string>& args) {
struct fstab *fstab;
int ret;
@ -547,16 +529,14 @@ int do_swapon_all(const std::vector<std::string>& args)
return ret;
}
int do_setprop(const std::vector<std::string>& args)
{
static int do_setprop(const std::vector<std::string>& args) {
const char* name = args[1].c_str();
const char* value = args[2].c_str();
property_set(name, value);
return 0;
}
int do_setrlimit(const std::vector<std::string>& args)
{
static int do_setrlimit(const std::vector<std::string>& args) {
struct rlimit limit;
int resource;
resource = std::stoi(args[1]);
@ -565,8 +545,7 @@ int do_setrlimit(const std::vector<std::string>& args)
return setrlimit(resource, &limit);
}
int do_start(const std::vector<std::string>& args)
{
static int do_start(const std::vector<std::string>& args) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
if (!svc) {
ERROR("do_start: Service %s not found\n", args[1].c_str());
@ -577,8 +556,7 @@ int do_start(const std::vector<std::string>& args)
return 0;
}
int do_stop(const std::vector<std::string>& args)
{
static int do_stop(const std::vector<std::string>& args) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
if (!svc) {
ERROR("do_stop: Service %s not found\n", args[1].c_str());
@ -588,8 +566,7 @@ int do_stop(const std::vector<std::string>& args)
return 0;
}
int do_restart(const std::vector<std::string>& args)
{
static int do_restart(const std::vector<std::string>& args) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
if (!svc) {
ERROR("do_restart: Service %s not found\n", args[1].c_str());
@ -599,8 +576,7 @@ int do_restart(const std::vector<std::string>& args)
return 0;
}
int do_powerctl(const std::vector<std::string>& args)
{
static int do_powerctl(const std::vector<std::string>& args) {
const char* command = args[1].c_str();
int len = 0;
unsigned int cmd = 0;
@ -636,34 +612,26 @@ int do_powerctl(const std::vector<std::string>& args)
callback_on_ro_remount);
}
int do_trigger(const std::vector<std::string>& args)
{
static int do_trigger(const std::vector<std::string>& args) {
ActionManager::GetInstance().QueueEventTrigger(args[1]);
return 0;
}
int do_symlink(const std::vector<std::string>& args)
{
static int do_symlink(const std::vector<std::string>& args) {
return symlink(args[1].c_str(), args[2].c_str());
}
int do_rm(const std::vector<std::string>& args)
{
static int do_rm(const std::vector<std::string>& args) {
return unlink(args[1].c_str());
}
int do_rmdir(const std::vector<std::string>& args)
{
static int do_rmdir(const std::vector<std::string>& args) {
return rmdir(args[1].c_str());
}
int do_sysclktz(const std::vector<std::string>& args)
{
static int do_sysclktz(const std::vector<std::string>& args) {
struct timezone tz;
if (args.size() != 2)
return -1;
memset(&tz, 0, sizeof(tz));
tz.tz_minuteswest = std::stoi(args[1]);
if (settimeofday(NULL, &tz))
@ -671,7 +639,7 @@ int do_sysclktz(const std::vector<std::string>& args)
return 0;
}
int do_verity_load_state(const std::vector<std::string>& args) {
static int do_verity_load_state(const std::vector<std::string>& args) {
int mode = -1;
int rc = fs_mgr_load_verity_state(&mode);
if (rc == 0 && mode == VERITY_MODE_LOGGING) {
@ -680,24 +648,23 @@ int do_verity_load_state(const std::vector<std::string>& args) {
return rc;
}
static void verity_update_property(fstab_rec *fstab, const char *mount_point, int mode, int status) {
static void verity_update_property(fstab_rec *fstab, const char *mount_point,
int mode, int status) {
property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(),
android::base::StringPrintf("%d", mode).c_str());
}
int do_verity_update_state(const std::vector<std::string>& args) {
static int do_verity_update_state(const std::vector<std::string>& args) {
return fs_mgr_update_verity_state(verity_update_property);
}
int do_write(const std::vector<std::string>& args)
{
static int do_write(const std::vector<std::string>& args) {
const char* path = args[1].c_str();
const char* value = args[2].c_str();
return write_file(path, value);
}
int do_copy(const std::vector<std::string>& args)
{
static int do_copy(const std::vector<std::string>& args) {
char *buffer = NULL;
int rc = 0;
int fd1 = -1, fd2 = -1;
@ -705,9 +672,6 @@ int do_copy(const std::vector<std::string>& args)
int brtw, brtr;
char *p;
if (args.size() != 3)
return -1;
if (stat(args[1].c_str(), &info) < 0)
return -1;
@ -758,7 +722,7 @@ out:
return rc;
}
int do_chown(const std::vector<std::string>& args) {
static int do_chown(const std::vector<std::string>& args) {
/* GID is optional. */
if (args.size() == 3) {
if (lchown(args[2].c_str(), decode_uid(args[1].c_str()), -1) == -1)
@ -786,7 +750,7 @@ static mode_t get_mode(const char *s) {
return mode;
}
int do_chmod(const std::vector<std::string>& args) {
static int do_chmod(const std::vector<std::string>& args) {
mode_t mode = get_mode(args[1].c_str());
if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) {
return -errno;
@ -794,7 +758,7 @@ int do_chmod(const std::vector<std::string>& args) {
return 0;
}
int do_restorecon(const std::vector<std::string>& args) {
static int do_restorecon(const std::vector<std::string>& args) {
int ret = 0;
for (auto it = std::next(args.begin()); it != args.end(); ++it) {
@ -804,7 +768,7 @@ int do_restorecon(const std::vector<std::string>& args) {
return ret;
}
int do_restorecon_recursive(const std::vector<std::string>& args) {
static int do_restorecon_recursive(const std::vector<std::string>& args) {
int ret = 0;
for (auto it = std::next(args.begin()); it != args.end(); ++it) {
@ -814,12 +778,7 @@ int do_restorecon_recursive(const std::vector<std::string>& args) {
return ret;
}
int do_loglevel(const std::vector<std::string>& args) {
if (args.size() != 2) {
ERROR("loglevel: missing argument\n");
return -EINVAL;
}
static int do_loglevel(const std::vector<std::string>& args) {
int log_level = std::stoi(args[1]);
if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
ERROR("loglevel: invalid log level'%d'\n", log_level);
@ -830,23 +789,16 @@ int do_loglevel(const std::vector<std::string>& args) {
}
int do_load_persist_props(const std::vector<std::string>& args) {
if (args.size() == 1) {
load_persist_props();
return 0;
}
return -1;
load_persist_props();
return 0;
}
int do_load_all_props(const std::vector<std::string>& args) {
if (args.size() == 1) {
load_all_props();
return 0;
}
return -1;
static int do_load_all_props(const std::vector<std::string>& args) {
load_all_props();
return 0;
}
int do_wait(const std::vector<std::string>& args)
{
static int do_wait(const std::vector<std::string>& args) {
if (args.size() == 2) {
return wait_for_file(args[1].c_str(), COMMAND_RETRY_TIMEOUT);
} else if (args.size() == 3) {
@ -858,8 +810,7 @@ int do_wait(const std::vector<std::string>& args)
/*
* Callback to make a directory from the ext4 code
*/
static int do_installkeys_ensure_dir_exists(const char* dir)
{
static int do_installkeys_ensure_dir_exists(const char* dir) {
if (make_dir(dir, 0700) && errno != EEXIST) {
return -1;
}
@ -867,12 +818,7 @@ static int do_installkeys_ensure_dir_exists(const char* dir)
return 0;
}
int do_installkey(const std::vector<std::string>& args)
{
if (args.size() != 2) {
return -1;
}
static int do_installkey(const std::vector<std::string>& args) {
std::string prop_value = property_get("ro.crypto.type");
if (prop_value != "file") {
return 0;
@ -881,3 +827,49 @@ int do_installkey(const std::vector<std::string>& args)
return e4crypt_create_device_key(args[1].c_str(),
do_installkeys_ensure_dir_exists);
}
BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
static const Map builtin_functions = {
{"bootchart_init", {0, 0, do_bootchart_init}},
{"chmod", {2, 2, do_chmod}},
{"chown", {2, 3, do_chown}},
{"class_reset", {1, 1, do_class_reset}},
{"class_start", {1, 1, do_class_start}},
{"class_stop", {1, 1, do_class_stop}},
{"copy", {2, 2, do_copy}},
{"domainname", {1, 1, do_domainname}},
{"enable", {1, 1, do_enable}},
{"exec", {1, kMax, do_exec}},
{"export", {2, 2, do_export}},
{"hostname", {1, 1, do_hostname}},
{"ifup", {1, 1, do_ifup}},
{"insmod", {1, kMax, do_insmod}},
{"installkey", {1, 1, do_installkey}},
{"load_all_props", {0, 0, do_load_all_props}},
{"load_persist_props", {0, 0, do_load_persist_props}},
{"loglevel", {1, 1, do_loglevel}},
{"mkdir", {1, 4, do_mkdir}},
{"mount_all", {1, 1, do_mount_all}},
{"mount", {3, kMax, do_mount}},
{"powerctl", {1, 1, do_powerctl}},
{"restart", {1, 1, do_restart}},
{"restorecon", {1, kMax, do_restorecon}},
{"restorecon_recursive", {1, kMax, do_restorecon_recursive}},
{"rm", {1, 1, do_rm}},
{"rmdir", {1, 1, do_rmdir}},
{"setprop", {2, 2, do_setprop}},
{"setrlimit", {3, 3, do_setrlimit}},
{"start", {1, 1, do_start}},
{"stop", {1, 1, do_stop}},
{"swapon_all", {1, 1, do_swapon_all}},
{"symlink", {2, 2, do_symlink}},
{"sysclktz", {1, 1, do_sysclktz}},
{"trigger", {1, 1, do_trigger}},
{"verity_load_state", {0, 0, do_verity_load_state}},
{"verity_update_state", {0, 0, do_verity_update_state}},
{"wait", {1, 2, do_wait}},
{"write", {2, 2, do_write}},
};
return builtin_functions;
}

35
init/builtins.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2015 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_BUILTINS_H
#define _INIT_BUILTINS_H
#include <map>
#include <string>
#include <vector>
#include "keyword_map.h"
using BuiltinFunction = int (*) (const std::vector<std::string>& args);
class BuiltinFunctionMap : public KeywordMap<BuiltinFunction> {
public:
BuiltinFunctionMap() {
}
private:
Map& map() const override;
};
#endif

55
init/import_parser.cpp Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2015 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 "import_parser.h"
#include "errno.h"
#include <string>
#include <vector>
#include "log.h"
#include "util.h"
bool ImportParser::ParseSection(const std::vector<std::string>& args,
std::string* err) {
if (args.size() != 2) {
*err = "single argument needed for import\n";
return false;
}
std::string conf_file;
bool ret = expand_props(args[1], &conf_file);
if (!ret) {
*err = "error while expanding import";
return false;
}
INFO("Added '%s' to import list\n", conf_file.c_str());
imports_.emplace_back(std::move(conf_file));
return true;
}
void ImportParser::EndFile(const std::string& filename) {
auto current_imports = std::move(imports_);
imports_.clear();
for (const auto& s : current_imports) {
if (!Parser::GetInstance().ParseConfig(s)) {
ERROR("could not import file '%s' from '%s': %s\n",
s.c_str(), filename.c_str(), strerror(errno));
}
}
}

43
init/import_parser.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2015 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_IMPORT_PARSER_H
#define _INIT_IMPORT_PARSER_H
#include "init_parser.h"
#include <string>
#include <vector>
class ImportParser : public SectionParser {
public:
ImportParser() {
}
bool ParseSection(const std::vector<std::string>& args,
std::string* err) override;
bool ParseLineSection(const std::vector<std::string>& args,
const std::string& filename, int line,
std::string* err) const override {
return true;
}
void EndSection() override {
}
void EndFile(const std::string& filename) override;
private:
std::vector<std::string> imports_;
};
#endif

View File

@ -55,6 +55,7 @@
#include "action.h"
#include "bootchart.h"
#include "devices.h"
#include "import_parser.h"
#include "init.h"
#include "init_parser.h"
#include "keychords.h"
@ -604,7 +605,14 @@ int main(int argc, char** argv) {
property_load_boot_defaults();
start_property_service();
init_parse_config("/init.rc");
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
Parser& parser = Parser::GetInstance();
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
parser.ParseConfig("/init.rc");
ActionManager& am = ActionManager::GetInstance();

View File

@ -14,387 +14,117 @@
* limitations under the License.
*/
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "action.h"
#include "init.h"
#include "init_parser.h"
#include "log.h"
#include "parser.h"
#include "property_service.h"
#include "service.h"
#include "util.h"
#include <base/stringprintf.h>
#include <cutils/iosched_policy.h>
#include <cutils/list.h>
static list_declare(service_list);
struct import {
struct listnode list;
const char *filename;
};
static void *parse_service(struct parse_state *state, int nargs, char **args);
static void parse_line_service(struct parse_state *state, int nargs, char **args);
static void *parse_action(struct parse_state *state, int nargs, char **args);
static void parse_line_action(struct parse_state *state, int nargs, char **args);
#define SECTION 0x01
#define COMMAND 0x02
#define OPTION 0x04
#include "keywords.h"
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
static struct {
const char *name;
int (*func)(const std::vector<std::string>& args);
size_t nargs;
unsigned char flags;
} keyword_info[KEYWORD_COUNT] = {
[ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
#include "keywords.h"
};
#undef KEYWORD
#define kw_is(kw, type) (keyword_info[kw].flags & (type))
#define kw_name(kw) (keyword_info[kw].name)
#define kw_func(kw) (keyword_info[kw].func)
#define kw_nargs(kw) (keyword_info[kw].nargs)
void dump_parser_state() {
ServiceManager::GetInstance().DumpState();
ActionManager::GetInstance().DumpState();
Parser::Parser() {
}
static int lookup_keyword(const char *s)
{
switch (*s++) {
case 'b':
if (!strcmp(s, "ootchart_init")) return K_bootchart_init;
break;
case 'c':
if (!strcmp(s, "opy")) return K_copy;
if (!strcmp(s, "lass")) return K_class;
if (!strcmp(s, "lass_start")) return K_class_start;
if (!strcmp(s, "lass_stop")) return K_class_stop;
if (!strcmp(s, "lass_reset")) return K_class_reset;
if (!strcmp(s, "onsole")) return K_console;
if (!strcmp(s, "hown")) return K_chown;
if (!strcmp(s, "hmod")) return K_chmod;
if (!strcmp(s, "ritical")) return K_critical;
break;
case 'd':
if (!strcmp(s, "isabled")) return K_disabled;
if (!strcmp(s, "omainname")) return K_domainname;
break;
case 'e':
if (!strcmp(s, "nable")) return K_enable;
if (!strcmp(s, "xec")) return K_exec;
if (!strcmp(s, "xport")) return K_export;
break;
case 'g':
if (!strcmp(s, "roup")) return K_group;
break;
case 'h':
if (!strcmp(s, "ostname")) return K_hostname;
break;
case 'i':
if (!strcmp(s, "oprio")) return K_ioprio;
if (!strcmp(s, "fup")) return K_ifup;
if (!strcmp(s, "nsmod")) return K_insmod;
if (!strcmp(s, "mport")) return K_import;
if (!strcmp(s, "nstallkey")) return K_installkey;
break;
case 'k':
if (!strcmp(s, "eycodes")) return K_keycodes;
break;
case 'l':
if (!strcmp(s, "oglevel")) return K_loglevel;
if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
if (!strcmp(s, "oad_all_props")) return K_load_all_props;
break;
case 'm':
if (!strcmp(s, "kdir")) return K_mkdir;
if (!strcmp(s, "ount_all")) return K_mount_all;
if (!strcmp(s, "ount")) return K_mount;
break;
case 'o':
if (!strcmp(s, "n")) return K_on;
if (!strcmp(s, "neshot")) return K_oneshot;
if (!strcmp(s, "nrestart")) return K_onrestart;
break;
case 'p':
if (!strcmp(s, "owerctl")) return K_powerctl;
break;
case 'r':
if (!strcmp(s, "estart")) return K_restart;
if (!strcmp(s, "estorecon")) return K_restorecon;
if (!strcmp(s, "estorecon_recursive")) return K_restorecon_recursive;
if (!strcmp(s, "mdir")) return K_rmdir;
if (!strcmp(s, "m")) return K_rm;
break;
case 's':
if (!strcmp(s, "eclabel")) return K_seclabel;
if (!strcmp(s, "ervice")) return K_service;
if (!strcmp(s, "etenv")) return K_setenv;
if (!strcmp(s, "etprop")) return K_setprop;
if (!strcmp(s, "etrlimit")) return K_setrlimit;
if (!strcmp(s, "ocket")) return K_socket;
if (!strcmp(s, "tart")) return K_start;
if (!strcmp(s, "top")) return K_stop;
if (!strcmp(s, "wapon_all")) return K_swapon_all;
if (!strcmp(s, "ymlink")) return K_symlink;
if (!strcmp(s, "ysclktz")) return K_sysclktz;
break;
case 't':
if (!strcmp(s, "rigger")) return K_trigger;
break;
case 'u':
if (!strcmp(s, "ser")) return K_user;
break;
case 'v':
if (!strcmp(s, "erity_load_state")) return K_verity_load_state;
if (!strcmp(s, "erity_update_state")) return K_verity_update_state;
break;
case 'w':
if (!strcmp(s, "rite")) return K_write;
if (!strcmp(s, "ritepid")) return K_writepid;
if (!strcmp(s, "ait")) return K_wait;
break;
}
return K_UNKNOWN;
Parser& Parser::GetInstance() {
static Parser instance;
return instance;
}
static void parse_line_no_op(struct parse_state*, int, char**) {
void Parser::AddSectionParser(const std::string& name,
std::unique_ptr<SectionParser> parser) {
section_parsers_[name] = std::move(parser);
}
int expand_props(const std::string& src, std::string* dst) {
const char *src_ptr = src.c_str();
if (!dst) {
return -1;
}
/* - variables can either be $x.y or ${x.y}, in case they are only part
* of the string.
* - will accept $$ as a literal $.
* - no nested property expansion, i.e. ${foo.${bar}} is not supported,
* bad things will happen
*/
while (*src_ptr) {
const char *c;
c = strchr(src_ptr, '$');
if (!c) {
dst->append(src_ptr);
break;
}
dst->append(src_ptr, c);
c++;
if (*c == '$') {
dst->push_back(*(c++));
src_ptr = c;
continue;
} else if (*c == '\0') {
break;
}
std::string prop_name;
if (*c == '{') {
c++;
const char* end = strchr(c, '}');
if (!end) {
// failed to find closing brace, abort.
ERROR("unexpected end of string in '%s', looking for }\n", src.c_str());
goto err;
}
prop_name = std::string(c, end);
c = end + 1;
} else {
prop_name = c;
ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
c);
c += prop_name.size();
}
if (prop_name.empty()) {
ERROR("invalid zero-length prop name in '%s'\n", src.c_str());
goto err;
}
std::string prop_val = property_get(prop_name.c_str());
if (prop_val.empty()) {
ERROR("property '%s' doesn't exist while expanding '%s'\n",
prop_name.c_str(), src.c_str());
goto err;
}
dst->append(prop_val);
src_ptr = c;
continue;
}
return 0;
err:
return -1;
}
static void parse_import(struct parse_state *state, int nargs, char **args)
{
if (nargs != 2) {
ERROR("single argument needed for import\n");
return;
}
std::string conf_file;
int ret = expand_props(args[1], &conf_file);
if (ret) {
ERROR("error while handling import on line '%d' in '%s'\n",
state->line, state->filename);
return;
}
struct import* import = (struct import*) calloc(1, sizeof(struct import));
import->filename = strdup(conf_file.c_str());
struct listnode *import_list = (listnode*) state->priv;
list_add_tail(import_list, &import->list);
INFO("Added '%s' to import list\n", import->filename);
}
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_service:
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service;
return;
}
break;
case K_on:
state->context = parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
case K_import:
parse_import(state, nargs, args);
break;
}
state->parse_line = parse_line_no_op;
}
static void parse_config(const char *fn, const std::string& data)
{
struct listnode import_list;
struct listnode *node;
char *args[INIT_PARSER_MAXARGS];
int nargs = 0;
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 = fn;
state.filename = filename.c_str();
state.line = 0;
state.ptr = &data_copy[0];
state.nexttoken = 0;
state.parse_line = parse_line_no_op;
list_init(&import_list);
state.priv = &import_list;
SectionParser* section_parser = nullptr;
std::vector<std::string> args;
for (;;) {
switch (next_token(&state)) {
case T_EOF:
state.parse_line(&state, 0, 0);
goto parser_done;
if (section_parser) {
section_parser->EndSection();
}
return;
case T_NEWLINE:
state.line++;
if (nargs) {
int kw = lookup_keyword(args[0]);
if (kw_is(kw, SECTION)) {
state.parse_line(&state, 0, 0);
parse_new_section(&state, kw, nargs, args);
} else {
state.parse_line(&state, nargs, args);
}
nargs = 0;
if (args.empty()) {
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(args, &ret_err)) {
parse_error(&state, "%s\n", ret_err.c_str());
section_parser = nullptr;
}
} else if (section_parser) {
std::string ret_err;
if (!section_parser->ParseLineSection(args, state.filename,
state.line, &ret_err)) {
parse_error(&state, "%s\n", ret_err.c_str());
}
}
args.clear();
break;
case T_TEXT:
if (nargs < INIT_PARSER_MAXARGS) {
args[nargs++] = state.text;
}
args.emplace_back(state.text);
break;
}
}
parser_done:
list_for_each(node, &import_list) {
struct import* import = node_to_item(node, struct import, list);
if (!init_parse_config(import->filename)) {
ERROR("could not import file '%s' from '%s': %s\n",
import->filename, fn, strerror(errno));
}
}
}
static bool init_parse_config_file(const char* path) {
INFO("Parsing file %s...\n", path);
bool Parser::ParseConfigFile(const std::string& path) {
INFO("Parsing file %s...\n", path.c_str());
Timer t;
std::string data;
if (!read_file(path, &data)) {
if (!read_file(path.c_str(), &data)) {
return false;
}
data.push_back('\n'); // TODO: fix parse_config.
parse_config(path, data);
dump_parser_state();
ParseData(path, data);
for (const auto& sp : section_parsers_) {
sp.second->EndFile(path);
}
DumpState();
NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration());
return true;
}
static bool init_parse_config_dir(const char* path) {
INFO("Parsing directory %s...\n", path);
std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path), closedir);
bool Parser::ParseConfigDir(const std::string& path) {
INFO("Parsing directory %s...\n", path.c_str());
std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
if (!config_dir) {
ERROR("Could not import directory '%s'\n", path);
ERROR("Could not import directory '%s'\n", path.c_str());
return false;
}
dirent* current_file;
while ((current_file = readdir(config_dir.get()))) {
std::string current_path =
android::base::StringPrintf("%s/%s", path, current_file->d_name);
android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
// Ignore directories and only process regular files.
if (current_file->d_type == DT_REG) {
if (!init_parse_config_file(current_path.c_str())) {
if (!ParseConfigFile(current_path)) {
ERROR("could not import file '%s'\n", current_path.c_str());
}
}
@ -402,97 +132,14 @@ static bool init_parse_config_dir(const char* path) {
return true;
}
bool init_parse_config(const char* path) {
if (is_dir(path)) {
return init_parse_config_dir(path);
bool Parser::ParseConfig(const std::string& path) {
if (is_dir(path.c_str())) {
return ParseConfigDir(path);
}
return init_parse_config_file(path);
return ParseConfigFile(path);
}
static void *parse_service(struct parse_state *state, int nargs, char **args)
{
if (nargs < 3) {
parse_error(state, "services must have a name and a program\n");
return nullptr;
}
std::vector<std::string> str_args(args + 2, args + nargs);
std::string ret_err;
Service* svc = ServiceManager::GetInstance().AddNewService(args[1], "default",
str_args, &ret_err);
if (!svc) {
parse_error(state, "%s\n", ret_err.c_str());
}
return svc;
}
static void parse_line_service(struct parse_state *state, int nargs, char **args)
{
if (nargs == 0) {
return;
}
Service* svc = static_cast<Service*>(state->context);
int kw = lookup_keyword(args[0]);
std::vector<std::string> str_args(args, args + nargs);
std::string ret_err;
bool ret = svc->HandleLine(kw, str_args, &ret_err);
if (!ret) {
parse_error(state, "%s\n", ret_err.c_str());
}
}
static void *parse_action(struct parse_state* state, int nargs, char **args)
{
std::string ret_err;
std::vector<std::string> triggers(args + 1, args + nargs);
Action* ret = ActionManager::GetInstance().AddNewAction(triggers, &ret_err);
if (!ret) {
parse_error(state, "%s\n", ret_err.c_str());
}
return ret;
}
bool add_command_to_action(Action* action, const std::vector<std::string>& args,
const std::string& filename, int line, std::string* err)
{
int kw;
size_t n;
kw = lookup_keyword(args[0].c_str());
if (!kw_is(kw, COMMAND)) {
*err = android::base::StringPrintf("invalid command '%s'\n", args[0].c_str());
return false;
}
n = kw_nargs(kw);
if (args.size() < n) {
*err = android::base::StringPrintf("%s requires %zu %s\n",
args[0].c_str(), n - 1,
n > 2 ? "arguments" : "argument");
return false;
}
action->AddCommand(kw_func(kw), args, filename, line);
return true;
}
static void parse_line_action(struct parse_state* state, int nargs, char **args)
{
if (nargs == 0) {
return;
}
Action* action = static_cast<Action*>(state->context);
std::vector<std::string> str_args(args, args + nargs);
std::string ret_err;
bool ret = add_command_to_action(action, str_args, state->filename,
state->line, &ret_err);
if (!ret) {
parse_error(state, "%s\n", ret_err.c_str());
}
void Parser::DumpState() const {
ServiceManager::GetInstance().DumpState();
ActionManager::GetInstance().DumpState();
}

View File

@ -17,16 +17,39 @@
#ifndef _INIT_INIT_PARSER_H_
#define _INIT_INIT_PARSER_H_
#include <map>
#include <string>
#include <vector>
#define INIT_PARSER_MAXARGS 64
class SectionParser {
public:
virtual ~SectionParser() {
}
virtual bool ParseSection(const std::vector<std::string>& args,
std::string* err) = 0;
virtual bool ParseLineSection(const std::vector<std::string>& args,
const std::string& filename, int line,
std::string* err) const = 0;
virtual void EndSection() = 0;
virtual void EndFile(const std::string& filename) = 0;
};
class Action;
class Parser {
public:
static Parser& GetInstance();
void DumpState() const;
bool ParseConfig(const std::string& path);
void AddSectionParser(const std::string& name,
std::unique_ptr<SectionParser> parser);
bool init_parse_config(const char* path);
int expand_props(const std::string& src, std::string* dst);
bool add_command_to_action(Action* action, const std::vector<std::string>& args,
const std::string& filename, int line, std::string* err);
private:
Parser();
void ParseData(const std::string& filename, const std::string& data);
bool ParseConfigFile(const std::string& path);
bool ParseConfigDir(const std::string& path);
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
};
#endif

77
init/keyword_map.h Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2015 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_KEYWORD_MAP_H_
#define _INIT_KEYWORD_MAP_H_
#include <map>
#include <string>
#include <base/stringprintf.h>
template <typename Function>
class KeywordMap {
public:
using FunctionInfo = std::tuple<std::size_t, std::size_t, Function>;
using Map = const std::map<std::string, FunctionInfo>;
virtual ~KeywordMap() {
}
const Function FindFunction(const std::string& keyword,
size_t num_args,
std::string* err) const {
using android::base::StringPrintf;
auto function_info_it = map().find(keyword);
if (function_info_it == map().end()) {
*err = StringPrintf("invalid keyword '%s'", keyword.c_str());
return nullptr;
}
auto function_info = function_info_it->second;
auto min_args = std::get<0>(function_info);
auto max_args = std::get<1>(function_info);
if (min_args == max_args && num_args != min_args) {
*err = StringPrintf("%s requires %zu argument%s",
keyword.c_str(), min_args,
(min_args > 1 || min_args == 0) ? "s" : "");
return nullptr;
}
if (num_args < min_args || num_args > max_args) {
if (max_args == std::numeric_limits<decltype(max_args)>::max()) {
*err = StringPrintf("%s requires at least %zu argument%s",
keyword.c_str(), min_args,
min_args > 1 ? "s" : "");
} else {
*err = StringPrintf("%s requires between %zu and %zu arguments",
keyword.c_str(), min_args, max_args);
}
return nullptr;
}
return std::get<Function>(function_info);
}
private:
//Map of keyword ->
//(minimum number of arguments, maximum number of arguments, function pointer)
virtual Map& map() const = 0;
};
#endif

View File

@ -1,109 +0,0 @@
#ifndef KEYWORD
#include <string>
#include <vector>
int do_bootchart_init(const std::vector<std::string>& args);
int do_class_start(const std::vector<std::string>& args);
int do_class_stop(const std::vector<std::string>& args);
int do_class_reset(const std::vector<std::string>& args);
int do_domainname(const std::vector<std::string>& args);
int do_enable(const std::vector<std::string>& args);
int do_exec(const std::vector<std::string>& args);
int do_export(const std::vector<std::string>& args);
int do_hostname(const std::vector<std::string>& args);
int do_ifup(const std::vector<std::string>& args);
int do_insmod(const std::vector<std::string>& args);
int do_installkey(const std::vector<std::string>& args);
int do_mkdir(const std::vector<std::string>& args);
int do_mount_all(const std::vector<std::string>& args);
int do_mount(const std::vector<std::string>& args);
int do_powerctl(const std::vector<std::string>& args);
int do_restart(const std::vector<std::string>& args);
int do_restorecon(const std::vector<std::string>& args);
int do_restorecon_recursive(const std::vector<std::string>& args);
int do_rm(const std::vector<std::string>& args);
int do_rmdir(const std::vector<std::string>& args);
int do_setprop(const std::vector<std::string>& args);
int do_setrlimit(const std::vector<std::string>& args);
int do_start(const std::vector<std::string>& args);
int do_stop(const std::vector<std::string>& args);
int do_swapon_all(const std::vector<std::string>& args);
int do_trigger(const std::vector<std::string>& args);
int do_symlink(const std::vector<std::string>& args);
int do_sysclktz(const std::vector<std::string>& args);
int do_write(const std::vector<std::string>& args);
int do_copy(const std::vector<std::string>& args);
int do_chown(const std::vector<std::string>& args);
int do_chmod(const std::vector<std::string>& args);
int do_loglevel(const std::vector<std::string>& args);
int do_load_persist_props(const std::vector<std::string>& args);
int do_load_all_props(const std::vector<std::string>& args);
int do_verity_load_state(const std::vector<std::string>& args);
int do_verity_update_state(const std::vector<std::string>& args);
int do_wait(const std::vector<std::string>& args);
#define __MAKE_KEYWORD_ENUM__
#define KEYWORD(symbol, flags, nargs, func) K_##symbol,
enum {
K_UNKNOWN,
#endif
KEYWORD(bootchart_init, COMMAND, 0, do_bootchart_init)
KEYWORD(chmod, COMMAND, 2, do_chmod)
KEYWORD(chown, COMMAND, 2, do_chown)
KEYWORD(class, OPTION, 0, 0)
KEYWORD(class_reset, COMMAND, 1, do_class_reset)
KEYWORD(class_start, COMMAND, 1, do_class_start)
KEYWORD(class_stop, COMMAND, 1, do_class_stop)
KEYWORD(console, OPTION, 0, 0)
KEYWORD(copy, COMMAND, 2, do_copy)
KEYWORD(critical, OPTION, 0, 0)
KEYWORD(disabled, OPTION, 0, 0)
KEYWORD(domainname, COMMAND, 1, do_domainname)
KEYWORD(enable, COMMAND, 1, do_enable)
KEYWORD(exec, COMMAND, 1, do_exec)
KEYWORD(export, COMMAND, 2, do_export)
KEYWORD(group, OPTION, 0, 0)
KEYWORD(hostname, COMMAND, 1, do_hostname)
KEYWORD(ifup, COMMAND, 1, do_ifup)
KEYWORD(import, SECTION, 1, 0)
KEYWORD(insmod, COMMAND, 1, do_insmod)
KEYWORD(installkey, COMMAND, 1, do_installkey)
KEYWORD(ioprio, OPTION, 0, 0)
KEYWORD(keycodes, OPTION, 0, 0)
KEYWORD(load_all_props, COMMAND, 0, do_load_all_props)
KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props)
KEYWORD(loglevel, COMMAND, 1, do_loglevel)
KEYWORD(mkdir, COMMAND, 1, do_mkdir)
KEYWORD(mount_all, COMMAND, 1, do_mount_all)
KEYWORD(mount, COMMAND, 3, do_mount)
KEYWORD(oneshot, OPTION, 0, 0)
KEYWORD(onrestart, OPTION, 0, 0)
KEYWORD(on, SECTION, 0, 0)
KEYWORD(powerctl, COMMAND, 1, do_powerctl)
KEYWORD(restart, COMMAND, 1, do_restart)
KEYWORD(restorecon, COMMAND, 1, do_restorecon)
KEYWORD(restorecon_recursive, COMMAND, 1, do_restorecon_recursive)
KEYWORD(rm, COMMAND, 1, do_rm)
KEYWORD(rmdir, COMMAND, 1, do_rmdir)
KEYWORD(seclabel, OPTION, 0, 0)
KEYWORD(service, SECTION, 0, 0)
KEYWORD(setenv, OPTION, 2, 0)
KEYWORD(setprop, COMMAND, 2, do_setprop)
KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)
KEYWORD(socket, OPTION, 0, 0)
KEYWORD(start, COMMAND, 1, do_start)
KEYWORD(stop, COMMAND, 1, do_stop)
KEYWORD(swapon_all, COMMAND, 1, do_swapon_all)
KEYWORD(symlink, COMMAND, 1, do_symlink)
KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
KEYWORD(trigger, COMMAND, 1, do_trigger)
KEYWORD(user, OPTION, 0, 0)
KEYWORD(verity_load_state, COMMAND, 0, do_verity_load_state)
KEYWORD(verity_update_state, COMMAND, 0, do_verity_update_state)
KEYWORD(wait, COMMAND, 1, do_wait)
KEYWORD(write, COMMAND, 2, do_write)
KEYWORD(writepid, OPTION, 0, 0)
#ifdef __MAKE_KEYWORD_ENUM__
KEYWORD_COUNT,
};
#undef __MAKE_KEYWORD_ENUM__
#undef KEYWORD
#endif

View File

@ -32,11 +32,13 @@
#include "action.h"
#include "init.h"
#include "init_parser.h"
#include "keywords.h"
#include "log.h"
#include "property_service.h"
#include "util.h"
using android::base::StringPrintf;
using android::base::WriteStringToFile;
#define CRITICAL_CRASH_THRESHOLD 4 // if we crash >4 times ...
#define CRITICAL_CRASH_WINDOW (4*60) // ... in 4 minutes, goto recovery
@ -84,7 +86,7 @@ void Service::NotifyStateChange(const std::string& new_state) const {
return;
}
std::string prop_name = android::base::StringPrintf("init.svc.%s", name_.c_str());
std::string prop_name = StringPrintf("init.svc.%s", name_.c_str());
if (prop_name.length() >= PROP_NAME_MAX) {
// If the property name would be too long, we can't set it.
ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n",
@ -104,8 +106,7 @@ bool Service::Reap() {
// Remove any sockets we may have created.
for (const auto& si : sockets_) {
std::string tmp = android::base::StringPrintf(ANDROID_SOCKET_DIR "/%s",
si.name.c_str());
std::string tmp = StringPrintf(ANDROID_SOCKET_DIR "/%s", si.name.c_str());
unlink(tmp.c_str());
}
@ -168,148 +169,156 @@ void Service::DumpState() const {
}
}
bool Service::HandleLine(int kw, const std::vector<std::string>& args, std::string* err) {
std::vector<std::string> str_args;
bool Service::HandleClass(const std::vector<std::string>& args, std::string* err) {
classname_ = args[1];
return true;
}
ioprio_class_ = IoSchedClass_NONE;
bool Service::HandleConsole(const std::vector<std::string>& args, std::string* err) {
flags_ |= SVC_CONSOLE;
return true;
}
switch (kw) {
case K_class:
if (args.size() != 2) {
*err = "class option requires a classname\n";
return false;
} else {
classname_ = args[1];
}
break;
case K_console:
flags_ |= SVC_CONSOLE;
break;
case K_disabled:
flags_ |= SVC_DISABLED;
flags_ |= SVC_RC_DISABLED;
break;
case K_ioprio:
if (args.size() != 3) {
*err = "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n";
return false;
} else {
ioprio_pri_ = std::stoul(args[2], 0, 8);
bool Service::HandleCritical(const std::vector<std::string>& args, std::string* err) {
flags_ |= SVC_CRITICAL;
return true;
}
if (ioprio_pri_ < 0 || ioprio_pri_ > 7) {
*err = "priority value must be range 0 - 7\n";
return false;
}
bool Service::HandleDisabled(const std::vector<std::string>& args, std::string* err) {
flags_ |= SVC_DISABLED;
flags_ |= SVC_RC_DISABLED;
return true;
}
if (args[1] == "rt") {
ioprio_class_ = IoSchedClass_RT;
} else if (args[1] == "be") {
ioprio_class_ = IoSchedClass_BE;
} else if (args[1] == "idle") {
ioprio_class_ = IoSchedClass_IDLE;
} else {
*err = "ioprio option usage: ioprio <rt|be|idle> <0-7>\n";
return false;
}
}
break;
case K_group:
if (args.size() < 2) {
*err = "group option requires a group id\n";
return false;
} else if (args.size() > NR_SVC_SUPP_GIDS + 2) {
*err = android::base::StringPrintf("group option accepts at most %d supp. groups\n",
NR_SVC_SUPP_GIDS);
return false;
} else {
gid_ = decode_uid(args[1].c_str());
for (std::size_t n = 2; n < args.size(); n++) {
supp_gids_.push_back(decode_uid(args[n].c_str()));
}
}
break;
case K_keycodes:
if (args.size() < 2) {
*err = "keycodes option requires atleast one keycode\n";
return false;
} else {
for (std::size_t i = 1; i < args.size(); i++) {
keycodes_.push_back(std::stoi(args[i]));
}
}
break;
case K_oneshot:
flags_ |= SVC_ONESHOT;
break;
case K_onrestart:
if (args.size() < 2) {
return false;
}
str_args.assign(args.begin() + 1, args.end());
add_command_to_action(&onrestart_, str_args, "", 0, err);
break;
case K_critical:
flags_ |= SVC_CRITICAL;
break;
case K_setenv: { /* name value */
if (args.size() < 3) {
*err = "setenv option requires name and value arguments\n";
return false;
}
envvars_.push_back({args[1], args[2]});
break;
}
case K_socket: {/* name type perm [ uid gid context ] */
if (args.size() < 4) {
*err = "socket option requires name, type, perm arguments\n";
return false;
}
if (args[2] != "dgram" && args[2] != "stream" &&
args[2] != "seqpacket") {
*err = "socket type must be 'dgram', 'stream' or 'seqpacket'\n";
return false;
}
int perm = std::stoul(args[3], 0, 8);
uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
std::string socketcon = args.size() > 6 ? args[6] : "";
sockets_.push_back({args[1], args[2], uid, gid, perm, socketcon});
break;
}
case K_user:
if (args.size() != 2) {
*err = "user option requires a user id\n";
return false;
} else {
uid_ = decode_uid(args[1].c_str());
}
break;
case K_seclabel:
if (args.size() != 2) {
*err = "seclabel option requires a label string\n";
return false;
} else {
seclabel_ = args[1];
}
break;
case K_writepid:
if (args.size() < 2) {
*err = "writepid option requires at least one filename\n";
return false;
}
writepid_files_.assign(args.begin() + 1, args.end());
break;
default:
*err = android::base::StringPrintf("invalid option '%s'\n", args[0].c_str());
return false;
bool Service::HandleGroup(const std::vector<std::string>& args, std::string* err) {
gid_ = decode_uid(args[1].c_str());
for (std::size_t n = 2; n < args.size(); n++) {
supp_gids_.emplace_back(decode_uid(args[n].c_str()));
}
return true;
}
bool Service::HandleIoprio(const std::vector<std::string>& args, std::string* err) {
ioprio_pri_ = std::stoul(args[2], 0, 8);
if (ioprio_pri_ < 0 || ioprio_pri_ > 7) {
*err = "priority value must be range 0 - 7";
return false;
}
if (args[1] == "rt") {
ioprio_class_ = IoSchedClass_RT;
} else if (args[1] == "be") {
ioprio_class_ = IoSchedClass_BE;
} else if (args[1] == "idle") {
ioprio_class_ = IoSchedClass_IDLE;
} else {
*err = "ioprio option usage: ioprio <rt|be|idle> <0-7>";
return false;
}
return true;
}
bool Service::HandleKeycodes(const std::vector<std::string>& args, std::string* err) {
for (std::size_t i = 1; i < args.size(); i++) {
keycodes_.emplace_back(std::stoi(args[i]));
}
return true;
}
bool Service::HandleOneshot(const std::vector<std::string>& args, std::string* err) {
flags_ |= SVC_ONESHOT;
return true;
}
bool Service::HandleOnrestart(const std::vector<std::string>& args, std::string* err) {
std::vector<std::string> str_args(args.begin() + 1, args.end());
onrestart_.AddCommand(str_args, "", 0, err);
return true;
}
bool Service::HandleSeclabel(const std::vector<std::string>& args, std::string* err) {
seclabel_ = args[1];
return true;
}
bool Service::HandleSetenv(const std::vector<std::string>& args, std::string* err) {
envvars_.emplace_back(args[1], args[2]);
return true;
}
/* name type perm [ uid gid context ] */
bool Service::HandleSocket(const std::vector<std::string>& args, std::string* err) {
if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
*err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
return false;
}
int perm = std::stoul(args[3], 0, 8);
uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
std::string socketcon = args.size() > 6 ? args[6] : "";
sockets_.emplace_back(args[1], args[2], uid, gid, perm, socketcon);
return true;
}
bool Service::HandleUser(const std::vector<std::string>& args, std::string* err) {
uid_ = decode_uid(args[1].c_str());
return true;
}
bool Service::HandleWritepid(const std::vector<std::string>& args, std::string* err) {
writepid_files_.assign(args.begin() + 1, args.end());
return true;
}
class Service::OptionHandlerMap : public KeywordMap<OptionHandler> {
public:
OptionHandlerMap() {
}
private:
Map& map() const override;
};
Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
static const Map option_handlers = {
{"class", {1, 1, &Service::HandleClass}},
{"console", {0, 0, &Service::HandleConsole}},
{"critical", {0, 0, &Service::HandleCritical}},
{"disabled", {0, 0, &Service::HandleDisabled}},
{"group", {1, NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},
{"ioprio", {2, 2, &Service::HandleIoprio}},
{"keycodes", {1, kMax, &Service::HandleKeycodes}},
{"oneshot", {0, 0, &Service::HandleOneshot}},
{"onrestart", {1, kMax, &Service::HandleOnrestart}},
{"seclabel", {1, 1, &Service::HandleSeclabel}},
{"setenv", {2, 2, &Service::HandleSetenv}},
{"socket", {3, 6, &Service::HandleSocket}},
{"user", {1, 1, &Service::HandleUser}},
{"writepid", {1, kMax, &Service::HandleWritepid}},
};
return option_handlers;
}
bool Service::HandleLine(const std::vector<std::string>& args, std::string* err) {
if (args.empty()) {
*err = "option needed, but not provided";
return false;
}
static const OptionHandlerMap handler_map;
auto handler = handler_map.FindFunction(args[0], args.size() - 1, err);
if (!handler) {
return false;
}
return (this->*handler)(args, err);
}
bool Service::Start(const std::vector<std::string>& dynamic_args) {
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
@ -396,7 +405,7 @@ bool Service::Start(const std::vector<std::string>& dynamic_args) {
umask(077);
if (properties_initialized()) {
get_property_workspace(&fd, &sz);
std::string tmp = android::base::StringPrintf("%d,%d", dup(fd), sz);
std::string tmp = StringPrintf("%d,%d", dup(fd), sz);
add_environment("ANDROID_PROPERTY_WORKSPACE", tmp.c_str());
}
@ -418,9 +427,9 @@ bool Service::Start(const std::vector<std::string>& dynamic_args) {
}
}
std::string pid_str = android::base::StringPrintf("%d", pid);
std::string pid_str = StringPrintf("%d", pid);
for (const auto& file : writepid_files_) {
if (!android::base::WriteStringToFile(pid_str, file)) {
if (!WriteStringToFile(pid_str, file)) {
ERROR("couldn't write %s to %s: %s\n",
pid_str.c_str(), file.c_str(), strerror(errno));
}
@ -609,9 +618,8 @@ void Service::OpenConsole() const {
}
void Service::PublishSocket(const std::string& name, int fd) const {
std::string key = android::base::StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s",
name.c_str());
std::string val = android::base::StringPrintf("%d", fd);
std::string key = StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s", name.c_str());
std::string val = StringPrintf("%d", fd);
add_environment(key.c_str(), val.c_str());
/* make sure we don't close-on-exec */
@ -628,31 +636,14 @@ ServiceManager& ServiceManager::GetInstance() {
return instance;
}
Service* ServiceManager::AddNewService(const std::string& name,
const std::string& classname,
const std::vector<std::string>& args,
std::string* err) {
if (!IsValidName(name)) {
*err = android::base::StringPrintf("invalid service name '%s'\n", name.c_str());
return nullptr;
void ServiceManager::AddService(std::unique_ptr<Service> service) {
Service* old_service = FindServiceByName(service->name());
if (old_service) {
ERROR("ignored duplicate definition of service '%s'",
service->name().c_str());
return;
}
Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
if (svc) {
*err = android::base::StringPrintf("ignored duplicate definition of service '%s'\n",
name.c_str());
return nullptr;
}
std::unique_ptr<Service> svc_p(new Service(name, classname, args));
if (!svc_p) {
ERROR("Couldn't allocate service for service '%s'", name.c_str());
return nullptr;
}
svc = svc_p.get();
services_.push_back(std::move(svc_p));
return svc;
services_.emplace_back(std::move(service));
}
Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) {
@ -677,8 +668,7 @@ Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>&
std::vector<std::string> str_args(args.begin() + command_arg, args.end());
exec_count_++;
std::string name = android::base::StringPrintf("exec %d (%s)", exec_count_,
str_args[0].c_str());
std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str());
unsigned flags = SVC_EXEC | SVC_ONESHOT;
std::string seclabel = "";
@ -770,8 +760,7 @@ void ServiceManager::ForEachServiceWithFlags(unsigned matchflags,
}
}
void ServiceManager::RemoveService(const Service& svc)
{
void ServiceManager::RemoveService(const Service& svc) {
auto svc_it = std::find_if(services_.begin(), services_.end(),
[&svc] (const std::unique_ptr<Service>& s) {
return svc.name() == s->name();
@ -783,8 +772,44 @@ void ServiceManager::RemoveService(const Service& svc)
services_.erase(svc_it);
}
bool ServiceManager::IsValidName(const std::string& name) const
{
void ServiceManager::DumpState() const {
for (const auto& s : services_) {
s->DumpState();
}
INFO("\n");
}
bool ServiceParser::ParseSection(const std::vector<std::string>& args,
std::string* err) {
if (args.size() < 3) {
*err = "services must have a name and a program";
return false;
}
const std::string& name = args[1];
if (!IsValidName(name)) {
*err = StringPrintf("invalid service name '%s'", name.c_str());
return false;
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
service_ = std::make_unique<Service>(name, "default", str_args);
return true;
}
bool ServiceParser::ParseLineSection(const std::vector<std::string>& args,
const std::string& filename, int line,
std::string* err) const {
return service_ ? service_->HandleLine(args, err) : false;
}
void ServiceParser::EndSection() {
if (service_) {
ServiceManager::GetInstance().AddService(std::move(service_));
}
}
bool ServiceParser::IsValidName(const std::string& name) const {
if (name.size() > 16) {
return false;
}
@ -795,11 +820,3 @@ bool ServiceManager::IsValidName(const std::string& name) const
}
return true;
}
void ServiceManager::DumpState() const
{
for (const auto& s : services_) {
s->DumpState();
}
INFO("\n");
}

View File

@ -26,6 +26,8 @@
#include <vector>
#include "action.h"
#include "init_parser.h"
#include "keyword_map.h"
#define SVC_DISABLED 0x001 // do not autostart with class
#define SVC_ONESHOT 0x002 // do not restart on exit
@ -73,7 +75,7 @@ public:
unsigned flags, uid_t uid, gid_t gid, const std::vector<gid_t>& supp_gids,
const std::string& seclabel, const std::vector<std::string>& args);
bool HandleLine(int kw, const std::vector<std::string>& args, std::string* err);
bool HandleLine(const std::vector<std::string>& args, std::string* err);
bool Start(const std::vector<std::string>& dynamic_args);
bool Start();
bool StartIfNotDisabled();
@ -99,12 +101,31 @@ public:
const std::vector<std::string>& args() const { return args_; }
private:
using OptionHandler = bool (Service::*) (const std::vector<std::string>& args,
std::string* err);
class OptionHandlerMap;
void NotifyStateChange(const std::string& new_state) const;
void StopOrReset(int how);
void ZapStdio() const;
void OpenConsole() const;
void PublishSocket(const std::string& name, int fd) const;
bool HandleClass(const std::vector<std::string>& args, std::string* err);
bool HandleConsole(const std::vector<std::string>& args, std::string* err);
bool HandleCritical(const std::vector<std::string>& args, std::string* err);
bool HandleDisabled(const std::vector<std::string>& args, std::string* err);
bool HandleGroup(const std::vector<std::string>& args, std::string* err);
bool HandleIoprio(const std::vector<std::string>& args, std::string* err);
bool HandleKeycodes(const std::vector<std::string>& args, std::string* err);
bool HandleOneshot(const std::vector<std::string>& args, std::string* err);
bool HandleOnrestart(const std::vector<std::string>& args, std::string* err);
bool HandleSeclabel(const std::vector<std::string>& args, std::string* err);
bool HandleSetenv(const std::vector<std::string>& args, std::string* err);
bool HandleSocket(const std::vector<std::string>& args, std::string* err);
bool HandleUser(const std::vector<std::string>& args, std::string* err);
bool HandleWritepid(const std::vector<std::string>& args, std::string* err);
std::string name_;
std::string classname_;
@ -141,9 +162,7 @@ class ServiceManager {
public:
static ServiceManager& GetInstance();
Service* AddNewService(const std::string& name, const std::string& classname,
const std::vector<std::string>& args,
std::string* err);
void AddService(std::unique_ptr<Service> service);
Service* MakeExecOneshotService(const std::vector<std::string>& args);
Service* FindServiceByName(const std::string& name) const;
Service* FindServiceByPid(pid_t pid) const;
@ -155,13 +174,30 @@ public:
void (*func)(Service* svc)) const;
void RemoveService(const Service& svc);
void DumpState() const;
private:
ServiceManager();
bool IsValidName(const std::string& name) const;
static int exec_count_; // Every service needs a unique name.
std::vector<std::unique_ptr<Service>> services_;
};
class ServiceParser : public SectionParser {
public:
ServiceParser() : service_(nullptr) {
}
bool ParseSection(const std::vector<std::string>& args,
std::string* err) override;
bool ParseLineSection(const std::vector<std::string>& args,
const std::string& filename, int line,
std::string* err) const override;
void EndSection() override;
void EndFile(const std::string&) override {
}
private:
bool IsValidName(const std::string& name) const;
std::unique_ptr<Service> service_;
};
#endif

View File

@ -233,7 +233,6 @@ int ueventd_parse_config_file(const char *fn)
data.push_back('\n'); // TODO: fix parse_config.
parse_config(fn, data);
dump_parser_state();
return 0;
}

View File

@ -43,6 +43,7 @@
#include "init.h"
#include "log.h"
#include "property_service.h"
#include "util.h"
/*
@ -476,3 +477,73 @@ bool is_dir(const char* pathname) {
}
return S_ISDIR(info.st_mode);
}
bool expand_props(const std::string& src, std::string* dst) {
const char* src_ptr = src.c_str();
if (!dst) {
return false;
}
/* - variables can either be $x.y or ${x.y}, in case they are only part
* of the string.
* - will accept $$ as a literal $.
* - no nested property expansion, i.e. ${foo.${bar}} is not supported,
* bad things will happen
*/
while (*src_ptr) {
const char* c;
c = strchr(src_ptr, '$');
if (!c) {
dst->append(src_ptr);
return true;
}
dst->append(src_ptr, c);
c++;
if (*c == '$') {
dst->push_back(*(c++));
src_ptr = c;
continue;
} else if (*c == '\0') {
return true;
}
std::string prop_name;
if (*c == '{') {
c++;
const char* end = strchr(c, '}');
if (!end) {
// failed to find closing brace, abort.
ERROR("unexpected end of string in '%s', looking for }\n", src.c_str());
return false;
}
prop_name = std::string(c, end);
c = end + 1;
} else {
prop_name = c;
ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
c);
c += prop_name.size();
}
if (prop_name.empty()) {
ERROR("invalid zero-length prop name in '%s'\n", src.c_str());
return false;
}
std::string prop_val = property_get(prop_name.c_str());
if (prop_val.empty()) {
ERROR("property '%s' doesn't exist while expanding '%s'\n",
prop_name.c_str(), src.c_str());
return false;
}
dst->append(prop_val);
src_ptr = c;
}
return true;
}

View File

@ -65,4 +65,5 @@ int restorecon(const char *pathname);
int restorecon_recursive(const char *pathname);
std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
bool is_dir(const char* pathname);
bool expand_props(const std::string& src, std::string* dst);
#endif