From: Felix Fietkau Date: Fri, 1 Jun 2012 21:14:57 +0000 (+0200) Subject: implement more parts of the service core api X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fprocd.git;a=commitdiff_plain;h=e0d721487a618490a7db06f76904868a71684071 implement more parts of the service core api --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 16e7cb5..4666b39 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 api.c) +SET(SOURCES main.c ubus.c service.c) SET(LIBS ubox ubus) diff --git a/api.c b/api.c deleted file mode 100644 index 623f123..0000000 --- a/api.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "procd.h" - -static int -service_handle_list(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - return 0; -} - -static struct ubus_method main_object_methods[] = { - { .name = "list", .handler = service_handle_list }, -}; - -static struct ubus_object_type main_object_type = - UBUS_OBJECT_TYPE("service", main_object_methods); - -static struct ubus_object main_object = { - .name = "service", - .type = &main_object_type, - .methods = main_object_methods, - .n_methods = ARRAY_SIZE(main_object_methods), -}; - - -void procd_register_objects(struct ubus_context *ctx) -{ - ubus_add_object(ctx, &main_object); -} diff --git a/procd.h b/procd.h index 8b33143..4009afc 100644 --- a/procd.h +++ b/procd.h @@ -5,6 +5,8 @@ #include #include +#define __init __attribute__((constructor)) + #define DPRINTF(fmt, ...) do { \ if (debug) \ fprintf(stderr, "DEBUG %s(%d): " fmt, __func__, __LINE__, ## __VA_ARGS__); \ @@ -13,6 +15,6 @@ extern int debug; extern char *ubus_socket; void procd_connect_ubus(void); -void procd_register_objects(struct ubus_context *ctx); +void procd_init_service(struct ubus_context *ctx); #endif diff --git a/service.c b/service.c new file mode 100644 index 0000000..f50daa7 --- /dev/null +++ b/service.c @@ -0,0 +1,231 @@ +#include +#include "procd.h" +#include "service.h" + +struct avl_tree services; +static struct blob_buf b; + +static void +service_instance_update(struct vlist_tree *tree, struct vlist_node *node_new, + struct vlist_node *node_old) +{ + struct service_instance *in_o = NULL, *in_n = NULL; + + if (node_old) + in_o = container_of(node_old, struct service_instance, node); + + if (node_new) + in_n = container_of(node_new, struct service_instance, node); + + do { + if (!in_o || !in_n) + break; + + /* full match, nothing to do */ + return; + } while (0); + + if (in_o) { + /* kill old process */ + free(in_o); + } + + if (in_n) { + /* start new process */ + } +} + +static void +service_instance_add(struct service *s, struct blob_attr *attr) +{ + struct service_instance *in; + const char *name = blobmsg_name(attr); + + if (blobmsg_type(attr) != BLOBMSG_TYPE_TABLE) + return; + + in = calloc(1, sizeof(*in)); + if (!in) + return; + + in->config = attr; + vlist_add(&s->instances, &in->node, (void *) name); +} + +static struct service * +service_alloc(const char *name) +{ + struct service *s; + + s = calloc(1, sizeof(*s)); + vlist_init(&s->instances, avl_strcmp, service_instance_update); + + return s; +} + +enum { + SERVICE_ATTR_NAME, + SERVICE_ATTR_SCRIPT, + SERVICE_ATTR_INSTANCES, + __SERVICE_ATTR_MAX +}; + +static const struct blobmsg_policy service_attrs[__SERVICE_ATTR_MAX] = { + [SERVICE_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING }, + [SERVICE_ATTR_SCRIPT] = { "script", BLOBMSG_TYPE_STRING }, + [SERVICE_ATTR_INSTANCES] = { "instances", BLOBMSG_TYPE_TABLE }, +}; + + +static int +service_update(struct service *s, struct blob_attr *config, struct blob_attr **tb) +{ + struct blob_attr *old_config = s->config; + struct blob_attr *cur; + int rem; + + /* only the pointer changes, the content stays the same, + * no avl update necessary */ + s->name = s->avl.key = blobmsg_data(tb[SERVICE_ATTR_NAME]); + s->config = config; + + if (tb[SERVICE_ATTR_INSTANCES]) { + vlist_update(&s->instances); + blobmsg_for_each_attr(cur, tb[SERVICE_ATTR_INSTANCES], rem) { + service_instance_add(s, cur); + } + vlist_flush(&s->instances); + } + + free(old_config); + + return 0; +} + +static void +service_delete(struct service *s) +{ + vlist_flush_all(&s->instances); + avl_delete(&services, &s->avl); + free(s->config); + free(s); +} + +static int +service_handle_set(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__SERVICE_ATTR_MAX], *cur; + struct service *s = NULL; + const char *name; + int ret = UBUS_STATUS_INVALID_ARGUMENT; + + msg = blob_memdup(msg); + if (!msg) + return UBUS_STATUS_UNKNOWN_ERROR; + + blobmsg_parse(service_attrs, __SERVICE_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); + cur = tb[SERVICE_ATTR_NAME]; + if (!cur) + goto free; + + name = blobmsg_data(cur); + + s = avl_find_element(&services, name, s, avl); + if (s) + return service_update(s, msg, tb); + + s = service_alloc(name); + if (!s) + return UBUS_STATUS_UNKNOWN_ERROR; + + ret = service_update(s, msg, tb); + if (ret) + goto free; + + avl_insert(&services, &s->avl); + + return 0; + +free: + free(msg); + return ret; +} + +static int +service_handle_list(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct service *s; + + blob_buf_init(&b, 0); + avl_for_each_element(&services, s, avl) { + void *c; + + c = blobmsg_open_table(&b, s->name); + blobmsg_close_table(&b, c); + } + + ubus_send_reply(ctx, req, b.head); + + return 0; +} + +enum { + SERVICE_DEL_NAME, + __SERVICE_DEL_MAX, +}; + +static const struct blobmsg_policy service_del_attrs[__SERVICE_DEL_MAX] = { + [SERVICE_DEL_NAME] = { "name", BLOBMSG_TYPE_STRING }, +}; + + +static int +service_handle_delete(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__SERVICE_DEL_MAX], *cur; + struct service *s, *tmp; + + blobmsg_parse(service_del_attrs, __SERVICE_DEL_MAX, tb, blob_data(msg), blob_len(msg)); + + cur = tb[SERVICE_ATTR_NAME]; + if (!cur) { + avl_for_each_element_safe(&services, s, avl, tmp) + service_delete(s); + return 0; + } + + s = avl_find_element(&services, blobmsg_data(cur), s, avl); + if (!s) + return UBUS_STATUS_NOT_FOUND; + + service_delete(s); + return 0; +} + +static struct ubus_method main_object_methods[] = { + { .name = "list", .handler = service_handle_list }, + { .name = "set", .handler = service_handle_set }, + { .name = "delete", .handler = service_handle_delete }, +}; + +static struct ubus_object_type main_object_type = + UBUS_OBJECT_TYPE("service", main_object_methods); + +static struct ubus_object main_object = { + .name = "service", + .type = &main_object_type, + .methods = main_object_methods, + .n_methods = ARRAY_SIZE(main_object_methods), +}; + +void procd_init_service(struct ubus_context *ctx) +{ + avl_init(&services, avl_strcmp, false, NULL); + ubus_add_object(ctx, &main_object); +} diff --git a/service.h b/service.h index 5b86b3a..c2afdae 100644 --- a/service.h +++ b/service.h @@ -1,10 +1,13 @@ #include #include +extern struct avl_tree services; + struct service { struct avl_node avl; const char *name; + struct blob_attr *config; struct vlist_tree instances; }; @@ -16,4 +19,3 @@ struct service_instance { struct uloop_process proc; }; - diff --git a/ubus.c b/ubus.c index 1ba7965..0bd9e49 100644 --- a/ubus.c +++ b/ubus.c @@ -59,7 +59,7 @@ static void procd_ubus_try_connect(void) ctx->connection_lost = procd_ubus_connection_lost; ubus_connected = true; - procd_register_objects(ctx); + procd_init_service(ctx); } static void procd_ubus_connection_lost(struct ubus_context *old_ctx)