Merge "adb/base win32 tests: fix comment and open() flags"
diff --git a/init/Android.mk b/init/Android.mk
index 58bff58..7670951 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -45,6 +45,7 @@
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
action.cpp \
+ import_parser.cpp \
init_parser.cpp \
log.cpp \
parser.cpp \
diff --git a/init/action.cpp b/init/action.cpp
index dd366d3..c6cbc2e 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -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 @@
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 @@
}
}
-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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_));
+ }
+}
diff --git a/init/action.h b/init/action.h
index 5088c71..6dee2d0 100644
--- a/init/action.h
+++ b/init/action.h
@@ -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 @@
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 @@
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 @@
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
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index efaee1c..a768762 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -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>
diff --git a/init/bootchart.h b/init/bootchart.h
index cf61d83..47eda7a 100644
--- a/init/bootchart.h
+++ b/init/bootchart.h
@@ -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 */
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 97151c0..3ffa2e8 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -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 @@
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 @@
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 @@
}
}
-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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
}
-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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 brtw, brtr;
char *p;
- if (args.size() != 3)
- return -1;
-
if (stat(args[1].c_str(), &info) < 0)
return -1;
@@ -758,7 +722,7 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
/*
* 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 @@
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 @@
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;
+}
diff --git a/init/builtins.h b/init/builtins.h
new file mode 100644
index 0000000..53f4a71
--- /dev/null
+++ b/init/builtins.h
@@ -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
diff --git a/init/import_parser.cpp b/init/import_parser.cpp
new file mode 100644
index 0000000..e2a0f83
--- /dev/null
+++ b/init/import_parser.cpp
@@ -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));
+ }
+ }
+}
diff --git a/init/import_parser.h b/init/import_parser.h
new file mode 100644
index 0000000..0e91025
--- /dev/null
+++ b/init/import_parser.h
@@ -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
diff --git a/init/init.cpp b/init/init.cpp
index c94a6fe..ee1351d 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -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 @@
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();
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 12f44f7..02b3985 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -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 @@
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();
}
diff --git a/init/init_parser.h b/init/init_parser.h
index 709dca8..5ed30ad 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -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
diff --git a/init/keyword_map.h b/init/keyword_map.h
new file mode 100644
index 0000000..dc2357b
--- /dev/null
+++ b/init/keyword_map.h
@@ -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
diff --git a/init/keywords.h b/init/keywords.h
deleted file mode 100644
index 922feee..0000000
--- a/init/keywords.h
+++ /dev/null
@@ -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
diff --git a/init/service.cpp b/init/service.cpp
index a370d25..a3c5ca4 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -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 @@
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 @@
// 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 @@
}
}
-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 @@
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 @@
}
}
- 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::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 @@
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 @@
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::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 @@
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 @@
}
return true;
}
-
-void ServiceManager::DumpState() const
-{
- for (const auto& s : services_) {
- s->DumpState();
- }
- INFO("\n");
-}
diff --git a/init/service.h b/init/service.h
index 1ecf78a..10eb736 100644
--- a/init/service.h
+++ b/init/service.h
@@ -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 @@
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 @@
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 @@
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 @@
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
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 497c606..09f4638 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -233,7 +233,6 @@
data.push_back('\n'); // TODO: fix parse_config.
parse_config(fn, data);
- dump_parser_state();
return 0;
}
diff --git a/init/util.cpp b/init/util.cpp
index f6131e3..1eb90e0 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -43,6 +43,7 @@
#include "init.h"
#include "log.h"
+#include "property_service.h"
#include "util.h"
/*
@@ -476,3 +477,73 @@
}
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;
+}
diff --git a/init/util.h b/init/util.h
index f08cb8d..a33209e 100644
--- a/init/util.h
+++ b/init/util.h
@@ -65,4 +65,5 @@
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