2
0

exec.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. * rpcd - UBUS RPC server
  3. *
  4. * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
  5. *
  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.
  9. *
  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.
  17. */
  18. #include <fcntl.h>
  19. #include <errno.h>
  20. #include <unistd.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <limits.h>
  24. #include <dirent.h>
  25. #include <sys/stat.h>
  26. #include <sys/wait.h>
  27. #include <rpcd/exec.h>
  28. static int
  29. rpc_errno_status(void)
  30. {
  31. switch (errno)
  32. {
  33. case EACCES:
  34. return UBUS_STATUS_PERMISSION_DENIED;
  35. case ENOTDIR:
  36. return UBUS_STATUS_INVALID_ARGUMENT;
  37. case ENOENT:
  38. return UBUS_STATUS_NOT_FOUND;
  39. case EINVAL:
  40. return UBUS_STATUS_INVALID_ARGUMENT;
  41. default:
  42. return UBUS_STATUS_UNKNOWN_ERROR;
  43. }
  44. }
  45. const char *
  46. rpc_exec_lookup(const char *cmd)
  47. {
  48. struct stat s;
  49. int plen = 0, clen = strlen(cmd) + 1;
  50. char *search, *p;
  51. static char path[PATH_MAX];
  52. if (!stat(cmd, &s) && S_ISREG(s.st_mode))
  53. return cmd;
  54. search = getenv("PATH");
  55. if (!search)
  56. search = "/bin:/usr/bin:/sbin:/usr/sbin";
  57. p = search;
  58. do
  59. {
  60. if (*p != ':' && *p != '\0')
  61. continue;
  62. plen = p - search;
  63. if ((plen + clen) >= sizeof(path))
  64. continue;
  65. strncpy(path, search, plen);
  66. sprintf(path + plen, "/%s", cmd);
  67. if (!stat(path, &s) && S_ISREG(s.st_mode))
  68. return path;
  69. search = p + 1;
  70. }
  71. while (*p++);
  72. return NULL;
  73. }
  74. static void
  75. rpc_ustream_to_blobmsg(struct blob_buf *blob, struct ustream *s,
  76. const char *name)
  77. {
  78. int len;
  79. char *rbuf, *wbuf;
  80. if ((len = ustream_pending_data(s, false)) > 0)
  81. {
  82. wbuf = blobmsg_alloc_string_buffer(blob, name, len + 1);
  83. if (!wbuf)
  84. return;
  85. ustream_for_each_read_buffer(s, rbuf, len)
  86. {
  87. memcpy(wbuf, rbuf, len);
  88. wbuf += len;
  89. }
  90. *wbuf = 0;
  91. blobmsg_add_string_buffer(blob);
  92. }
  93. }
  94. static void
  95. rpc_exec_reply(struct rpc_exec_context *c, int rv)
  96. {
  97. uloop_timeout_cancel(&c->timeout);
  98. uloop_process_delete(&c->process);
  99. if (rv == UBUS_STATUS_OK)
  100. {
  101. if (!c->stdout_cb && !c->stderr_cb && !c->finish_cb)
  102. {
  103. blobmsg_add_u32(&c->blob, "code", WEXITSTATUS(c->stat));
  104. rpc_ustream_to_blobmsg(&c->blob, &c->opipe.stream, "stdout");
  105. rpc_ustream_to_blobmsg(&c->blob, &c->epipe.stream, "stderr");
  106. }
  107. }
  108. if (c->finish_cb)
  109. rv = c->finish_cb(&c->blob, c->stat, c->priv);
  110. if (rv == UBUS_STATUS_OK)
  111. ubus_send_reply(c->context, &c->request, c->blob.head);
  112. ubus_complete_deferred_request(c->context, &c->request, rv);
  113. blob_buf_free(&c->blob);
  114. ustream_free(&c->opipe.stream);
  115. ustream_free(&c->epipe.stream);
  116. close(c->opipe.fd.fd);
  117. close(c->epipe.fd.fd);
  118. if (c->priv)
  119. free(c->priv);
  120. free(c);
  121. }
  122. static void
  123. rpc_exec_timeout_cb(struct uloop_timeout *t)
  124. {
  125. struct rpc_exec_context *c =
  126. container_of(t, struct rpc_exec_context, timeout);
  127. kill(c->process.pid, SIGKILL);
  128. rpc_exec_reply(c, UBUS_STATUS_TIMEOUT);
  129. }
  130. static void
  131. rpc_exec_process_cb(struct uloop_process *p, int stat)
  132. {
  133. struct rpc_exec_context *c =
  134. container_of(p, struct rpc_exec_context, process);
  135. c->stat = stat;
  136. ustream_poll(&c->opipe.stream);
  137. ustream_poll(&c->epipe.stream);
  138. close(c->opipe.fd.fd);
  139. close(c->epipe.fd.fd);
  140. ustream_poll(&c->opipe.stream);
  141. ustream_poll(&c->epipe.stream);
  142. }
  143. static void
  144. rpc_exec_ipipe_write_cb(struct ustream *s, int bytes)
  145. {
  146. struct rpc_exec_context *c =
  147. container_of(s, struct rpc_exec_context, ipipe.stream);
  148. if (c->stdin_cb(s, c->priv) <= 0)
  149. {
  150. ustream_free(&c->ipipe.stream);
  151. close(c->ipipe.fd.fd);
  152. }
  153. }
  154. static void
  155. rpc_exec_opipe_read_cb(struct ustream *s, int bytes)
  156. {
  157. int len, rv;
  158. char *buf;
  159. struct rpc_exec_context *c =
  160. container_of(s, struct rpc_exec_context, opipe.stream);
  161. if (c->stdout_cb)
  162. {
  163. do {
  164. buf = ustream_get_read_buf(s, &len);
  165. if (!buf || !len)
  166. break;
  167. rv = c->stdout_cb(&c->blob, buf, len, c->priv);
  168. if (rv <= 0)
  169. break;
  170. ustream_consume(s, rv);
  171. } while(1);
  172. }
  173. else if (ustream_read_buf_full(s))
  174. {
  175. rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
  176. }
  177. }
  178. static void
  179. rpc_exec_epipe_read_cb(struct ustream *s, int bytes)
  180. {
  181. int len, rv;
  182. char *buf;
  183. struct rpc_exec_context *c =
  184. container_of(s, struct rpc_exec_context, epipe.stream);
  185. if (c->stderr_cb)
  186. {
  187. do {
  188. buf = ustream_get_read_buf(s, &len);
  189. if (!buf || !len)
  190. break;
  191. rv = c->stderr_cb(&c->blob, buf, len, c->priv);
  192. if (rv <= 0)
  193. break;
  194. ustream_consume(s, rv);
  195. } while(1);
  196. }
  197. else if (ustream_read_buf_full(s))
  198. {
  199. rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
  200. }
  201. }
  202. static void
  203. rpc_exec_opipe_state_cb(struct ustream *s)
  204. {
  205. struct rpc_exec_context *c =
  206. container_of(s, struct rpc_exec_context, opipe.stream);
  207. if (c->opipe.stream.eof && c->epipe.stream.eof)
  208. rpc_exec_reply(c, UBUS_STATUS_OK);
  209. }
  210. static void
  211. rpc_exec_epipe_state_cb(struct ustream *s)
  212. {
  213. struct rpc_exec_context *c =
  214. container_of(s, struct rpc_exec_context, epipe.stream);
  215. if (c->opipe.stream.eof && c->epipe.stream.eof)
  216. rpc_exec_reply(c, UBUS_STATUS_OK);
  217. }
  218. int
  219. rpc_exec(const char **args, rpc_exec_write_cb_t in,
  220. rpc_exec_read_cb_t out, rpc_exec_read_cb_t err,
  221. rpc_exec_done_cb_t end, void *priv, struct ubus_context *ctx,
  222. struct ubus_request_data *req)
  223. {
  224. pid_t pid;
  225. int ipipe[2];
  226. int opipe[2];
  227. int epipe[2];
  228. const char *cmd;
  229. struct rpc_exec_context *c;
  230. cmd = rpc_exec_lookup(args[0]);
  231. if (!cmd)
  232. return UBUS_STATUS_NOT_FOUND;
  233. c = malloc(sizeof(*c));
  234. if (!c)
  235. return UBUS_STATUS_UNKNOWN_ERROR;
  236. if (pipe(ipipe))
  237. goto fail_ipipe;
  238. if (pipe(opipe))
  239. goto fail_opipe;
  240. if (pipe(epipe))
  241. goto fail_epipe;
  242. switch ((pid = fork()))
  243. {
  244. case -1:
  245. goto fail_fork;
  246. case 0:
  247. uloop_done();
  248. dup2(ipipe[0], 0);
  249. dup2(opipe[1], 1);
  250. dup2(epipe[1], 2);
  251. close(ipipe[0]);
  252. close(ipipe[1]);
  253. close(opipe[0]);
  254. close(opipe[1]);
  255. close(epipe[0]);
  256. close(epipe[1]);
  257. if (execv(cmd, (char * const *)args))
  258. return rpc_errno_status();
  259. default:
  260. memset(c, 0, sizeof(*c));
  261. blob_buf_init(&c->blob, 0);
  262. c->stdin_cb = in;
  263. c->stdout_cb = out;
  264. c->stderr_cb = err;
  265. c->finish_cb = end;
  266. c->priv = priv;
  267. ustream_declare_read(c->opipe, opipe[0], opipe);
  268. ustream_declare_read(c->epipe, epipe[0], epipe);
  269. c->process.pid = pid;
  270. c->process.cb = rpc_exec_process_cb;
  271. uloop_process_add(&c->process);
  272. c->timeout.cb = rpc_exec_timeout_cb;
  273. uloop_timeout_set(&c->timeout, rpc_exec_timeout);
  274. if (c->stdin_cb)
  275. {
  276. ustream_declare_write(c->ipipe, ipipe[1], ipipe);
  277. rpc_exec_ipipe_write_cb(&c->ipipe.stream, 0);
  278. }
  279. else
  280. {
  281. close(ipipe[1]);
  282. }
  283. close(ipipe[0]);
  284. close(opipe[1]);
  285. close(epipe[1]);
  286. c->context = ctx;
  287. ubus_defer_request(ctx, req, &c->request);
  288. }
  289. return UBUS_STATUS_OK;
  290. fail_fork:
  291. close(epipe[0]);
  292. close(epipe[1]);
  293. fail_epipe:
  294. close(opipe[0]);
  295. close(opipe[1]);
  296. fail_opipe:
  297. close(ipipe[0]);
  298. close(ipipe[1]);
  299. fail_ipipe:
  300. free(c);
  301. return rpc_errno_status();
  302. }