init: Create classes for Action and Command
This creates the concept of 'event_trigger' vs 'property_trigger'
Previously these were merged into one, such that 'on property:a=b &&
property:b=c' is triggered when properties a=b and b=c as expected,
however combinations such as 'on early-boot && boot' would trigger
during both early-boot and boot. Similarly, 'on early-boot &&
property:a=b' would trigger on both early-boot and again when property
a equals b.
The event trigger distinction ensures that the first example fails to
parse and the second example only triggers on early-boot if
property a equals b.
This coalesces Actions with the same triggers into a single Action object
Change-Id: I8f661d96e8a2d40236f252301bfe10979d663ea6
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 460f5ac..ab0dbc3 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 @@
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 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 @@
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 @@
}
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 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 @@
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_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 @@
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_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) {
@@ -984,11 +813,7 @@
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);
}