X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fprocd.git;a=blobdiff_plain;f=plug%2Fhotplug.c;h=b5ebd07467b1376a5434a080c9c25f59249d2562;hp=ca1e823b65c5fdeac1c5d30f2633669abb2e5a56;hb=ad3ddbf04850a9ab229e21b70bf637090b33bf00;hpb=916f95cb58604038695347ee41a430d8ca1f0556 diff --git a/plug/hotplug.c b/plug/hotplug.c index ca1e823..b5ebd07 100644 --- a/plug/hotplug.c +++ b/plug/hotplug.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -34,20 +35,57 @@ #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 button_timeout { + struct list_head list; + struct uloop_timeout timeout; + char *name; + int seen; + struct blob_attr *data; }; static LIST_HEAD(cmd_queue); +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) { @@ -156,15 +194,23 @@ static void handle_exec(struct blob_attr *msg, struct blob_attr *data) exit(-1); } +static void handle_button_start(struct blob_attr *msg, struct blob_attr *data) +{ + char *button = hotplug_msg_find_var(msg, "BUTTON"); + + if (button) + button_timeout_remove(button); +} + static void handle_firmware(struct blob_attr *msg, struct blob_attr *data) { char *dir = blobmsg_get_string(blobmsg_data(data)); char *file = hotplug_msg_find_var(msg, "FIRMWARE"); char *dev = hotplug_msg_find_var(msg, "DEVPATH"); - void *fw_data; - struct stat s; + struct stat s = { 0 }; char *path, loadpath[256], syspath[256]; - int fw, load, sys, len; + int fw, src, load, len; + static char buf[4096]; DEBUG(2, "Firmware request for %s/%s\n", dir, file); @@ -173,62 +219,62 @@ static void handle_firmware(struct blob_attr *msg, struct blob_attr *data) exit(-1); } - path = malloc(strlen(dir) + strlen(file) + 2); - if (!path) { - ERROR("Failed to allocate memory\n"); - exit(-1); - } + path = alloca(strlen(dir) + strlen(file) + 2); sprintf(path, "%s/%s", dir, file); if (stat(path, &s)) { ERROR("Could not find firmware %s\n", path); - exit(-1); + src = -1; + s.st_size = 0; + goto send_to_kernel; } - fw_data = malloc(s.st_size); - if (!fw_data) { - ERROR("Failed to allocate firmware data memory\n"); - exit(-1); - } - - fw = open(path, O_RDONLY); - if (!fw) { + src = open(path, O_RDONLY); + if (src < 0) { ERROR("Failed to open %s\n", path); - exit(-1); + s.st_size = 0; + goto send_to_kernel; } - if (read(fw, fw_data, s.st_size) != s.st_size) { - ERROR("Failed to read firmware data\n"); - exit(-1); - } - close(fw); +send_to_kernel: snprintf(loadpath, sizeof(loadpath), "/sys/%s/loading", dev); load = open(loadpath, O_WRONLY); if (!load) { ERROR("Failed to open %s\n", loadpath); exit(-1); } - write(load, "1", 1); + if (write(load, "1", 1) == -1) { + ERROR("Failed to write to %s\n", loadpath); + exit(-1); + } close(load); snprintf(syspath, sizeof(syspath), "/sys/%s/data", dev); - sys = open(syspath, O_WRONLY); - if (!sys) { + fw = open(syspath, O_WRONLY); + if (fw < 0) { ERROR("Failed to open %s\n", syspath); exit(-1); } len = s.st_size; - while (len > 4096) { - write(fw, fw_data, 4096); - len -= 4096; + while (len) { + len = read(src, buf, sizeof(buf)); + if (len <= 0) + break; + + if (write(fw, buf, len) == -1) { + ERROR("failed to write firmware file %s/%s to %s\n", dir, file, dev); + break; + } } - if (len) - write(fw, fw_data, len); + + if (src >= 0) + close(src); close(fw); load = open(loadpath, O_WRONLY); - write(load, "0", 1); + if (write(load, "0", 1) == -1) + ERROR("failed to write to %s\n", loadpath); close(load); DEBUG(2, "Done loading %s\n", path); @@ -236,23 +282,42 @@ 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, - }, { + }, + [HANDLER_BUTTON] = { + .name = "button", + .handler = handle_exec, + .start = handle_button_start, + .complete = handle_button_complete, + }, + [HANDLER_FW] = { .name = "load-firmware", .handler = handle_firmware, }, @@ -273,10 +338,13 @@ static void queue_next(void) 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; @@ -291,6 +359,11 @@ static void queue_proc_cb(struct uloop_process *c, int ret) { 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(); } @@ -313,10 +386,53 @@ static void queue_add(struct cmd_handler *h, struct blob_attr *msg, struct blob_ 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, "BUTTON", b->name); + 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; @@ -342,7 +458,7 @@ rule_handle_file(struct json_script_ctx *ctx, const char *name) json_object *obj; obj = json_object_from_file((char*)name); - if (is_error(obj)) + if (!obj) return NULL; blob_buf_init(&script, 0); @@ -399,6 +515,18 @@ static struct json_script_ctx jctx = { .handle_file = rule_handle_file, }; +static void hotplug_handler_debug(struct blob_attr *data) +{ + char *str; + + if (debug < 3) + return; + + str = blobmsg_format_json(data, true); + DEBUG(3, "%s\n", str); + free(str); +} + static void hotplug_handler(struct uloop_fd *u, unsigned int ev) { int i = 0; @@ -421,7 +549,7 @@ static void hotplug_handler(struct uloop_fd *u, unsigned int ev) i += l; } blobmsg_close_table(&b, index); - DEBUG(3, "%s\n", blobmsg_format_json(b.head, true)); + hotplug_handler_debug(b.head); json_script_run(&jctx, rule_file, blob_data(b.head)); } @@ -441,6 +569,7 @@ void hotplug_last_event(uloop_timeout_handler handler) void hotplug(char *rules) { struct sockaddr_nl nls; + int nlbufsize = 512 * 1024; rule_file = strdup(rules); memset(&nls,0,sizeof(struct sockaddr_nl)); @@ -457,6 +586,9 @@ void hotplug(char *rules) exit(1); } + if (setsockopt(hotplug_fd.fd, SOL_SOCKET, SO_RCVBUFFORCE, &nlbufsize, sizeof(nlbufsize))) + ERROR("Failed to resize receive buffer: %s\n", strerror(errno)); + json_script_init(&jctx); queue_proc.cb = queue_proc_cb; uloop_fd_add(&hotplug_fd, ULOOP_READ);