5 * Gonzalo Paniagua Javier (gonzalo@novell.com
7 * (C) 2006 Novell, Inc.
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files (the
11 * "Software"), to deal in the Software without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sublicense, and/or sell copies of the Software, and to
14 * permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #include <sys/types.h>
42 #ifdef HAVE_SYS_TIME_H
46 #ifdef HAVE_SYS_WAIT_H
57 /* windows pipe api details: http://msdn2.microsoft.com/en-us/library/edze9h7e(VS.80).aspx */
58 #define pipe(x) _pipe(x, 256, 0)
61 #define set_error(msg, ...) do { if (error != NULL) *error = g_error_new (G_LOG_DOMAIN, 1, msg, __VA_ARGS__); } while (0)
62 #define set_error_cond(cond,msg, ...) do { if ((cond) && error != NULL) *error = g_error_new (G_LOG_DOMAIN, 1, msg, __VA_ARGS__); } while (0)
63 #define set_error_status(status,msg, ...) do { if (error != NULL) *error = g_error_new (G_LOG_DOMAIN, status, msg, __VA_ARGS__); } while (0)
64 #define NO_INTR(var,cmd) do { (var) = (cmd); } while ((var) == -1 && errno == EINTR)
65 #define CLOSE_PIPE(p) do { close (p [0]); close (p [1]); } while (0)
68 /* Apple defines this in crt_externs.h but doesn't provide that header for
69 * arm-apple-darwin9. We'll manually define the symbol on Apple as it does
70 * in fact exist on all implementations (so far)
72 gchar
***_NSGetEnviron();
73 #define environ (*_NSGetEnviron())
77 safe_read (int fd
, gchar
*buffer
, gint count
, GError
**error
)
81 NO_INTR (res
, read (fd
, buffer
, count
));
82 set_error_cond (res
== -1, "%s", "Error reading from pipe.");
87 read_pipes (int outfd
, gchar
**out_str
, int errfd
, gchar
**err_str
, GError
**error
)
98 out_closed
= (outfd
< 0);
99 err_closed
= (errfd
< 0);
102 out
= g_string_new ("");
107 err
= g_string_new ("");
111 if (out_closed
&& err_closed
)
115 #pragma warning(push)
116 #pragma warning(disable:4389)
120 if (!out_closed
&& outfd
>= 0)
121 FD_SET (outfd
, &rfds
);
122 if (!err_closed
&& errfd
>= 0)
123 FD_SET (errfd
, &rfds
);
129 res
= select (MAX (outfd
, errfd
) + 1, &rfds
, NULL
, NULL
, NULL
);
132 buffer
= g_malloc (1024);
133 if (!out_closed
&& FD_ISSET (outfd
, &rfds
)) {
134 nread
= safe_read (outfd
, buffer
, 1024, error
);
140 g_string_append_len (out
, buffer
, nread
);
147 if (!err_closed
&& FD_ISSET (errfd
, &rfds
)) {
148 nread
= safe_read (errfd
, buffer
, 1024, error
);
154 g_string_append_len (err
, buffer
, nread
);
161 } while (res
> 0 || (res
== -1 && errno
== EINTR
));
165 *out_str
= g_string_free (out
, FALSE
);
168 *err_str
= g_string_free (err
, FALSE
);
174 create_pipe (int *fds
, GError
**error
)
176 if (pipe (fds
) == -1) {
177 set_error ("%s", "Error creating pipe.");
184 g_spawn_command_line_sync (const gchar
*command_line
,
185 gchar
**standard_output
,
186 gchar
**standard_error
,
195 int stdout_pipe
[2] = { -1, -1 };
196 int stderr_pipe
[2] = { -1, -1 };
200 if (!g_shell_parse_argv (command_line
, &argc
, &argv
, error
))
203 if (standard_output
&& !create_pipe (stdout_pipe
, error
))
206 if (standard_error
&& !create_pipe (stderr_pipe
, error
)) {
207 if (standard_output
) {
208 CLOSE_PIPE (stdout_pipe
);
217 if (standard_output
) {
218 close (stdout_pipe
[0]);
219 dup2 (stdout_pipe
[1], STDOUT_FILENO
);
222 if (standard_error
) {
223 close (stderr_pipe
[0]);
224 dup2 (stderr_pipe
[1], STDERR_FILENO
);
226 for (i
= getdtablesize () - 1; i
>= 3; i
--)
229 /* G_SPAWN_SEARCH_PATH is always enabled for g_spawn_command_line_sync */
230 if (!g_path_is_absolute (argv
[0])) {
233 arg0
= g_find_program_in_path (argv
[0]);
240 execv (argv
[0], argv
);
241 exit (1); /* TODO: What now? */
246 close (stdout_pipe
[1]);
249 close (stderr_pipe
[1]);
251 if (standard_output
|| standard_error
) {
252 res
= read_pipes (stdout_pipe
[0], standard_output
, stderr_pipe
[0], standard_error
, error
);
254 waitpid (pid
, &status
, WNOHANG
); /* avoid zombie */
259 NO_INTR (res
, waitpid (pid
, &status
, 0));
261 /* TODO: What if error? */
262 if (WIFEXITED (status
) && exit_status
) {
263 *exit_status
= WEXITSTATUS (status
);
270 * This is the only use we have in mono/metadata
271 !g_spawn_async_with_pipes (NULL, (char**)addr_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &child_pid, &ch_in, &ch_out, NULL, NULL)
274 g_spawn_async_with_pipes (const gchar
*working_directory
,
278 GSpawnChildSetupFunc child_setup
,
281 gint
*standard_input
,
282 gint
*standard_output
,
283 gint
*standard_error
,
290 int in_pipe
[2] = { -1, -1 };
291 int out_pipe
[2] = { -1, -1 };
292 int err_pipe
[2] = { -1, -1 };
295 g_return_val_if_fail (argv
!= NULL
, FALSE
); /* Only mandatory arg */
297 if (!create_pipe (info_pipe
, error
))
300 if (standard_output
&& !create_pipe (out_pipe
, error
)) {
301 CLOSE_PIPE (info_pipe
);
305 if (standard_error
&& !create_pipe (err_pipe
, error
)) {
306 CLOSE_PIPE (info_pipe
);
307 CLOSE_PIPE (out_pipe
);
311 if (standard_input
&& !create_pipe (in_pipe
, error
)) {
312 CLOSE_PIPE (info_pipe
);
313 CLOSE_PIPE (out_pipe
);
314 CLOSE_PIPE (err_pipe
);
320 CLOSE_PIPE (info_pipe
);
321 CLOSE_PIPE (out_pipe
);
322 CLOSE_PIPE (err_pipe
);
323 CLOSE_PIPE (in_pipe
);
324 set_error ("%s", "Error in fork ()");
329 /* No zombie left behind */
330 if ((flags
& G_SPAWN_DO_NOT_REAP_CHILD
) == 0) {
335 exit (pid
== -1 ? 1 : 0);
343 close (info_pipe
[0]);
345 close (out_pipe
[0]);
346 close (err_pipe
[0]);
348 /* when exec* succeeds, we want to close this fd, which will return
349 * a 0 read on the parent. We're not supposed to keep it open forever.
350 * If exec fails, we still can write the error to it before closing.
352 fcntl (info_pipe
[1], F_SETFD
, FD_CLOEXEC
);
354 if ((flags
& G_SPAWN_DO_NOT_REAP_CHILD
) == 0) {
356 NO_INTR (unused
, write (info_pipe
[1], &pid
, sizeof (pid_t
)));
359 if (working_directory
&& chdir (working_directory
) == -1) {
361 NO_INTR (unused
, write (info_pipe
[1], &err
, sizeof (int)));
365 if (standard_output
) {
366 dup2 (out_pipe
[1], STDOUT_FILENO
);
367 } else if ((flags
& G_SPAWN_STDOUT_TO_DEV_NULL
) != 0) {
368 fd
= open ("/dev/null", O_WRONLY
);
369 dup2 (fd
, STDOUT_FILENO
);
372 if (standard_error
) {
373 dup2 (err_pipe
[1], STDERR_FILENO
);
374 } else if ((flags
& G_SPAWN_STDERR_TO_DEV_NULL
) != 0) {
375 fd
= open ("/dev/null", O_WRONLY
);
376 dup2 (fd
, STDERR_FILENO
);
379 if (standard_input
) {
380 dup2 (in_pipe
[0], STDERR_FILENO
);
381 } else if ((flags
& G_SPAWN_CHILD_INHERITS_STDIN
) == 0) {
382 fd
= open ("/dev/null", O_RDONLY
);
383 dup2 (fd
, STDERR_FILENO
);
386 if ((flags
& G_SPAWN_LEAVE_DESCRIPTORS_OPEN
) != 0) {
387 for (i
= getdtablesize () - 1; i
>= 3; i
--)
391 actual_args
= ((flags
& G_SPAWN_FILE_AND_ARGV_ZERO
) == 0) ? argv
: argv
+ 1;
396 child_setup (user_data
);
399 if (!g_path_is_absolute (arg0
) || (flags
& G_SPAWN_SEARCH_PATH
) != 0) {
400 arg0
= g_find_program_in_path (argv
[0]);
403 write (info_pipe
[1], &err
, sizeof (int));
408 execve (arg0
, actual_args
, envp
);
409 write (info_pipe
[1], &errno
, sizeof (int));
412 } else if ((flags
& G_SPAWN_DO_NOT_REAP_CHILD
) == 0) {
414 /* Wait for the first child if two are created */
415 NO_INTR (w
, waitpid (pid
, &status
, 0));
416 if (status
== 1 || w
== -1) {
417 CLOSE_PIPE (info_pipe
);
418 CLOSE_PIPE (out_pipe
);
419 CLOSE_PIPE (err_pipe
);
420 CLOSE_PIPE (in_pipe
);
421 set_error ("Error in fork (): %d", status
);
425 close (info_pipe
[1]);
427 close (out_pipe
[1]);
428 close (err_pipe
[1]);
430 if ((flags
& G_SPAWN_DO_NOT_REAP_CHILD
) == 0) {
432 NO_INTR (x
, read (info_pipe
[0], &pid
, sizeof (pid_t
))); /* if we read < sizeof (pid_t)... */
439 if (read (info_pipe
[0], &status
, sizeof (int)) != 0) {
440 close (info_pipe
[0]);
442 close (out_pipe
[1]);
443 close (err_pipe
[1]);
444 set_error_status (status
, "Error in exec (%d -> %s)", status
, strerror (status
));
448 close (info_pipe
[0]);
450 *standard_input
= in_pipe
[1];
452 *standard_output
= out_pipe
[0];
454 *standard_error
= err_pipe
[0];