From 0b41512a2ea3d5fbb2b82841557a96417398c398 Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Fri, 10 Oct 2014 23:19:06 -0700 Subject: [PATCH] init: Add support "&&" operator in property triggers "&&" operator can now be used to test the validity of two of more properties. For example: on property:test.a=1 && property:test.b=1 setprop test.c 1 The above stub sets the test.c to 1 only when both test.a=1 and test.b=1 (cherry-pick of 162f7d797c67019a7a3f08c3b0f0ffc91d548ddc.) Change-Id: I72c19f7aa92231372a416193618ee6c7fd368141 Signed-off-by: Badhri Jagan Sridharan --- init/init.c | 22 +++++++- init/init.h | 10 +++- init/init_parser.c | 132 ++++++++++++++++++++++++++++----------------- init/parser.c | 9 +++- init/readme.txt | 9 ++++ 5 files changed, 127 insertions(+), 55 deletions(-) diff --git a/init/init.c b/init/init.c index fef8a2e46..d3dd019cf 100644 --- a/init/init.c +++ b/init/init.c @@ -540,17 +540,35 @@ static int is_last_command(struct action *act, struct command *cmd) return (list_tail(&act->commands) == &cmd->clist); } + +void build_triggers_string(char *name_str, int length, struct action *cur_action) { + 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) { + strlcat(name_str, " " , length); + } + strlcat(name_str, cur_trigger->name , length); + } +} + void execute_one_command(void) { int ret, i; char cmd_str[256] = ""; + char name_str[256] = ""; 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; - INFO("processing action %p (%s)\n", cur_action, cur_action->name); + + build_triggers_string(name_str, sizeof(name_str), cur_action); + + INFO("processing action %p (%s)\n", cur_action, name_str); cur_command = get_first_command(cur_action); } else { cur_command = get_next_command(cur_action, cur_command); @@ -568,7 +586,7 @@ void execute_one_command(void) } } INFO("command '%s' action=%s status=%d (%s:%d)\n", - cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename, + cmd_str, cur_action ? name_str : "", ret, cur_command->filename, cur_command->line); } } diff --git a/init/init.h b/init/init.h index a7615a367..e03bd53ba 100644 --- a/init/init.h +++ b/init/init.h @@ -37,6 +37,11 @@ struct command char *args[1]; }; +struct trigger { + struct listnode nlist; + const char *name; +}; + struct action { /* node in list of all actions */ struct listnode alist; @@ -46,12 +51,15 @@ struct action { struct listnode tlist; unsigned hash; - const char *name; + /* list of actions which triggers the commands*/ + struct listnode triggers; struct listnode commands; struct command *current; }; +void build_triggers_string(char *name_str, int length, struct action *cur_action); + struct socketinfo { struct socketinfo *next; const char *name; diff --git a/init/init_parser.c b/init/init_parser.c index 2b4db8ecf..a124fa224 100644 --- a/init/init_parser.c +++ b/init/init_parser.c @@ -499,77 +499,92 @@ void service_for_each_flags(unsigned matchflags, void action_for_each_trigger(const char *trigger, void (*func)(struct action *act)) { - struct listnode *node; + 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); - if (!strcmp(act->name, trigger)) { - func(act); + 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; + 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); - if (!strncmp(act->name, "property:", strlen("property:"))) { - const char *test = act->name + strlen("property:"); - int name_length = strlen(name); + 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) { + char prop_name[PROP_NAME_MAX + 1]; + char value[PROP_VALUE_MAX]; + int length = equals - test; + if (length <= PROP_NAME_MAX) { + int ret; + memcpy(prop_name, test, length); + prop_name[length] = 0; - if (!strncmp(name, test, name_length) && - test[name_length] == '=' && - (!strcmp(test + name_length + 1, value) || - !strcmp(test + name_length + 1, "*"))) { - action_add_queue_tail(act); - } + /* does the property exist, and match the trigger value? */ + ret = property_get(prop_name, value); + if (ret > 0 && (!strcmp(equals + 1, value) || + !strcmp(equals + 1, "*"))) { + continue; + } + } + } + } + } + match = false; + break; + } + if (match) { + action_add_queue_tail(act); } } } void queue_all_property_triggers() { - struct listnode *node; - struct action *act; - list_for_each(node, &action_list) { - act = node_to_item(node, struct action, alist); - if (!strncmp(act->name, "property:", strlen("property:"))) { - /* parse property name and value - syntax is property:= */ - const char* name = act->name + strlen("property:"); - const char* equals = strchr(name, '='); - if (equals) { - char prop_name[PROP_NAME_MAX + 1]; - char value[PROP_VALUE_MAX]; - int length = equals - name; - if (length > PROP_NAME_MAX) { - ERROR("property name too long in trigger %s", act->name); - } else { - int ret; - memcpy(prop_name, name, length); - prop_name[length] = 0; - - /* does the property exist, and match the trigger value? */ - ret = property_get(prop_name, value); - if (ret > 0 && (!strcmp(equals + 1, value) || - !strcmp(equals + 1, "*"))) { - action_add_queue_tail(act); - } - } - } - } - } + queue_property_triggers(NULL, NULL); } void queue_builtin_action(int (*func)(int nargs, char **args), char *name) { struct action *act; struct command *cmd; + struct trigger *cur_trigger; act = calloc(1, sizeof(*act)); - act->name = name; + cur_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); @@ -611,6 +626,7 @@ int action_queue_empty() static void *parse_service(struct parse_state *state, int nargs, char **args) { struct service *svc; + struct trigger *cur_trigger; if (nargs < 3) { parse_error(state, "services must have a name and a program\n"); return 0; @@ -635,9 +651,12 @@ static void *parse_service(struct parse_state *state, int nargs, char **args) svc->name = args[1]; svc->classname = "default"; memcpy(svc->args, args + 2, sizeof(char*) * nargs); + cur_trigger = calloc(1, sizeof(*cur_trigger)); svc->args[nargs] = 0; svc->nargs = nargs; - svc->onrestart.name = "onrestart"; + list_init(&svc->onrestart.triggers); + cur_trigger->name = "onrestart"; + list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist); list_init(&svc->onrestart.commands); list_add_tail(&service_list, &svc->slist); return svc; @@ -821,16 +840,29 @@ 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) { struct action *act; + struct trigger *cur_trigger; + int i; if (nargs < 2) { parse_error(state, "actions must have a trigger\n"); return 0; } - if (nargs > 2) { - parse_error(state, "actions may not have extra parameters\n"); - return 0; - } + act = calloc(1, sizeof(*act)); - act->name = args[1]; + list_init(&act->triggers); + + for (i = 1; i < nargs; i++) { + if (!(i % 2)) { + if (strcmp(args[i], "&&")) { + parse_error(state, "& is the only symbol allowed to concatenate actions\n"); + return 0; + } else + continue; + } + cur_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); diff --git a/init/parser.c b/init/parser.c index 48e7aec23..80bfb095f 100644 --- a/init/parser.c +++ b/init/parser.c @@ -15,9 +15,10 @@ void DUMP(void) struct command *cmd; struct listnode *node; struct listnode *node2; + char name_str[256] = ""; struct socketinfo *si; int n; - + list_for_each(node, &service_list) { svc = node_to_item(node, struct service, slist); RAW("service %s\n", svc->name); @@ -34,7 +35,11 @@ void DUMP(void) list_for_each(node, &action_list) { act = node_to_item(node, struct action, alist); - RAW("on %s\n", act->name); + RAW("on "); + build_triggers_string(name_str, sizeof(name_str), act); + RAW("%s", name_str); + RAW("\n"); + list_for_each(node2, &act->commands) { cmd = node_to_item(node2, struct command, clist); RAW(" %p", cmd->func); diff --git a/init/readme.txt b/init/readme.txt index 750d9534c..0b43fd564 100644 --- a/init/readme.txt +++ b/init/readme.txt @@ -123,6 +123,15 @@ boot Triggers of this form occur when the property is set to the specific value . + One can also test Mutliple properties to execute a group + of commands. For example: + + on property:test.a=1 && property:test.b=1 + setprop test.c 1 + + The above stub sets test.c to 1 only when + both test.a=1 and test.b=1 + Commands --------