uci: reset uci_ptr flags when merging options during section add
[oweals/rpcd.git] / plugin.c
index afc138315b7219030b7e7fb83065d57e6596fecc..b0315dc15836f6f2b4972ff681adce09eb6b7bec 100644 (file)
--- a/plugin.c
+++ b/plugin.c
@@ -1,7 +1,7 @@
 /*
  * rpcd - UBUS RPC server
  *
- *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
+ *   Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -16,7 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "plugin.h"
+#include <rpcd/plugin.h>
 
 static struct blob_buf buf;
 
@@ -51,6 +51,74 @@ rpc_plugin_lookup_plugin(struct ubus_context *ctx, struct ubus_object *obj,
        return c.found;
 }
 
+static void
+rpc_plugin_json_array_to_blob(struct array_list *a, struct blob_buf *blob);
+
+static void
+rpc_plugin_json_object_to_blob(json_object *o, struct blob_buf *blob);
+
+static void
+rpc_plugin_json_element_to_blob(const char *name, json_object *val,
+                                struct blob_buf *blob)
+{
+       void *c;
+       int64_t n;
+
+       switch (json_object_get_type(val)) {
+       case json_type_object:
+               c = blobmsg_open_table(blob, name);
+               rpc_plugin_json_object_to_blob(val, blob);
+               blobmsg_close_table(blob, c);
+               break;
+
+       case json_type_array:
+               c = blobmsg_open_array(blob, name);
+               rpc_plugin_json_array_to_blob(json_object_get_array(val), blob);
+               blobmsg_close_array(blob, c);
+               break;
+
+       case json_type_string:
+               blobmsg_add_string(blob, name, json_object_get_string(val));
+               break;
+
+       case json_type_boolean:
+               blobmsg_add_u8(blob, name, json_object_get_boolean(val));
+               break;
+
+       case json_type_int:
+               n = json_object_get_int64(val);
+               if (n >= INT32_MIN && n <= INT32_MAX)
+                       blobmsg_add_u32(blob, name, n);
+               else
+                       blobmsg_add_u64(blob, name, n);
+               break;
+
+       case json_type_double:
+               blobmsg_add_double(blob, name, json_object_get_double(val));
+               break;
+
+       case json_type_null:
+               blobmsg_add_field(blob, BLOBMSG_TYPE_UNSPEC, name, NULL, 0);
+               break;
+       }
+}
+
+static void
+rpc_plugin_json_array_to_blob(struct array_list *a, struct blob_buf *blob)
+{
+       int i, len;
+
+       for (i = 0, len = array_list_length(a); i < len; i++)
+               rpc_plugin_json_element_to_blob(NULL, array_list_get_idx(a, i), blob);
+}
+
+static void
+rpc_plugin_json_object_to_blob(json_object *o, struct blob_buf *blob)
+{
+       json_object_object_foreach(o, key, val)
+               rpc_plugin_json_element_to_blob(key, val, blob);
+}
+
 struct call_context {
        char path[PATH_MAX];
        const char *argv[4];
@@ -108,10 +176,9 @@ rpc_plugin_call_finish_cb(struct blob_buf *blob, int stat, void *priv)
        {
                if (c->obj)
                {
-                       if (json_object_get_type(c->obj) == json_type_object ||
-                           json_object_get_type(c->obj) == json_type_array)
+                       if (json_object_get_type(c->obj) == json_type_object)
                        {
-                               blobmsg_add_json_element(blob, NULL, c->obj);
+                               rpc_plugin_json_object_to_blob(c->obj, blob);
                                rv = UBUS_STATUS_OK;
                        }
 
@@ -126,7 +193,6 @@ rpc_plugin_call_finish_cb(struct blob_buf *blob, int stat, void *priv)
        json_tokener_free(c->tok);
 
        free(c->input);
-       free(c->method);
 
        return rv;
 }
@@ -138,18 +204,18 @@ rpc_plugin_call(struct ubus_context *ctx, struct ubus_object *obj,
 {
        int rv = UBUS_STATUS_UNKNOWN_ERROR;
        struct call_context *c;
-       char *plugin;
+       char *plugin, *mptr;
 
-       c = calloc(1, sizeof(*c));
+       c = calloc_a(sizeof(*c), &mptr, strlen(method) + 1);
 
        if (!c)
                goto fail;
 
-       c->method = strdup(method);
+       c->method = strcpy(mptr, method);
        c->input = blobmsg_format_json(msg, true);
        c->tok = json_tokener_new();
 
-       if (!c->method || !c->input || !c->tok)
+       if (!c->input || !c->tok)
                goto fail;
 
        plugin = c->path + sprintf(c->path, "%s/", RPC_PLUGIN_DIRECTORY);
@@ -164,16 +230,16 @@ rpc_plugin_call(struct ubus_context *ctx, struct ubus_object *obj,
        c->argv[1] = "call";
        c->argv[2] = c->method;
 
-       return rpc_exec(c->argv, rpc_plugin_call_stdin_cb,
-                       rpc_plugin_call_stdout_cb, rpc_plugin_call_stderr_cb,
-                       rpc_plugin_call_finish_cb, c, ctx, req);
+       rv = rpc_exec(c->argv, rpc_plugin_call_stdin_cb,
+                     rpc_plugin_call_stdout_cb, rpc_plugin_call_stderr_cb,
+                     rpc_plugin_call_finish_cb, c, ctx, req);
+
+       if (rv == UBUS_STATUS_OK)
+               return rv;
 
 fail:
        if (c)
        {
-               if (c->method)
-                       free(c->method);
-
                if (c->input)
                        free(c->input);
 
@@ -194,7 +260,7 @@ rpc_plugin_parse_signature(struct blob_attr *sig, struct ubus_method *method)
        struct blob_attr *attr;
        struct blobmsg_policy *policy = NULL;
 
-       if (!sig || blob_id(sig) != BLOBMSG_TYPE_TABLE)
+       if (!sig || blobmsg_type(sig) != BLOBMSG_TYPE_TABLE)
                return false;
 
        n_attr = 0;
@@ -213,7 +279,7 @@ rpc_plugin_parse_signature(struct blob_attr *sig, struct ubus_method *method)
 
                blobmsg_for_each_attr(attr, sig, rem)
                {
-                       type = blob_id(attr);
+                       type = blobmsg_type(attr);
 
                        if (type == BLOBMSG_TYPE_INT32)
                        {
@@ -324,10 +390,17 @@ rpc_plugin_parse_exec(const char *name, int fd)
 
        obj_type = calloc(1, sizeof(*obj_type));
 
-       if (!obj_type)
+       if (!obj_type) {
+               free(obj);
                return NULL;
+       }
+
+       if (asprintf((char **)&obj_type->name, "luci-rpc-plugin-%s", name) < 0) {
+               free(obj);
+               free(obj_type);
+               return NULL;
+       }
 
-       asprintf((char **)&obj_type->name, "luci-rpc-plugin-%s", name);
        obj_type->methods = methods;
        obj_type->n_methods = n_method;
 
@@ -405,6 +478,7 @@ static const struct rpc_daemon_ops ops = {
        .session_create_cb  = rpc_session_create_cb,
        .session_destroy_cb = rpc_session_destroy_cb,
        .exec               = rpc_exec,
+       .exec_timeout       = &rpc_exec_timeout,
 };
 
 static int
@@ -413,7 +487,7 @@ rpc_plugin_register_library(struct ubus_context *ctx, const char *path)
        struct rpc_plugin *p;
        void *dlh;
 
-       dlh = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
+       dlh = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
 
        if (!dlh)
                return UBUS_STATUS_UNKNOWN_ERROR;