2 * rpcd - UBUS RPC server
4 * Copyright (C) 2013-2014 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.
19 #include <rpcd/plugin.h>
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_json_array_to_blob(struct array_list
*a
, struct blob_buf
*blob
);
58 rpc_plugin_json_object_to_blob(json_object
*o
, struct blob_buf
*blob
);
61 rpc_plugin_json_element_to_blob(const char *name
, json_object
*val
,
62 struct blob_buf
*blob
)
67 switch (json_object_get_type(val
)) {
68 case json_type_object
:
69 c
= blobmsg_open_table(blob
, name
);
70 rpc_plugin_json_object_to_blob(val
, blob
);
71 blobmsg_close_table(blob
, c
);
75 c
= blobmsg_open_array(blob
, name
);
76 rpc_plugin_json_array_to_blob(json_object_get_array(val
), blob
);
77 blobmsg_close_array(blob
, c
);
80 case json_type_string
:
81 blobmsg_add_string(blob
, name
, json_object_get_string(val
));
84 case json_type_boolean
:
85 blobmsg_add_u8(blob
, name
, json_object_get_boolean(val
));
89 n
= json_object_get_int64(val
);
90 if (n
>= INT32_MIN
&& n
<= INT32_MAX
)
91 blobmsg_add_u32(blob
, name
, n
);
93 blobmsg_add_u64(blob
, name
, n
);
96 case json_type_double
:
97 blobmsg_add_double(blob
, name
, json_object_get_double(val
));
101 blobmsg_add_field(blob
, BLOBMSG_TYPE_UNSPEC
, name
, NULL
, 0);
107 rpc_plugin_json_array_to_blob(struct array_list
*a
, struct blob_buf
*blob
)
111 for (i
= 0, len
= array_list_length(a
); i
< len
; i
++)
112 rpc_plugin_json_element_to_blob(NULL
, array_list_get_idx(a
, i
), blob
);
116 rpc_plugin_json_object_to_blob(json_object
*o
, struct blob_buf
*blob
)
118 json_object_object_foreach(o
, key
, val
)
119 rpc_plugin_json_element_to_blob(key
, val
, blob
);
122 struct call_context
{
134 rpc_plugin_call_stdin_cb(struct ustream
*s
, void *priv
)
136 struct call_context
*c
= priv
;
140 ustream_write(s
, c
->input
, strlen(c
->input
), false);
141 c
->input_done
= true;
148 rpc_plugin_call_stdout_cb(struct blob_buf
*blob
, char *buf
, int len
, void *priv
)
150 struct call_context
*c
= priv
;
154 c
->obj
= json_tokener_parse_ex(c
->tok
, buf
, len
);
156 if (json_tokener_get_error(c
->tok
) != json_tokener_continue
)
157 c
->output_done
= true;
164 rpc_plugin_call_stderr_cb(struct blob_buf
*blob
, char *buf
, int len
, void *priv
)
170 rpc_plugin_call_finish_cb(struct blob_buf
*blob
, int stat
, void *priv
)
172 struct call_context
*c
= priv
;
173 int rv
= UBUS_STATUS_INVALID_ARGUMENT
;
175 if (json_tokener_get_error(c
->tok
) == json_tokener_success
)
179 if (json_object_get_type(c
->obj
) == json_type_object
)
181 rpc_plugin_json_object_to_blob(c
->obj
, blob
);
185 json_object_put(c
->obj
);
189 rv
= UBUS_STATUS_NO_DATA
;
193 json_tokener_free(c
->tok
);
201 rpc_plugin_call(struct ubus_context
*ctx
, struct ubus_object
*obj
,
202 struct ubus_request_data
*req
, const char *method
,
203 struct blob_attr
*msg
)
205 int rv
= UBUS_STATUS_UNKNOWN_ERROR
;
206 struct call_context
*c
;
209 c
= calloc_a(sizeof(*c
), &mptr
, strlen(method
) + 1);
214 c
->method
= strcpy(mptr
, method
);
215 c
->input
= blobmsg_format_json(msg
, true);
216 c
->tok
= json_tokener_new();
218 if (!c
->input
|| !c
->tok
)
221 plugin
= c
->path
+ sprintf(c
->path
, "%s/", RPC_PLUGIN_DIRECTORY
);
223 if (!rpc_plugin_lookup_plugin(ctx
, obj
, plugin
))
225 rv
= UBUS_STATUS_NOT_FOUND
;
229 c
->argv
[0] = c
->path
;
231 c
->argv
[2] = c
->method
;
233 rv
= rpc_exec(c
->argv
, rpc_plugin_call_stdin_cb
,
234 rpc_plugin_call_stdout_cb
, rpc_plugin_call_stderr_cb
,
235 rpc_plugin_call_finish_cb
, c
, ctx
, req
);
237 if (rv
== UBUS_STATUS_OK
)
247 json_tokener_free(c
->tok
);
256 rpc_plugin_parse_signature(struct blob_attr
*sig
, struct ubus_method
*method
)
259 enum blobmsg_type type
;
260 struct blob_attr
*attr
;
261 struct blobmsg_policy
*policy
= NULL
;
263 if (!sig
|| blobmsg_type(sig
) != BLOBMSG_TYPE_TABLE
)
268 blobmsg_for_each_attr(attr
, sig
, rem
)
273 policy
= calloc(n_attr
, sizeof(*policy
));
280 blobmsg_for_each_attr(attr
, sig
, rem
)
282 type
= blobmsg_type(attr
);
284 if (type
== BLOBMSG_TYPE_INT32
)
286 switch (blobmsg_get_u32(attr
))
289 type
= BLOBMSG_TYPE_INT8
;
293 type
= BLOBMSG_TYPE_INT16
;
297 type
= BLOBMSG_TYPE_INT64
;
301 type
= BLOBMSG_TYPE_INT32
;
306 policy
[n_attr
].name
= strdup(blobmsg_name(attr
));
307 policy
[n_attr
].type
= type
;
313 method
->name
= strdup(blobmsg_name(sig
));
314 method
->handler
= rpc_plugin_call
;
315 method
->policy
= policy
;
316 method
->n_policy
= n_attr
;
321 static struct ubus_object
*
322 rpc_plugin_parse_exec(const char *name
, int fd
)
324 int len
, rem
, n_method
;
325 struct blob_attr
*cur
;
326 struct ubus_method
*methods
;
327 struct ubus_object_type
*obj_type
;
328 struct ubus_object
*obj
;
334 blob_buf_init(&buf
, 0);
336 tok
= json_tokener_new();
341 while ((len
= read(fd
, outbuf
, sizeof(outbuf
))) > 0)
343 jsobj
= json_tokener_parse_ex(tok
, outbuf
, len
);
345 if (json_tokener_get_error(tok
) == json_tokener_continue
)
348 if (json_tokener_get_error(tok
) != json_tokener_success
)
353 if (json_object_get_type(jsobj
) == json_type_object
)
354 blobmsg_add_object(&buf
, jsobj
);
356 json_object_put(jsobj
);
361 json_tokener_free(tok
);
365 blob_for_each_attr(cur
, buf
.head
, rem
)
371 methods
= calloc(n_method
, sizeof(*methods
));
378 blob_for_each_attr(cur
, buf
.head
, rem
)
380 if (!rpc_plugin_parse_signature(cur
, &methods
[n_method
]))
386 obj
= calloc(1, sizeof(*obj
));
391 obj_type
= calloc(1, sizeof(*obj_type
));
398 if (asprintf((char **)&obj_type
->name
, "luci-rpc-plugin-%s", name
) < 0) {
404 obj_type
->methods
= methods
;
405 obj_type
->n_methods
= n_method
;
407 obj
->name
= strdup(name
);
408 obj
->type
= obj_type
;
409 obj
->methods
= methods
;
410 obj
->n_methods
= n_method
;
416 rpc_plugin_register_exec(struct ubus_context
*ctx
, const char *path
)
419 int rv
= UBUS_STATUS_NO_DATA
, fd
, fds
[2];
421 struct ubus_object
*plugin
;
423 name
= strrchr(path
, '/');
426 return UBUS_STATUS_INVALID_ARGUMENT
;
429 return UBUS_STATUS_UNKNOWN_ERROR
;
431 switch ((pid
= fork()))
434 return UBUS_STATUS_UNKNOWN_ERROR
;
437 fd
= open("/dev/null", O_RDWR
);
453 if (execl(path
, path
, "list", NULL
))
454 return UBUS_STATUS_UNKNOWN_ERROR
;
457 plugin
= rpc_plugin_parse_exec(name
+ 1, fds
[0]);
462 rv
= ubus_add_object(ctx
, plugin
);
467 waitpid(pid
, NULL
, 0);
474 static LIST_HEAD(plugins
);
476 static const struct rpc_daemon_ops ops
= {
477 .session_access
= rpc_session_access
,
478 .session_create_cb
= rpc_session_create_cb
,
479 .session_destroy_cb
= rpc_session_destroy_cb
,
481 .exec_timeout
= &rpc_exec_timeout
,
485 rpc_plugin_register_library(struct ubus_context
*ctx
, const char *path
)
487 struct rpc_plugin
*p
;
490 dlh
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
493 return UBUS_STATUS_UNKNOWN_ERROR
;
495 p
= dlsym(dlh
, "rpc_plugin");
498 return UBUS_STATUS_NOT_FOUND
;
500 list_add(&p
->list
, &plugins
);
502 return p
->init(&ops
, ctx
);
505 int rpc_plugin_api_init(struct ubus_context
*ctx
)
513 if ((d
= opendir(RPC_PLUGIN_DIRECTORY
)) != NULL
)
515 while ((e
= readdir(d
)) != NULL
)
517 snprintf(path
, sizeof(path
) - 1,
518 RPC_PLUGIN_DIRECTORY
"/%s", e
->d_name
);
520 if (stat(path
, &s
) || !S_ISREG(s
.st_mode
) || !(s
.st_mode
& S_IXUSR
))
523 rv
|= rpc_plugin_register_exec(ctx
, path
);
529 if ((d
= opendir(RPC_LIBRARY_DIRECTORY
)) != NULL
)
531 while ((e
= readdir(d
)) != NULL
)
533 snprintf(path
, sizeof(path
) - 1,
534 RPC_LIBRARY_DIRECTORY
"/%s", e
->d_name
);
536 if (stat(path
, &s
) || !S_ISREG(s
.st_mode
))
539 rv
|= rpc_plugin_register_library(ctx
, path
);