2 * luci-rpcd - LuCI UBUS RPC server
4 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 static struct blob_buf buf;
24 struct rpc_plugin_lookup_context {
31 rpc_plugin_lookup_plugin_cb(struct ubus_context *ctx,
32 struct ubus_object_data *obj, void *priv)
34 struct rpc_plugin_lookup_context *c = priv;
39 sprintf(c->name, "%s", obj->path);
44 rpc_plugin_lookup_plugin(struct ubus_context *ctx, struct ubus_object *obj,
47 struct rpc_plugin_lookup_context c = { .id = obj->id, .name = strptr };
49 if (ubus_lookup(ctx, NULL, rpc_plugin_lookup_plugin_cb, &c))
67 rpc_plugin_call_stdin_cb(struct ustream *s, void *priv)
69 struct call_context *c = priv;
73 ustream_write(s, c->input, strlen(c->input), false);
81 rpc_plugin_call_stdout_cb(struct blob_buf *blob, char *buf, int len, void *priv)
83 struct call_context *c = priv;
87 c->obj = json_tokener_parse_ex(c->tok, buf, len);
89 if (json_tokener_get_error(c->tok) != json_tokener_continue)
90 c->output_done = true;
97 rpc_plugin_call_finish_cb(struct blob_buf *blob, int stat, void *priv)
99 struct call_context *c = priv;
100 int rv = UBUS_STATUS_INVALID_ARGUMENT;
102 if (json_tokener_get_error(c->tok) == json_tokener_success)
106 if (json_object_get_type(c->obj) == json_type_object ||
107 json_object_get_type(c->obj) == json_type_array)
109 blobmsg_add_json_element(blob, NULL, c->obj);
113 json_object_put(c->obj);
117 rv = UBUS_STATUS_NO_DATA;
121 json_tokener_free(c->tok);
130 rpc_plugin_call(struct ubus_context *ctx, struct ubus_object *obj,
131 struct ubus_request_data *req, const char *method,
132 struct blob_attr *msg)
134 int rv = UBUS_STATUS_UNKNOWN_ERROR;
135 struct call_context *c;
138 c = calloc(1, sizeof(*c));
143 c->method = strdup(method);
144 c->input = blobmsg_format_json(msg, true);
145 c->tok = json_tokener_new();
147 if (!c->method || !c->input || !c->tok)
150 plugin = c->path + sprintf(c->path, "%s/", RPC_PLUGIN_DIRECTORY);
152 if (!rpc_plugin_lookup_plugin(ctx, obj, plugin))
154 rv = UBUS_STATUS_NOT_FOUND;
158 c->argv[0] = c->path;
160 c->argv[2] = c->method;
162 return rpc_exec(c->argv, rpc_plugin_call_stdin_cb,
163 rpc_plugin_call_stdout_cb, NULL, rpc_plugin_call_finish_cb,
176 json_tokener_free(c->tok);
185 rpc_plugin_parse_signature(struct blob_attr *sig, struct ubus_method *method)
188 enum blobmsg_type type;
189 struct blob_attr *attr;
190 struct blobmsg_policy *policy = NULL;
192 if (!sig || blob_id(sig) != BLOBMSG_TYPE_TABLE)
197 blobmsg_for_each_attr(attr, sig, rem)
202 policy = calloc(n_attr, sizeof(*policy));
209 blobmsg_for_each_attr(attr, sig, rem)
211 type = blob_id(attr);
213 if (type == BLOBMSG_TYPE_INT32)
215 switch (blobmsg_get_u32(attr))
218 type = BLOBMSG_TYPE_INT8;
222 type = BLOBMSG_TYPE_INT16;
226 type = BLOBMSG_TYPE_INT64;
230 type = BLOBMSG_TYPE_INT32;
235 policy[n_attr].name = strdup(blobmsg_name(attr));
236 policy[n_attr].type = type;
242 method->name = strdup(blobmsg_name(sig));
243 method->handler = rpc_plugin_call;
244 method->policy = policy;
245 method->n_policy = n_attr;
250 static struct ubus_object *
251 rpc_plugin_parse_plugin(const char *name, int fd)
253 int len, rem, n_method;
254 struct blob_attr *cur;
255 struct ubus_method *methods;
256 struct ubus_object_type *obj_type;
257 struct ubus_object *obj;
263 blob_buf_init(&buf, 0);
265 tok = json_tokener_new();
270 while ((len = read(fd, outbuf, sizeof(outbuf))) > 0)
272 jsobj = json_tokener_parse_ex(tok, outbuf, len);
274 if (json_tokener_get_error(tok) == json_tokener_continue)
277 if (json_tokener_get_error(tok) != json_tokener_success)
282 if (json_object_get_type(jsobj) == json_type_object)
283 blobmsg_add_object(&buf, jsobj);
285 json_object_put(jsobj);
290 json_tokener_free(tok);
294 blob_for_each_attr(cur, buf.head, rem)
300 methods = calloc(n_method, sizeof(*methods));
307 blob_for_each_attr(cur, buf.head, rem)
309 if (!rpc_plugin_parse_signature(cur, &methods[n_method]))
315 obj = calloc(1, sizeof(*obj));
320 obj_type = calloc(1, sizeof(*obj_type));
325 asprintf((char **)&obj_type->name, "luci-rpc-plugin-%s", name);
326 obj_type->methods = methods;
327 obj_type->n_methods = n_method;
329 obj->name = strdup(name);
330 obj->type = obj_type;
331 obj->methods = methods;
332 obj->n_methods = n_method;
338 rpc_plugin_register(struct ubus_context *ctx, const char *path)
341 int rv = UBUS_STATUS_NO_DATA, fd, fds[2];
343 struct ubus_object *plugin;
345 name = strrchr(path, '/');
348 return UBUS_STATUS_INVALID_ARGUMENT;
351 return UBUS_STATUS_UNKNOWN_ERROR;
353 switch ((pid = fork()))
356 return UBUS_STATUS_UNKNOWN_ERROR;
359 fd = open("/dev/null", O_RDWR);
375 if (execl(path, path, "list", NULL))
376 return UBUS_STATUS_UNKNOWN_ERROR;
379 plugin = rpc_plugin_parse_plugin(name + 1, fds[0]);
384 rv = ubus_add_object(ctx, plugin);
389 waitpid(pid, NULL, 0);
395 int rpc_plugin_api_init(struct ubus_context *ctx)
403 d = opendir(RPC_PLUGIN_DIRECTORY);
406 return UBUS_STATUS_NOT_FOUND;
408 while ((e = readdir(d)) != NULL)
410 snprintf(path, sizeof(path) - 1, RPC_PLUGIN_DIRECTORY "/%s", e->d_name);
412 if (stat(path, &s) || !S_ISREG(s.st_mode) || !(s.st_mode & S_IXUSR))
415 rv |= rpc_plugin_register(ctx, path);