summaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
authorTom Cherry <tomcherry@google.com>2015-07-30 21:03:48 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-07-30 21:03:48 +0000
commitd548e30f04b2eb7aa00deab42f5559d08396c38e (patch)
treed497a9db9abe101a277e3787da9d00097a810c01 /init
parenteb0b151369371993a70c2079b8253f6dd24814b7 (diff)
parentfa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378 (diff)
downloadcore-d548e30f04b2eb7aa00deab42f5559d08396c38e.tar.gz
core-d548e30f04b2eb7aa00deab42f5559d08396c38e.tar.bz2
core-d548e30f04b2eb7aa00deab42f5559d08396c38e.zip
Merge "init: Create classes for Action and Command"
Diffstat (limited to 'init')
-rw-r--r--init/Android.mk1
-rw-r--r--init/action.cpp383
-rw-r--r--init/action.h82
-rw-r--r--init/builtins.cpp9
-rw-r--r--init/init.cpp142
-rw-r--r--init/init.h45
-rw-r--r--init/init_parser.cpp223
-rw-r--r--init/init_parser.h12
-rw-r--r--init/signal_handler.cpp15
9 files changed, 522 insertions, 390 deletions
diff --git a/init/Android.mk b/init/Android.mk
index 1611b8111..045e213e6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -44,6 +44,7 @@ endif
include $(CLEAR_VARS)
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
+ action.cpp \
init_parser.cpp \
log.cpp \
parser.cpp \
diff --git a/init/action.cpp b/init/action.cpp
new file mode 100644
index 000000000..bd5fe7574
--- /dev/null
+++ b/init/action.cpp
@@ -0,0 +1,383 @@
+/*
+ * 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 "action.h"
+
+#include <errno.h>
+
+#include <base/strings.h>
+#include <base/stringprintf.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)(int nargs, char** args),
+ const std::vector<std::string>& args,
+ const std::string& filename,
+ int line);
+
+ int InvokeFunc() const;
+ std::string BuildCommandString() const;
+ std::string BuildSourceString() const;
+
+private:
+ int (*func_)(int nargs, char** args);
+ const std::vector<std::string> args_;
+ const std::string filename_;
+ int line_;
+};
+
+Action::Command::Command(int (*f)(int nargs, char** args),
+ 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
+{
+ std::vector<std::string> strs;
+ strs.resize(args_.size());
+ strs[0] = args_[0];
+ for (std::size_t i = 1; i < args_.size(); ++i) {
+ if (expand_props(args_[i], &strs[i]) == -1) {
+ ERROR("%s: cannot expand '%s'\n", args_[0].c_str(), args_[i].c_str());
+ return -EINVAL;
+ }
+ }
+
+ std::vector<char*> args;
+ for (auto& s : strs) {
+ args.push_back(&s[0]);
+ }
+
+ return func_(args.size(), &args[0]);
+}
+
+std::string Action::Command::BuildCommandString() const
+{
+ return android::base::Join(args_, ' ');
+}
+
+std::string Action::Command::BuildSourceString() const
+{
+ if (!filename_.empty()) {
+ return android::base::StringPrintf(" (%s:%d)", filename_.c_str(), line_);
+ } else {
+ return std::string();
+ }
+}
+
+Action::Action()
+{
+}
+
+void Action::AddCommand(int (*f)(int nargs, char** args),
+ 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);
+}
+
+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();
+
+ if (klog_get_level() >= KLOG_INFO_LEVEL) {
+ std::string trigger_name = BuildTriggersString();
+ std::string cmd_str = command.BuildCommandString();
+ std::string source = command.BuildSourceString();
+
+ INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
+ cmd_str.c_str(), trigger_name.c_str(), source.c_str(),
+ result, t.duration());
+ }
+}
+
+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('=');
+ if (equal_pos == std::string::npos) {
+ *err = "property trigger found without matching '='";
+ return false;
+ }
+
+ std::string prop_value(prop_name.substr(equal_pos + 1));
+ prop_name.erase(equal_pos);
+
+ auto res = property_triggers_.emplace(prop_name, prop_value);
+ if (res.second == false) {
+ *err = "multiple property triggers found for same property";
+ return false;
+ }
+ return true;
+}
+
+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) {
+ if (args[i].compare("&&")) {
+ *err = "&& is the only symbol allowed to concatenate actions";
+ return false;
+ } else {
+ continue;
+ }
+ }
+
+ if (!args[i].compare(0, prop_str.length(), prop_str)) {
+ if (!ParsePropertyTrigger(args[i], err)) {
+ return false;
+ }
+ } else {
+ if (!event_trigger_.empty()) {
+ *err = "multiple event triggers are not allowed";
+ return false;
+ }
+
+ event_trigger_ = args[i];
+ }
+ }
+
+ return true;
+}
+
+bool Action::InitSingleTrigger(const std::string& trigger)
+{
+ std::vector<std::string> name_vector{trigger};
+ std::string err;
+ return InitTriggers(name_vector, &err);
+}
+
+bool Action::CheckPropertyTriggers(const std::string& name,
+ const std::string& value) const
+{
+ bool found = !name.compare("");
+ if (property_triggers_.empty()) {
+ return true;
+ }
+
+ for (const auto& t : property_triggers_) {
+ if (!t.first.compare(name)) {
+ if (t.second.compare("*") &&
+ t.second.compare(value)) {
+ return false;
+ } else {
+ found = true;
+ }
+ } else {
+ std::string prop_val = property_get(t.first.c_str());
+ if (prop_val.empty() ||
+ (t.second.compare("*") &&
+ t.second.compare(prop_val))) {
+ return false;
+ }
+ }
+ }
+ return found;
+}
+
+bool Action::CheckEventTrigger(const std::string& trigger) const
+{
+ return !event_trigger_.empty() &&
+ !trigger.compare(event_trigger_) &&
+ CheckPropertyTriggers();
+}
+
+bool Action::CheckPropertyTrigger(const std::string& name,
+ const std::string& value) const
+{
+ return event_trigger_.empty() && CheckPropertyTriggers(name, value);
+}
+
+bool Action::TriggersEqual(const class Action& other) const
+{
+ return property_triggers_.size() == other.property_triggers_.size() &&
+ std::equal(property_triggers_.begin(), property_triggers_.end(),
+ other.property_triggers_.begin()) &&
+ !event_trigger_.compare(other.event_trigger_);
+}
+
+std::string Action::BuildTriggersString() const
+{
+ std::string result;
+
+ for (const auto& t : property_triggers_) {
+ result += t.first;
+ result += '=';
+ result += t.second;
+ result += ' ';
+ }
+ if (!event_trigger_.empty()) {
+ result += event_trigger_;
+ result += ' ';
+ }
+ result.pop_back();
+ return result;
+}
+
+void Action::DumpState() const
+{
+ INFO("on ");
+ std::string trigger_name = BuildTriggersString();
+ INFO("%s", trigger_name.c_str());
+ INFO("\n");
+
+ for (const auto& c : commands_) {
+ std::string cmd_str = c->BuildCommandString();
+ INFO(" %s", cmd_str.c_str());
+ }
+ INFO("\n");
+}
+
+ActionManager::ActionManager() : cur_command_(0)
+{
+}
+
+ActionManager& ActionManager::GetInstance() {
+ static ActionManager instance;
+ return instance;
+}
+
+void ActionManager::QueueEventTrigger(const std::string& trigger)
+{
+ for (const auto& a : action_list_) {
+ if (a->CheckEventTrigger(trigger)) {
+ action_queue_.push(a);
+ }
+ }
+}
+
+void ActionManager::QueuePropertyTrigger(const std::string& name,
+ const std::string& value)
+{
+ for (const auto& a : action_list_) {
+ if (a->CheckPropertyTrigger(name, value)) {
+ action_queue_.push(a);
+ }
+ }
+}
+
+void ActionManager::QueueAllPropertyTriggers()
+{
+ QueuePropertyTrigger("", "");
+}
+
+void ActionManager::QueueBuiltinAction(int (*func)(int nargs, char** args),
+ const std::string& name)
+{
+ Action* act = new Action();
+ std::vector<std::string> name_vector{name};
+
+ if (!act->InitSingleTrigger(name)) {
+ return;
+ }
+
+ act->AddCommand(func, name_vector);
+
+ action_queue_.push(act);
+}
+
+void ActionManager::ExecuteOneCommand() {
+ if (action_queue_.empty()) {
+ return;
+ }
+
+ Action* action = action_queue_.front();
+ if (!action->NumCommands()) {
+ action_queue_.pop();
+ return;
+ }
+
+ if (cur_command_ == 0) {
+ std::string trigger_name = action->BuildTriggersString();
+ INFO("processing action %p (%s)\n", action, trigger_name.c_str());
+ }
+
+ action->ExecuteOneCommand(cur_command_++);
+ if (cur_command_ == action->NumCommands()) {
+ cur_command_ = 0;
+ action_queue_.pop();
+ }
+}
+
+bool ActionManager::HasMoreCommands() const
+{
+ return !action_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(action_list_.begin(), action_list_.end(),
+ [&act] (Action* a) { return act->TriggersEqual(*a); });
+
+ if (old_act_it != action_list_.end()) {
+ delete act;
+ return *old_act_it;
+ }
+
+ action_list_.push_back(act);
+ return act;
+}
+
+void ActionManager::DumpState() const
+{
+ for (const auto& a : action_list_) {
+ a->DumpState();
+ }
+ INFO("\n");
+}
diff --git a/init/action.h b/init/action.h
new file mode 100644
index 000000000..8ee09b021
--- /dev/null
+++ b/init/action.h
@@ -0,0 +1,82 @@
+/*
+ * 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_ACTION_H
+#define _INIT_ACTION_H
+
+#include <map>
+#include <queue>
+#include <string>
+#include <vector>
+
+class Action {
+public:
+ Action();
+
+ void AddCommand(int (*f)(int nargs, char** args),
+ const std::vector<std::string>& args,
+ const std::string& filename = "", int line = 0);
+ bool InitTriggers(const std::vector<std::string>& args, std::string* err);
+ bool InitSingleTrigger(const std::string& trigger);
+ std::size_t NumCommands() const;
+ void ExecuteOneCommand(std::size_t command) const;
+ void ExecuteAllCommands() const;
+ 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;
+ std::string BuildTriggersString() const;
+ void DumpState() const;
+
+private:
+ class Command;
+
+ void ExecuteCommand(const Command& command) const;
+ bool CheckPropertyTriggers(const std::string& name = "",
+ const std::string& value = "") const;
+ bool ParsePropertyTrigger(const std::string& trigger, std::string* err);
+
+ std::map<std::string, std::string> property_triggers_;
+ std::string event_trigger_;
+ std::vector<Command*> commands_;
+};
+
+class ActionManager {
+public:
+ static ActionManager& GetInstance();
+ void QueueEventTrigger(const std::string& trigger);
+ void QueuePropertyTrigger(const std::string& name, const std::string& value);
+ void QueueAllPropertyTriggers();
+ void QueueBuiltinAction(int (*func)(int nargs, char** args),
+ const std::string& name);
+ void ExecuteOneCommand();
+ bool HasMoreCommands() const;
+ Action* AddNewAction(const std::vector<std::string>& triggers,
+ std::string* err);
+ void DumpState() const;
+
+private:
+ ActionManager();
+
+ ActionManager(ActionManager const&) = delete;
+ void operator=(ActionManager const&) = delete;
+
+ std::vector<Action*> action_list_;
+ std::queue<Action*> action_queue_;
+ std::size_t cur_command_;
+};
+
+#endif
diff --git a/init/builtins.cpp b/init/builtins.cpp
index d05f046f2..4bc3b875e 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -43,6 +43,7 @@
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
+#include "action.h"
#include "init.h"
#include "keywords.h"
#include "property_service.h"
@@ -513,7 +514,7 @@ int do_mount_all(int nargs, char **args)
/* If fs_mgr determined this is an unencrypted device, then trigger
* that action.
*/
- action_for_each_trigger("nonencrypted", action_add_queue_tail);
+ ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
} else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
/* Setup a wipe via recovery, and reboot into recovery */
ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
@@ -528,7 +529,7 @@ int do_mount_all(int nargs, char **args)
// Although encrypted, we have device key, so we do not need to
// do anything different from the nonencrypted case.
- action_for_each_trigger("nonencrypted", action_add_queue_tail);
+ ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
} else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) {
if (e4crypt_install_keyring()) {
return -1;
@@ -639,7 +640,7 @@ int do_powerctl(int nargs, char **args)
int do_trigger(int nargs, char **args)
{
- action_for_each_trigger(args[1], action_add_queue_tail);
+ ActionManager::GetInstance().QueueEventTrigger(args[1]);
return 0;
}
@@ -676,7 +677,7 @@ int do_verity_load_state(int nargs, char **args) {
int mode = -1;
int rc = fs_mgr_load_verity_state(&mode);
if (rc == 0 && mode == VERITY_MODE_LOGGING) {
- action_for_each_trigger("verity-logging", action_add_queue_tail);
+ ActionManager::GetInstance().QueueEventTrigger("verity-logging");
}
return rc;
}
diff --git a/init/init.cpp b/init/init.cpp
index 4be16ea00..66143bf13 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -53,6 +53,7 @@
#include <memory>
+#include "action.h"
#include "devices.h"
#include "init.h"
#include "log.h"
@@ -72,9 +73,6 @@ static int property_triggers_enabled = 0;
static char qemu[32];
-static struct action *cur_action = NULL;
-static struct command *cur_command = NULL;
-
static int have_console;
static std::string console_name = "/dev/console";
static time_t process_needs_restart;
@@ -453,7 +451,7 @@ void service_restart(struct service *svc)
void property_changed(const char *name, const char *value)
{
if (property_triggers_enabled)
- queue_property_triggers(name, value);
+ ActionManager::GetInstance().QueuePropertyTrigger(name, value);
}
static void restart_service_if_needed(struct service *svc)
@@ -542,114 +540,6 @@ void handle_control_message(const char *msg, const char *arg)
}
}
-static struct command *get_first_command(struct action *act)
-{
- struct listnode *node;
- node = list_head(&act->commands);
- if (!node || list_empty(&act->commands))
- return NULL;
-
- return node_to_item(node, struct command, clist);
-}
-
-static struct command *get_next_command(struct action *act, struct command *cmd)
-{
- struct listnode *node;
- node = cmd->clist.next;
- if (!node)
- return NULL;
- if (node == &act->commands)
- return NULL;
-
- return node_to_item(node, struct command, clist);
-}
-
-static int is_last_command(struct action *act, struct command *cmd)
-{
- return (list_tail(&act->commands) == &cmd->clist);
-}
-
-
-std::string build_triggers_string(struct action *cur_action) {
- std::string result;
- struct listnode *node;
- struct trigger *cur_trigger;
-
- list_for_each(node, &cur_action->triggers) {
- cur_trigger = node_to_item(node, struct trigger, nlist);
- if (node != cur_action->triggers.next) {
- result.push_back(' ');
- }
- result += cur_trigger->name;
- }
- return result;
-}
-
-bool expand_command_arguments(int nargs, char** args, std::vector<std::string>* expanded_args) {
- std::vector<std::string>& strs = *expanded_args;
- strs.resize(nargs);
- strs[0] = args[0];
- for (int i = 1; i < nargs; ++i) {
- if (expand_props(args[i], &strs[i]) == -1) {
- ERROR("%s: cannot expand '%s'\n", args[0], args[i]);
- return false;
- }
- }
- return true;
-}
-
-void execute_one_command() {
- Timer t;
-
- if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
- cur_action = action_remove_queue_head();
- cur_command = NULL;
- if (!cur_action) {
- return;
- }
-
- std::string trigger_name = build_triggers_string(cur_action);
- INFO("processing action %p (%s)\n", cur_action, trigger_name.c_str());
- cur_command = get_first_command(cur_action);
- } else {
- cur_command = get_next_command(cur_action, cur_command);
- }
-
- if (!cur_command) {
- return;
- }
- int result = 0;
- std::vector<std::string> arg_strs;
- if (!expand_command_arguments(cur_command->nargs, cur_command->args, &arg_strs)) {
- result = -EINVAL;
- }
- if (result == 0) {
- std::vector<char*> args;
- for (auto& s : arg_strs) {
- args.push_back(&s[0]);
- }
- result = cur_command->func(args.size(), &args[0]);
- }
- if (klog_get_level() >= KLOG_INFO_LEVEL) {
- std::string cmd_str;
- for (int i = 0; i < cur_command->nargs; ++i) {
- if (i > 0) {
- cmd_str.push_back(' ');
- }
- cmd_str += cur_command->args[i];
- }
- std::string trigger_name = build_triggers_string(cur_action);
-
- std::string source;
- if (cur_command->filename) {
- source = android::base::StringPrintf(" (%s:%d)", cur_command->filename, cur_command->line);
- }
-
- INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
- cmd_str.c_str(), trigger_name.c_str(), source.c_str(), result, t.duration());
- }
-}
-
static int wait_for_coldboot_done_action(int nargs, char **args) {
Timer t;
@@ -865,7 +755,7 @@ static void process_kernel_cmdline() {
static int queue_property_triggers_action(int nargs, char **args)
{
- queue_all_property_triggers();
+ ActionManager::GetInstance().QueueAllPropertyTriggers();
/* enable property triggers */
property_triggers_enabled = 1;
return 0;
@@ -1059,36 +949,38 @@ int main(int argc, char** argv) {
init_parse_config("/init.rc");
- action_for_each_trigger("early-init", action_add_queue_tail);
+ ActionManager& am = ActionManager::GetInstance();
+
+ am.QueueEventTrigger("early-init");
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
- queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
+ am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
- queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
- queue_builtin_action(keychord_init_action, "keychord_init");
- queue_builtin_action(console_init_action, "console_init");
+ am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+ am.QueueBuiltinAction(keychord_init_action, "keychord_init");
+ am.QueueBuiltinAction(console_init_action, "console_init");
// Trigger all the boot actions to get us started.
- action_for_each_trigger("init", action_add_queue_tail);
+ am.QueueEventTrigger("init");
// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
// wasn't ready immediately after wait_for_coldboot_done
- queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+ am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
// Don't mount filesystems or start core system services in charger mode.
std::string bootmode = property_get("ro.bootmode");
if (bootmode == "charger") {
- action_for_each_trigger("charger", action_add_queue_tail);
+ am.QueueEventTrigger("charger");
} else {
- action_for_each_trigger("late-init", action_add_queue_tail);
+ am.QueueEventTrigger("late-init");
}
// Run all property triggers based on current state of the properties.
- queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
+ am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
while (true) {
if (!waiting_for_exec) {
- execute_one_command();
+ am.ExecuteOneCommand();
restart_processes();
}
@@ -1099,7 +991,7 @@ int main(int argc, char** argv) {
timeout = 0;
}
- if (!action_queue_empty() || cur_action) {
+ if (am.HasMoreCommands()) {
timeout = 0;
}
diff --git a/init/init.h b/init/init.h
index d2b2dfb30..4d231030f 100644
--- a/init/init.h
+++ b/init/init.h
@@ -18,47 +18,17 @@
#define _INIT_INIT_H
#include <sys/types.h>
+#include <stdlib.h>
+#include <list>
+#include <map>
#include <string>
#include <vector>
#include <cutils/list.h>
#include <cutils/iosched_policy.h>
-struct command
-{
- /* list of commands in an action */
- struct listnode clist;
-
- int (*func)(int nargs, char **args);
-
- int line;
- const char *filename;
-
- int nargs;
- char *args[1];
-};
-
-struct trigger {
- struct listnode nlist;
- const char *name;
-};
-
-struct action {
- /* node in list of all actions */
- struct listnode alist;
- /* node in the queue of pending actions */
- struct listnode qlist;
- /* node in list of actions for a trigger */
- struct listnode tlist;
-
- unsigned hash;
-
- /* list of actions which triggers the commands*/
- struct listnode triggers;
- struct listnode commands;
- struct command *current;
-};
+class Action;
struct socketinfo {
struct socketinfo *next;
@@ -117,7 +87,7 @@ struct service {
struct socketinfo *sockets;
struct svcenvinfo *envvars;
- struct action onrestart; /* Actions to execute on restart. */
+ Action* onrestart; /* Commands to execute on restart. */
std::vector<std::string>* writepid_files_;
@@ -138,8 +108,6 @@ extern bool waiting_for_exec;
extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle_prop;
-std::string build_triggers_string(struct action *cur_action);
-
void handle_control_message(const char *msg, const char *arg);
struct service *service_find_by_name(const char *name);
@@ -161,6 +129,5 @@ int selinux_reload_policy(void);
void zap_stdio(void);
void register_epoll_handler(int fd, void (*fn)());
-bool expand_command_arguments(int nargs, char** args, std::vector<std::string>* expanded_args);
-#endif /* _INIT_INIT_H */
+#endif /* _INIT_INIT_H */
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 460f5acd2..ab0dbc3e6 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -26,6 +26,7 @@
#include <string.h>
#include <unistd.h>
+#include "action.h"
#include "init.h"
#include "parser.h"
#include "init_parser.h"
@@ -38,8 +39,6 @@
#include <cutils/list.h>
static list_declare(service_list);
-static list_declare(action_list);
-static list_declare(action_queue);
struct import {
struct listnode list;
@@ -93,25 +92,7 @@ void dump_parser_state() {
INFO(" socket %s %s 0%o\n", si->name, si->type, si->perm);
}
}
-
- list_for_each(node, &action_list) {
- action* act = node_to_item(node, struct action, alist);
- INFO("on ");
- std::string trigger_name = build_triggers_string(act);
- INFO("%s", trigger_name.c_str());
- INFO("\n");
-
- struct listnode* node2;
- list_for_each(node2, &act->commands) {
- command* cmd = node_to_item(node2, struct command, clist);
- INFO(" %p", cmd->func);
- for (int n = 0; n < cmd->nargs; n++) {
- INFO(" %s", cmd->args[n]);
- }
- INFO("\n");
- }
- INFO("\n");
- }
+ ActionManager::GetInstance().DumpState();
}
}
@@ -217,10 +198,10 @@ static int lookup_keyword(const char *s)
static void parse_line_no_op(struct parse_state*, int, char**) {
}
-int expand_props(const char *src, std::string *dst) {
- const char *src_ptr = src;
+int expand_props(const std::string& src, std::string* dst) {
+ const char *src_ptr = src.c_str();
- if (!src || !dst) {
+ if (!dst) {
return -1;
}
@@ -256,7 +237,7 @@ int expand_props(const char *src, std::string *dst) {
const char* end = strchr(c, '}');
if (!end) {
// failed to find closing brace, abort.
- ERROR("unexpected end of string in '%s', looking for }\n", src);
+ ERROR("unexpected end of string in '%s', looking for }\n", src.c_str());
goto err;
}
prop_name = std::string(c, end);
@@ -269,14 +250,14 @@ int expand_props(const char *src, std::string *dst) {
}
if (prop_name.empty()) {
- ERROR("invalid zero-length prop name in '%s'\n", src);
+ 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);
+ prop_name.c_str(), src.c_str());
goto err;
}
@@ -527,125 +508,6 @@ void service_for_each_flags(unsigned matchflags,
}
}
-void action_for_each_trigger(const char *trigger,
- void (*func)(struct action *act))
-{
- struct listnode *node, *node2;
- struct action *act;
- struct trigger *cur_trigger;
-
- list_for_each(node, &action_list) {
- act = node_to_item(node, struct action, alist);
- list_for_each(node2, &act->triggers) {
- cur_trigger = node_to_item(node2, struct trigger, nlist);
- if (!strcmp(cur_trigger->name, trigger)) {
- func(act);
- }
- }
- }
-}
-
-
-void queue_property_triggers(const char *name, const char *value)
-{
- struct listnode *node, *node2;
- struct action *act;
- struct trigger *cur_trigger;
- bool match;
- int name_length;
-
- list_for_each(node, &action_list) {
- act = node_to_item(node, struct action, alist);
- match = !name;
- list_for_each(node2, &act->triggers) {
- cur_trigger = node_to_item(node2, struct trigger, nlist);
- if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) {
- const char *test = cur_trigger->name + strlen("property:");
- if (!match) {
- name_length = strlen(name);
- if (!strncmp(name, test, name_length) &&
- test[name_length] == '=' &&
- (!strcmp(test + name_length + 1, value) ||
- !strcmp(test + name_length + 1, "*"))) {
- match = true;
- continue;
- }
- } else {
- const char* equals = strchr(test, '=');
- if (equals) {
- int length = equals - test;
- if (length <= PROP_NAME_MAX) {
- std::string prop_name(test, length);
- std::string value = property_get(prop_name.c_str());
-
- /* does the property exist, and match the trigger value? */
- if (!value.empty() && (!strcmp(equals + 1, value.c_str()) ||
- !strcmp(equals + 1, "*"))) {
- continue;
- }
- }
- }
- }
- }
- match = false;
- break;
- }
- if (match) {
- action_add_queue_tail(act);
- }
- }
-}
-
-void queue_all_property_triggers()
-{
- queue_property_triggers(NULL, NULL);
-}
-
-void queue_builtin_action(int (*func)(int nargs, char **args), const char *name)
-{
- action* act = (action*) calloc(1, sizeof(*act));
- trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
- cur_trigger->name = name;
- list_init(&act->triggers);
- list_add_tail(&act->triggers, &cur_trigger->nlist);
- list_init(&act->commands);
- list_init(&act->qlist);
-
- command* cmd = (command*) calloc(1, sizeof(*cmd));
- cmd->func = func;
- cmd->args[0] = const_cast<char*>(name);
- cmd->nargs = 1;
- list_add_tail(&act->commands, &cmd->clist);
-
- list_add_tail(&action_list, &act->alist);
- action_add_queue_tail(act);
-}
-
-void action_add_queue_tail(struct action *act)
-{
- if (list_empty(&act->qlist)) {
- list_add_tail(&action_queue, &act->qlist);
- }
-}
-
-struct action *action_remove_queue_head(void)
-{
- if (list_empty(&action_queue)) {
- return 0;
- } else {
- struct listnode *node = list_head(&action_queue);
- struct action *act = node_to_item(node, struct action, qlist);
- list_remove(node);
- list_init(node);
- return act;
- }
-}
-
-int action_queue_empty()
-{
- return list_empty(&action_queue);
-}
-
service* make_exec_oneshot_service(int nargs, char** args) {
// Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
// SECLABEL can be a - to denote default
@@ -732,13 +594,10 @@ static void *parse_service(struct parse_state *state, int nargs, char **args)
svc->name = strdup(args[1]);
svc->classname = "default";
memcpy(svc->args, args + 2, sizeof(char*) * nargs);
- trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
svc->args[nargs] = 0;
svc->nargs = nargs;
- list_init(&svc->onrestart.triggers);
- cur_trigger->name = "onrestart";
- list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist);
- list_init(&svc->onrestart.commands);
+ svc->onrestart = new Action();
+ svc->onrestart->InitSingleTrigger("onrestart");
list_add_tail(&service_list, &svc->slist);
return svc;
}
@@ -746,8 +605,8 @@ 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)
{
struct service *svc = (service*) state->context;
- struct command *cmd;
int i, kw, kw_nargs;
+ std::vector<std::string> str_args;
if (nargs == 0) {
return;
@@ -840,12 +699,8 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args
kw_nargs > 2 ? "arguments" : "argument");
break;
}
-
- cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
- cmd->func = kw_func(kw);
- cmd->nargs = nargs;
- memcpy(cmd->args, args, sizeof(char*) * nargs);
- list_add_tail(&svc->onrestart.commands, &cmd->clist);
+ str_args.assign(args, args + nargs);
+ svc->onrestart->AddCommand(kw_func(kw), str_args);
break;
case K_critical:
svc->flags |= SVC_CRITICAL;
@@ -924,48 +779,22 @@ 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_action(struct parse_state* state, int nargs, char **args)
{
- struct trigger *cur_trigger;
- int i;
- if (nargs < 2) {
- parse_error(state, "actions must have a trigger\n");
- return 0;
- }
-
- action* act = (action*) calloc(1, sizeof(*act));
- list_init(&act->triggers);
+ std::string ret_err;
+ std::vector<std::string> triggers(args + 1, args + nargs);
+ Action* ret = ActionManager::GetInstance().AddNewAction(triggers, &ret_err);
- for (i = 1; i < nargs; i++) {
- if (!(i % 2)) {
- if (strcmp(args[i], "&&")) {
- struct listnode *node;
- struct listnode *node2;
- parse_error(state, "& is the only symbol allowed to concatenate actions\n");
- list_for_each_safe(node, node2, &act->triggers) {
- struct trigger *trigger = node_to_item(node, struct trigger, nlist);
- free(trigger);
- }
- free(act);
- return 0;
- } else
- continue;
- }
- cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
- cur_trigger->name = args[i];
- list_add_tail(&act->triggers, &cur_trigger->nlist);
+ if (!ret) {
+ parse_error(state, "%s\n", ret_err.c_str());
}
- list_init(&act->commands);
- list_init(&act->qlist);
- list_add_tail(&action_list, &act->alist);
- /* XXX add to hash */
- return act;
+ return ret;
}
static void parse_line_action(struct parse_state* state, int nargs, char **args)
{
- struct action *act = (action*) state->context;
+ Action* act = (Action*) state->context;
int kw, n;
if (nargs == 0) {
@@ -984,11 +813,7 @@ static void parse_line_action(struct parse_state* state, int nargs, char **args)
n > 2 ? "arguments" : "argument");
return;
}
- command* cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
- cmd->func = kw_func(kw);
- cmd->line = state->line;
- cmd->filename = state->filename;
- cmd->nargs = nargs;
- memcpy(cmd->args, args, sizeof(char*) * nargs);
- list_add_tail(&act->commands, &cmd->clist);
+
+ std::vector<std::string> str_args(args, args + nargs);
+ act->AddCommand(kw_func(kw), str_args, state->filename, state->line);
}
diff --git a/init/init_parser.h b/init/init_parser.h
index 1ebb1ef21..fe96bdc66 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -21,20 +21,10 @@
#define INIT_PARSER_MAXARGS 64
-struct action;
struct service;
-struct action *action_remove_queue_head(void);
-void action_add_queue_tail(struct action *act);
-void action_for_each_trigger(const char *trigger,
- void (*func)(struct action *act));
-int action_queue_empty(void);
-void queue_property_triggers(const char *name, const char *value);
-void queue_all_property_triggers();
-void queue_builtin_action(int (*func)(int nargs, char **args), const char *name);
-
bool init_parse_config(const char* path);
-int expand_props(const char *src, std::string *dst);
+int expand_props(const std::string& src, std::string* dst);
service* make_exec_oneshot_service(int argc, char** argv);
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 68931632f..5a875bb47 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -28,6 +28,7 @@
#include <cutils/list.h>
#include <cutils/sockets.h>
+#include "action.h"
#include "init.h"
#include "log.h"
#include "util.h"
@@ -133,18 +134,8 @@ static bool wait_for_one_process() {
svc->flags |= SVC_RESTARTING;
// Execute all onrestart commands for this service.
- struct listnode* node;
- list_for_each(node, &svc->onrestart.commands) {
- command* cmd = node_to_item(node, struct command, clist);
- std::vector<std::string> arg_strs;
- if (expand_command_arguments(cmd->nargs, cmd->args, &arg_strs)) {
- std::vector<char*> args;
- for (auto& s : arg_strs) {
- args.push_back(&s[0]);
- }
- cmd->func(args.size(), &args[0]);
- }
- }
+ svc->onrestart->ExecuteAllCommands();
+
svc->NotifyStateChange("restarting");
return true;
}