#include <linux/types.h>
#include <linux/netlink.h>
-#include <libubox/avl-cmp.h>
#include <libubox/blobmsg_json.h>
#include <libubox/json_script.h>
#include <libubox/uloop.h>
#define HOTPLUG_WAIT 500
+struct cmd_handler;
struct cmd_queue {
struct list_head list;
struct blob_attr *msg;
struct blob_attr *data;
+ int timeout;
+
void (*handler)(struct blob_attr *msg, struct blob_attr *data);
+ void (*start)(struct blob_attr *msg, struct blob_attr *data);
+ void (*complete)(struct blob_attr *msg, struct blob_attr *data, int ret);
};
-struct cmd_interval {
- struct avl_node avl;
-
- bool cancelled;
- struct timespec start;
+struct button_timeout {
+ struct list_head list;
struct uloop_timeout timeout;
- struct uloop_process process;
-
- struct blob_attr *msg;
+ char *name;
+ int seen;
struct blob_attr *data;
};
static LIST_HEAD(cmd_queue);
-static AVL_TREE(cmd_intervals, avl_strcmp, false, NULL);
+static LIST_HEAD(button_timer);
static struct uloop_process queue_proc;
static struct uloop_timeout last_event;
-static struct blob_buf b;
+static struct blob_buf b, button_buf;
static char *rule_file;
static struct blob_buf script;
+static struct cmd_queue *current;
+
+static void queue_add(struct cmd_handler *h, struct blob_attr *msg, struct blob_attr *data);
+static void handle_button_complete(struct blob_attr *msg, struct blob_attr *data, int ret);
+
+static void button_free(struct button_timeout *b)
+{
+ uloop_timeout_cancel(&b->timeout);
+ list_del(&b->list);
+ free(b->data);
+ free(b->name);
+ free(b);
+}
+
+static void button_timeout_remove(char *button)
+{
+ struct button_timeout *b, *c;
+
+ if (!list_empty(&button_timer)) list_for_each_entry_safe(b, c, &button_timer, list) {
+ if (!strcmp(b->name, button))
+ button_free(b);
+ }
+}
static char *hotplug_msg_find_var(struct blob_attr *msg, const char *name)
{
exit(-1);
}
-static void handle_set_interval_timeout(struct uloop_timeout *timeout)
-{
- struct cmd_interval *interval = container_of(timeout, struct cmd_interval, timeout);
- struct blob_attr *cur;
- char *argv[8];
- int rem, fd;
- int msecs = 0;
- int i = 0;
-
- blobmsg_for_each_attr(cur, interval->data, rem) {
- switch (i) {
- case 0:
- break;
- case 1:
- msecs = strtol(blobmsg_get_string(cur), NULL, 0);
- break;
- default:
- argv[i - 2] = blobmsg_data(cur);
- }
- i++;
- if (i - 2 == 7)
- break;
- }
-
- if (interval->process.pending) {
- uloop_timeout_set(&interval->timeout, msecs);
- return;
- }
-
- interval->process.pid = fork();
- if (interval->process.pid < 0) {
- perror("fork");
- } else if (interval->process.pid == 0) {
- struct timespec now;
- char elapsed[6];
-
- if (i - 2 <= 0)
- return;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- snprintf(elapsed, sizeof(elapsed), "%ld", now.tv_sec - interval->start.tv_sec);
-
- blobmsg_for_each_attr(cur, interval->msg, rem)
- setenv(blobmsg_name(cur), blobmsg_data(cur), 1);
- setenv("ACTION", "interval", 1);
- setenv("ELAPSED", elapsed, 1);
- unsetenv("SEEN");
-
- if (debug < 3) {
- fd = open("/dev/null", O_RDWR);
- if (fd > -1) {
- dup2(fd, STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- if (fd > STDERR_FILENO)
- close(fd);
- }
- }
-
- argv[i - 2] = NULL;
- execvp(argv[0], &argv[0]);
- exit(-1);
- } else {
- uloop_process_add(&interval->process);
- uloop_timeout_set(&interval->timeout, msecs);
- }
-}
-
-static void handle_set_interval_process_cb(struct uloop_process *process, int ret)
+static void handle_button_start(struct blob_attr *msg, struct blob_attr *data)
{
- struct cmd_interval *interval = container_of(process, struct cmd_interval, process);
+ char *button = hotplug_msg_find_var(msg, "BUTTON");
- if (interval->cancelled)
- free(interval);
-}
-
-static void handle_set_interval(struct blob_attr *msg, struct blob_attr *data)
-{
- static struct blobmsg_policy set_interval_policy[2] = {
- { .type = BLOBMSG_TYPE_STRING },
- { .type = BLOBMSG_TYPE_STRING },
- };
- struct blob_attr *tb[2];
- struct cmd_interval *interval;
- struct blob_attr *_msg, *_data;
- char *_key;
- char *name;
- int msecs;
-
- blobmsg_parse_array(set_interval_policy, 2, tb, blobmsg_data(data), blobmsg_data_len(data));
- if (!tb[0] || !tb[1])
- return;
- name = blobmsg_get_string(tb[0]);
- msecs = strtol(blobmsg_get_string(tb[1]), NULL, 0);
-
- interval = calloc_a(sizeof(struct cmd_interval),
- &_key, strlen(name) + 1,
- &_msg, blob_pad_len(msg),
- &_data, blob_pad_len(data),
- NULL);
- if (!interval)
- return;
-
- strcpy(_key, name);
- interval->avl.key = _key;
- interval->msg = _msg;
- interval->data = _data;
- clock_gettime(CLOCK_MONOTONIC, &interval->start);
- interval->timeout.cb = handle_set_interval_timeout;
- interval->process.cb = handle_set_interval_process_cb;
-
- memcpy(interval->msg, msg, blob_pad_len(msg));
- memcpy(interval->data, data, blob_pad_len(data));
-
- avl_insert(&cmd_intervals, &interval->avl);
-
- uloop_timeout_set(&interval->timeout, msecs);
-}
-
-static void handle_clear_interval(struct blob_attr *msg, struct blob_attr *data)
-{
- static struct blobmsg_policy clear_interval_policy = {
- .type = BLOBMSG_TYPE_STRING,
- };
- struct blob_attr *tb;
- struct cmd_interval *interval;
- char *name;
-
- blobmsg_parse_array(&clear_interval_policy, 1, &tb, blobmsg_data(data), blobmsg_data_len(data));
- if (!tb)
- return;
- name = blobmsg_get_string(tb);
-
- interval = avl_find_element(&cmd_intervals, name, interval, avl);
- if (interval) {
- uloop_timeout_cancel(&interval->timeout);
- avl_delete(&cmd_intervals, &interval->avl);
- if (interval->process.pending)
- interval->cancelled = true;
- else
- free(interval);
- }
+ if (button)
+ button_timeout_remove(button);
}
static void handle_firmware(struct blob_attr *msg, struct blob_attr *data)
exit(-1);
}
+enum {
+ HANDLER_MKDEV = 0,
+ HANDLER_RM,
+ HANDLER_EXEC,
+ HANDLER_BUTTON,
+ HANDLER_FW,
+};
+
static struct cmd_handler {
char *name;
int atomic;
void (*handler)(struct blob_attr *msg, struct blob_attr *data);
+ void (*start)(struct blob_attr *msg, struct blob_attr *data);
+ void (*complete)(struct blob_attr *msg, struct blob_attr *data, int ret);
} handlers[] = {
- {
+ [HANDLER_MKDEV] = {
.name = "makedev",
.atomic = 1,
.handler = handle_makedev,
- }, {
+ },
+ [HANDLER_RM] = {
.name = "rm",
.atomic = 1,
.handler = handle_rm,
- }, {
+ },
+ [HANDLER_EXEC] = {
.name = "exec",
.handler = handle_exec,
- }, {
- .name = "set-interval",
- .atomic = 1,
- .handler = handle_set_interval,
- }, {
- .name = "clear-interval",
- .atomic = 1,
- .handler = handle_clear_interval,
- }, {
+ },
+ [HANDLER_BUTTON] = {
+ .name = "button",
+ .handler = handle_exec,
+ .start = handle_button_start,
+ .complete = handle_button_complete,
+ },
+ [HANDLER_FW] = {
.name = "load-firmware",
.handler = handle_firmware,
},
c->handler(c->msg, c->data);
exit(0);
}
-
+ if (c->start)
+ c->start(c->msg, c->data);
list_del(&c->list);
- free(c);
-
+ if (c->complete)
+ current = c;
+ else
+ free(c);
if (queue_proc.pid <= 0) {
queue_next();
return;
{
DEBUG(4, "Finished hotplug exec instance, pid=%d\n", (int) c->pid);
+ if (current) {
+ current->complete(current->msg, current->data, ret);
+ free(current);
+ current = NULL;
+ }
queue_next();
}
memcpy(c->msg, msg, blob_pad_len(msg));
memcpy(c->data, data, blob_pad_len(data));
c->handler = h->handler;
+ c->complete = h->complete;
+ c->start = h->start;
list_add_tail(&c->list, &cmd_queue);
queue_next();
}
+static void handle_button_timeout(struct uloop_timeout *t)
+{
+ struct button_timeout *b;
+ char seen[16];
+
+ b = container_of(t, struct button_timeout, timeout);
+ blob_buf_init(&button_buf, 0);
+ blobmsg_add_string(&button_buf, "ACTION", "timeout");
+ snprintf(seen, sizeof(seen), "%d", b->seen);
+ blobmsg_add_string(&button_buf, "SEEN", seen);
+ queue_add(&handlers[HANDLER_EXEC], button_buf.head, b->data);
+ button_free(b);
+}
+
+static void handle_button_complete(struct blob_attr *msg, struct blob_attr *data, int ret)
+{
+ char *name = hotplug_msg_find_var(msg, "BUTTON");
+ struct button_timeout *b;
+ int timeout = ret >> 8;
+
+ if (!timeout)
+ return;
+
+ b = malloc(sizeof(*b));
+ if (!b || !name)
+ return;
+
+ memset(b, 0, sizeof(*b));
+
+ b->data = malloc(blob_pad_len(data));
+ b->name = strdup(name);
+ b->seen = timeout;
+
+ memcpy(b->data, data, blob_pad_len(data));
+ b->timeout.cb = handle_button_timeout;
+
+ uloop_timeout_set(&b->timeout, timeout * 1000);
+ list_add(&b->list, &button_timer);
+}
+
static const char* rule_handle_var(struct json_script_ctx *ctx, const char *name, struct blob_attr *vars)
{
const char *str, *sep;