X-Git-Url: http://git.openwrt.org/?p=project%2Fprocd.git;a=blobdiff_plain;f=service%2Ftrigger.c;h=440830b26b72ff9afeac701cdd1fb89c6234ef58;hp=55d07e4dfa9b1611eb90b540befc32513d31656e;hb=a0372ac0713957365120cf42c5469c635c1e0232;hpb=8eecf942b50d88dbcd7517817fe5c557f10541e0 diff --git a/service/trigger.c b/service/trigger.c index 55d07e4..440830b 100644 --- a/service/trigger.c +++ b/service/trigger.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -32,37 +34,30 @@ struct trigger { struct list_head list; + void *id; char *type; - - int pending; - int remove; int timeout; - void *id; - struct blob_attr *rule; struct blob_attr *data; - struct uloop_timeout delay; struct json_script_ctx jctx; }; -struct job; -struct cmd { - char *name; - void (*handler)(struct job *job, struct blob_attr *exec, struct blob_attr *env); -}; +struct trigger_command { + struct avl_node avl; + struct uloop_timeout delay; + bool requeue; -struct job { struct runqueue_process proc; - struct cmd *cmd; - struct trigger *trigger; - struct blob_attr *exec; - struct blob_attr *env; + struct json_script_ctx jctx; + + struct blob_attr data[]; }; static LIST_HEAD(triggers); static RUNQUEUE(q, 1); +static AVL_TREE(trigger_pending, avl_blobcmp, false, NULL); static const char* rule_handle_var(struct json_script_ctx *ctx, const char *name, struct blob_attr *vars) { @@ -80,81 +75,45 @@ rule_load_script(struct json_script_ctx *ctx, const char *name) return json_script_file_from_blobmsg(t->type, t->rule, blob_pad_len(t->rule)); } -static void q_job_run(struct runqueue *q, struct runqueue_task *t) -{ - struct job *j = container_of(t, struct job, proc.task); - - DEBUG(4, "handle event %s\n", j->cmd->name); - j->cmd->handler(j, j->exec, j->env); -} - static void trigger_free(struct trigger *t) { json_script_free(&t->jctx); - uloop_timeout_cancel(&t->delay); free(t->data); list_del(&t->list); free(t); } -static void q_job_complete(struct runqueue *q, struct runqueue_task *p) +static void trigger_command_complete(struct runqueue *q, struct runqueue_task *p) { - struct job *j = container_of(p, struct job, proc.task); + struct trigger_command *cmd = container_of(p, struct trigger_command, proc.task); - if (j->trigger->remove) { - trigger_free(j->trigger); - } else { - j->trigger->pending = 0; + if (cmd->requeue) { + cmd->requeue = false; + runqueue_task_add(q, p, false); + return; } - free(j); -} -static void add_job(struct trigger *t, struct cmd *cmd, struct blob_attr *exec, struct blob_attr *data) -{ - static const struct runqueue_task_type job_type = { - .run = q_job_run, - .cancel = runqueue_process_cancel_cb, - .kill = runqueue_process_kill_cb, - }; - struct blob_attr *d, *e; - struct job *j = calloc_a(sizeof(*j), &e, blob_pad_len(exec), &d, blob_pad_len(data)); - - j->env = d; - j->exec = e; - j->cmd = cmd; - j->trigger = t; - j->proc.task.type = &job_type; - j->proc.task.complete = q_job_complete; - t->pending = 1; - - memcpy(j->exec, exec, blob_pad_len(exec)); - memcpy(j->env, data, blob_pad_len(data)); - - runqueue_task_add(&q, &j->proc.task, false); + avl_delete(&trigger_pending, &cmd->avl); + free(cmd); } -static void _setenv(const char *key, const char *val) +static void trigger_command_run(struct runqueue *q, struct runqueue_task *t) { - char _key[32]; - - snprintf(_key, sizeof(_key), "PARAM_%s", key); - setenv(_key, val, 1); -} - -static void handle_run_script(struct job *j, struct blob_attr *exec, struct blob_attr *env) -{ - char *argv[8]; + struct trigger_command *cmd = container_of(t, struct trigger_command, proc.task); struct blob_attr *cur; - int rem; - int i = 0; + char **argv; pid_t pid; + int n = 0; + int rem; pid = fork(); - if (pid < 0) + if (pid < 0) { + trigger_command_complete(q, t); return; + } if (pid) { - runqueue_process_add(&q, &j->proc, pid); + runqueue_process_add(q, &cmd->proc, pid); return; } @@ -164,46 +123,75 @@ static void handle_run_script(struct job *j, struct blob_attr *exec, struct blob close(STDERR_FILENO); } - _setenv("type", j->trigger->type); - blobmsg_for_each_attr(cur, j->env, rem) - _setenv(blobmsg_name(cur), blobmsg_data(cur)); + blobmsg_for_each_attr(cur, cmd->data, rem) + n++; - blobmsg_for_each_attr(cur, j->exec, rem) { - argv[i] = blobmsg_data(cur); - i++; - if (i == 7) - break; - } + argv = alloca((n + 1) * sizeof(*argv)); + n = 0; + blobmsg_for_each_attr(cur, cmd->data, rem) + argv[n++] = blobmsg_get_string(cur); + argv[n] = NULL; - if (i > 0) { - argv[i] = NULL; + if (n > 0) execvp(argv[0], &argv[0]); - } exit(1); } -static struct cmd handlers[] = { - { - .name = "run_script", - .handler = handle_run_script, - }, -}; +static void trigger_command_start(struct uloop_timeout *timeout) +{ + static const struct runqueue_task_type trigger_command_type = { + .run = trigger_command_run, + .cancel = runqueue_process_cancel_cb, + .kill = runqueue_process_kill_cb, + }; + struct trigger_command *cmd = container_of(timeout, struct trigger_command, delay); + + cmd->proc.task.type = &trigger_command_type; + cmd->proc.task.complete = trigger_command_complete; + runqueue_task_add(&q, &cmd->proc.task, false); +} + +static void trigger_command_add(struct trigger *t, struct blob_attr *data) +{ + struct trigger_command *cmd; + int remaining; + + cmd = avl_find_element(&trigger_pending, data, cmd, avl); + if (cmd) { + /* Command currently running? */ + if (!cmd->delay.pending) { + cmd->requeue = true; + return; + } + + /* Extend timer if trigger timeout is bigger than remaining time */ + remaining = uloop_timeout_remaining(&cmd->delay); + if (remaining < t->timeout) + uloop_timeout_set(&cmd->delay, t->timeout); + + return; + } + + cmd = calloc(1, sizeof(*cmd) + blob_pad_len(data)); + if (!cmd) + return; + + cmd->avl.key = cmd->data; + cmd->delay.cb = trigger_command_start; + memcpy(cmd->data, data, blob_pad_len(data)); + avl_insert(&trigger_pending, &cmd->avl); + uloop_timeout_set(&cmd->delay, t->timeout > 0 ? t->timeout : 1); +} static void rule_handle_command(struct json_script_ctx *ctx, const char *name, struct blob_attr *exec, struct blob_attr *vars) { struct trigger *t = container_of(ctx, struct trigger, jctx); - int i; - if (t->pending) + if (!strcmp(name, "run_script")) { + trigger_command_add(t, exec); return; - - for (i = 0; i < ARRAY_SIZE(handlers); i++) { - if (!strcmp(handlers[i].name, name)) { - add_job(t, &handlers[i], exec, vars); - break; - } } } @@ -217,15 +205,6 @@ static void rule_handle_error(struct json_script_ctx *ctx, const char *msg, free(s); } -static void trigger_delay_cb(struct uloop_timeout *tout) -{ - struct trigger *t = container_of(tout, struct trigger, delay); - - json_script_run(&t->jctx, t->type, t->data); - free(t->data); - t->data = NULL; -} - static struct trigger* _trigger_add(char *type, struct blob_attr *rule, int timeout, void *id) { char *_t; @@ -234,10 +213,7 @@ static struct trigger* _trigger_add(char *type, struct blob_attr *rule, int time t->type = _t; t->rule = _r; - t->delay.cb = trigger_delay_cb; t->timeout = timeout; - t->pending = 0; - t->remove = 0; t->id = id; t->jctx.handle_var = rule_handle_var, t->jctx.handle_error = rule_handle_error, @@ -303,11 +279,6 @@ void trigger_del(void *id) if (t->id != id) continue; - if (t->pending) { - t->remove = 1; - continue; - } - trigger_free(t); } } @@ -325,16 +296,8 @@ void trigger_event(const char *type, struct blob_attr *data) struct trigger *t; list_for_each_entry(t, &triggers, list) { - if (t->remove) - continue; if (!trigger_match(type, t->type)) continue; - if (t->timeout) { - free(t->data); - t->data = blob_memdup(data); - uloop_timeout_set(&t->delay, t->timeout); - } else { - json_script_run(&t->jctx, t->type, data); - } + json_script_run(&t->jctx, t->type, data); } }