diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | service.c | 64 | ||||
-rw-r--r-- | service.h | 25 | ||||
-rw-r--r-- | service_validate.c | 161 | ||||
-rw-r--r-- | state.c | 2 | ||||
-rw-r--r-- | validate.c | 7 |
6 files changed, 259 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5162610..a521ea7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ IF(APPLE) LINK_DIRECTORIES(/opt/local/lib) ENDIF() -SET(SOURCES main.c ubus.c service.c instance.c utils.c md5.c hotplug.c state.c mkdev.c early.c inittab.c preinit.c coldplug.c syslog.c log.c watchdog.c signal.c system.c debug.c rcS.c trigger.c measure.c) +SET(SOURCES main.c ubus.c service.c service_validate.c instance.c utils.c md5.c hotplug.c state.c mkdev.c early.c inittab.c preinit.c coldplug.c syslog.c log.c watchdog.c signal.c system.c debug.c rcS.c trigger.c measure.c) find_library(json NAMES json-c json) SET(LIBS ubox ubus ${json} blobmsg_json json_script) @@ -77,6 +77,7 @@ service_alloc(const char *name) s->instances.keep_old = true; s->name = new_name; s->avl.key = s->name; + INIT_LIST_HEAD(&s->validators); return s; } @@ -86,6 +87,7 @@ enum { SERVICE_SET_SCRIPT, SERVICE_SET_INSTANCES, SERVICE_SET_TRIGGER, + SERVICE_SET_VALIDATE, __SERVICE_SET_MAX }; @@ -94,6 +96,7 @@ static const struct blobmsg_policy service_set_attrs[__SERVICE_SET_MAX] = { [SERVICE_SET_SCRIPT] = { "script", BLOBMSG_TYPE_STRING }, [SERVICE_SET_INSTANCES] = { "instances", BLOBMSG_TYPE_TABLE }, [SERVICE_SET_TRIGGER] = { "triggers", BLOBMSG_TYPE_ARRAY }, + [SERVICE_SET_VALIDATE] = { "validate", BLOBMSG_TYPE_ARRAY }, }; static int @@ -108,6 +111,8 @@ service_update(struct service *s, struct blob_attr *config, struct blob_attr **t s->trigger = NULL; } + service_validate_del(s); + if (tb[SERVICE_SET_TRIGGER] && blobmsg_data_len(tb[SERVICE_SET_TRIGGER])) { s->trigger = malloc(blob_pad_len(tb[SERVICE_SET_TRIGGER])); if (!s->trigger) @@ -116,6 +121,11 @@ service_update(struct service *s, struct blob_attr *config, struct blob_attr **t trigger_add(s->trigger, s); } + if (tb[SERVICE_SET_VALIDATE] && blobmsg_data_len(tb[SERVICE_SET_VALIDATE])) { + blobmsg_for_each_attr(cur, tb[SERVICE_SET_VALIDATE], rem) + service_validate_add(s, cur); + } + if (tb[SERVICE_SET_INSTANCES]) { if (!add) vlist_update(&s->instances); @@ -140,6 +150,7 @@ service_delete(struct service *s) s->trigger = NULL; free(s->trigger); free(s); + service_validate_del(s); } enum { @@ -182,6 +193,19 @@ static const struct blobmsg_policy event_policy[__EVENT_MAX] = { [EVENT_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, }; +enum { + VALIDATE_PACKAGE, + VALIDATE_TYPE, + VALIDATE_SERVICE, + __VALIDATE_MAX +}; + +static const struct blobmsg_policy validate_policy[__VALIDATE_MAX] = { + [VALIDATE_PACKAGE] = { .name = "package", .type = BLOBMSG_TYPE_STRING }, + [VALIDATE_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING }, + [VALIDATE_SERVICE] = { .name = "service", .type = BLOBMSG_TYPE_STRING }, +}; + static int service_handle_set(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, @@ -243,6 +267,8 @@ service_dump(struct service *s, int verbose) blobmsg_close_table(&b, i); if (verbose && s->trigger) blobmsg_add_blob(&b, s->trigger); + if (verbose && !list_empty(&s->validators)) + service_validate_dump(&b, s); blobmsg_close_table(&b, c); } @@ -350,6 +376,34 @@ service_handle_event(struct ubus_context *ctx, struct ubus_object *obj, return 0; } +static int +service_handle_validate(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__VALIDATE_MAX]; + char *p = NULL, *t = NULL; + + if (!msg) + return UBUS_STATUS_INVALID_ARGUMENT; + + blobmsg_parse(validate_policy, __VALIDATE_MAX, tb, blob_data(msg), blob_len(msg)); + if (tb[VALIDATE_SERVICE]) { + return 0; + } + if (tb[VALIDATE_PACKAGE]) + p = blobmsg_get_string(tb[VALIDATE_PACKAGE]); + + if (tb[VALIDATE_TYPE]) + t = blobmsg_get_string(tb[VALIDATE_TYPE]); + + blob_buf_init(&b, 0); + service_validate_dump_all(&b, p, t); + ubus_send_reply(ctx, req, b.head); + + return 0; +} + static struct ubus_method main_object_methods[] = { UBUS_METHOD("set", service_handle_set, service_set_attrs), UBUS_METHOD("add", service_handle_set, service_set_attrs), @@ -358,6 +412,7 @@ static struct ubus_method main_object_methods[] = { UBUS_METHOD("update_start", service_handle_update, service_attrs), UBUS_METHOD("update_complete", service_handle_update, service_attrs), UBUS_METHOD("event", service_handle_event, event_policy), + UBUS_METHOD("validate", service_handle_validate, validate_policy), }; static struct ubus_object_type main_object_type = @@ -372,6 +427,13 @@ static struct ubus_object main_object = { void ubus_init_service(struct ubus_context *ctx) { - avl_init(&services, avl_strcmp, false, NULL); ubus_add_object(ctx, &main_object); } + +void +service_init(void) +{ + avl_init(&services, avl_strcmp, false, NULL); + service_validate_init(); +} + @@ -17,15 +17,40 @@ #include <libubox/avl.h> #include <libubox/vlist.h> +#include <libubox/list.h> extern struct avl_tree services; +struct vrule { + struct avl_node avl; + char *option; + char *rule; +}; + +struct validate { + struct avl_node avl; + struct list_head list; + + char *package; + char *type; + + struct avl_tree rules; +}; + struct service { struct avl_node avl; const char *name; struct blob_attr *trigger; struct vlist_tree instances; + struct list_head validators; }; +void service_validate_add(struct service *s, struct blob_attr *attr); +void service_validate_dump(struct blob_buf *b, struct service *s); +void service_validate_dump_all(struct blob_buf *b, char *p, char *s); +void service_validate_del(struct service *s); +void service_validate_init(void); +void service_init(void); + #endif diff --git a/service_validate.c b/service_validate.c new file mode 100644 index 0000000..3522cde --- /dev/null +++ b/service_validate.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * + * 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 <libubox/blobmsg_json.h> +#include <libubox/avl-cmp.h> + +#include "procd.h" +#include "service.h" + +enum { + SERVICE_VAL_PACKAGE, + SERVICE_VAL_TYPE, + SERVICE_VAL_DATA, + __SERVICE_VAL_MAX +}; + +static const struct blobmsg_policy service_validate_attrs[__SERVICE_VAL_MAX] = { + [SERVICE_VAL_PACKAGE] = { "package", BLOBMSG_TYPE_STRING }, + [SERVICE_VAL_TYPE] = { "type", BLOBMSG_TYPE_STRING }, + [SERVICE_VAL_DATA] = { "data", BLOBMSG_TYPE_TABLE }, +}; + +static struct avl_tree validators; + +void +service_validate_dump_all(struct blob_buf *b, char *p, char *s) +{ + struct json_object *r = json_object_new_object(); + struct validate *v; + + if (!r) + return; + + avl_for_each_element(&validators, v, avl) { + struct json_object *o, *t; + struct vrule *vr; + + if (p && strcmp(p, v->package)) + continue; + + if (s && strcmp(s, v->type)) + continue; + + o = json_object_object_get(r, v->package); + if (!o) { + o = json_object_new_object(); + json_object_object_add(r, v->package, o); + } + t = json_object_object_get(o, v->type); + if (!t) { + t = json_object_new_object(); + json_object_object_add(o, v->type, t); + } + avl_for_each_element(&v->rules, vr, avl) + json_object_object_add(t, vr->option, json_object_new_string(vr->rule)); + } + blobmsg_add_object(b, r); +} + +void +service_validate_dump(struct blob_buf *b, struct service *s) +{ + struct validate *v; + void *i = blobmsg_open_array(b, "validate"); + + list_for_each_entry(v, &s->validators, list) { + struct vrule *vr; + void *k, *j = blobmsg_open_table(b, "validate"); + + blobmsg_add_string(b, "package", v->package); + blobmsg_add_string(b, "type", v->type); + k = blobmsg_open_table(b, "rules"); + avl_for_each_element(&v->rules, vr, avl) + blobmsg_add_string(b, vr->option, vr->rule); + blobmsg_close_table(b, k); + blobmsg_close_table(b, j); + } + blobmsg_close_array(b, i); +} + +void +service_validate_del(struct service *s) +{ + struct validate *v, *n; + + if (list_empty(&s->validators)) + return; + + list_for_each_entry_safe(v, n, &s->validators, list) { + struct vrule *vr, *a; + + avl_for_each_element_safe(&v->rules, vr, avl, a) { + avl_delete(&v->rules, &vr->avl); + free(vr); + } + avl_delete(&validators, &v->avl); + list_del(&v->list); + free(v); + } +} + +void +service_validate_add(struct service *s, struct blob_attr *msg) +{ + struct blob_attr *tb[__SERVICE_VAL_MAX]; + struct validate *v; + char *type, *package; + struct blob_attr *cur; + int rem; + + blobmsg_parse(service_validate_attrs, __SERVICE_VAL_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); + if (!tb[SERVICE_VAL_PACKAGE] || !tb[SERVICE_VAL_TYPE] || !tb[SERVICE_VAL_DATA]) + return; + + v = calloc_a(sizeof(*v), &package, blobmsg_data_len(tb[SERVICE_VAL_PACKAGE]) + 1, + &type, blobmsg_data_len(tb[SERVICE_VAL_TYPE]) + 1); + if (!v) + return; + + v->type = type; + v->avl.key = v->package = package; + strcpy(v->package, blobmsg_get_string(tb[SERVICE_VAL_PACKAGE])); + strcpy(v->type, blobmsg_get_string(tb[SERVICE_VAL_TYPE])); + + list_add(&v->list, &s->validators); + if (avl_insert(&validators, &v->avl)) { + free(v); + return; + } + avl_init(&v->rules, avl_strcmp, false, NULL); + + blobmsg_for_each_attr(cur, tb[SERVICE_VAL_DATA], rem) { + char *option; + char *rule; + struct vrule *vr = calloc_a(sizeof(*vr), &option, strlen(blobmsg_name(cur)) + 1, + &rule, strlen(blobmsg_get_string(cur)) + 1); + + vr->avl.key = vr->option = option; + vr->rule = rule; + strcpy(vr->option, blobmsg_name(cur)); + strcpy(vr->rule, blobmsg_get_string(cur)); + if (avl_insert(&v->rules, &vr->avl)) + free(vr); + } +} + +void +service_validate_init(void) +{ + avl_init(&validators, avl_strcmp, true, NULL); +} @@ -20,6 +20,7 @@ #include "syslog.h" #include "hotplug.h" #include "watchdog.h" +#include "service.h" enum { STATE_NONE = 0, @@ -51,6 +52,7 @@ static void state_enter(void) LOG("- init -\n"); log_init(); procd_connect_ubus(); + service_init(); procd_inittab(); procd_inittab_run("respawn"); procd_inittab_run("askconsole"); @@ -314,6 +314,12 @@ dt_type_bool(struct dt_state *s, int nargs) } static bool +dt_type_string(struct dt_state *s, int nargs) +{ + return true; +} + +static bool dt_type_ip4addr(struct dt_state *s, int nargs) { struct in6_addr a; @@ -682,6 +688,7 @@ static struct dt_fun dt_types[] = { { "float", dt_type_float }, { "ufloat", dt_type_ufloat }, { "bool", dt_type_bool }, + { "string", dt_type_string }, { "ip4addr", dt_type_ip4addr }, { "ip6addr", dt_type_ip6addr }, { "ipaddr", dt_type_ipaddr }, |