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.
21 static struct blob_buf buf;
23 struct rpc_plugin_lookup_context {
30 rpc_plugin_lookup_plugin_cb(struct ubus_context *ctx,
31 struct ubus_object_data *obj, void *priv)
33 struct rpc_plugin_lookup_context *c = priv;
38 sprintf(c->name, "%s", obj->path);
43 rpc_plugin_lookup_plugin(struct ubus_context *ctx, struct ubus_object *obj,
46 struct rpc_plugin_lookup_context c = { .id = obj->id, .name = strptr };
48 if (ubus_lookup(ctx, NULL, rpc_plugin_lookup_plugin_cb, &c))
55 rpc_plugin_call(struct ubus_context *ctx, struct ubus_object *obj,
56 struct ubus_request_data *req, const char *method,
57 struct blob_attr *msg)
61 int rv, fd, in_fds[2], out_fds[2];
62 char *input, *plugin, *meth, output[4096] = { 0 }, path[PATH_MAX] = { 0 };
64 meth = strdup(method);
65 input = blobmsg_format_json(msg, true);
66 plugin = path + sprintf(path, "%s/", RPC_PLUGIN_DIRECTORY);
68 if (!rpc_plugin_lookup_plugin(ctx, obj, plugin))
69 return UBUS_STATUS_NOT_FOUND;
71 if (stat(path, &s) || !(s.st_mode & S_IXUSR))
72 return UBUS_STATUS_NOT_FOUND;
74 if (pipe(in_fds) || pipe(out_fds))
75 return UBUS_STATUS_UNKNOWN_ERROR;
77 switch ((pid = fork()))
80 return UBUS_STATUS_UNKNOWN_ERROR;
85 fd = open("/dev/null", O_RDWR);
103 if (execl(path, plugin, "call", meth, NULL))
104 return UBUS_STATUS_UNKNOWN_ERROR;
107 rv = UBUS_STATUS_NO_DATA;
111 write(in_fds[1], input, strlen(input));
118 if (read(out_fds[0], output, sizeof(output) - 1) > 0)
120 blob_buf_init(&buf, 0);
122 if (!blobmsg_add_json_from_string(&buf, output))
123 rv = UBUS_STATUS_INVALID_ARGUMENT;
131 waitpid(pid, NULL, 0);
134 ubus_send_reply(ctx, req, buf.head);
143 rpc_plugin_parse_signature(struct blob_attr *sig, struct ubus_method *method)
146 enum blobmsg_type type;
147 struct blob_attr *attr;
148 struct blobmsg_policy *policy = NULL;
150 if (!sig || blob_id(sig) != BLOBMSG_TYPE_TABLE)
155 blobmsg_for_each_attr(attr, sig, rem)
160 policy = calloc(n_attr, sizeof(*policy));
167 blobmsg_for_each_attr(attr, sig, rem)
169 type = blob_id(attr);
171 if (type == BLOBMSG_TYPE_INT32)
173 switch (blobmsg_get_u32(attr))
176 type = BLOBMSG_TYPE_INT8;
180 type = BLOBMSG_TYPE_INT16;
184 type = BLOBMSG_TYPE_INT64;
188 type = BLOBMSG_TYPE_INT32;
193 policy[n_attr].name = strdup(blobmsg_name(attr));
194 policy[n_attr].type = type;
200 method->name = strdup(blobmsg_name(sig));
201 method->handler = rpc_plugin_call;
202 method->policy = policy;
203 method->n_policy = n_attr;
208 static struct ubus_object *
209 rpc_plugin_parse_plugin(const char *name, const char *listbuf)
212 struct blob_attr *cur;
213 struct ubus_method *methods;
214 struct ubus_object_type *obj_type;
215 struct ubus_object *obj;
217 blob_buf_init(&buf, 0);
219 if (!blobmsg_add_json_from_string(&buf, listbuf))
224 blob_for_each_attr(cur, buf.head, rem)
230 methods = calloc(n_method, sizeof(*methods));
237 blob_for_each_attr(cur, buf.head, rem)
239 if (!rpc_plugin_parse_signature(cur, &methods[n_method]))
245 obj = calloc(1, sizeof(*obj));
250 obj_type = calloc(1, sizeof(*obj_type));
255 asprintf((char **)&obj_type->name, "luci-rpc-plugin-%s", name);
256 obj_type->methods = methods;
257 obj_type->n_methods = n_method;
259 obj->name = strdup(name);
260 obj->type = obj_type;
261 obj->methods = methods;
262 obj->n_methods = n_method;
268 rpc_plugin_register(struct ubus_context *ctx, const char *path)
273 char listbuf[4096] = { 0 };
274 struct ubus_object *plugin;
276 name = strrchr(path, '/');
279 return UBUS_STATUS_INVALID_ARGUMENT;
282 return UBUS_STATUS_UNKNOWN_ERROR;
284 switch ((pid = fork()))
287 return UBUS_STATUS_UNKNOWN_ERROR;
290 fd = open("/dev/null", O_RDWR);
306 if (execl(path, path, "list", NULL))
307 return UBUS_STATUS_UNKNOWN_ERROR;
312 if (read(fds[0], listbuf, sizeof(listbuf) - 1) <= 0)
315 plugin = rpc_plugin_parse_plugin(name + 1, listbuf);
320 rv = ubus_add_object(ctx, plugin);
325 waitpid(pid, NULL, 0);
331 int rpc_plugin_api_init(struct ubus_context *ctx)
339 d = opendir(RPC_PLUGIN_DIRECTORY);
342 return UBUS_STATUS_NOT_FOUND;
344 while ((e = readdir(d)) != NULL)
346 snprintf(path, sizeof(path) - 1, RPC_PLUGIN_DIRECTORY "/%s", e->d_name);
348 if (stat(path, &s) || !S_ISREG(s.st_mode) || !(s.st_mode & S_IXUSR))
351 rv |= rpc_plugin_register(ctx, path);