2 * rpcd - 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.
32 rpc_errno_status(void)
37 return UBUS_STATUS_PERMISSION_DENIED;
40 return UBUS_STATUS_INVALID_ARGUMENT;
43 return UBUS_STATUS_NOT_FOUND;
46 return UBUS_STATUS_INVALID_ARGUMENT;
49 return UBUS_STATUS_UNKNOWN_ERROR;
54 rpc_exec_lookup(const char *cmd)
57 int plen = 0, clen = strlen(cmd) + 1;
59 static char path[PATH_MAX];
61 if (!stat(cmd, &s) && S_ISREG(s.st_mode))
64 search = getenv("PATH");
67 search = "/bin:/usr/bin:/sbin:/usr/sbin";
73 if (*p != ':' && *p != '\0')
78 if ((plen + clen) >= sizeof(path))
81 strncpy(path, search, plen);
82 sprintf(path + plen, "/%s", cmd);
84 if (!stat(path, &s) && S_ISREG(s.st_mode))
96 rpc_ustream_to_blobmsg(struct blob_buf *blob, struct ustream *s,
102 if ((len = ustream_pending_data(s, false)) > 0)
104 wbuf = blobmsg_alloc_string_buffer(blob, name, len + 1);
109 ustream_for_each_read_buffer(s, rbuf, len)
111 memcpy(wbuf, rbuf, len);
116 blobmsg_add_string_buffer(blob);
121 rpc_exec_reply(struct rpc_exec_context *c, int rv)
123 uloop_timeout_cancel(&c->timeout);
124 uloop_process_delete(&c->process);
126 if (rv == UBUS_STATUS_OK)
128 if (!c->stdout_cb && !c->stderr_cb && !c->finish_cb)
130 blobmsg_add_u32(&c->blob, "code", WEXITSTATUS(c->stat));
131 rpc_ustream_to_blobmsg(&c->blob, &c->opipe.stream, "stdout");
132 rpc_ustream_to_blobmsg(&c->blob, &c->epipe.stream, "stderr");
136 rv = c->finish_cb(&c->blob, c->stat, c->priv);
138 if (rv == UBUS_STATUS_OK)
139 ubus_send_reply(c->context, &c->request, c->blob.head);
142 ubus_complete_deferred_request(c->context, &c->request, rv);
144 blob_buf_free(&c->blob);
146 ustream_free(&c->opipe.stream);
147 ustream_free(&c->epipe.stream);
149 close(c->opipe.fd.fd);
150 close(c->epipe.fd.fd);
159 rpc_exec_timeout_cb(struct uloop_timeout *t)
161 struct rpc_exec_context *c =
162 container_of(t, struct rpc_exec_context, timeout);
164 kill(c->process.pid, SIGKILL);
165 rpc_exec_reply(c, UBUS_STATUS_TIMEOUT);
169 rpc_exec_process_cb(struct uloop_process *p, int stat)
171 struct rpc_exec_context *c =
172 container_of(p, struct rpc_exec_context, process);
176 ustream_poll(&c->opipe.stream);
177 ustream_poll(&c->epipe.stream);
181 rpc_exec_ipipe_write_cb(struct ustream *s, int bytes)
183 struct rpc_exec_context *c =
184 container_of(s, struct rpc_exec_context, ipipe.stream);
186 if (c->stdin_cb(s, c->priv) <= 0)
188 ustream_free(&c->ipipe.stream);
189 close(c->ipipe.fd.fd);
194 rpc_exec_opipe_read_cb(struct ustream *s, int bytes)
198 struct rpc_exec_context *c =
199 container_of(s, struct rpc_exec_context, opipe.stream);
204 buf = ustream_get_read_buf(s, &len);
209 rv = c->stdout_cb(&c->blob, buf, len, c->priv);
214 ustream_consume(s, rv);
217 else if (ustream_read_buf_full(s))
219 rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
224 rpc_exec_epipe_read_cb(struct ustream *s, int bytes)
228 struct rpc_exec_context *c =
229 container_of(s, struct rpc_exec_context, epipe.stream);
234 buf = ustream_get_read_buf(s, &len);
239 rv = c->stderr_cb(&c->blob, buf, len, c->priv);
244 ustream_consume(s, rv);
247 else if (ustream_read_buf_full(s))
249 rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
254 rpc_exec_opipe_state_cb(struct ustream *s)
256 struct rpc_exec_context *c =
257 container_of(s, struct rpc_exec_context, opipe.stream);
259 if (c->opipe.stream.eof && c->epipe.stream.eof)
260 rpc_exec_reply(c, UBUS_STATUS_OK);
264 rpc_exec_epipe_state_cb(struct ustream *s)
266 struct rpc_exec_context *c =
267 container_of(s, struct rpc_exec_context, epipe.stream);
269 if (c->opipe.stream.eof && c->epipe.stream.eof)
270 rpc_exec_reply(c, UBUS_STATUS_OK);
274 rpc_exec(const char **args, rpc_exec_write_cb_t in,
275 rpc_exec_read_cb_t out, rpc_exec_read_cb_t err,
276 rpc_exec_done_cb_t end, void *priv, struct ubus_context *ctx,
277 struct ubus_request_data *req)
286 struct rpc_exec_context *c;
288 cmd = rpc_exec_lookup(args[0]);
291 return UBUS_STATUS_NOT_FOUND;
293 c = malloc(sizeof(*c));
296 return UBUS_STATUS_UNKNOWN_ERROR;
307 switch ((pid = fork()))
310 return rpc_errno_status();
326 if (execv(cmd, (char * const *)args))
327 return rpc_errno_status();
330 memset(c, 0, sizeof(*c));
331 blob_buf_init(&c->blob, 0);
339 ustream_declare_read(c->opipe, opipe[0], opipe);
340 ustream_declare_read(c->epipe, epipe[0], epipe);
342 c->process.pid = pid;
343 c->process.cb = rpc_exec_process_cb;
344 uloop_process_add(&c->process);
346 c->timeout.cb = rpc_exec_timeout_cb;
347 uloop_timeout_set(&c->timeout, RPC_EXEC_MAX_RUNTIME);
351 ustream_declare_write(c->ipipe, ipipe[1], ipipe);
352 rpc_exec_ipipe_write_cb(&c->ipipe.stream, 0);
364 ubus_defer_request(ctx, req, &c->request);
367 return UBUS_STATUS_OK;
378 return rpc_errno_status();