[mod_openssl] remove erroneous SSL_set_shutdown()
[lighttpd.git] / src / proc_open.c
blobea6eb893ddbb20c458fa925d7c8b741d24f22f6b
1 #include "first.h"
3 #include "proc_open.h"
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <errno.h>
10 #ifdef WIN32
11 # include <io.h>
12 # include <fcntl.h>
13 #else
14 # include <sys/wait.h>
15 # include <unistd.h>
16 #endif
19 #ifdef WIN32
20 /* {{{ win32 stuff */
21 # define SHELLENV "ComSpec"
22 # define SECURITY_DC , SECURITY_ATTRIBUTES *security
23 # define SECURITY_CC , security
24 # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
25 static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
27 HANDLE copy, self = GetCurrentProcess();
29 if (!DuplicateHandle(self, src, self, &copy, 0, inherit, DUPLICATE_SAME_ACCESS |
30 (closeorig ? DUPLICATE_CLOSE_SOURCE : 0)))
31 return NULL;
32 return copy;
34 # define close_descriptor(fd) CloseHandle(fd)
35 static void pipe_close_parent(pipe_t *p) {
36 /* don't let the child inherit the parent side of the pipe */
37 p->parent = dup_handle(p->parent, FALSE, TRUE);
39 static void pipe_close_child(pipe_t *p) {
40 close_descriptor(p->child);
41 p->fd = _open_osfhandle((long)p->parent,
42 (p->fd == 0 ? O_RDONLY : O_WRONLY)|O_BINARY);
44 /* }}} */
45 #else /* WIN32 */
46 /* {{{ unix way */
47 # define SHELLENV "SHELL"
48 # define SECURITY_DC
49 # define SECURITY_CC
50 # define close_descriptor(fd) close(fd)
51 static void pipe_close_parent(pipe_t *p) {
52 /* don't close stdin */
53 close_descriptor(p->parent);
54 if (dup2(p->child, p->fd) != p->fd) {
55 perror("pipe_child dup2");
56 } else {
57 close_descriptor(p->child);
58 p->child = p->fd;
61 static void pipe_close_child(pipe_t *p) {
62 close_descriptor(p->child);
63 p->fd = p->parent;
65 /* }}} */
66 #endif /* WIN32 */
68 /* {{{ pipe_close */
69 static void pipe_close(pipe_t *p) {
70 close_descriptor(p->parent);
71 close_descriptor(p->child);
72 #ifdef WIN32
73 close(p->fd);
74 #endif
76 /* }}} */
77 /* {{{ pipe_open */
78 static int pipe_open(pipe_t *p, int fd SECURITY_DC) {
79 descriptor_t newpipe[2];
81 if (0 != pipe(newpipe)) {
82 fprintf(stderr, "can't open pipe");
83 return -1;
85 if (0 == fd) {
86 p->parent = newpipe[1]; /* write */
87 p->child = newpipe[0]; /* read */
88 } else {
89 p->parent = newpipe[0]; /* read */
90 p->child = newpipe[1]; /* write */
92 p->fd = fd;
94 return 0;
96 /* }}} */
98 /* {{{ proc_open_pipes */
99 static int proc_open_pipes(proc_handler_t *proc SECURITY_DC) {
100 if (pipe_open(&(proc->in), 0 SECURITY_CC) != 0) {
101 return -1;
103 if (pipe_open(&(proc->out), 1 SECURITY_CC) != 0) {
104 return -1;
106 if (pipe_open(&(proc->err), 2 SECURITY_CC) != 0) {
107 return -1;
109 return 0;
111 /* }}} */
112 /* {{{ proc_close_pipes */
113 static void proc_close_pipes(proc_handler_t *proc) {
114 pipe_close(&proc->in);
115 pipe_close(&proc->out);
116 pipe_close(&proc->err);
118 /* }}} */
119 /* {{{ proc_close_parents */
120 static void proc_close_parents(proc_handler_t *proc) {
121 pipe_close_parent(&proc->in);
122 pipe_close_parent(&proc->out);
123 pipe_close_parent(&proc->err);
125 /* }}} */
126 /* {{{ proc_close_childs */
127 static void proc_close_childs(proc_handler_t *proc) {
128 pipe_close_child(&proc->in);
129 pipe_close_child(&proc->out);
130 pipe_close_child(&proc->err);
132 /* }}} */
134 #ifdef WIN32
135 /* {{{ proc_close */
136 int proc_close(proc_handler_t *proc) {
137 proc_pid_t child = proc->child;
138 DWORD wstatus;
140 proc_close_pipes(proc);
141 WaitForSingleObject(child, INFINITE);
142 GetExitCodeProcess(child, &wstatus);
143 CloseHandle(child);
145 return wstatus;
147 /* }}} */
148 /* {{{ proc_open */
149 int proc_open(proc_handler_t *proc, const char *command) {
150 PROCESS_INFORMATION pi;
151 STARTUPINFO si;
152 BOOL procok;
153 SECURITY_ATTRIBUTES security;
154 const char *shell = NULL;
155 const char *windir = NULL;
156 buffer *cmdline;
158 if (NULL == (shell = getenv(SHELLENV)) &&
159 NULL == (windir = getenv("SystemRoot")) &&
160 NULL == (windir = getenv("windir"))) {
161 fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
162 return -1;
165 /* we use this to allow the child to inherit handles */
166 memset(&security, 0, sizeof(security));
167 security.nLength = sizeof(security);
168 security.bInheritHandle = TRUE;
169 security.lpSecurityDescriptor = NULL;
171 if (proc_open_pipes(proc, &security) != 0) {
172 return -1;
174 proc_close_parents(proc);
176 memset(&si, 0, sizeof(si));
177 si.cb = sizeof(si);
178 si.dwFlags = STARTF_USESTDHANDLES;
179 si.hStdInput = proc->in.child;
180 si.hStdOutput = proc->out.child;
181 si.hStdError = proc->err.child;
183 memset(&pi, 0, sizeof(pi));
185 cmdline = buffer_init();
186 if (shell) {
187 buffer_append_string(cmdline, shell);
188 } else {
189 buffer_append_string(cmdline, windir);
190 buffer_append_string_len(cmdline, CONST_STR_LEN("\\system32\\cmd.exe"));
192 buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
193 buffer_append_string(cmdline, command);
194 procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
195 NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
197 if (FALSE == procok) {
198 fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
199 buffer_free(cmdline);
200 return -1;
202 buffer_free(cmdline);
204 proc->child = pi.hProcess;
205 CloseHandle(pi.hThread);
207 proc_close_childs(proc);
209 return 0;
211 /* }}} */
212 #else /* WIN32 */
213 /* {{{ proc_close */
214 int proc_close(proc_handler_t *proc) {
215 pid_t child = proc->child;
216 int wstatus;
217 pid_t wait_pid;
219 proc_close_pipes(proc);
221 do {
222 wait_pid = waitpid(child, &wstatus, 0);
223 } while (wait_pid == -1 && errno == EINTR);
225 if (wait_pid == -1) {
226 return -1;
227 } else {
228 if (WIFEXITED(wstatus))
229 wstatus = WEXITSTATUS(wstatus);
232 return wstatus;
234 /* }}} */
235 /* {{{ proc_open */
236 int proc_open(proc_handler_t *proc, const char *command) {
237 pid_t child;
238 const char *shell;
240 if (NULL == (shell = getenv(SHELLENV))) {
241 shell = "/bin/sh";
244 if (proc_open_pipes(proc) != 0) {
245 return -1;
248 /* the unix way */
250 child = fork();
252 if (child == 0) {
253 /* this is the child process */
255 /* close those descriptors that we just opened for the parent stuff,
256 * dup new descriptors into required descriptors and close the original
257 * cruft
259 proc_close_parents(proc);
261 execl(shell, shell, "-c", command, (char *)NULL);
262 fprintf(stderr, "failed to execute shell: %s -c %s: %s\n", shell, command, strerror(errno));
263 _exit(127);
265 } else if (child < 0) {
266 fprintf(stderr, "failed to forking");
267 proc_close(proc);
268 return -1;
270 } else {
271 proc->child = child;
272 proc_close_childs(proc);
273 return 0;
276 /* }}} */
277 #endif /* WIN32 */
279 /* {{{ proc_read_fd_to_buffer */
280 static void proc_read_fd_to_buffer(int fd, buffer *b) {
281 ssize_t s;
283 for (;;) {
284 buffer_string_prepare_append(b, 1024);
285 if ((s = read(fd, (void *)(b->ptr + buffer_string_length(b)), buffer_string_space(b))) <= 0) {
286 break;
288 buffer_commit(b, s);
291 /* }}} */
292 /* {{{ proc_open_buffer */
293 int proc_open_buffer(const char *command, buffer *in, buffer *out, buffer *err) {
294 proc_handler_t proc;
296 if (proc_open(&proc, command) != 0) {
297 return -1;
300 if (in) {
301 if (write(proc.in.fd, CONST_BUF_LEN(in)) < 0) {
302 perror("error writing pipe");
303 return -1;
306 pipe_close(&proc.in);
308 if (out) {
309 proc_read_fd_to_buffer(proc.out.fd, out);
311 pipe_close(&proc.out);
313 if (err) {
314 proc_read_fd_to_buffer(proc.err.fd, err);
315 } else {
316 buffer *tmp = buffer_init();
317 proc_read_fd_to_buffer(proc.err.fd, tmp);
318 if (!buffer_string_is_empty(tmp) && write(2, CONST_BUF_LEN(tmp)) < 0) {
319 perror("error writing pipe");
320 buffer_free(tmp);
321 return -1;
323 buffer_free(tmp);
325 pipe_close(&proc.err);
327 proc_close(&proc);
329 return 0;
331 /* }}} */
333 /* {{{ test */
334 #ifdef DEBUG_PROC_OPEN
335 int main(void) {
336 proc_handler_t proc;
337 buffer *in = buffer_init(), *out = buffer_init(), *err = buffer_init();
338 int wstatus;
340 #define FREE() do { \
341 buffer_free(in); \
342 buffer_free(out); \
343 buffer_free(err); \
344 } while (0)
346 #define RESET() do { \
347 buffer_reset(in); \
348 buffer_reset(out); \
349 buffer_reset(err); \
350 wstatus = proc_close(&proc); \
351 if (0&&wstatus != 0) { \
352 fprintf(stdout, "exitstatus %d\n", wstatus); \
353 return __LINE__ - 200; \
355 } while (0)
357 #define ERROR_OUT() do { \
358 fprintf(stdout, "failed opening proc\n"); \
359 wstatus = proc_close(&proc); \
360 fprintf(stdout, "exitstatus %d\n", wstatus); \
361 FREE(); \
362 return __LINE__ - 300; \
363 } while (0)
365 #ifdef WIN32
366 #define CMD_CAT "pause"
367 #else
368 #define CMD_CAT "cat"
369 #endif
371 do {
372 fprintf(stdout, "test: echo 123 without read\n");
373 if (proc_open(&proc, "echo 321") != 0) {
374 ERROR_OUT();
376 close_descriptor(proc.in.parent);
377 close_descriptor(proc.out.parent);
378 close_descriptor(proc.err.parent);
379 RESET();
381 fprintf(stdout, "test: echo 321 with read\n"); fflush(stdout);
382 if (proc_open_buffer("echo 321", NULL, out, err) != 0) {
383 ERROR_OUT();
385 fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
386 RESET();
388 fprintf(stdout, "test: echo 123 | " CMD_CAT "\n"); fflush(stdout);
389 buffer_copy_string_len(in, CONST_STR_LEN("123\n"));
390 if (proc_open_buffer(CMD_CAT, in, out, err) != 0) {
391 ERROR_OUT();
393 fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
394 RESET();
395 } while (0);
397 #undef RESET
398 #undef ERROR_OUT
400 fprintf(stdout, "ok\n");
402 FREE();
403 return 0;
405 #endif /* DEBUG_PROC_OPEN */
406 /* }}} */