iwinfo: zero out ccode buffer since library doesn't
[project/rpcd.git] / 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                 if (c->finish_cb)
136                         rv = c->finish_cb(&c->blob, c->stat, c->priv);
137
138                 if (rv == UBUS_STATUS_OK)
139                         ubus_send_reply(c->context, &c->request, c->blob.head);
140         }
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_timeout_cb(struct uloop_timeout *t)
160 {
161         struct rpc_exec_context *c =
162                 container_of(t, struct rpc_exec_context, timeout);
163
164         kill(c->process.pid, SIGKILL);
165         rpc_exec_reply(c, UBUS_STATUS_TIMEOUT);
166 }
167
168 static void
169 rpc_exec_process_cb(struct uloop_process *p, int stat)
170 {
171         struct rpc_exec_context *c =
172                 container_of(p, struct rpc_exec_context, process);
173
174         c->stat = stat;
175
176         ustream_poll(&c->opipe.stream);
177         ustream_poll(&c->epipe.stream);
178 }
179
180 static void
181 rpc_exec_ipipe_write_cb(struct ustream *s, int bytes)
182 {
183         struct rpc_exec_context *c =
184                 container_of(s, struct rpc_exec_context, ipipe.stream);
185
186         if (c->stdin_cb(s, c->priv) <= 0)
187         {
188                 ustream_free(&c->ipipe.stream);
189                 close(c->ipipe.fd.fd);
190         }
191 }
192
193 static void
194 rpc_exec_opipe_read_cb(struct ustream *s, int bytes)
195 {
196         int len, rv;
197         char *buf;
198         struct rpc_exec_context *c =
199                 container_of(s, struct rpc_exec_context, opipe.stream);
200
201         if (c->stdout_cb)
202         {
203                 do {
204                         buf = ustream_get_read_buf(s, &len);
205
206                         if (!buf || !len)
207                                 break;
208
209                         rv = c->stdout_cb(&c->blob, buf, len, c->priv);
210
211                         if (rv <= 0)
212                                 break;
213
214                         ustream_consume(s, rv);
215                 } while(1);
216         }
217         else if (ustream_read_buf_full(s))
218         {
219                 rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
220         }
221 }
222
223 static void
224 rpc_exec_epipe_read_cb(struct ustream *s, int bytes)
225 {
226         int len, rv;
227         char *buf;
228         struct rpc_exec_context *c =
229                 container_of(s, struct rpc_exec_context, epipe.stream);
230
231         if (c->stderr_cb)
232         {
233                 do {
234                         buf = ustream_get_read_buf(s, &len);
235
236                         if (!buf || !len)
237                                 break;
238
239                         rv = c->stderr_cb(&c->blob, buf, len, c->priv);
240
241                         if (rv <= 0)
242                                 break;
243
244                         ustream_consume(s, rv);
245                 } while(1);
246         }
247         else if (ustream_read_buf_full(s))
248         {
249                 rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
250         }
251 }
252
253 static void
254 rpc_exec_opipe_state_cb(struct ustream *s)
255 {
256         struct rpc_exec_context *c =
257                 container_of(s, struct rpc_exec_context, opipe.stream);
258
259         if (c->opipe.stream.eof && c->epipe.stream.eof)
260                 rpc_exec_reply(c, UBUS_STATUS_OK);
261 }
262
263 static void
264 rpc_exec_epipe_state_cb(struct ustream *s)
265 {
266         struct rpc_exec_context *c =
267                 container_of(s, struct rpc_exec_context, epipe.stream);
268
269         if (c->opipe.stream.eof && c->epipe.stream.eof)
270                 rpc_exec_reply(c, UBUS_STATUS_OK);
271 }
272
273 int
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)
278 {
279         pid_t pid;
280
281         int ipipe[2];
282         int opipe[2];
283         int epipe[2];
284
285         const char *cmd;
286         struct rpc_exec_context *c;
287
288         cmd = rpc_exec_lookup(args[0]);
289
290         if (!cmd)
291                 return UBUS_STATUS_NOT_FOUND;
292
293         c = malloc(sizeof(*c));
294
295         if (!c)
296                 return UBUS_STATUS_UNKNOWN_ERROR;
297
298         if (pipe(ipipe))
299                 goto fail_ipipe;
300
301         if (pipe(opipe))
302                 goto fail_opipe;
303
304         if (pipe(epipe))
305                 goto fail_epipe;
306
307         switch ((pid = fork()))
308         {
309         case -1:
310                 return rpc_errno_status();
311
312         case 0:
313                 uloop_done();
314
315                 dup2(ipipe[0], 0);
316                 dup2(opipe[1], 1);
317                 dup2(epipe[1], 2);
318
319                 close(ipipe[0]);
320                 close(ipipe[1]);
321                 close(opipe[0]);
322                 close(opipe[1]);
323                 close(epipe[0]);
324                 close(epipe[1]);
325
326                 if (execv(cmd, (char * const *)args))
327                         return rpc_errno_status();
328
329         default:
330                 memset(c, 0, sizeof(*c));
331                 blob_buf_init(&c->blob, 0);
332
333                 c->stdin_cb  = in;
334                 c->stdout_cb = out;
335                 c->stderr_cb = err;
336                 c->finish_cb = end;
337                 c->priv      = priv;
338
339                 ustream_declare_read(c->opipe, opipe[0], opipe);
340                 ustream_declare_read(c->epipe, epipe[0], epipe);
341
342                 c->process.pid = pid;
343                 c->process.cb = rpc_exec_process_cb;
344                 uloop_process_add(&c->process);
345
346                 c->timeout.cb = rpc_exec_timeout_cb;
347                 uloop_timeout_set(&c->timeout, RPC_EXEC_MAX_RUNTIME);
348
349                 if (c->stdin_cb)
350                 {
351                         ustream_declare_write(c->ipipe, ipipe[1], ipipe);
352                         rpc_exec_ipipe_write_cb(&c->ipipe.stream, 0);
353                 }
354                 else
355                 {
356                         close(ipipe[1]);
357                 }
358
359                 close(ipipe[0]);
360                 close(opipe[1]);
361                 close(epipe[1]);
362
363                 c->context = ctx;
364                 ubus_defer_request(ctx, req, &c->request);
365         }
366
367         return UBUS_STATUS_OK;
368
369 fail_epipe:
370         close(opipe[0]);
371         close(opipe[1]);
372
373 fail_opipe:
374         close(ipipe[0]);
375         close(ipipe[1]);
376
377 fail_ipipe:
378         return rpc_errno_status();
379 }