ctdb-common: Fix memory leak in run_proc
[amitay/samba.git] / ctdb / common / run_proc.c
1 /*
2    Run a child process and collect the output
3
4    Copyright (C) Amitay Isaacs  2016
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/wait.h"
23
24 #include <talloc.h>
25 #include <tevent.h>
26
27 #include "lib/util/tevent_unix.h"
28 #include "lib/util/sys_rw.h"
29 #include "lib/util/blocking.h"
30 #include "lib/util/dlinklist.h"
31
32 #include "common/run_proc.h"
33
34 /*
35  * Process abstraction
36  */
37
38 struct run_proc_context;
39
40 struct proc_context {
41         struct proc_context *prev, *next;
42
43         pid_t pid;
44
45         int fd;
46         struct tevent_fd *fde;
47
48         char *output;
49         struct run_proc_result result;
50
51         struct tevent_req *req;
52 };
53
54 static int proc_destructor(struct proc_context *proc);
55
56 static struct proc_context *proc_new(TALLOC_CTX *mem_ctx,
57                                      struct run_proc_context *run_ctx)
58 {
59         struct proc_context *proc;
60
61         proc = talloc_zero(mem_ctx, struct proc_context);
62         if (proc == NULL) {
63                 return NULL;
64         }
65
66         proc->pid = -1;
67         proc->fd = -1;
68
69         talloc_set_destructor(proc, proc_destructor);
70
71         return proc;
72 }
73
74 static void run_proc_kill(struct tevent_req *req);
75
76 static int proc_destructor(struct proc_context *proc)
77 {
78         if (proc->req != NULL) {
79                 run_proc_kill(proc->req);
80         }
81
82         talloc_free(proc->fde);
83         if (proc->pid != -1) {
84                 kill(-proc->pid, SIGKILL);
85         }
86
87         return 0;
88 }
89
90 static void proc_read_handler(struct tevent_context *ev,
91                               struct tevent_fd *fde, uint16_t flags,
92                               void *private_data);
93
94 static int proc_start(struct proc_context *proc, struct tevent_context *ev,
95                       const char *path, const char **argv, int stdin_fd)
96 {
97         int fd[2];
98         int ret;
99
100         ret = pipe(fd);
101         if (ret != 0) {
102                 return ret;
103         }
104
105         proc->pid = fork();
106         if (proc->pid == -1) {
107                 ret = errno;
108                 close(fd[0]);
109                 close(fd[1]);
110                 return ret;
111         }
112
113         if (proc->pid == 0) {
114                 close(fd[0]);
115
116                 ret = dup2(fd[1], STDOUT_FILENO);
117                 if (ret == -1) {
118                         exit(64 + errno);
119                 }
120                 ret = dup2(fd[1], STDERR_FILENO);
121                 if (ret == -1) {
122                         exit(64 + errno);
123                 }
124
125                 close(fd[1]);
126
127                 if (stdin_fd != -1) {
128                         ret = dup2(stdin_fd, STDIN_FILENO);
129                         if (ret == -1) {
130                                 exit(64 + errno);
131                         }
132                 }
133
134                 ret = setpgid(0, 0);
135                 if (ret != 0) {
136                         exit(64 + errno);
137                 }
138
139                 ret = execv(path, discard_const(argv));
140                 if (ret != 0) {
141                         exit(64 + errno);
142                 }
143
144                 exit(64 + ENOEXEC);
145         }
146
147         close(fd[1]);
148
149         proc->fd = fd[0];
150         proc->fde = tevent_add_fd(ev, proc, fd[0], TEVENT_FD_READ,
151                                   proc_read_handler, proc);
152         if (proc->fde == NULL) {
153                 close(fd[0]);
154                 return ENOMEM;
155         }
156
157         tevent_fd_set_auto_close(proc->fde);
158
159         return 0;
160 }
161
162 static void proc_read_handler(struct tevent_context *ev,
163                               struct tevent_fd *fde, uint16_t flags,
164                               void *private_data)
165 {
166         struct proc_context *proc = talloc_get_type_abort(
167                 private_data, struct proc_context);
168         size_t offset;
169         ssize_t nread;
170         int len = 0;
171         int ret;
172
173         ret = ioctl(proc->fd, FIONREAD, &len);
174         if (ret != 0) {
175                 goto fail;
176         }
177
178         if (len == 0) {
179                 /* pipe closed */
180                 goto close;
181         }
182
183         offset = (proc->output == NULL) ? 0 : strlen(proc->output);
184
185         proc->output = talloc_realloc(proc, proc->output, char, offset+len+1);
186         if (proc->output == NULL) {
187                 goto fail;
188         }
189
190         nread = sys_read(proc->fd, proc->output + offset, len);
191         if (nread == -1) {
192                 goto fail;
193         }
194         proc->output[offset+nread] = '\0';
195         return;
196
197 fail:
198         if (proc->pid != -1) {
199                 kill(-proc->pid, SIGKILL);
200                 proc->pid = -1;
201         }
202 close:
203         TALLOC_FREE(proc->fde);
204         proc->fd = -1;
205 }
206
207
208 /*
209  * Run proc abstraction
210  */
211
212 struct run_proc_context {
213         struct tevent_context *ev;
214         struct tevent_signal *se;
215         struct proc_context *plist;
216 };
217
218 static void run_proc_signal_handler(struct tevent_context *ev,
219                                     struct tevent_signal *se,
220                                     int signum, int count, void *siginfo,
221                                     void *private_data);
222 static int run_proc_context_destructor(struct run_proc_context *run_ctx);
223 static void run_proc_done(struct tevent_req *req);
224
225 int run_proc_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
226                   struct run_proc_context **result)
227 {
228         struct run_proc_context *run_ctx;
229
230         run_ctx = talloc_zero(mem_ctx, struct run_proc_context);
231         if (run_ctx == NULL) {
232                 return ENOMEM;
233         }
234
235         run_ctx->ev = ev;
236         run_ctx->se = tevent_add_signal(ev, run_ctx, SIGCHLD, 0,
237                                        run_proc_signal_handler, run_ctx);
238         if (run_ctx->se == NULL) {
239                 talloc_free(run_ctx);
240                 return ENOMEM;
241         }
242
243         talloc_set_destructor(run_ctx, run_proc_context_destructor);
244
245         *result = run_ctx;
246         return 0;
247 }
248
249 static void run_proc_signal_handler(struct tevent_context *ev,
250                                     struct tevent_signal *se,
251                                     int signum, int count, void *siginfo,
252                                     void *private_data)
253 {
254         struct run_proc_context *run_ctx = talloc_get_type_abort(
255                 private_data, struct run_proc_context);
256         struct proc_context *proc;
257         pid_t pid = -1;
258         int status;
259
260 again:
261         pid = waitpid(-1, &status, WNOHANG);
262         if (pid == -1) {
263                 return;
264         }
265
266         if (pid == 0) {
267                 return;
268         }
269
270         for (proc = run_ctx->plist; proc != NULL; proc = proc->next) {
271                 if (proc->pid == pid) {
272                         break;
273                 }
274         }
275
276         if (proc == NULL) {
277                 /* unknown process */
278                 goto again;
279         }
280
281         /* Mark the process as terminated */
282         proc->pid = -1;
283
284         /* Update process status */
285         if (WIFEXITED(status)) {
286                 int pstatus = WEXITSTATUS(status);
287                 if (WIFSIGNALED(status)) {
288                         proc->result.sig = WTERMSIG(status);
289                 } else if (pstatus >= 64 && pstatus < 255) {
290                         proc->result.err = pstatus-64;
291                 } else {
292                         proc->result.status = pstatus;
293                 }
294         } else if (WIFSIGNALED(status)) {
295                 proc->result.sig = WTERMSIG(status);
296         }
297
298         /* Confirm that all data has been read from the pipe */
299         if (proc->fd != -1) {
300                 proc_read_handler(ev, proc->fde, 0, proc);
301                 TALLOC_FREE(proc->fde);
302                 proc->fd = -1;
303         }
304
305         DLIST_REMOVE(run_ctx->plist, proc);
306
307         /* Active run_proc request */
308         if (proc->req != NULL) {
309                 run_proc_done(proc->req);
310         } else {
311                 talloc_free(proc);
312         }
313
314         goto again;
315 }
316
317 static int run_proc_context_destructor(struct run_proc_context *run_ctx)
318 {
319         struct proc_context *proc;
320
321         /* Get rid of signal handler */
322         TALLOC_FREE(run_ctx->se);
323
324         /* Kill any pending processes */
325         while ((proc = run_ctx->plist) != NULL) {
326                 DLIST_REMOVE(run_ctx->plist, proc);
327                 talloc_free(proc);
328         }
329
330         return 0;
331 }
332
333 struct run_proc_state {
334         struct tevent_context *ev;
335         struct run_proc_context *run_ctx;
336         struct proc_context *proc;
337
338         struct run_proc_result result;
339         char *output;
340         pid_t pid;
341 };
342
343 static int run_proc_state_destructor(struct run_proc_state *state);
344 static void run_proc_timedout(struct tevent_req *subreq);
345
346 struct tevent_req *run_proc_send(TALLOC_CTX *mem_ctx,
347                                  struct tevent_context *ev,
348                                  struct run_proc_context *run_ctx,
349                                  const char *path, const char **argv,
350                                  int stdin_fd, struct timeval timeout)
351 {
352         struct tevent_req *req;
353         struct run_proc_state *state;
354         struct stat st;
355         int ret;
356
357         req = tevent_req_create(mem_ctx, &state, struct run_proc_state);
358         if (req == NULL) {
359                 return NULL;
360         }
361
362         state->ev = ev;
363         state->run_ctx = run_ctx;
364         state->pid = -1;
365
366         ret = stat(path, &st);
367         if (ret != 0) {
368                 state->result.err = errno;
369                 tevent_req_done(req);
370                 return tevent_req_post(req, ev);
371         }
372
373         if (! (st.st_mode & S_IXUSR)) {
374                 state->result.err = EACCES;
375                 tevent_req_done(req);
376                 return tevent_req_post(req, ev);
377         }
378
379         state->proc = proc_new(run_ctx, run_ctx);
380         if (tevent_req_nomem(state->proc, req)) {
381                 return tevent_req_post(req, ev);
382         }
383
384         state->proc->req = req;
385         DLIST_ADD(run_ctx->plist, state->proc);
386
387         ret = proc_start(state->proc, ev, path, argv, stdin_fd);
388         if (ret != 0) {
389                 tevent_req_error(req, ret);
390                 return tevent_req_post(req, ev);
391         }
392
393         talloc_set_destructor(state, run_proc_state_destructor);
394
395         if (! tevent_timeval_is_zero(&timeout)) {
396                 struct tevent_req *subreq;
397
398                 subreq = tevent_wakeup_send(state, ev, timeout);
399                 if (tevent_req_nomem(subreq, req)) {
400                         return tevent_req_post(req, ev);
401                 }
402                 tevent_req_set_callback(subreq, run_proc_timedout, req);
403         }
404
405         return req;
406 }
407
408 static int run_proc_state_destructor(struct run_proc_state *state)
409 {
410         /* Do not get rid of the child process if timeout has occurred */
411         if (state->proc->req != NULL) {
412                 state->proc->req = NULL;
413                 DLIST_REMOVE(state->run_ctx->plist, state->proc);
414                 talloc_free(state->proc);
415         }
416
417         return 0;
418 }
419
420 static void run_proc_done(struct tevent_req *req)
421 {
422         struct run_proc_state *state = tevent_req_data(
423                 req, struct run_proc_state);
424
425         state->proc->req = NULL;
426
427         state->result = state->proc->result;
428         if (state->proc->output != NULL) {
429                 state->output = talloc_steal(state, state->proc->output);
430         }
431         talloc_steal(state, state->proc);
432
433         tevent_req_done(req);
434 }
435
436 static void run_proc_kill(struct tevent_req *req)
437 {
438         struct run_proc_state *state = tevent_req_data(
439                 req, struct run_proc_state);
440
441         state->proc->req = NULL;
442
443         state->result.sig = SIGKILL;
444
445         tevent_req_done(req);
446 }
447
448 static void run_proc_timedout(struct tevent_req *subreq)
449 {
450         struct tevent_req *req = tevent_req_callback_data(
451                 subreq, struct tevent_req);
452         struct run_proc_state *state = tevent_req_data(
453                 req, struct run_proc_state);
454         bool status;
455
456         state->proc->req = NULL;
457
458         status = tevent_wakeup_recv(subreq);
459         TALLOC_FREE(subreq);
460         if (! status) {
461                 tevent_req_error(req, EIO);
462                 return;
463         }
464
465         state->result.err = ETIMEDOUT;
466         if (state->proc->output != NULL) {
467                 state->output = talloc_steal(state, state->proc->output);
468         }
469         state->pid = state->proc->pid;
470
471         tevent_req_done(req);
472 }
473
474 bool run_proc_recv(struct tevent_req *req, int *perr,
475                    struct run_proc_result *result, pid_t *pid,
476                    TALLOC_CTX *mem_ctx, char **output)
477 {
478         struct run_proc_state *state = tevent_req_data(
479                 req, struct run_proc_state);
480         int ret;
481
482         if (tevent_req_is_unix_error(req, &ret)) {
483                 if (perr != NULL) {
484                         *perr = ret;
485                 }
486                 return false;
487         }
488
489         if (result != NULL) {
490                 *result = state->result;
491         }
492
493         if (pid != NULL) {
494                 *pid = state->pid;
495         }
496
497         if (output != NULL) {
498                 *output = talloc_steal(mem_ctx, state->output);
499         }
500
501         return true;
502 }