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>
44 #ifdef HAVE_SYS_SELECT_H
45 #include <sys/select.h>
48 #ifdef HAVE_SYS_TIME_H
52 #ifdef HAVE_SYS_WAIT_H
56 #ifdef HAVE_SYS_RESOURCE_H
57 # include <sys/resource.h>
67 /* windows pipe api details: http://msdn2.microsoft.com/en-us/library/edze9h7e(VS.80).aspx */
68 #define pipe(x) _pipe(x, 256, 0)
71 #define set_error(msg, ...) do { if (error != NULL) *error = g_error_new (G_LOG_DOMAIN, 1, msg, __VA_ARGS__); } while (0)
72 #define set_error_cond(cond,msg, ...) do { if ((cond) && error != NULL) *error = g_error_new (G_LOG_DOMAIN, 1, msg, __VA_ARGS__); } while (0)
73 #define set_error_status(status,msg, ...) do { if (error != NULL) *error = g_error_new (G_LOG_DOMAIN, status, msg, __VA_ARGS__); } while (0)
74 #define NO_INTR(var,cmd) do { (var) = (cmd); } while ((var) == -1 && errno == EINTR)
75 #define CLOSE_PIPE(p) do { close (p [0]); close (p [1]); } while (0)
77 #if defined(__APPLE__) && !defined (__arm__) && !defined (__aarch64__)
78 /* Apple defines this in crt_externs.h but doesn't provide that header for
79 * arm-apple-darwin9. We'll manually define the symbol on Apple as it does
80 * in fact exist on all implementations (so far)
82 gchar ***_NSGetEnviron();
83 #define environ (*_NSGetEnviron())
84 #elif defined(_MSC_VER)
85 /* MS defines this in stdlib.h */
87 extern char **environ;
92 safe_read (int fd, gchar *buffer, gint count, GError **error)
96 NO_INTR (res, read (fd, buffer, count));
97 set_error_cond (res == -1, "%s", "Error reading from pipe.");
102 read_pipes (int outfd, gchar **out_str, int errfd, gchar **err_str, GError **error)
110 gchar *buffer = NULL;
113 out_closed = (outfd < 0);
114 err_closed = (errfd < 0);
117 out = g_string_new ("");
122 err = g_string_new ("");
126 if (out_closed && err_closed)
130 #pragma warning(push)
131 #pragma warning(disable:4389)
135 if (!out_closed && outfd >= 0)
136 FD_SET (outfd, &rfds);
137 if (!err_closed && errfd >= 0)
138 FD_SET (errfd, &rfds);
144 res = select (MAX (outfd, errfd) + 1, &rfds, NULL, NULL, NULL);
147 buffer = g_malloc (1024);
148 if (!out_closed && FD_ISSET (outfd, &rfds)) {
149 nread = safe_read (outfd, buffer, 1024, error);
155 g_string_append_len (out, buffer, nread);
162 if (!err_closed && FD_ISSET (errfd, &rfds)) {
163 nread = safe_read (errfd, buffer, 1024, error);
169 g_string_append_len (err, buffer, nread);
176 } while (res > 0 || (res == -1 && errno == EINTR));
180 *out_str = g_string_free (out, FALSE);
183 *err_str = g_string_free (err, FALSE);
189 create_pipe (int *fds, GError **error)
191 if (pipe (fds) == -1) {
192 set_error ("%s", "Error creating pipe.");
197 #endif /* G_OS_WIN32 */
200 write_all (int fd, const void *vbuf, size_t n)
202 const char *buf = (const char *) vbuf;
208 w = write (fd, buf + nwritten, n - nwritten);
209 } while (w == -1 && errno == EINTR);
215 } while (nwritten < n);
222 eg_getdtablesize (void)
224 #ifdef HAVE_GETRLIMIT
228 res = getrlimit (RLIMIT_NOFILE, &limit);
230 return limit.rlim_cur;
232 return getdtablesize ();
237 eg_getdtablesize (void)
239 g_error ("Should not be called");
244 g_spawn_command_line_sync (const gchar *command_line,
245 gchar **standard_output,
246 gchar **standard_error,
255 int stdout_pipe [2] = { -1, -1 };
256 int stderr_pipe [2] = { -1, -1 };
260 if (!g_shell_parse_argv (command_line, &argc, &argv, error))
263 if (standard_output && !create_pipe (stdout_pipe, error))
266 if (standard_error && !create_pipe (stderr_pipe, error)) {
267 if (standard_output) {
268 CLOSE_PIPE (stdout_pipe);
277 if (standard_output) {
278 close (stdout_pipe [0]);
279 dup2 (stdout_pipe [1], STDOUT_FILENO);
282 if (standard_error) {
283 close (stderr_pipe [0]);
284 dup2 (stderr_pipe [1], STDERR_FILENO);
286 for (i = eg_getdtablesize () - 1; i >= 3; i--)
289 /* G_SPAWN_SEARCH_PATH is always enabled for g_spawn_command_line_sync */
290 if (!g_path_is_absolute (argv [0])) {
293 arg0 = g_find_program_in_path (argv [0]);
300 execv (argv [0], argv);
301 exit (1); /* TODO: What now? */
306 close (stdout_pipe [1]);
309 close (stderr_pipe [1]);
311 if (standard_output || standard_error) {
312 res = read_pipes (stdout_pipe [0], standard_output, stderr_pipe [0], standard_error, error);
314 waitpid (pid, &status, WNOHANG); /* avoid zombie */
319 NO_INTR (res, waitpid (pid, &status, 0));
321 /* TODO: What if error? */
322 if (WIFEXITED (status) && exit_status) {
323 *exit_status = WEXITSTATUS (status);
330 * This is the only use we have in mono/metadata
331 !g_spawn_async_with_pipes (NULL, (char**)addr_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &child_pid, &ch_in, &ch_out, NULL, NULL)
334 g_spawn_async_with_pipes (const gchar *working_directory,
338 GSpawnChildSetupFunc child_setup,
341 gint *standard_input,
342 gint *standard_output,
343 gint *standard_error,
350 int in_pipe [2] = { -1, -1 };
351 int out_pipe [2] = { -1, -1 };
352 int err_pipe [2] = { -1, -1 };
355 g_return_val_if_fail (argv != NULL, FALSE); /* Only mandatory arg */
357 if (!create_pipe (info_pipe, error))
360 if (standard_output && !create_pipe (out_pipe, error)) {
361 CLOSE_PIPE (info_pipe);
365 if (standard_error && !create_pipe (err_pipe, error)) {
366 CLOSE_PIPE (info_pipe);
367 CLOSE_PIPE (out_pipe);
371 if (standard_input && !create_pipe (in_pipe, error)) {
372 CLOSE_PIPE (info_pipe);
373 CLOSE_PIPE (out_pipe);
374 CLOSE_PIPE (err_pipe);
380 CLOSE_PIPE (info_pipe);
381 CLOSE_PIPE (out_pipe);
382 CLOSE_PIPE (err_pipe);
383 CLOSE_PIPE (in_pipe);
384 set_error ("%s", "Error in fork ()");
389 /* No zombie left behind */
390 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
395 exit (pid == -1 ? 1 : 0);
403 close (info_pipe [0]);
405 close (out_pipe [0]);
406 close (err_pipe [0]);
408 /* when exec* succeeds, we want to close this fd, which will return
409 * a 0 read on the parent. We're not supposed to keep it open forever.
410 * If exec fails, we still can write the error to it before closing.
412 fcntl (info_pipe [1], F_SETFD, FD_CLOEXEC);
414 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
416 NO_INTR (unused, write_all (info_pipe [1], &pid, sizeof (pid_t)));
419 if (working_directory && chdir (working_directory) == -1) {
421 NO_INTR (unused, write_all (info_pipe [1], &err, sizeof (int)));
425 if (standard_output) {
426 dup2 (out_pipe [1], STDOUT_FILENO);
427 } else if ((flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0) {
428 fd = open ("/dev/null", O_WRONLY);
429 dup2 (fd, STDOUT_FILENO);
432 if (standard_error) {
433 dup2 (err_pipe [1], STDERR_FILENO);
434 } else if ((flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0) {
435 fd = open ("/dev/null", O_WRONLY);
436 dup2 (fd, STDERR_FILENO);
439 if (standard_input) {
440 dup2 (in_pipe [0], STDIN_FILENO);
441 } else if ((flags & G_SPAWN_CHILD_INHERITS_STDIN) == 0) {
442 fd = open ("/dev/null", O_RDONLY);
443 dup2 (fd, STDIN_FILENO);
446 if ((flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN) != 0) {
447 for (i = eg_getdtablesize () - 1; i >= 3; i--)
451 actual_args = ((flags & G_SPAWN_FILE_AND_ARGV_ZERO) == 0) ? argv : argv + 1;
456 child_setup (user_data);
459 if (!g_path_is_absolute (arg0) || (flags & G_SPAWN_SEARCH_PATH) != 0) {
460 arg0 = g_find_program_in_path (argv [0]);
463 write_all (info_pipe [1], &err, sizeof (int));
468 execve (arg0, actual_args, envp);
469 write_all (info_pipe [1], &errno, sizeof (int));
472 } else if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
474 /* Wait for the first child if two are created */
475 NO_INTR (w, waitpid (pid, &status, 0));
476 if (status == 1 || w == -1) {
477 CLOSE_PIPE (info_pipe);
478 CLOSE_PIPE (out_pipe);
479 CLOSE_PIPE (err_pipe);
480 CLOSE_PIPE (in_pipe);
481 set_error ("Error in fork (): %d", status);
485 close (info_pipe [1]);
487 close (out_pipe [1]);
488 close (err_pipe [1]);
490 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
492 NO_INTR (x, read (info_pipe [0], &pid, sizeof (pid_t))); /* if we read < sizeof (pid_t)... */
499 if (read (info_pipe [0], &status, sizeof (int)) != 0) {
500 close (info_pipe [0]);
502 close (out_pipe [1]);
503 close (err_pipe [1]);
504 set_error_status (status, "Error in exec (%d -> %s)", status, strerror (status));
508 close (info_pipe [0]);
510 *standard_input = in_pipe [1];
512 *standard_output = out_pipe [0];
514 *standard_error = err_pipe [0];