2 Unix SMB/CIFS implementation.
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
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);
46 if (state->fd_stdin != -1) {
47 close(state->fd_stdin);
52 static void samba_runcmd_io_handler(struct tevent_context *ev,
53 struct tevent_fd *fde,
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,
68 const char * const *argv0, ...)
70 struct tevent_req *req;
71 struct samba_runcmd_state *state;
72 int p1[2], p2[2], p3[2];
80 req = tevent_req_create(mem_ctx, &state,
81 struct samba_runcmd_state);
86 state->stdout_log_level = stdout_log_level;
87 state->stderr_log_level = stderr_log_level;
90 state->arg0 = talloc_strdup(state, argv0[0]);
91 if (tevent_req_nomem(state->arg0, req)) {
92 return tevent_req_post(req, ev);
96 tevent_req_error(req, errno);
97 return tevent_req_post(req, ev);
102 tevent_req_error(req, errno);
103 return tevent_req_post(req, ev);
110 tevent_req_error(req, errno);
111 return tevent_req_post(req, ev);
114 state->tfork = tfork_create();
115 if (state->tfork == NULL) {
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) {
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,
151 samba_runcmd_io_handler,
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,
164 samba_runcmd_io_handler,
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,
177 samba_runcmd_io_handler,
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);
202 /* we want to ensure that all of the network sockets we had
204 tevent_re_initialise(ev);
206 /* setup for logging to go to the parents debug log */
215 argv = str_list_copy(state, discard_const_p(const char *, argv0));
217 fprintf(stderr, "Out of memory in child\n");
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);
229 fprintf(stderr, "Out of memory in child\n");
232 argv = discard_const_p(char *, l);
236 (void)execvp(state->arg0, argv);
237 fprintf(stderr, "Failed to exec child - %s\n", strerror(errno));
243 handle stdout/stderr from the child
245 static void samba_runcmd_io_handler(struct tevent_context *ev,
246 struct tevent_fd *fde,
250 struct tevent_req *req = talloc_get_type_abort(private_data,
252 struct samba_runcmd_state *state = tevent_req_data(req,
253 struct samba_runcmd_state);
258 if (!(flags & TEVENT_FD_READ)) {
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;
271 status = tfork_status(&state->tfork, false);
273 if (errno == EAGAIN || errno == EWOULDBLOCK) {
276 DBG_ERR("Bad read on status pipe\n");
277 tevent_req_error(req, errno);
283 if (WIFEXITED(status)) {
284 status = WEXITSTATUS(status);
285 } else if (WIFSIGNALED(status)) {
286 status = WTERMSIG(status);
291 DBG_NOTICE("Child %s exited %d\n", state->arg0, status);
293 tevent_req_error(req, status);
297 tevent_req_done(req);
301 n = read(fd, &state->buf[state->buf_used],
302 sizeof(state->buf) - state->buf_used);
304 state->buf_used += n;
306 if (fde == state->fde_stdout) {
308 state->fde_stdout = NULL;
311 if (fde == state->fde_stderr) {
313 state->fde_stderr = NULL;
319 while (state->buf_used > 0 &&
320 (p = (char *)memchr(state->buf, '\n', state->buf_used)) != NULL) {
321 int n1 = (p - state->buf)+1;
323 /* swallow \r from child processes */
324 if (n2 > 0 && state->buf[n2-1] == '\r') {
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));
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);
349 tevent_req_received(req);