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_stderr_cb(struct blob_buf
*blob
, char *buf
, int len
, void *priv
)
103 rpc_plugin_call_finish_cb(struct blob_buf
*blob
, int stat
, void *priv
)
105 struct call_context
*c
= priv
;
106 int rv
= UBUS_STATUS_INVALID_ARGUMENT
;
108 if (json_tokener_get_error(c
->tok
) == json_tokener_success
)
112 if (json_object_get_type(c
->obj
) == json_type_object
||
113 json_object_get_type(c
->obj
) == json_type_array
)
115 blobmsg_add_json_element(blob
, NULL
, c
->obj
);
119 json_object_put(c
->obj
);
123 rv
= UBUS_STATUS_NO_DATA
;
127 json_tokener_free(c
->tok
);
136 rpc_plugin_call(struct ubus_context
*ctx
, struct ubus_object
*obj
,
137 struct ubus_request_data
*req
, const char *method
,
138 struct blob_attr
*msg
)
140 int rv
= UBUS_STATUS_UNKNOWN_ERROR
;
141 struct call_context
*c
;
144 c
= calloc(1, sizeof(*c
));
149 c
->method
= strdup(method
);
150 c
->input
= blobmsg_format_json(msg
, true);
151 c
->tok
= json_tokener_new();
153 if (!c
->method
|| !c
->input
|| !c
->tok
)
156 plugin
= c
->path
+ sprintf(c
->path
, "%s/", RPC_PLUGIN_DIRECTORY
);
158 if (!rpc_plugin_lookup_plugin(ctx
, obj
, plugin
))
160 rv
= UBUS_STATUS_NOT_FOUND
;
164 c
->argv
[0] = c
->path
;
166 c
->argv
[2] = c
->method
;
168 return rpc_exec(c
->argv
, rpc_plugin_call_stdin_cb
,
169 rpc_plugin_call_stdout_cb
, rpc_plugin_call_stderr_cb
,
170 rpc_plugin_call_finish_cb
, c
, ctx
, req
);
182 json_tokener_free(c
->tok
);
191 rpc_plugin_parse_signature(struct blob_attr
*sig
, struct ubus_method
*method
)
194 enum blobmsg_type type
;
195 struct blob_attr
*attr
;
196 struct blobmsg_policy
*policy
= NULL
;
198 if (!sig
|| blob_id(sig
) != BLOBMSG_TYPE_TABLE
)
203 blobmsg_for_each_attr(attr
, sig
, rem
)
208 policy
= calloc(n_attr
, sizeof(*policy
));
215 blobmsg_for_each_attr(attr
, sig
, rem
)
217 type
= blob_id(attr
);
219 if (type
== BLOBMSG_TYPE_INT32
)
221 switch (blobmsg_get_u32(attr
))
224 type
= BLOBMSG_TYPE_INT8
;
228 type
= BLOBMSG_TYPE_INT16
;
232 type
= BLOBMSG_TYPE_INT64
;
236 type
= BLOBMSG_TYPE_INT32
;
241 policy
[n_attr
].name
= strdup(blobmsg_name(attr
));
242 policy
[n_attr
].type
= type
;
248 method
->name
= strdup(blobmsg_name(sig
));
249 method
->handler
= rpc_plugin_call
;
250 method
->policy
= policy
;
251 method
->n_policy
= n_attr
;
256 static struct ubus_object
*
257 rpc_plugin_parse_plugin(const char *name
, int fd
)
259 int len
, rem
, n_method
;
260 struct blob_attr
*cur
;
261 struct ubus_method
*methods
;
262 struct ubus_object_type
*obj_type
;
263 struct ubus_object
*obj
;
269 blob_buf_init(&buf
, 0);
271 tok
= json_tokener_new();
276 while ((len
= read(fd
, outbuf
, sizeof(outbuf
))) > 0)
278 jsobj
= json_tokener_parse_ex(tok
, outbuf
, len
);
280 if (json_tokener_get_error(tok
) == json_tokener_continue
)
283 if (json_tokener_get_error(tok
) != json_tokener_success
)
288 if (json_object_get_type(jsobj
) == json_type_object
)
289 blobmsg_add_object(&buf
, jsobj
);
291 json_object_put(jsobj
);
296 json_tokener_free(tok
);
300 blob_for_each_attr(cur
, buf
.head
, rem
)
306 methods
= calloc(n_method
, sizeof(*methods
));
313 blob_for_each_attr(cur
, buf
.head
, rem
)
315 if (!rpc_plugin_parse_signature(cur
, &methods
[n_method
]))
321 obj
= calloc(1, sizeof(*obj
));
326 obj_type
= calloc(1, sizeof(*obj_type
));
331 asprintf((char **)&obj_type
->name
, "luci-rpc-plugin-%s", name
);
332 obj_type
->methods
= methods
;
333 obj_type
->n_methods
= n_method
;
335 obj
->name
= strdup(name
);
336 obj
->type
= obj_type
;
337 obj
->methods
= methods
;
338 obj
->n_methods
= n_method
;
344 rpc_plugin_register(struct ubus_context
*ctx
, const char *path
)
347 int rv
= UBUS_STATUS_NO_DATA
, fd
, fds
[2];
349 struct ubus_object
*plugin
;
351 name
= strrchr(path
, '/');
354 return UBUS_STATUS_INVALID_ARGUMENT
;
357 return UBUS_STATUS_UNKNOWN_ERROR
;
359 switch ((pid
= fork()))
362 return UBUS_STATUS_UNKNOWN_ERROR
;
365 fd
= open("/dev/null", O_RDWR
);
381 if (execl(path
, path
, "list", NULL
))
382 return UBUS_STATUS_UNKNOWN_ERROR
;
385 plugin
= rpc_plugin_parse_plugin(name
+ 1, fds
[0]);
390 rv
= ubus_add_object(ctx
, plugin
);
395 waitpid(pid
, NULL
, 0);
401 int rpc_plugin_api_init(struct ubus_context
*ctx
)
409 d
= opendir(RPC_PLUGIN_DIRECTORY
);
412 return UBUS_STATUS_NOT_FOUND
;
414 while ((e
= readdir(d
)) != NULL
)
416 snprintf(path
, sizeof(path
) - 1, RPC_PLUGIN_DIRECTORY
"/%s", e
->d_name
);
418 if (stat(path
, &s
) || !S_ISREG(s
.st_mode
) || !(s
.st_mode
& S_IXUSR
))
421 rv
|= rpc_plugin_register(ctx
, path
);