• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/rpcd/exec.c

  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 
 19 #include <fcntl.h>
 20 #include <errno.h>
 21 #include <unistd.h>
 22 #include <stdlib.h>
 23 #include <string.h>
 24 #include <limits.h>
 25 #include <dirent.h>
 26 #include <sys/stat.h>
 27 #include <sys/wait.h>
 28 
 29 #include <rpcd/exec.h>
 30 
 31 static int
 32 rpc_errno_status(void)
 33 {
 34         switch (errno)
 35         {
 36         case EACCES:
 37                 return UBUS_STATUS_PERMISSION_DENIED;
 38 
 39         case ENOTDIR:
 40                 return UBUS_STATUS_INVALID_ARGUMENT;
 41 
 42         case ENOENT:
 43                 return UBUS_STATUS_NOT_FOUND;
 44 
 45         case EINVAL:
 46                 return UBUS_STATUS_INVALID_ARGUMENT;
 47 
 48         default:
 49                 return UBUS_STATUS_UNKNOWN_ERROR;
 50         }
 51 }
 52 
 53 const char *
 54 rpc_exec_lookup(const char *cmd)
 55 {
 56         struct stat s;
 57         int plen = 0, clen = strlen(cmd) + 1;
 58         char *search, *p;
 59         static char path[PATH_MAX];
 60 
 61         if (!stat(cmd, &s) && S_ISREG(s.st_mode))
 62                 return cmd;
 63 
 64         search = getenv("PATH");
 65 
 66         if (!search)
 67                 search = "/bin:/usr/bin:/sbin:/usr/sbin";
 68 
 69         p = search;
 70 
 71         do
 72         {
 73                 if (*p != ':' && *p != '\0')
 74                         continue;
 75 
 76                 plen = p - search;
 77 
 78                 if ((plen + clen) >= sizeof(path))
 79                         continue;
 80 
 81                 strncpy(path, search, plen);
 82                 sprintf(path + plen, "/%s", cmd);
 83 
 84                 if (!stat(path, &s) && S_ISREG(s.st_mode))
 85                         return path;
 86 
 87                 search = p + 1;
 88         }
 89         while (*p++);
 90 
 91         return NULL;
 92 }
 93 
 94 
 95 static void
 96 rpc_ustream_to_blobmsg(struct blob_buf *blob, struct ustream *s,
 97                        const char *name)
 98 {
 99         int len;
100         char *rbuf, *wbuf;
101 
102         if ((len = ustream_pending_data(s, false)) > 0)
103         {
104                 wbuf = blobmsg_alloc_string_buffer(blob, name, len + 1);
105 
106                 if (!wbuf)
107                         return;
108 
109                 ustream_for_each_read_buffer(s, rbuf, len)
110                 {
111                         memcpy(wbuf, rbuf, len);
112                         wbuf += len;
113                 }
114 
115                 *wbuf = 0;
116                 blobmsg_add_string_buffer(blob);
117         }
118 }
119 
120 static void
121 rpc_exec_reply(struct rpc_exec_context *c, int rv)
122 {
123         uloop_timeout_cancel(&c->timeout);
124         uloop_process_delete(&c->process);
125 
126         if (rv == UBUS_STATUS_OK)
127         {
128                 if (!c->stdout_cb && !c->stderr_cb && !c->finish_cb)
129                 {
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");
133                 }
134         }
135 
136         if (c->finish_cb)
137                 rv = c->finish_cb(&c->blob, c->stat, c->priv);
138 
139         if (rv == UBUS_STATUS_OK)
140                 ubus_send_reply(c->context, &c->request, c->blob.head);
141 
142         ubus_complete_deferred_request(c->context, &c->request, rv);
143 
144         blob_buf_free(&c->blob);
145 
146         ustream_free(&c->opipe.stream);
147         ustream_free(&c->epipe.stream);
148 
149         close(c->opipe.fd.fd);
150         close(c->epipe.fd.fd);
151 
152         if (c->priv)
153                 free(c->priv);
154 
155         free(c);
156 }
157 
158 static void
159 rpc_exec_reply_cb(struct uloop_timeout *t)
160 {
161         struct rpc_exec_context *c =
162                 container_of(t, struct rpc_exec_context, timeout);
163 
164         rpc_exec_reply(c, c->deferred_status);
165 }
166 
167 static void
168 rpc_exec_schedule_reply(struct rpc_exec_context *c, int rv)
169 {
170         c->deferred_status = rv;
171         c->timeout.cb = rpc_exec_reply_cb;
172         uloop_timeout_set(&c->timeout, 0);
173 }
174 
175 static void
176 rpc_exec_timeout_cb(struct uloop_timeout *t)
177 {
178         struct rpc_exec_context *c =
179                 container_of(t, struct rpc_exec_context, timeout);
180 
181         kill(c->process.pid, SIGKILL);
182         rpc_exec_schedule_reply(c, UBUS_STATUS_TIMEOUT);
183 }
184 
185 static void
186 rpc_exec_process_cb(struct uloop_process *p, int stat)
187 {
188         struct rpc_exec_context *c =
189                 container_of(p, struct rpc_exec_context, process);
190 
191         c->stat = stat;
192 
193         ustream_poll(&c->opipe.stream);
194         ustream_poll(&c->epipe.stream);
195 
196         close(c->opipe.fd.fd);
197         close(c->epipe.fd.fd);
198 
199         /* ustream_free() does not reset the fd, and rpc_exec_reply() closes it
200          * again later.  Mark the descriptors as consumed so that the second
201          * close() cannot accidentally close an unrelated, meanwhile reused fd. */
202         c->opipe.fd.fd = -1;
203         c->epipe.fd.fd = -1;
204 
205         ustream_poll(&c->opipe.stream);
206         ustream_poll(&c->epipe.stream);
207 }
208 
209 static void
210 rpc_exec_ipipe_write_cb(struct ustream *s, int bytes)
211 {
212         struct rpc_exec_context *c =
213                 container_of(s, struct rpc_exec_context, ipipe.stream);
214 
215         if (c->stdin_cb(s, c->priv) <= 0)
216         {
217                 ustream_free(&c->ipipe.stream);
218                 close(c->ipipe.fd.fd);
219         }
220 }
221 
222 static void
223 rpc_exec_opipe_read_cb(struct ustream *s, int bytes)
224 {
225         int len, rv;
226         char *buf;
227         struct rpc_exec_context *c =
228                 container_of(s, struct rpc_exec_context, opipe.stream);
229 
230         if (c->stdout_cb)
231         {
232                 do {
233                         buf = ustream_get_read_buf(s, &len);
234 
235                         if (!buf || !len)
236                                 break;
237 
238                         rv = c->stdout_cb(&c->blob, buf, len, c->priv);
239 
240                         if (rv <= 0)
241                                 break;
242 
243                         ustream_consume(s, rv);
244                 } while(1);
245         }
246         else if (ustream_read_buf_full(s))
247         {
248                 rpc_exec_schedule_reply(c, UBUS_STATUS_NOT_SUPPORTED);
249         }
250 }
251 
252 static void
253 rpc_exec_epipe_read_cb(struct ustream *s, int bytes)
254 {
255         int len, rv;
256         char *buf;
257         struct rpc_exec_context *c =
258                 container_of(s, struct rpc_exec_context, epipe.stream);
259 
260         if (c->stderr_cb)
261         {
262                 do {
263                         buf = ustream_get_read_buf(s, &len);
264 
265                         if (!buf || !len)
266                                 break;
267 
268                         rv = c->stderr_cb(&c->blob, buf, len, c->priv);
269 
270                         if (rv <= 0)
271                                 break;
272 
273                         ustream_consume(s, rv);
274                 } while(1);
275         }
276         else if (ustream_read_buf_full(s))
277         {
278                 rpc_exec_schedule_reply(c, UBUS_STATUS_NOT_SUPPORTED);
279         }
280 }
281 
282 static void
283 rpc_exec_opipe_state_cb(struct ustream *s)
284 {
285         struct rpc_exec_context *c =
286                 container_of(s, struct rpc_exec_context, opipe.stream);
287 
288         if (c->opipe.stream.eof && c->epipe.stream.eof)
289                 rpc_exec_schedule_reply(c, UBUS_STATUS_OK);
290 }
291 
292 static void
293 rpc_exec_epipe_state_cb(struct ustream *s)
294 {
295         struct rpc_exec_context *c =
296                 container_of(s, struct rpc_exec_context, epipe.stream);
297 
298         if (c->opipe.stream.eof && c->epipe.stream.eof)
299                 rpc_exec_schedule_reply(c, UBUS_STATUS_OK);
300 }
301 
302 int
303 rpc_exec(const char **args, rpc_exec_write_cb_t in,
304          rpc_exec_read_cb_t out, rpc_exec_read_cb_t err,
305          rpc_exec_done_cb_t end, void *priv, struct ubus_context *ctx,
306          struct ubus_request_data *req)
307 {
308         pid_t pid;
309 
310         int ipipe[2];
311         int opipe[2];
312         int epipe[2];
313 
314         const char *cmd;
315         struct rpc_exec_context *c;
316 
317         cmd = rpc_exec_lookup(args[0]);
318 
319         if (!cmd)
320                 return UBUS_STATUS_NOT_FOUND;
321 
322         c = malloc(sizeof(*c));
323 
324         if (!c)
325                 return UBUS_STATUS_UNKNOWN_ERROR;
326 
327         if (pipe(ipipe))
328                 goto fail_ipipe;
329 
330         if (pipe(opipe))
331                 goto fail_opipe;
332 
333         if (pipe(epipe))
334                 goto fail_epipe;
335 
336         switch ((pid = fork()))
337         {
338         case -1:
339                 goto fail_fork;
340 
341         case 0:
342                 uloop_done();
343 
344                 dup2(ipipe[0], 0);
345                 dup2(opipe[1], 1);
346                 dup2(epipe[1], 2);
347 
348                 close(ipipe[0]);
349                 close(ipipe[1]);
350                 close(opipe[0]);
351                 close(opipe[1]);
352                 close(epipe[0]);
353                 close(epipe[1]);
354 
355                 if (execv(cmd, (char * const *)args))
356                         _exit(127);
357 
358         default:
359                 memset(c, 0, sizeof(*c));
360                 blob_buf_init(&c->blob, 0);
361 
362                 c->stdin_cb  = in;
363                 c->stdout_cb = out;
364                 c->stderr_cb = err;
365                 c->finish_cb = end;
366                 c->priv      = priv;
367 
368                 ustream_declare_read(c->opipe, opipe[0], opipe);
369                 ustream_declare_read(c->epipe, epipe[0], epipe);
370 
371                 c->process.pid = pid;
372                 c->process.cb = rpc_exec_process_cb;
373                 uloop_process_add(&c->process);
374 
375                 c->timeout.cb = rpc_exec_timeout_cb;
376                 uloop_timeout_set(&c->timeout, rpc_exec_timeout);
377 
378                 if (c->stdin_cb)
379                 {
380                         ustream_declare_write(c->ipipe, ipipe[1], ipipe);
381                         rpc_exec_ipipe_write_cb(&c->ipipe.stream, 0);
382                 }
383                 else
384                 {
385                         close(ipipe[1]);
386                 }
387 
388                 close(ipipe[0]);
389                 close(opipe[1]);
390                 close(epipe[1]);
391 
392                 c->context = ctx;
393                 ubus_defer_request(ctx, req, &c->request);
394         }
395 
396         return UBUS_STATUS_OK;
397 
398 fail_fork:
399         close(epipe[0]);
400         close(epipe[1]);
401 
402 fail_epipe:
403         close(opipe[0]);
404         close(opipe[1]);
405 
406 fail_opipe:
407         close(ipipe[0]);
408         close(ipipe[1]);
409 
410 fail_ipipe:
411         free(c);
412         return rpc_errno_status();
413 }
414 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt