s4-smbtorture: add more paranoid checks for REG_DWORD SetPrinterDataEx tests.
[Samba/kamenim.git] / lib / util / util_runcmd.c
blobdea3ff91b1d5590ffdf588543d30a3d1be43e2b9
1 /*
2 Unix SMB/CIFS mplementation.
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/tevent/tevent.h"
31 #include "libcli/composite/composite.h"
33 struct samba_runcmd {
34 int stdout_log_level;
35 int stderr_log_level;
36 struct tevent_fd *fde_stdout;
37 struct tevent_fd *fde_stderr;
38 int fd_stdout, fd_stderr;
39 char *arg0;
40 pid_t pid;
41 char buf[1024];
42 uint16_t buf_used;
46 called when a command times out
48 static void runcmd_timeout(struct tevent_context *ev,
49 struct tevent_timer *te,
50 struct timeval current_time,
51 void *private_data)
53 struct composite_context *c = talloc_get_type_abort(private_data, struct composite_context);
54 struct samba_runcmd *r = talloc_get_type_abort(c->private_data, struct samba_runcmd);
55 kill(r->pid, SIGKILL);
56 waitpid(r->pid, NULL, 0);
57 talloc_free(r->fde_stderr);
58 talloc_free(r->fde_stdout);
59 composite_error(c, NT_STATUS_IO_TIMEOUT);
63 handle stdout/stderr from the child
65 static void runcmd_io_handler(struct tevent_context *ev,
66 struct tevent_fd *fde,
67 uint16_t flags,
68 void *private_data)
70 struct composite_context *c = talloc_get_type_abort(private_data, struct composite_context);
71 struct samba_runcmd *r = talloc_get_type_abort(c->private_data, struct samba_runcmd);
72 int level;
73 char *p;
74 int n, fd;
76 if (fde == r->fde_stdout) {
77 level = r->stdout_log_level;
78 fd = r->fd_stdout;
79 } else {
80 level = r->stderr_log_level;
81 fd = r->fd_stderr;
84 if (!(flags & TEVENT_FD_READ)) {
85 return;
88 n = read(fd, &r->buf[r->buf_used],
89 sizeof(r->buf) - r->buf_used);
90 if (n > 0) {
91 r->buf_used += n;
92 } else if (n == 0) {
93 if (fde == r->fde_stdout) {
94 talloc_free(fde);
95 r->fde_stdout = NULL;
97 if (fde == r->fde_stderr) {
98 talloc_free(fde);
99 r->fde_stderr = NULL;
101 if (r->fde_stdout == NULL &&
102 r->fde_stderr == NULL) {
103 int status;
104 /* the child has closed both stdout and
105 * stderr, assume its dead */
106 pid_t pid = waitpid(r->pid, &status, 0);
107 if (pid != r->pid) {
108 DEBUG(0,("Error in waitpid() for child %s\n", r->arg0));
109 composite_error(c, map_nt_error_from_unix(errno));
110 return;
112 status = WEXITSTATUS(status);
113 DEBUG(3,("Child %s exited with status %d\n", r->arg0, status));
114 if (status == 0) {
115 composite_done(c);
116 } else {
117 composite_error(c, map_nt_error_from_unix(status));
119 return;
121 return;
124 while (r->buf_used > 0 &&
125 (p = memchr(r->buf, '\n', r->buf_used)) != NULL) {
126 int n1 = (p - r->buf)+1;
127 int n2 = n1 - 1;
128 /* swallow \r from child processes */
129 if (n2 > 0 && r->buf[n2-1] == '\r') {
130 n2--;
132 DEBUG(level,("%s: %*.*s\n", r->arg0, n2, n2, r->buf));
133 memmove(r->buf, p+1, sizeof(r->buf) - n1);
134 r->buf_used -= n1;
137 /* the buffer could have completely filled - unfortunately we have
138 no choice but to dump it out straight away */
139 if (r->buf_used == sizeof(r->buf)) {
140 DEBUG(level,("%s: %*.*s\n", r->arg0, r->buf_used, r->buf_used, r->buf));
141 r->buf_used = 0;
147 run a command as a child process, with a timeout.
149 any stdout/stderr from the child will appear in the Samba logs with
150 the specified log levels
152 struct composite_context *samba_runcmd(struct tevent_context *ev,
153 TALLOC_CTX *mem_ctx,
154 struct timeval timeout,
155 int stdout_log_level,
156 int stderr_log_level,
157 const char **argv0, ...)
159 struct samba_runcmd *r;
160 int p1[2], p2[2];
161 char **argv;
162 int ret;
163 va_list ap;
164 struct composite_context *c;
166 c = composite_create(mem_ctx, ev);
167 if (c == NULL) return NULL;
169 r = talloc_zero(c, struct samba_runcmd);
170 if (composite_nomem(r, c)) return c;
172 c->private_data = r;
174 r->stdout_log_level = stdout_log_level;
175 r->stderr_log_level = stderr_log_level;
177 r->arg0 = talloc_strdup(r, argv0[0]);
178 if (composite_nomem(r->arg0, c)) return c;
180 if (pipe(p1) != 0) {
181 composite_error(c, map_nt_error_from_unix(errno));
182 return c;
184 if (pipe(p2) != 0) {
185 composite_error(c, map_nt_error_from_unix(errno));
186 close(p1[0]);
187 close(p1[1]);
188 return c;
191 r->pid = fork();
192 if (r->pid == (pid_t)-1) {
193 composite_error(c, map_nt_error_from_unix(errno));
194 close(p1[0]);
195 close(p1[1]);
196 close(p2[0]);
197 close(p2[1]);
198 return c;
201 if (r->pid != 0) {
202 /* the parent */
203 close(p1[1]);
204 close(p2[1]);
205 r->fd_stdout = p1[0];
206 r->fd_stderr = p2[0];
207 set_blocking(r->fd_stdout, false);
208 set_blocking(r->fd_stderr, false);
209 r->fde_stdout = tevent_add_fd(ev, r, r->fd_stdout, TEVENT_FD_READ, runcmd_io_handler, c);
210 tevent_fd_set_auto_close(r->fde_stdout);
211 r->fde_stderr = tevent_add_fd(ev, r, r->fd_stderr, TEVENT_FD_READ, runcmd_io_handler, c);
212 tevent_fd_set_auto_close(r->fde_stderr);
213 if (!timeval_is_zero(&timeout)) {
214 tevent_add_timer(ev, r, timeout, runcmd_timeout, c);
216 return c;
219 /* the child */
220 close(p1[0]);
221 close(p2[0]);
222 close(0);
223 close(1);
224 close(2);
226 /* setup for logging to go to the parents debug log */
227 open("/dev/null", O_RDONLY); /* for stdin */
228 dup2(p1[1], 1);
229 dup2(p2[1], 2);
231 argv = str_list_copy(r, argv0);
232 if (!argv) {
233 fprintf(stderr, "Out of memory in child\n");
234 _exit(255);
237 va_start(ap, argv0);
238 while (1) {
239 char *arg = va_arg(ap, char *);
240 if (arg == NULL) break;
241 argv = discard_const_p(char *, str_list_add((const char **)argv, arg));
242 if (!argv) {
243 fprintf(stderr, "Out of memory in child\n");
244 _exit(255);
247 va_end(ap);
249 ret = execv(r->arg0, argv);
250 fprintf(stderr, "Failed to exec child - %s\n", strerror(errno));
251 _exit(255);
252 return NULL;