summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--service.c64
-rw-r--r--service.h25
-rw-r--r--service_validate.c161
-rw-r--r--state.c2
-rw-r--r--validate.c7
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)
diff --git a/service.c b/service.c
index 29acc57..c5f5bf3 100644
--- a/service.c
+++ b/service.c
@@ -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();
+}
+
diff --git a/service.h b/service.h
index 9d3c308..6448e5e 100644
--- a/service.h
+++ b/service.h
@@ -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);
+}
diff --git a/state.c b/state.c
index 90e883c..f83032c 100644
--- a/state.c
+++ b/state.c
@@ -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");
diff --git a/validate.c b/validate.c
index 85b69af..f94a071 100644
--- a/validate.c
+++ b/validate.c
@@ -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 },