From: John Crispin Date: Fri, 8 Mar 2013 22:49:24 +0000 (+0100) Subject: fix hotplug X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fprocd.git;a=commitdiff_plain;h=54108c71df643b35a5684e9bce4551543f63ddc4 fix hotplug --- diff --git a/hotplug-rule.c b/hotplug-rule.c deleted file mode 100644 index 1f3189d..0000000 --- a/hotplug-rule.c +++ /dev/null @@ -1,519 +0,0 @@ -#include - -#include -#include - -#include -#include -#include - -#include "hotplug.h" - -static struct blob_buf b; - -static int rule_process_expr(struct blob_attr *cur, struct blob_attr *msg); -static int rule_process_cmd(struct blob_attr *cur, struct blob_attr *msg); - -static char *__msg_find_var(struct blob_attr *msg, const char *name) -{ - struct blob_attr *cur; - int rem; - - blob_for_each_attr(cur, msg, rem) { - if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) - continue; - - if (strcmp(blobmsg_name(cur), name) != 0) - continue; - - return blobmsg_data(cur); - } - - return NULL; -} - -static char *msg_find_var(struct blob_attr *msg, const char *name) -{ - char *str; - - if (!strcmp(name, "DEVICENAME") || !strcmp(name, "DEVNAME")) { - str = __msg_find_var(msg, "DEVPATH"); - if (!str) - return NULL; - - return basename(str); - } - - return __msg_find_var(msg, name); -} - -static void -rule_get_tuple(struct blob_attr *cur, struct blob_attr **tb, int t1, int t2) -{ - static struct blobmsg_policy expr_tuple[3] = { - { .type = BLOBMSG_TYPE_STRING }, - {}, - {}, - }; - - expr_tuple[1].type = t1; - expr_tuple[2].type = t2; - blobmsg_parse_array(expr_tuple, 3, tb, blobmsg_data(cur), blobmsg_data_len(cur)); -} - -static int handle_if(struct blob_attr *expr, struct blob_attr *msg) -{ - struct blob_attr *tb[4]; - int ret; - - static const struct blobmsg_policy if_tuple[4] = { - { .type = BLOBMSG_TYPE_STRING }, - { .type = BLOBMSG_TYPE_ARRAY }, - { .type = BLOBMSG_TYPE_ARRAY }, - { .type = BLOBMSG_TYPE_ARRAY }, - }; - - blobmsg_parse_array(if_tuple, 4, tb, blobmsg_data(expr), blobmsg_data_len(expr)); - - if (!tb[1] || !tb[2]) - return 0; - - ret = rule_process_expr(tb[1], msg); - if (ret < 0) - return 0; - - if (ret) - return rule_process_cmd(tb[2], msg); - - if (!tb[3]) - return 0; - - return rule_process_cmd(tb[3], msg); -} - -static int handle_case(struct blob_attr *expr, struct blob_attr *msg) -{ - struct blob_attr *tb[3], *cur; - const char *var; - int rem; - - rule_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, BLOBMSG_TYPE_TABLE); - if (!tb[1] || !tb[2]) - return 0; - - var = msg_find_var(msg, blobmsg_data(tb[1])); - if (!var) - return 0; - - blobmsg_for_each_attr(cur, tb[2], rem) { - if (!strcmp(var, blobmsg_name(cur))) - return rule_process_cmd(cur, msg); - } - - return 0; -} - -static int handle_return(struct blob_attr *expr, struct blob_attr *msg) -{ - return -2; -} - -static int handle_include(struct blob_attr *expr, struct blob_attr *msg) -{ - struct blob_attr *tb[3]; - struct rule_file *r; - - rule_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0); - if (!tb[1]) - return 0; - - r = rule_file_get(blobmsg_data(tb[1])); - if (!r) - return 0; - - return rule_process_cmd(r->data, msg); -} - -static const struct rule_handler cmd[] = { - { "if", handle_if }, - { "case", handle_case }, - { "return", handle_return }, - { "include", handle_include }, -}; - -static int eq_regex_cmp(const char *str, const char *pattern, bool regex) -{ - regex_t reg; - int ret; - - if (!regex) - return !strcmp(str, pattern); - - if (regcomp(®, pattern, REG_EXTENDED | REG_NOSUB)) - return 0; - - ret = !regexec(®, str, 0, NULL, 0); - regfree(®); - - return ret; -} - -static int expr_eq_regex(struct blob_attr *expr, struct blob_attr *msg, bool regex) -{ - struct blob_attr *tb[3], *cur; - const char *var; - int rem; - - rule_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0); - if (!tb[1] || !tb[2]) - return -1; - - var = msg_find_var(msg, blobmsg_data(tb[1])); - if (!var) - return 0; - - switch(blobmsg_type(tb[2])) { - case BLOBMSG_TYPE_STRING: - return eq_regex_cmp(var, blobmsg_data(tb[2]), regex); - case BLOBMSG_TYPE_ARRAY: - blobmsg_for_each_attr(cur, tb[2], rem) { - if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) { - rule_error(cur, "Unexpected element type"); - return -1; - } - - if (eq_regex_cmp(var, blobmsg_data(cur), regex)) - return 1; - } - return 0; - default: - rule_error(tb[2], "Unexpected element type"); - return -1; - } -} - -static int handle_expr_eq(struct blob_attr *expr, struct blob_attr *msg) -{ - return expr_eq_regex(expr, msg, false); -} - -static int handle_expr_regex(struct blob_attr *expr, struct blob_attr *msg) -{ - return expr_eq_regex(expr, msg, true); -} - -static int handle_expr_has(struct blob_attr *expr, struct blob_attr *msg) -{ - struct blob_attr *tb[3], *cur; - int rem; - - rule_get_tuple(expr, tb, 0, 0); - if (!tb[1]) - return -1; - - switch(blobmsg_type(tb[1])) { - case BLOBMSG_TYPE_STRING: - return !!msg_find_var(msg, blobmsg_data(tb[1])); - case BLOBMSG_TYPE_ARRAY: - blobmsg_for_each_attr(cur, tb[1], rem) { - if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) { - rule_error(cur, "Unexpected element type"); - return -1; - } - - if (msg_find_var(msg, blobmsg_data(cur))) - return 1; - } - return 0; - default: - rule_error(tb[1], "Unexpected element type"); - return -1; - } -} - -static int expr_and_or(struct blob_attr *expr, struct blob_attr *msg, bool and) -{ - struct blob_attr *cur; - int ret, rem; - int i = 0; - - blobmsg_for_each_attr(cur, expr, rem) { - if (i++ < 1) - continue; - - ret = rule_process_expr(cur, msg); - if (ret < 0) - return ret; - - if (ret != and) - return ret; - } - - return and; -} - -static int handle_expr_and(struct blob_attr *expr, struct blob_attr *msg) -{ - return expr_and_or(expr, msg, 1); -} - -static int handle_expr_or(struct blob_attr *expr, struct blob_attr *msg) -{ - return expr_and_or(expr, msg, 0); -} - -static int handle_expr_not(struct blob_attr *expr, struct blob_attr *msg) -{ - struct blob_attr *tb[3]; - - rule_get_tuple(expr, tb, BLOBMSG_TYPE_ARRAY, 0); - if (!tb[1]) - return -1; - - return rule_process_expr(tb[1], msg); -} - -static const struct rule_handler expr[] = { - { "eq", handle_expr_eq }, - { "regex", handle_expr_regex }, - { "has", handle_expr_has }, - { "and", handle_expr_and }, - { "or", handle_expr_or }, - { "not", handle_expr_not }, -}; - -static int -__rule_process_type(struct blob_attr *cur, struct blob_attr *msg, - const struct rule_handler *h, int n, bool *found) -{ - const char *name = blobmsg_data(blobmsg_data(cur)); - int i; - - for (i = 0; i < n; i++) { - if (strcmp(name, h[i].name) != 0) - continue; - - *found = true; - return h[i].handler(cur, msg); - } - - *found = false; - return -1; -} - -static int rule_process_expr(struct blob_attr *cur, struct blob_attr *msg) -{ - bool found; - int ret; - - if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || - blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) { - rule_error(cur, "Unexpected element type"); - return -1; - } - - ret = __rule_process_type(cur, msg, expr, ARRAY_SIZE(expr), &found); - if (!found) - rule_error(cur, "Unknown expression type"); - - return ret; -} - -static void cmd_add_string(const char *pattern, struct blob_attr *msg) -{ - char *dest, *next, *str; - int len = 0; - bool var = false; - - dest = blobmsg_alloc_string_buffer(&b, NULL, 1); - str = alloca(strlen(pattern) + 1); - strcpy(str, pattern); - next = str; - - while (*str) { - const char *cur; - int cur_len = 0; - - next = strchr(str, '%'); - if (!next) - next = str + strlen(str); - - if (var) { - if (next > str) { - *next = 0; - cur = msg_find_var(msg, str); - if (cur) - cur_len = strlen(cur); - } else { - cur = str - 1; - cur_len = 1; - } - } else { - cur = str; - cur_len = next - str; - } - - if (cur_len) { - dest = blobmsg_realloc_string_buffer(&b, cur_len + 1); - memcpy(dest + len, cur, cur_len); - len += cur_len; - } - - var = !var; - str = next + 1; - } - - dest[len] = 0; - blobmsg_add_string_buffer(&b); -} - -static int cmd_process_strings(struct blob_attr *attr, struct blob_attr *msg) -{ - struct blob_attr *cur; - int args = -1; - int rem; - void *c; - - blob_buf_init(&b, 0); - c = blobmsg_open_array(&b, NULL); - blobmsg_for_each_attr(cur, attr, rem) { - if (args++ < 0) - continue; - - if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) { - rule_error(attr, "Invalid argument in command"); - return -1; - } - - cmd_add_string(blobmsg_data(cur), msg); - } - - blobmsg_close_array(&b, c); - - return 0; -} - -static int __rule_process_cmd(struct blob_attr *cur, struct blob_attr *msg) -{ - const char *name; - bool found; - int ret; - - if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || - blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) { - rule_error(cur, "Unexpected element type"); - return -1; - } - - ret = __rule_process_type(cur, msg, cmd, ARRAY_SIZE(cmd), &found); - if (found) - return ret; - - name = blobmsg_data(blobmsg_data(cur)); - ret = cmd_process_strings(cur, msg); - if (ret) - return ret; - - rule_handle_command(name, blob_data(b.head)); - - return 0; -} - -static int rule_process_cmd(struct blob_attr *block, struct blob_attr *msg) -{ - struct blob_attr *cur; - int rem; - int ret; - int i = 0; - - if (blobmsg_type(block) != BLOBMSG_TYPE_ARRAY) { - rule_error(block, "Unexpected element type"); - return -1; - } - - blobmsg_for_each_attr(cur, block, rem) { - switch(blobmsg_type(cur)) { - case BLOBMSG_TYPE_STRING: - if (!i) - return __rule_process_cmd(block, msg); - default: - ret = rule_process_cmd(cur, msg); - if (ret < -1) - return ret; - break; - } - i++; - } - - return 0; -} - -void rule_process_msg(struct rule_file *f, struct blob_attr *msg) -{ - rule_process_cmd(f->data, msg); -} - -static struct rule_file * -rule_file_load(const char *filename) -{ - struct rule_file *r; - struct stat st; - - json_object *obj = NULL; - - blob_buf_init(&b, 0); - - if (stat(filename, &st)) - return NULL; - - obj = json_object_from_file((char *) filename); - if (is_error(obj)) - return NULL; - - if (!json_object_is_type(obj, json_type_array)) { - json_object_put(obj); - return NULL; - } - - blobmsg_add_json_element(&b, filename, obj); - json_object_put(obj); - - r = calloc(1, sizeof(*r) + blob_len(b.head)); - memcpy(r->data, blob_data(b.head), blob_len(b.head)); - r->avl.key = blobmsg_name(r->data); - - return r; -} - -static struct avl_tree rule_files; - -struct rule_file * -rule_file_get(const char *filename) -{ - struct rule_file *r; - - if (!rule_files.comp) - avl_init(&rule_files, avl_strcmp, false, NULL); - - r = avl_find_element(&rule_files, filename, r, avl); - if (r) - return r; - - r = rule_file_load(filename); - if (!r) - return NULL; - - avl_insert(&rule_files, &r->avl); - return r; -} - -void -rule_file_free_all(void) -{ - struct rule_file *r, *next; - - avl_remove_all_elements(&rule_files, r, avl, next) - free(r); - - blob_buf_free(&b); -} diff --git a/hotplug.c b/hotplug.c index 7e681f9..6583de4 100644 --- a/hotplug.c +++ b/hotplug.c @@ -1,10 +1,438 @@ +/* + * Copyright (C) 2013 Felix Fietkau + * Copyright (C) 2013 John Crispin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "procd.h" #include "hotplug.h" -void rule_handle_command(const char *name, struct blob_attr *data) +#define HOTPLUG_WAIT 500 + +struct cmd_queue { + struct list_head list; + + struct blob_attr *msg; + struct blob_attr *data; + void (*handler)(struct blob_attr *msg, struct blob_attr *data); +}; + +static LIST_HEAD(cmd_queue); +static struct uloop_process queue_proc; +static struct uloop_timeout last_event; +static struct blob_buf b; +static char *rule_file; +static struct blob_buf script; + +static char *hotplug_msg_find_var(struct blob_attr *msg, const char *name) +{ + struct blob_attr *cur; + int rem; + + blobmsg_for_each_attr(cur, msg, rem) { + if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) + continue; + + if (strcmp(blobmsg_name(cur), name) != 0) + continue; + + return blobmsg_data(cur); + } + + return NULL; +} + +static void handle_makedev(struct blob_attr *msg, struct blob_attr *data) { + static struct blobmsg_policy mkdev_policy[2] = { + { .type = BLOBMSG_TYPE_STRING }, + { .type = BLOBMSG_TYPE_STRING }, + }; + struct blob_attr *tb[2]; + char *minor = hotplug_msg_find_var(msg, "MINOR"); + char *major = hotplug_msg_find_var(msg, "MAJOR"); + char *subsystem = hotplug_msg_find_var(msg, "SUBSYSTEM"); + + blobmsg_parse_array(mkdev_policy, 2, tb, blobmsg_data(data), blobmsg_data_len(data)); + if (tb[0] && tb[1] && minor && major && subsystem) { + mode_t m = S_IFCHR; + if (!strcmp(subsystem, "block")) + m = S_IFBLK; + mknod(blobmsg_get_string(tb[0]), + m | strtoul(blobmsg_data(tb[1]), NULL, 8), + makedev(atoi(major), atoi(minor))); + } } -void rule_error(struct blob_attr *cur, const char *msg) +static void handle_rm(struct blob_attr *msg, struct blob_attr *data) { + static struct blobmsg_policy rm_policy = { + .type = BLOBMSG_TYPE_STRING, + }; + struct blob_attr *tb; + + blobmsg_parse_array(&rm_policy, 1, &tb, blobmsg_data(data), blobmsg_data_len(data)); + if (tb) + unlink(blobmsg_data(tb)); +} + +static void handle_exec(struct blob_attr *msg, struct blob_attr *data) +{ + char *argv[8]; + struct blob_attr *cur; + int rem; + int i = 0; + + blobmsg_for_each_attr(cur, msg, rem) + setenv(blobmsg_name(cur), blobmsg_data(cur), 1); + + blobmsg_for_each_attr(cur, data, rem) { + argv[i] = blobmsg_data(cur); + i++; + if (i == 7) + break; + } + + if (debug < 2) { + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + } + + if (i > 0) { + argv[i] = NULL; + execvp(argv[0], &argv[0]); + } + exit(-1); +} + +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; + char *path, loadpath[256], syspath[256]; + int fw, load, sys, len; + + DEBUG(1, "Firmware request for %s/%s\n", dir, file); + + if (!file || !dir || !dev) { + ERROR("Request for unknown firmware %s/%s\n", dir, file); + exit(-1); + } + + path = malloc(strlen(dir) + strlen(file) + 2); + if (!path) { + ERROR("Failed to allocate memory\n"); + exit(-1); + } + sprintf(path, "%s/%s", dir, file); + + if (stat(path, &s)) { + ERROR("Could not find firmware %s\n", path); + exit(-1); + } + + 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) { + ERROR("Failed to open %s\n", path); + exit(-1); + } + if (read(fw, fw_data, s.st_size) != s.st_size) { + ERROR("Failed to read firmware data\n"); + exit(-1); + } + close(fw); + + 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); + close(load); + + snprintf(syspath, sizeof(syspath), "/sys/%s/data", dev); + sys = open(syspath, O_WRONLY); + if (!sys) { + ERROR("Failed to open %s\n", syspath); + exit(-1); + } + + len = s.st_size; + while (len > 4096) { + write(fw, fw_data, 4096); + len -= 4096; + } + if (len) + write(fw, fw_data, len); + close(fw); + + load = open(loadpath, O_WRONLY); + write(load, "0", 1); + close(load); + + DEBUG(1, "Done loading %s\n", path); + + exit(-1); +} + +static struct cmd_handler { + char *name; + int atomic; + void (*handler)(struct blob_attr *msg, struct blob_attr *data); +} handlers[] = { + { + .name = "makedev", + .atomic = 1, + .handler = handle_makedev, + }, { + .name = "rm", + .atomic = 1, + .handler = handle_rm, + }, { + .name = "exec", + .handler = handle_exec, + }, { + .name = "load-firmware", + .handler = handle_firmware, + }, +}; + +static void queue_next(void) +{ + struct cmd_queue *c; + + if (queue_proc.pending || list_empty(&cmd_queue)) + return; + + c = list_first_entry(&cmd_queue, struct cmd_queue, list); + + queue_proc.pid = fork(); + if (!queue_proc.pid) { + c->handler(c->msg, c->data); + exit(0); + } + + list_del(&c->list); + free(c); + + if (queue_proc.pid <= 0) { + queue_next(); + return; + } + + uloop_process_add(&queue_proc); + + DEBUG(2, "Launched hotplug exec instance, pid=%d\n", (int) queue_proc.pid); } +static void queue_proc_cb(struct uloop_process *c, int ret) +{ + DEBUG(2, "Finished hotplug exec instance, pid=%d\n", (int) c->pid); + + queue_next(); +} + +static void queue_add(struct cmd_handler *h, struct blob_attr *msg, struct blob_attr *data) +{ + struct cmd_queue *c = NULL; + struct blob_attr *_msg, *_data; + + c = calloc_a(sizeof(struct cmd_queue), + &_msg, blob_pad_len(msg), + &_data, blob_pad_len(data), + NULL); + + c->msg = _msg; + c->data = _data; + + if (!c) + return; + + memcpy(c->msg, msg, blob_pad_len(msg)); + memcpy(c->data, data, blob_pad_len(data)); + c->handler = h->handler; + list_add_tail(&c->list, &cmd_queue); + queue_next(); +} + +static const char* rule_handle_var(struct json_script_ctx *ctx, const char *name, struct blob_attr *vars) +{ + const char *str, *sep; + + if (!strcmp(name, "DEVICENAME") || !strcmp(name, "DEVNAME")) { + str = json_script_find_var(ctx, vars, "DEVPATH"); + if (!str) + return NULL; + + sep = strrchr(str, '/'); + if (sep) + return sep + 1; + + return str; + } + + return NULL; +} + +static struct json_script_file * +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)) + return NULL; + + blob_buf_init(&script, 0); + blobmsg_add_json_element(&script, "", obj); + + return json_script_file_from_blobmsg(name, blob_data(script.head), blob_len(script.head)); +} + +static void rule_handle_command(struct json_script_ctx *ctx, const char *name, + struct blob_attr *data, struct blob_attr *vars) +{ + struct blob_attr *cur; + int rem, i; + + if (debug > 1) { + DEBUG(2, "Command: %s", name); + blobmsg_for_each_attr(cur, data, rem) + DEBUG(2, " %s", (char *) blobmsg_data(cur)); + DEBUG(2, "\n"); + + DEBUG(2, "Message:"); + blobmsg_for_each_attr(cur, vars, rem) + DEBUG(2, " %s=%s", blobmsg_name(cur), (char *) blobmsg_data(cur)); + DEBUG(2, "\n"); + } + + for (i = 0; i < ARRAY_SIZE(handlers); i++) + if (!strcmp(handlers[i].name, name)) { + if (handlers[i].atomic) + handlers[i].handler(vars, data); + else + queue_add(&handlers[i], vars, data); + break; + } + + if (last_event.cb) + uloop_timeout_set(&last_event, HOTPLUG_WAIT); +} + +static void rule_handle_error(struct json_script_ctx *ctx, const char *msg, + struct blob_attr *context) +{ + char *s; + + s = blobmsg_format_json(context, false); + ERROR("ERROR: %s in block: %s\n", msg, s); + free(s); +} + +static struct json_script_ctx jctx = { + .handle_var = rule_handle_var, + .handle_error = rule_handle_error, + .handle_command = rule_handle_command, + .handle_file = rule_handle_file, +}; + +static void hotplug_handler(struct uloop_fd *u, unsigned int ev) +{ + int i = 0; + static char buf[4096]; + int len = recv(u->fd, buf, sizeof(buf), MSG_DONTWAIT); + void *index; + if (len < 1) + return; + + blob_buf_init(&b, 0); + index = blobmsg_open_table(&b, NULL); + while (i < len) { + int l = strlen(buf + i) + 1; + char *e = strstr(&buf[i], "="); + + if (e) { + *e = '\0'; + blobmsg_add_string(&b, &buf[i], &e[1]); + } + i += l; + } + blobmsg_close_table(&b, index); + DEBUG(3, "%s\n", blobmsg_format_json(b.head, true)); + json_script_run(&jctx, rule_file, blob_data(b.head)); +} + +static struct uloop_fd hotplug_fd = { + .cb = hotplug_handler, +}; + +void hotplug_last_event(uloop_timeout_handler handler) +{ + last_event.cb = handler; + if (handler) + uloop_timeout_set(&last_event, HOTPLUG_WAIT); + else + uloop_timeout_cancel(&last_event); +} + +void hotplug(char *rules) +{ + struct sockaddr_nl nls; + + rule_file = strdup(rules); + memset(&nls,0,sizeof(struct sockaddr_nl)); + nls.nl_family = AF_NETLINK; + nls.nl_pid = getpid(); + nls.nl_groups = -1; + + if ((hotplug_fd.fd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)) == -1) { + ERROR("Failed to open hotplug socket\n"); + perror("socket"); + exit(1); + } + if (bind(hotplug_fd.fd, (void *)&nls, sizeof(struct sockaddr_nl))) { + ERROR("Failed to bind hotplug socket\n"); + perror("socket"); + exit(1); + } + + json_script_init(&jctx); + queue_proc.cb = queue_proc_cb; + uloop_fd_add(&hotplug_fd, ULOOP_READ); +} diff --git a/hotplug.h b/hotplug.h index 2fa9cfe..7018d23 100644 --- a/hotplug.h +++ b/hotplug.h @@ -1,25 +1,23 @@ +/* + * Copyright (C) 2013 Felix Fietkau + * Copyright (C) 2013 John Crispin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + #ifndef __PROCD_HOTPLUG_H #define __PROCD_HOTPLUG_H -#include -#include -#include -#include - -struct rule_file { - struct avl_node avl; - struct blob_attr data[]; -}; - -struct rule_handler { - const char *name; - int (*handler)(struct blob_attr *cur, struct blob_attr *msg); -}; +#include -struct rule_file *rule_file_get(const char *filename); -void rule_file_free_all(void); -void rule_error(struct blob_attr *cur, const char *msg); -void rule_process_msg(struct rule_file *f, struct blob_attr *msg); -void rule_handle_command(const char *name, struct blob_attr *data); +void hotplug(char *rules); +void hotplug_last_event(uloop_timeout_handler handler); #endif