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