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
);