Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 162f7d79 authored by Badhri Jagan Sridharan's avatar Badhri Jagan Sridharan
Browse files

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

Change-Id: I72c19f7aa92231372a416193618ee6c7fd368141
Signed-off-by: default avatarBadhri Jagan Sridharan <badhri@google.com>
parent 6d463a5f
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -542,17 +542,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);
@@ -570,7 +588,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);
    }
}
+9 −1
Original line number Diff line number Diff line
@@ -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;
+83 −51
Original line number Diff line number Diff line
@@ -504,77 +504,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)) {
        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, "*"))) {
                action_add_queue_tail(act);
            }
        }
    }
                        match = true;
                        continue;
                    }

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, '=');
                } else {
                     const char* equals = strchr(test, '=');
                     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 length = equals - test;
                         if (length <= PROP_NAME_MAX) {
                             int ret;
                    memcpy(prop_name, name, length);
                             memcpy(prop_name, test, 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);
                                 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), 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);

@@ -616,6 +631,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;
@@ -640,9 +656,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;
@@ -826,16 +845,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");

    act = calloc(1, sizeof(*act));
    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;
        }
    act = calloc(1, sizeof(*act));
    act->name = args[1];
        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);
+7 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ void DUMP(void)
    struct command *cmd;
    struct listnode *node;
    struct listnode *node2;
    char name_str[256] = "";
    struct socketinfo *si;
    int n;

@@ -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);
+9 −0
Original line number Diff line number Diff line
@@ -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
--------