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