Merge "init: Add support "&&" operator in property triggers"

This commit is contained in:
Elliott Hughes 2015-02-03 00:22:25 +00:00 committed by Gerrit Code Review
commit 46adfa69b6
5 changed files with 127 additions and 55 deletions

View file

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

View file

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

View file

@ -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:<name>=<value> */
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);

View file

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

View file

@ -123,6 +123,15 @@ boot
Triggers of this form occur when the property <name> is set
to the specific value <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
--------