14 # include <sys/wait.h>
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
, ©
, 0, inherit
, DUPLICATE_SAME_ACCESS
|
30 (closeorig
? DUPLICATE_CLOSE_SOURCE
: 0)))
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
);
47 # define SHELLENV "SHELL"
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");
57 close_descriptor(p
->child
);
61 static void pipe_close_child(pipe_t
*p
) {
62 close_descriptor(p
->child
);
69 static void pipe_close(pipe_t
*p
) {
70 close_descriptor(p
->parent
);
71 close_descriptor(p
->child
);
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");
86 p
->parent
= newpipe
[1]; /* write */
87 p
->child
= newpipe
[0]; /* read */
89 p
->parent
= newpipe
[0]; /* read */
90 p
->child
= newpipe
[1]; /* write */
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) {
103 if (pipe_open(&(proc
->out
), 1 SECURITY_CC
) != 0) {
106 if (pipe_open(&(proc
->err
), 2 SECURITY_CC
) != 0) {
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
);
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
);
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
);
136 int proc_close(proc_handler_t
*proc
) {
137 proc_pid_t child
= proc
->child
;
140 proc_close_pipes(proc
);
141 WaitForSingleObject(child
, INFINITE
);
142 GetExitCodeProcess(child
, &wstatus
);
149 int proc_open(proc_handler_t
*proc
, const char *command
) {
150 PROCESS_INFORMATION pi
;
153 SECURITY_ATTRIBUTES security
;
154 const char *shell
= NULL
;
155 const char *windir
= NULL
;
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
);
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) {
174 proc_close_parents(proc
);
176 memset(&si
, 0, 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();
187 buffer_append_string(cmdline
, shell
);
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
);
202 buffer_free(cmdline
);
204 proc
->child
= pi
.hProcess
;
205 CloseHandle(pi
.hThread
);
207 proc_close_childs(proc
);
214 int proc_close(proc_handler_t
*proc
) {
215 pid_t child
= proc
->child
;
219 proc_close_pipes(proc
);
222 wait_pid
= waitpid(child
, &wstatus
, 0);
223 } while (wait_pid
== -1 && errno
== EINTR
);
225 if (wait_pid
== -1) {
228 if (WIFEXITED(wstatus
))
229 wstatus
= WEXITSTATUS(wstatus
);
236 int proc_open(proc_handler_t
*proc
, const char *command
) {
240 if (NULL
== (shell
= getenv(SHELLENV
))) {
244 if (proc_open_pipes(proc
) != 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
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
));
265 } else if (child
< 0) {
266 fprintf(stderr
, "failed to forking");
272 proc_close_childs(proc
);
279 /* {{{ proc_read_fd_to_buffer */
280 static void proc_read_fd_to_buffer(int fd
, buffer
*b
) {
284 buffer_string_prepare_append(b
, 1024);
285 if ((s
= read(fd
, (void *)(b
->ptr
+ buffer_string_length(b
)), buffer_string_space(b
))) <= 0) {
292 /* {{{ proc_open_buffer */
293 int proc_open_buffer(const char *command
, buffer
*in
, buffer
*out
, buffer
*err
) {
296 if (proc_open(&proc
, command
) != 0) {
301 if (write(proc
.in
.fd
, CONST_BUF_LEN(in
)) < 0) {
302 perror("error writing pipe");
306 pipe_close(&proc
.in
);
309 proc_read_fd_to_buffer(proc
.out
.fd
, out
);
311 pipe_close(&proc
.out
);
314 proc_read_fd_to_buffer(proc
.err
.fd
, err
);
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");
325 pipe_close(&proc
.err
);
334 #ifdef DEBUG_PROC_OPEN
337 buffer
*in
= buffer_init(), *out
= buffer_init(), *err
= buffer_init();
340 #define FREE() do { \
346 #define RESET() do { \
350 wstatus = proc_close(&proc); \
351 if (0&&wstatus != 0) { \
352 fprintf(stdout, "exitstatus %d\n", wstatus); \
353 return __LINE__ - 200; \
357 #define ERROR_OUT() do { \
358 fprintf(stdout, "failed opening proc\n"); \
359 wstatus = proc_close(&proc); \
360 fprintf(stdout, "exitstatus %d\n", wstatus); \
362 return __LINE__ - 300; \
366 #define CMD_CAT "pause"
368 #define CMD_CAT "cat"
372 fprintf(stdout
, "test: echo 123 without read\n");
373 if (proc_open(&proc
, "echo 321") != 0) {
376 close_descriptor(proc
.in
.parent
);
377 close_descriptor(proc
.out
.parent
);
378 close_descriptor(proc
.err
.parent
);
381 fprintf(stdout
, "test: echo 321 with read\n"); fflush(stdout
);
382 if (proc_open_buffer("echo 321", NULL
, out
, err
) != 0) {
385 fprintf(stdout
, "result: ->%s<-\n\n", out
->ptr
); fflush(stdout
);
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) {
393 fprintf(stdout
, "result: ->%s<-\n\n", out
->ptr
); fflush(stdout
);
400 fprintf(stdout
, "ok\n");
405 #endif /* DEBUG_PROC_OPEN */