ctdb-tests: Strengthen some tests
[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
31 #include "common/db_hash.h"
32 #include "common/run_proc.h"
33
34 /*
35  * Process abstraction
36  */
37
38 struct proc_context {
39         pid_t pid;
40
41         int fd;
42         struct tevent_fd *fde;
43
44         char *output;
45         struct run_proc_result result;
46
47         struct tevent_req *req;
48 };
49
50 static struct proc_context *proc_new(TALLOC_CTX *mem_ctx)
51 {
52         struct proc_context *proc;
53
54         proc = talloc_zero(mem_ctx, struct proc_context);
55         if (proc == NULL) {
56                 return NULL;
57         }
58
59         proc->pid = -1;
60         proc->fd = -1;
61
62         return proc;
63 }
64
65 static void proc_read_handler(struct tevent_context *ev,
66                               struct tevent_fd *fde, uint16_t flags,
67                               void *private_data);
68
69 static int proc_start(struct proc_context *proc, struct tevent_context *ev,
70                       const char *path, const char **argv, int stdin_fd)
71 {
72         int fd[2];
73         int ret;
74
75         ret = pipe(fd);
76         if (ret != 0) {
77                 return ret;
78         }
79
80         proc->pid = fork();
81         if (proc->pid == -1) {
82                 ret = errno;
83                 close(fd[0]);
84                 close(fd[1]);
85                 return ret;
86         }
87
88         if (proc->pid == 0) {
89                 close(fd[0]);
90
91                 ret = dup2(fd[1], STDOUT_FILENO);
92                 if (ret == -1) {
93                         exit(64 + errno);
94                 }
95                 ret = dup2(fd[1], STDERR_FILENO);
96                 if (ret == -1) {
97                         exit(64 + errno);
98                 }
99
100                 close(fd[1]);
101
102                 if (stdin_fd != -1) {
103                         ret = dup2(stdin_fd, STDIN_FILENO);
104                         if (ret == -1) {
105                                 exit(64 + errno);
106                         }
107                 }
108
109                 ret = setpgid(0, 0);
110                 if (ret != 0) {
111                         exit(64 + errno);
112                 }
113
114                 ret = execv(path, discard_const(argv));
115                 if (ret != 0) {
116                         exit(64 + errno);
117                 }
118
119                 exit(64 + ENOEXEC);
120         }
121
122         close(fd[1]);
123
124         proc->fd = fd[0];
125         proc->fde = tevent_add_fd(ev, proc, fd[0], TEVENT_FD_READ,
126                                   proc_read_handler, proc);
127         if (proc->fde == NULL) {
128                 return ENOMEM;
129         }
130
131         tevent_fd_set_auto_close(proc->fde);
132
133         return 0;
134 }
135
136 static void proc_read_handler(struct tevent_context *ev,
137                               struct tevent_fd *fde, uint16_t flags,
138                               void *private_data)
139 {
140         struct proc_context *proc = talloc_get_type_abort(
141                 private_data, struct proc_context);
142         size_t offset;
143         ssize_t nread;
144         int len = 0;
145         int ret;
146
147         ret = ioctl(proc->fd, FIONREAD, &len);
148         if (ret != 0) {
149                 goto fail;
150         }
151
152         if (len == 0) {
153                 /* pipe closed */
154                 goto close;
155         }
156
157         offset = (proc->output == NULL) ? 0 : strlen(proc->output);
158
159         proc->output = talloc_realloc(proc, proc->output, char, offset+len+1);
160         if (proc->output == NULL) {
161                 goto fail;
162         }
163
164         nread = sys_read(proc->fd, proc->output + offset, len);
165         if (nread == -1) {
166                 goto fail;
167         }
168         proc->output[offset+nread] = '\0';
169         return;
170
171 fail:
172         kill(-proc->pid, SIGKILL);
173 close:
174         TALLOC_FREE(proc->fde);
175         proc->fd = -1;
176 }
177
178 /*
179  * Processes database
180  */
181
182 static int proc_db_init(TALLOC_CTX *mem_ctx, struct db_hash_context **result)
183 {
184         struct db_hash_context *pdb = NULL;
185         int ret;
186
187         ret = db_hash_init(pdb, "proc_db", 1001, DB_HASH_COMPLEX, &pdb);
188         if (ret != 0) {
189                 return ret;
190         }
191
192         *result = pdb;
193         return 0;
194 }
195
196 static int proc_db_add(struct db_hash_context *pdb, pid_t pid,
197                        struct proc_context *proc)
198 {
199         return db_hash_insert(pdb, (uint8_t *)&pid, sizeof(pid_t),
200                               (uint8_t *)&proc, sizeof(struct proc_context *));
201 }
202
203 static int proc_db_remove(struct db_hash_context *pdb, pid_t pid)
204 {
205         return db_hash_delete(pdb, (uint8_t *)&pid, sizeof(pid_t));
206 }
207
208 static int proc_db_fetch_parser(uint8_t *keybuf, size_t keylen,
209                                 uint8_t *databuf, size_t datalen,
210                                 void *private_data)
211 {
212         struct proc_context **result = (struct proc_context **)private_data;
213
214         if (datalen != sizeof(struct proc_context *)) {
215                 return EINVAL;
216         }
217
218         *result = *(struct proc_context **)databuf;
219         return 0;
220 }
221
222 static int proc_db_fetch(struct db_hash_context *pdb, pid_t pid,
223                          struct proc_context **result)
224 {
225         return db_hash_fetch(pdb, (uint8_t *)&pid, sizeof(pid_t),
226                              proc_db_fetch_parser, result);
227 }
228
229 static int proc_db_killall_parser(uint8_t *keybuf, size_t keylen,
230                                   uint8_t *databuf, size_t datalen,
231                                   void *private_data)
232 {
233         struct db_hash_context *pdb = talloc_get_type_abort(
234                 private_data, struct db_hash_context);
235         struct proc_context *proc;
236         pid_t pid;
237
238         if (keylen != sizeof(pid_t) ||
239             datalen != sizeof(struct proc_context *)) {
240                 /* skip */
241                 return 0;
242         }
243
244         pid = *(pid_t *)keybuf;
245         proc = talloc_steal(pdb, *(struct proc_context **)databuf);
246
247         TALLOC_FREE(proc->req);
248         TALLOC_FREE(proc->fde);
249
250         kill(-pid, SIGKILL);
251         return 0;
252 }
253
254 static void proc_db_killall(struct db_hash_context *pdb)
255 {
256         (void) db_hash_traverse(pdb, proc_db_killall_parser, pdb, NULL);
257 }
258
259
260 /*
261  * Run proc abstraction
262  */
263
264 struct run_proc_context {
265         struct tevent_context *ev;
266         struct tevent_signal *se;
267         struct db_hash_context *pdb;
268 };
269
270 static void run_proc_signal_handler(struct tevent_context *ev,
271                                     struct tevent_signal *se,
272                                     int signum, int count, void *siginfo,
273                                     void *private_data);
274 static int run_proc_context_destructor(struct run_proc_context *run_ctx);
275 static void run_proc_done(struct tevent_req *req);
276
277 int run_proc_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
278                   struct run_proc_context **result)
279 {
280         struct run_proc_context *run_ctx;
281         int ret;
282
283         run_ctx = talloc_zero(mem_ctx, struct run_proc_context);
284         if (run_ctx == NULL) {
285                 return ENOMEM;
286         }
287
288         run_ctx->ev = ev;
289         run_ctx->se = tevent_add_signal(ev, run_ctx, SIGCHLD, 0,
290                                        run_proc_signal_handler, run_ctx);
291         if (run_ctx->se == NULL) {
292                 talloc_free(run_ctx);
293                 return ENOMEM;
294         }
295
296         ret = proc_db_init(run_ctx, &run_ctx->pdb);
297         if (ret != 0) {
298                 talloc_free(run_ctx);
299                 return ret;
300         }
301
302         talloc_set_destructor(run_ctx, run_proc_context_destructor);
303
304         *result = run_ctx;
305         return 0;
306 }
307
308 static void run_proc_signal_handler(struct tevent_context *ev,
309                                     struct tevent_signal *se,
310                                     int signum, int count, void *siginfo,
311                                     void *private_data)
312 {
313         struct run_proc_context *run_ctx = talloc_get_type_abort(
314                 private_data, struct run_proc_context);
315         struct proc_context *proc;
316         pid_t pid = -1;
317         int ret, status;
318
319 again:
320         pid = waitpid(-1, &status, WNOHANG);
321         if (pid == -1) {
322                 return;
323         }
324
325         if (pid == 0) {
326                 return;
327         }
328
329         ret = proc_db_fetch(run_ctx->pdb, pid, &proc);
330         if (ret != 0) {
331                 /* unknown process */
332                 return;
333         }
334
335         /* Mark the process as terminated */
336         proc->pid = -1;
337
338         /* Update process status */
339         if (WIFEXITED(status)) {
340                 int pstatus = WEXITSTATUS(status);
341                 if (WIFSIGNALED(status)) {
342                         proc->result.sig = WTERMSIG(status);
343                 } else if (pstatus >= 64 && pstatus < 255) {
344                         proc->result.err = pstatus-64;
345                 } else {
346                         proc->result.status = pstatus;
347                 }
348         } else if (WIFSIGNALED(status)) {
349                 proc->result.sig = WTERMSIG(status);
350         }
351
352         /* Active run_proc request */
353         if (proc->req != NULL) {
354                 run_proc_done(proc->req);
355         }
356
357         proc_db_remove(run_ctx->pdb, pid);
358         talloc_free(proc);
359
360         goto again;
361
362 }
363
364 static int run_proc_context_destructor(struct run_proc_context *run_ctx)
365 {
366         /* Get rid of signal handler */
367         TALLOC_FREE(run_ctx->se);
368
369         /* Kill any pending processes */
370         proc_db_killall(run_ctx->pdb);
371         TALLOC_FREE(run_ctx->pdb);
372
373         return 0;
374 }
375
376 struct run_proc_state {
377         struct tevent_context *ev;
378         struct proc_context *proc;
379
380         struct run_proc_result result;
381         char *output;
382         pid_t pid;
383 };
384
385 static int run_proc_state_destructor(struct run_proc_state *state);
386 static void run_proc_timedout(struct tevent_req *subreq);
387
388 struct tevent_req *run_proc_send(TALLOC_CTX *mem_ctx,
389                                  struct tevent_context *ev,
390                                  struct run_proc_context *run_ctx,
391                                  const char *path, const char **argv,
392                                  int stdin_fd, struct timeval timeout)
393 {
394         struct tevent_req *req;
395         struct run_proc_state *state;
396         struct stat st;
397         int ret;
398
399         req = tevent_req_create(mem_ctx, &state, struct run_proc_state);
400         if (req == NULL) {
401                 return NULL;
402         }
403
404         state->ev = ev;
405         state->pid = -1;
406
407         ret = stat(path, &st);
408         if (ret != 0) {
409                 state->result.err = errno;
410                 tevent_req_done(req);
411                 return tevent_req_post(req, ev);
412         }
413
414         if (! (st.st_mode & S_IXUSR)) {
415                 state->result.err = EACCES;
416                 tevent_req_done(req);
417                 return tevent_req_post(req, ev);
418         }
419
420         state->proc = proc_new(run_ctx);
421         if (tevent_req_nomem(state->proc, req)) {
422                 return tevent_req_post(req, ev);
423         }
424
425         ret = proc_start(state->proc, ev, path, argv, stdin_fd);
426         if (ret != 0) {
427                 tevent_req_error(req, ret);
428                 return tevent_req_post(req, ev);
429         }
430
431         state->proc->req = req;
432         talloc_set_destructor(state, run_proc_state_destructor);
433
434         ret = proc_db_add(run_ctx->pdb, state->proc->pid, state->proc);
435         if (ret != 0) {
436                 tevent_req_error(req, ret);
437                 return tevent_req_post(req, ev);
438         }
439
440         if (! tevent_timeval_is_zero(&timeout)) {
441                 struct tevent_req *subreq;
442
443                 subreq = tevent_wakeup_send(state, ev, timeout);
444                 if (tevent_req_nomem(subreq, req)) {
445                         return tevent_req_post(req, ev);
446                 }
447                 tevent_req_set_callback(subreq, run_proc_timedout, req);
448         }
449
450         return req;
451 }
452
453 static int run_proc_state_destructor(struct run_proc_state *state)
454 {
455         /* Do not get rid of the child process if timeout has occurred */
456         if (state->proc->req != NULL) {
457                 state->proc->req = NULL;
458                 if (state->proc->pid != -1) {
459                         kill(-state->proc->pid, SIGTERM);
460                 }
461         }
462
463         return 0;
464 }
465
466 static void run_proc_done(struct tevent_req *req)
467 {
468         struct run_proc_state *state = tevent_req_data(
469                 req, struct run_proc_state);
470
471         state->proc->req = NULL;
472
473         state->result = state->proc->result;
474         if (state->proc->output != NULL) {
475                 state->output = talloc_steal(state, state->proc->output);
476         }
477
478         tevent_req_done(req);
479 }
480
481 static void run_proc_timedout(struct tevent_req *subreq)
482 {
483         struct tevent_req *req = tevent_req_callback_data(
484                 subreq, struct tevent_req);
485         struct run_proc_state *state = tevent_req_data(
486                 req, struct run_proc_state);
487         bool status;
488
489         state->proc->req = NULL;
490
491         status = tevent_wakeup_recv(subreq);
492         TALLOC_FREE(subreq);
493         if (! status) {
494                 tevent_req_error(req, EIO);
495                 return;
496         }
497
498         state->result.err = ETIME;
499         if (state->proc->output != NULL) {
500                 state->output = talloc_steal(state, state->proc->output);
501         }
502         state->pid = state->proc->pid;
503
504         tevent_req_done(req);
505 }
506
507 bool run_proc_recv(struct tevent_req *req, int *perr,
508                    struct run_proc_result *result, pid_t *pid,
509                    TALLOC_CTX *mem_ctx, char **output)
510 {
511         struct run_proc_state *state = tevent_req_data(
512                 req, struct run_proc_state);
513         int ret;
514
515         if (tevent_req_is_unix_error(req, &ret)) {
516                 if (perr != NULL) {
517                         *perr = ret;
518                 }
519                 return false;
520         }
521
522         if (result != NULL) {
523                 *result = state->result;
524         }
525
526         if (pid != NULL) {
527                 *pid = state->pid;
528         }
529
530         if (output != NULL) {
531                 *output = talloc_steal(mem_ctx, state->output);
532         }
533
534         return true;
535 }