15 # include <sys/wait.h>
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
)
28 HANDLE copy
, self
= GetCurrentProcess();
30 if (!DuplicateHandle(self
, src
, self
, ©
, 0, inherit
, DUPLICATE_SAME_ACCESS
|
31 (closeorig
? DUPLICATE_CLOSE_SOURCE
: 0)))
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
);
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
);
48 # define SHELLENV "SHELL"
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");
58 close_descriptor(p
->child
);
62 static void pipe_close_child(pipe_t
*p
) {
63 close_descriptor(p
->child
);
70 static void pipe_close(pipe_t
*p
) {
71 close_descriptor(p
->parent
);
72 close_descriptor(p
->child
);
79 static int pipe_open(pipe_t
*p
, int fd SECURITY_DC
) {
80 descriptor_t newpipe
[2];
82 if (0 != pipe(newpipe
)) {
83 fprintf(stderr
, "can't open pipe");
87 p
->parent
= newpipe
[1]; /* write */
88 p
->child
= newpipe
[0]; /* read */
90 p
->parent
= newpipe
[0]; /* read */
91 p
->child
= newpipe
[1]; /* write */
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) {
104 if (pipe_open(&(proc
->out
), 1 SECURITY_CC
) != 0) {
107 if (pipe_open(&(proc
->err
), 2 SECURITY_CC
) != 0) {
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
);
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
);
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
);
137 int proc_close(proc_handler_t
*proc
) {
138 proc_pid_t child
= proc
->child
;
141 proc_close_pipes(proc
);
142 WaitForSingleObject(child
, INFINITE
);
143 GetExitCodeProcess(child
, &wstatus
);
150 int proc_open(proc_handler_t
*proc
, const char *command
) {
151 PROCESS_INFORMATION pi
;
154 SECURITY_ATTRIBUTES security
;
155 const char *shell
= NULL
;
156 const char *windir
= NULL
;
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
);
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
;
172 if (proc_open_pipes(proc
, &security
) != 0) {
175 proc_close_parents(proc
);
177 memset(&si
, 0, 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
;
184 memset(&pi
, 0, sizeof(pi
));
186 cmdline
= buffer_init();
188 buffer_append_string(cmdline
, shell
);
190 buffer_append_string(cmdline
, windir
);
191 buffer_append_string_len(cmdline
, CONST_STR_LEN("\\system32\\cmd.exe"));
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
);
198 if (FALSE
== procok
) {
199 fprintf(stderr
, "failed to CreateProcess: %s", cmdline
->ptr
);
200 buffer_free(cmdline
);
203 buffer_free(cmdline
);
205 proc
->child
= pi
.hProcess
;
206 CloseHandle(pi
.hThread
);
208 proc_close_childs(proc
);
215 int proc_close(proc_handler_t
*proc
) {
216 pid_t child
= proc
->child
;
220 proc_close_pipes(proc
);
223 wait_pid
= waitpid(child
, &wstatus
, 0);
224 } while (wait_pid
== -1 && errno
== EINTR
);
226 if (wait_pid
== -1) {
229 if (WIFEXITED(wstatus
))
230 wstatus
= WEXITSTATUS(wstatus
);
237 int proc_open(proc_handler_t
*proc
, const char *command
) {
241 if (NULL
== (shell
= getenv(SHELLENV
))) {
245 if (proc_open_pipes(proc
) != 0) {
254 /* this is the child process */
256 /* close those descriptors that we just opened for the parent stuff,
257 * dup new descriptors into required descriptors and close the original
260 proc_close_parents(proc
);
262 execl(shell
, shell
, "-c", command
, (char *)NULL
);
263 fprintf(stderr
, "failed to execute shell: %s -c %s: %s\n", shell
, command
, strerror(errno
));
266 } else if (child
< 0) {
267 fprintf(stderr
, "failed to forking");
273 proc_close_childs(proc
);
280 /* {{{ proc_read_fd_to_buffer */
281 static void proc_read_fd_to_buffer(int fd
, buffer
*b
) {
285 buffer_string_prepare_append(b
, 1024);
286 if ((s
= read(fd
, (void *)(b
->ptr
+ buffer_string_length(b
)), buffer_string_space(b
))) <= 0) {
293 /* {{{ proc_open_buffer */
294 int proc_open_buffer(const char *command
, buffer
*in
, buffer
*out
, buffer
*err
) {
297 if (proc_open(&proc
, command
) != 0) {
302 if (write(proc
.in
.fd
, CONST_BUF_LEN(in
)) < 0) {
303 perror("error writing pipe");
307 pipe_close(&proc
.in
);
310 proc_read_fd_to_buffer(proc
.out
.fd
, out
);
312 pipe_close(&proc
.out
);
315 proc_read_fd_to_buffer(proc
.err
.fd
, err
);
317 buffer
*tmp
= buffer_init();
318 proc_read_fd_to_buffer(proc
.err
.fd
, tmp
);
319 if (!buffer_string_is_empty(tmp
) && write(2, CONST_BUF_LEN(tmp
)) < 0) {
320 perror("error writing pipe");
326 pipe_close(&proc
.err
);
335 #ifdef DEBUG_PROC_OPEN
338 buffer
*in
= buffer_init(), *out
= buffer_init(), *err
= buffer_init();
341 #define FREE() do { \
347 #define RESET() do { \
351 wstatus = proc_close(&proc); \
352 if (0&&wstatus != 0) { \
353 fprintf(stdout, "exitstatus %d\n", wstatus); \
354 return __LINE__ - 200; \
358 #define ERROR_OUT() do { \
359 fprintf(stdout, "failed opening proc\n"); \
360 wstatus = proc_close(&proc); \
361 fprintf(stdout, "exitstatus %d\n", wstatus); \
363 return __LINE__ - 300; \
367 #define CMD_CAT "pause"
369 #define CMD_CAT "cat"
373 fprintf(stdout
, "test: echo 123 without read\n");
374 if (proc_open(&proc
, "echo 321") != 0) {
377 close_descriptor(proc
.in
.parent
);
378 close_descriptor(proc
.out
.parent
);
379 close_descriptor(proc
.err
.parent
);
382 fprintf(stdout
, "test: echo 321 with read\n"); fflush(stdout
);
383 if (proc_open_buffer("echo 321", NULL
, out
, err
) != 0) {
386 fprintf(stdout
, "result: ->%s<-\n\n", out
->ptr
); fflush(stdout
);
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) {
394 fprintf(stdout
, "result: ->%s<-\n\n", out
->ptr
); fflush(stdout
);
401 fprintf(stdout
, "ok\n");
406 #endif /* DEBUG_PROC_OPEN */