s4/torture: fruit: remove use of localdir from test_adouble_conversion test
[Samba.git] / lib / util / util_runcmd.c
blob42d84a895bf21aa11381ea1b1c3e5763d9123abe
1 /*
2 Unix SMB/CIFS implementation.
4 run a child command
6 Copyright (C) Andrew Tridgell 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 this runs a child command with stdout and stderr going to the Samba
25 log
28 #include "includes.h"
29 #include "system/filesys.h"
30 #include "../lib/util/tevent_unix.h"
31 #include "../lib/util/util_runcmd.h"
32 #include "../lib/util/tfork.h"
33 #include "../lib/util/sys_rw.h"
35 static void samba_runcmd_cleanup_fn(struct tevent_req *req,
36 enum tevent_req_state req_state)
38 struct samba_runcmd_state *state = tevent_req_data(
39 req, struct samba_runcmd_state);
41 if (state->tfork != NULL) {
42 tfork_destroy(&state->tfork);
44 state->pid = -1;
46 if (state->fd_stdin != -1) {
47 close(state->fd_stdin);
48 state->fd_stdin = -1;
52 static void samba_runcmd_io_handler(struct tevent_context *ev,
53 struct tevent_fd *fde,
54 uint16_t flags,
55 void *private_data);
58 run a command as a child process, with a timeout.
60 any stdout/stderr from the child will appear in the Samba logs with
61 the specified log levels
63 struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
64 struct tevent_context *ev,
65 struct timeval endtime,
66 int stdout_log_level,
67 int stderr_log_level,
68 const char * const *argv0, ...)
70 struct tevent_req *req;
71 struct samba_runcmd_state *state;
72 int p1[2], p2[2], p3[2];
73 char **argv;
74 va_list ap;
76 if (argv0 == NULL) {
77 return NULL;
80 req = tevent_req_create(mem_ctx, &state,
81 struct samba_runcmd_state);
82 if (req == NULL) {
83 return NULL;
86 state->stdout_log_level = stdout_log_level;
87 state->stderr_log_level = stderr_log_level;
88 state->fd_stdin = -1;
90 state->arg0 = talloc_strdup(state, argv0[0]);
91 if (tevent_req_nomem(state->arg0, req)) {
92 return tevent_req_post(req, ev);
95 if (pipe(p1) != 0) {
96 tevent_req_error(req, errno);
97 return tevent_req_post(req, ev);
99 if (pipe(p2) != 0) {
100 close(p1[0]);
101 close(p1[1]);
102 tevent_req_error(req, errno);
103 return tevent_req_post(req, ev);
105 if (pipe(p3) != 0) {
106 close(p1[0]);
107 close(p1[1]);
108 close(p2[0]);
109 close(p2[1]);
110 tevent_req_error(req, errno);
111 return tevent_req_post(req, ev);
114 state->tfork = tfork_create();
115 if (state->tfork == NULL) {
116 close(p1[0]);
117 close(p1[1]);
118 close(p2[0]);
119 close(p2[1]);
120 close(p3[0]);
121 close(p3[1]);
122 tevent_req_error(req, errno);
123 return tevent_req_post(req, ev);
125 state->pid = tfork_child_pid(state->tfork);
126 if (state->pid != 0) {
127 /* the parent */
128 close(p1[1]);
129 close(p2[1]);
130 close(p3[0]);
131 state->fd_stdout = p1[0];
132 state->fd_stderr = p2[0];
133 state->fd_stdin = p3[1];
134 state->fd_status = tfork_event_fd(state->tfork);
136 set_blocking(state->fd_stdout, false);
137 set_blocking(state->fd_stderr, false);
138 set_blocking(state->fd_stdin, false);
139 set_blocking(state->fd_status, false);
141 smb_set_close_on_exec(state->fd_stdin);
142 smb_set_close_on_exec(state->fd_stdout);
143 smb_set_close_on_exec(state->fd_stderr);
144 smb_set_close_on_exec(state->fd_status);
146 tevent_req_set_cleanup_fn(req, samba_runcmd_cleanup_fn);
148 state->fde_stdout = tevent_add_fd(ev, state,
149 state->fd_stdout,
150 TEVENT_FD_READ,
151 samba_runcmd_io_handler,
152 req);
153 if (tevent_req_nomem(state->fde_stdout, req)) {
154 close(state->fd_stdout);
155 close(state->fd_stderr);
156 close(state->fd_status);
157 return tevent_req_post(req, ev);
159 tevent_fd_set_auto_close(state->fde_stdout);
161 state->fde_stderr = tevent_add_fd(ev, state,
162 state->fd_stderr,
163 TEVENT_FD_READ,
164 samba_runcmd_io_handler,
165 req);
166 if (tevent_req_nomem(state->fde_stdout, req)) {
167 close(state->fd_stdout);
168 close(state->fd_stderr);
169 close(state->fd_status);
170 return tevent_req_post(req, ev);
172 tevent_fd_set_auto_close(state->fde_stderr);
174 state->fde_status = tevent_add_fd(ev, state,
175 state->fd_status,
176 TEVENT_FD_READ,
177 samba_runcmd_io_handler,
178 req);
179 if (tevent_req_nomem(state->fde_stdout, req)) {
180 close(state->fd_stdout);
181 close(state->fd_stderr);
182 close(state->fd_status);
183 return tevent_req_post(req, ev);
185 tevent_fd_set_auto_close(state->fde_status);
187 if (!timeval_is_zero(&endtime)) {
188 tevent_req_set_endtime(req, ev, endtime);
191 return req;
194 /* the child */
195 close(p1[0]);
196 close(p2[0]);
197 close(p3[1]);
198 close(0);
199 close(1);
200 close(2);
202 /* we want to ensure that all of the network sockets we had
203 open are closed */
204 tevent_re_initialise(ev);
206 /* setup for logging to go to the parents debug log */
207 dup2(p3[0], 0);
208 dup2(p1[1], 1);
209 dup2(p2[1], 2);
211 close(p1[1]);
212 close(p2[1]);
213 close(p3[0]);
215 argv = str_list_copy(state, discard_const_p(const char *, argv0));
216 if (!argv) {
217 fprintf(stderr, "Out of memory in child\n");
218 _exit(255);
221 va_start(ap, argv0);
222 while (1) {
223 const char **l;
224 char *arg = va_arg(ap, char *);
225 if (arg == NULL) break;
226 l = discard_const_p(const char *, argv);
227 l = str_list_add(l, arg);
228 if (l == NULL) {
229 fprintf(stderr, "Out of memory in child\n");
230 _exit(255);
232 argv = discard_const_p(char *, l);
234 va_end(ap);
236 (void)execvp(state->arg0, argv);
237 fprintf(stderr, "Failed to exec child - %s\n", strerror(errno));
238 _exit(255);
239 return NULL;
243 handle stdout/stderr from the child
245 static void samba_runcmd_io_handler(struct tevent_context *ev,
246 struct tevent_fd *fde,
247 uint16_t flags,
248 void *private_data)
250 struct tevent_req *req = talloc_get_type_abort(private_data,
251 struct tevent_req);
252 struct samba_runcmd_state *state = tevent_req_data(req,
253 struct samba_runcmd_state);
254 int level;
255 char *p;
256 int n, fd;
258 if (!(flags & TEVENT_FD_READ)) {
259 return;
262 if (fde == state->fde_stdout) {
263 level = state->stdout_log_level;
264 fd = state->fd_stdout;
265 } else if (fde == state->fde_stderr) {
266 level = state->stderr_log_level;
267 fd = state->fd_stderr;
268 } else {
269 int status;
271 status = tfork_status(&state->tfork, false);
272 if (status == -1) {
273 if (errno == EAGAIN || errno == EWOULDBLOCK) {
274 return;
276 DBG_ERR("Bad read on status pipe\n");
277 tevent_req_error(req, errno);
278 return;
280 state->pid = -1;
281 TALLOC_FREE(fde);
283 if (WIFEXITED(status)) {
284 status = WEXITSTATUS(status);
285 } else if (WIFSIGNALED(status)) {
286 status = WTERMSIG(status);
287 } else {
288 status = ECHILD;
291 DBG_NOTICE("Child %s exited %d\n", state->arg0, status);
292 if (status != 0) {
293 tevent_req_error(req, status);
294 return;
297 tevent_req_done(req);
298 return;
301 n = read(fd, &state->buf[state->buf_used],
302 sizeof(state->buf) - state->buf_used);
303 if (n > 0) {
304 state->buf_used += n;
305 } else if (n == 0) {
306 if (fde == state->fde_stdout) {
307 talloc_free(fde);
308 state->fde_stdout = NULL;
309 return;
311 if (fde == state->fde_stderr) {
312 talloc_free(fde);
313 state->fde_stderr = NULL;
314 return;
316 return;
319 while (state->buf_used > 0 &&
320 (p = (char *)memchr(state->buf, '\n', state->buf_used)) != NULL) {
321 int n1 = (p - state->buf)+1;
322 int n2 = n1 - 1;
323 /* swallow \r from child processes */
324 if (n2 > 0 && state->buf[n2-1] == '\r') {
325 n2--;
327 DEBUG(level,("%s: %*.*s\n", state->arg0, n2, n2, state->buf));
328 memmove(state->buf, p+1, sizeof(state->buf) - n1);
329 state->buf_used -= n1;
332 /* the buffer could have completely filled - unfortunately we have
333 no choice but to dump it out straight away */
334 if (state->buf_used == sizeof(state->buf)) {
335 DEBUG(level,("%s: %*.*s\n",
336 state->arg0, state->buf_used,
337 state->buf_used, state->buf));
338 state->buf_used = 0;
342 int samba_runcmd_recv(struct tevent_req *req, int *perrno)
344 if (tevent_req_is_unix_error(req, perrno)) {
345 tevent_req_received(req);
346 return -1;
349 tevent_req_received(req);
350 return 0;