am a21d8562: am d548e30f: Merge "init: Create classes for Action and Command"

* commit 'a21d85620560896bbed0cd43db9ed3224ab4e974':
  init: Create classes for Action and Command
This commit is contained in:
Tom Cherry 2015-07-30 21:31:38 +00:00 committed by Android Git Automerger
commit 7da270df1d
9 changed files with 523 additions and 391 deletions

View File

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

383
init/action.cpp Normal file
View File

@ -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");
}

82
init/action.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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();
}
}
@ -218,10 +199,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;
}
@ -257,7 +238,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);
@ -270,14 +251,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;
}
@ -528,125 +509,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
@ -733,13 +595,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;
}
@ -747,8 +606,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;
@ -841,12 +700,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;
@ -925,48 +780,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;
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());
}
action* act = (action*) calloc(1, sizeof(*act));
list_init(&act->triggers);
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);
}
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) {
@ -985,11 +814,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);
}

View File

@ -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);

View File

@ -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;
}