s3:tests: Remove the non-working test_kerberos_upn_denied of smbget
[Samba.git] / ctdb / common / run_proc.c
blob84bc343ba1fffb76b9637e11886040d857df17a6
1 /*
2 Run a child process and collect the output
4 Copyright (C) Amitay Isaacs 2016
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.
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.
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/>.
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/wait.h"
24 #include <talloc.h>
25 #include <tevent.h>
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"
32 #include "common/run_proc.h"
35 * Process abstraction
38 struct run_proc_context;
40 struct proc_context {
41 struct proc_context *prev, *next;
43 pid_t pid;
45 int fd;
46 struct tevent_fd *fde;
48 char *output;
49 struct run_proc_result result;
51 struct tevent_req *req;
54 static int proc_destructor(struct proc_context *proc);
56 static struct proc_context *proc_new(TALLOC_CTX *mem_ctx,
57 struct run_proc_context *run_ctx)
59 struct proc_context *proc;
61 proc = talloc_zero(mem_ctx, struct proc_context);
62 if (proc == NULL) {
63 return NULL;
66 proc->pid = -1;
67 proc->fd = -1;
69 talloc_set_destructor(proc, proc_destructor);
71 return proc;
74 static void run_proc_kill(struct tevent_req *req);
76 static int proc_destructor(struct proc_context *proc)
78 if (proc->req != NULL) {
79 run_proc_kill(proc->req);
82 talloc_free(proc->fde);
83 if (proc->pid != -1) {
84 kill(-proc->pid, SIGKILL);
87 return 0;
90 static void proc_read_handler(struct tevent_context *ev,
91 struct tevent_fd *fde, uint16_t flags,
92 void *private_data);
94 static int proc_start(struct proc_context *proc, struct tevent_context *ev,
95 const char *path, const char **argv, int stdin_fd)
97 int fd[2];
98 int ret;
100 ret = pipe(fd);
101 if (ret != 0) {
102 return ret;
105 proc->pid = fork();
106 if (proc->pid == -1) {
107 ret = errno;
108 close(fd[0]);
109 close(fd[1]);
110 return ret;
113 if (proc->pid == 0) {
114 close(fd[0]);
116 ret = dup2(fd[1], STDOUT_FILENO);
117 if (ret == -1) {
118 exit(64 + errno);
120 ret = dup2(fd[1], STDERR_FILENO);
121 if (ret == -1) {
122 exit(64 + errno);
125 close(fd[1]);
127 if (stdin_fd != -1) {
128 ret = dup2(stdin_fd, STDIN_FILENO);
129 if (ret == -1) {
130 exit(64 + errno);
134 ret = setpgid(0, 0);
135 if (ret != 0) {
136 exit(64 + errno);
139 ret = execv(path, discard_const(argv));
140 if (ret != 0) {
141 exit(64 + errno);
144 exit(64 + ENOEXEC);
147 close(fd[1]);
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;
157 tevent_fd_set_auto_close(proc->fde);
159 return 0;
162 static void proc_read_handler(struct tevent_context *ev,
163 struct tevent_fd *fde, uint16_t flags,
164 void *private_data)
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;
173 ret = ioctl(proc->fd, FIONREAD, &len);
174 if (ret != 0) {
175 goto fail;
178 if (len == 0) {
179 /* pipe closed */
180 goto close;
183 offset = (proc->output == NULL) ? 0 : strlen(proc->output);
185 proc->output = talloc_realloc(proc, proc->output, char, offset+len+1);
186 if (proc->output == NULL) {
187 goto fail;
190 nread = sys_read(proc->fd, proc->output + offset, len);
191 if (nread == -1) {
192 goto fail;
194 proc->output[offset+nread] = '\0';
195 return;
197 fail:
198 if (proc->pid != -1) {
199 kill(-proc->pid, SIGKILL);
200 proc->pid = -1;
202 close:
203 TALLOC_FREE(proc->fde);
204 proc->fd = -1;
209 * Run proc abstraction
212 struct run_proc_context {
213 struct tevent_context *ev;
214 struct tevent_signal *se;
215 struct proc_context *plist;
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);
225 int run_proc_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
226 struct run_proc_context **result)
228 struct run_proc_context *run_ctx;
230 run_ctx = talloc_zero(mem_ctx, struct run_proc_context);
231 if (run_ctx == NULL) {
232 return ENOMEM;
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;
243 talloc_set_destructor(run_ctx, run_proc_context_destructor);
245 *result = run_ctx;
246 return 0;
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)
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;
260 again:
261 pid = waitpid(-1, &status, WNOHANG);
262 if (pid == -1) {
263 return;
266 if (pid == 0) {
267 return;
270 for (proc = run_ctx->plist; proc != NULL; proc = proc->next) {
271 if (proc->pid == pid) {
272 break;
276 if (proc == NULL) {
277 /* unknown process */
278 goto again;
281 /* Mark the process as terminated */
282 proc->pid = -1;
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;
294 } else if (WIFSIGNALED(status)) {
295 proc->result.sig = WTERMSIG(status);
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;
305 DLIST_REMOVE(run_ctx->plist, proc);
307 /* Active run_proc request */
308 if (proc->req != NULL) {
309 run_proc_done(proc->req);
310 } else {
311 talloc_free(proc);
314 goto again;
317 static int run_proc_context_destructor(struct run_proc_context *run_ctx)
319 struct proc_context *proc;
321 /* Get rid of signal handler */
322 TALLOC_FREE(run_ctx->se);
324 /* Kill any pending processes */
325 while ((proc = run_ctx->plist) != NULL) {
326 DLIST_REMOVE(run_ctx->plist, proc);
327 talloc_free(proc);
330 return 0;
333 struct run_proc_state {
334 struct tevent_context *ev;
335 struct run_proc_context *run_ctx;
336 struct proc_context *proc;
338 struct run_proc_result result;
339 char *output;
340 pid_t pid;
343 static int run_proc_state_destructor(struct run_proc_state *state);
344 static void run_proc_timedout(struct tevent_req *subreq);
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)
352 struct tevent_req *req;
353 struct run_proc_state *state;
354 struct stat st;
355 int ret;
357 req = tevent_req_create(mem_ctx, &state, struct run_proc_state);
358 if (req == NULL) {
359 return NULL;
362 state->ev = ev;
363 state->run_ctx = run_ctx;
364 state->pid = -1;
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);
373 if (! (st.st_mode & S_IXUSR)) {
374 state->result.err = EACCES;
375 tevent_req_done(req);
376 return tevent_req_post(req, ev);
379 state->proc = proc_new(run_ctx, run_ctx);
380 if (tevent_req_nomem(state->proc, req)) {
381 return tevent_req_post(req, ev);
384 state->proc->req = req;
385 DLIST_ADD(run_ctx->plist, state->proc);
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);
393 talloc_set_destructor(state, run_proc_state_destructor);
395 if (! tevent_timeval_is_zero(&timeout)) {
396 struct tevent_req *subreq;
398 subreq = tevent_wakeup_send(state, ev, timeout);
399 if (tevent_req_nomem(subreq, req)) {
400 return tevent_req_post(req, ev);
402 tevent_req_set_callback(subreq, run_proc_timedout, req);
405 return req;
408 static int run_proc_state_destructor(struct run_proc_state *state)
410 /* Do not get rid of the child process if timeout has occurred */
411 if ((state->proc != NULL) && (state->proc->req != NULL)) {
412 state->proc->req = NULL;
413 DLIST_REMOVE(state->run_ctx->plist, state->proc);
414 TALLOC_FREE(state->proc);
417 return 0;
420 static void run_proc_done(struct tevent_req *req)
422 struct run_proc_state *state = tevent_req_data(
423 req, struct run_proc_state);
425 state->proc->req = NULL;
427 state->result = state->proc->result;
428 if (state->proc->output != NULL) {
429 state->output = talloc_move(state, &state->proc->output);
431 talloc_steal(state, state->proc);
433 tevent_req_done(req);
436 static void run_proc_kill(struct tevent_req *req)
438 struct run_proc_state *state = tevent_req_data(
439 req, struct run_proc_state);
441 state->proc->req = NULL;
442 state->proc = NULL;
444 state->result.sig = SIGKILL;
446 tevent_req_done(req);
449 static void run_proc_timedout(struct tevent_req *subreq)
451 struct tevent_req *req = tevent_req_callback_data(
452 subreq, struct tevent_req);
453 struct run_proc_state *state = tevent_req_data(
454 req, struct run_proc_state);
455 bool status;
457 state->proc->req = NULL;
459 status = tevent_wakeup_recv(subreq);
460 TALLOC_FREE(subreq);
461 if (! status) {
462 tevent_req_error(req, EIO);
463 return;
466 state->result.err = ETIMEDOUT;
467 if (state->proc->output != NULL) {
468 state->output = talloc_move(state, &state->proc->output);
470 state->pid = state->proc->pid;
472 tevent_req_done(req);
475 bool run_proc_recv(struct tevent_req *req, int *perr,
476 struct run_proc_result *result, pid_t *pid,
477 TALLOC_CTX *mem_ctx, char **output)
479 struct run_proc_state *state = tevent_req_data(
480 req, struct run_proc_state);
481 int ret;
483 if (tevent_req_is_unix_error(req, &ret)) {
484 if (perr != NULL) {
485 *perr = ret;
487 return false;
490 if (result != NULL) {
491 *result = state->result;
494 if (pid != NULL) {
495 *pid = state->pid;
498 if (output != NULL) {
499 *output = talloc_move(mem_ctx, &state->output);
502 return true;