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.
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 c
->finish_cb(&c
->blob
, c
->stat
, c
->priv
);
138 ubus_send_reply(c
->context
, &c
->request
, c
->blob
.head
);
141 ubus_complete_deferred_request(c
->context
, &c
->request
, rv
);
143 blob_buf_free(&c
->blob
);
145 ustream_free(&c
->opipe
.stream
);
146 ustream_free(&c
->epipe
.stream
);
148 close(c
->opipe
.fd
.fd
);
149 close(c
->epipe
.fd
.fd
);
158 rpc_exec_timestdout_cb(struct uloop_timeout
*t
)
160 struct rpc_exec_context
*c
=
161 container_of(t
, struct rpc_exec_context
, timeout
);
163 kill(c
->process
.pid
, SIGKILL
);
164 rpc_exec_reply(c
, UBUS_STATUS_TIMEOUT
);
168 rpc_exec_process_cb(struct uloop_process
*p
, int stat
)
170 struct rpc_exec_context
*c
=
171 container_of(p
, struct rpc_exec_context
, process
);
175 ustream_poll(&c
->opipe
.stream
);
176 ustream_poll(&c
->epipe
.stream
);
180 rpc_exec_opipe_read_cb(struct ustream
*s
, int bytes
)
184 struct rpc_exec_context
*c
=
185 container_of(s
, struct rpc_exec_context
, opipe
.stream
);
190 buf
= ustream_get_read_buf(s
, &len
);
195 rv
= c
->stdout_cb(&c
->blob
, buf
, len
, c
->priv
);
200 ustream_consume(s
, rv
);
203 else if (ustream_read_buf_full(s
))
205 rpc_exec_reply(c
, UBUS_STATUS_NOT_SUPPORTED
);
210 rpc_exec_epipe_read_cb(struct ustream
*s
, int bytes
)
214 struct rpc_exec_context
*c
=
215 container_of(s
, struct rpc_exec_context
, epipe
.stream
);
220 buf
= ustream_get_read_buf(s
, &len
);
225 rv
= c
->stderr_cb(&c
->blob
, buf
, len
, c
->priv
);
230 ustream_consume(s
, rv
);
233 else if (ustream_read_buf_full(s
))
235 rpc_exec_reply(c
, UBUS_STATUS_NOT_SUPPORTED
);
240 rpc_exec_opipe_state_cb(struct ustream
*s
)
242 struct rpc_exec_context
*c
=
243 container_of(s
, struct rpc_exec_context
, opipe
.stream
);
245 if (c
->opipe
.stream
.eof
&& c
->epipe
.stream
.eof
)
246 rpc_exec_reply(c
, UBUS_STATUS_OK
);
250 rpc_exec_epipe_state_cb(struct ustream
*s
)
252 struct rpc_exec_context
*c
=
253 container_of(s
, struct rpc_exec_context
, epipe
.stream
);
255 if (c
->opipe
.stream
.eof
&& c
->epipe
.stream
.eof
)
256 rpc_exec_reply(c
, UBUS_STATUS_OK
);
260 rpc_exec(const char **args
, rpc_exec_read_cb_t out
, rpc_exec_read_cb_t err
,
261 rpc_exec_done_cb_t end
, void *priv
, struct ubus_context
*ctx
,
262 struct ubus_request_data
*req
)
270 struct rpc_exec_context
*c
;
272 cmd
= rpc_exec_lookup(args
[0]);
275 return UBUS_STATUS_NOT_FOUND
;
277 c
= malloc(sizeof(*c
));
280 return UBUS_STATUS_UNKNOWN_ERROR
;
282 if (pipe(opipe
) || pipe(epipe
))
283 return rpc_errno_status();
285 switch ((pid
= fork()))
288 return rpc_errno_status();
302 if (execv(cmd
, (char * const *)args
))
303 return rpc_errno_status();
306 memset(c
, 0, sizeof(*c
));
307 blob_buf_init(&c
->blob
, 0);
314 ustream_declare(c
->opipe
, opipe
[0], opipe
);
315 ustream_declare(c
->epipe
, epipe
[0], epipe
);
317 c
->process
.pid
= pid
;
318 c
->process
.cb
= rpc_exec_process_cb
;
319 uloop_process_add(&c
->process
);
321 c
->timeout
.cb
= rpc_exec_timestdout_cb
;
322 uloop_timeout_set(&c
->timeout
, RPC_EXEC_MAX_RUNTIME
);
328 ubus_defer_request(ctx
, req
, &c
->request
);
331 return UBUS_STATUS_OK
;