[interp] Always intrinsify MemoryBarrier method
[mono-project.git] / mono / eglib / gspawn.c
blob64ac161f716f9d7b6105f18c6844b0295ae7f4ae
1 /*
2 * Spawning processes.
4 * Author:
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.
28 #include <config.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
35 #include <glib.h>
37 #ifdef HAVE_UNISTD_H
38 #ifndef __USE_GNU
39 #define __USE_GNU
40 #endif
41 #include <unistd.h>
42 #endif
44 #ifdef HAVE_SYS_SELECT_H
45 #include <sys/select.h>
46 #endif
48 #ifdef HAVE_SYS_TIME_H
49 #include <sys/time.h>
50 #endif
52 #ifdef HAVE_SYS_WAIT_H
53 #include <sys/wait.h>
54 #endif
56 #ifdef HAVE_SYS_RESOURCE_H
57 # include <sys/resource.h>
58 #endif
60 #ifdef G_OS_WIN32
61 #include <io.h>
62 #include <winsock2.h>
63 #define open _open
64 #define close _close
65 #define read _read
66 #define write _write
67 /* windows pipe api details: http://msdn2.microsoft.com/en-us/library/edze9h7e(VS.80).aspx */
68 #define pipe(x) _pipe(x, 256, 0)
69 #endif
71 #define set_error(msg, ...) do { if (gerror != NULL) *gerror = g_error_new (G_LOG_DOMAIN, 1, msg, __VA_ARGS__); } while (0)
72 #define set_error_cond(cond,msg, ...) do { if ((cond) && gerror != NULL) *gerror = g_error_new (G_LOG_DOMAIN, 1, msg, __VA_ARGS__); } while (0)
73 #define set_error_status(status,msg, ...) do { if (gerror != NULL) *gerror = 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__)
78 #if defined (TARGET_OSX)
79 /* Apple defines this in crt_externs.h but doesn't provide that header for
80 * arm-apple-darwin9. We'll manually define the symbol on Apple as it does
81 * in fact exist on all implementations (so far)
83 G_BEGIN_DECLS
84 gchar ***_NSGetEnviron(void);
85 G_END_DECLS
86 #define environ (*_NSGetEnviron())
87 #else
88 static char *mono_environ[1] = { NULL };
89 #define environ mono_environ
90 #endif /* defined (TARGET_OSX) */
91 #elif defined(_MSC_VER)
92 /* MS defines this in stdlib.h */
93 #else
94 G_BEGIN_DECLS
95 extern char **environ;
96 G_END_DECLS
97 #endif
99 #if !defined (G_OS_WIN32) && defined (HAVE_FORK) && defined (HAVE_EXECV)
100 static int
101 safe_read (int fd, gchar *buffer, gint count, GError **gerror)
103 int res;
105 NO_INTR (res, read (fd, buffer, count));
106 set_error_cond (res == -1, "%s", "Error reading from pipe.");
107 return res;
110 static int
111 read_pipes (int outfd, gchar **out_str, int errfd, gchar **err_str, GError **gerror)
113 fd_set rfds;
114 int res;
115 gboolean out_closed;
116 gboolean err_closed;
117 GString *out = NULL;
118 GString *err = NULL;
119 gchar *buffer = NULL;
120 gint nread;
122 out_closed = (outfd < 0);
123 err_closed = (errfd < 0);
124 if (out_str) {
125 *out_str = NULL;
126 out = g_string_new ("");
129 if (err_str) {
130 *err_str = NULL;
131 err = g_string_new ("");
134 do {
135 if (out_closed && err_closed)
136 break;
138 FD_ZERO (&rfds);
139 if (!out_closed && outfd >= 0)
140 FD_SET (outfd, &rfds);
141 if (!err_closed && errfd >= 0)
142 FD_SET (errfd, &rfds);
144 res = select (MAX (outfd, errfd) + 1, &rfds, NULL, NULL, NULL);
145 if (res > 0) {
146 if (buffer == NULL)
147 buffer = g_malloc (1024);
148 if (!out_closed && FD_ISSET (outfd, &rfds)) {
149 nread = safe_read (outfd, buffer, 1024, gerror);
150 if (nread < 0) {
151 close (errfd);
152 close (outfd);
153 return -1;
155 g_string_append_len (out, buffer, nread);
156 if (nread <= 0) {
157 out_closed = TRUE;
158 close (outfd);
162 if (!err_closed && FD_ISSET (errfd, &rfds)) {
163 nread = safe_read (errfd, buffer, 1024, gerror);
164 if (nread < 0) {
165 close (errfd);
166 close (outfd);
167 return -1;
169 g_string_append_len (err, buffer, nread);
170 if (nread <= 0) {
171 err_closed = TRUE;
172 close (errfd);
176 } while (res > 0 || (res == -1 && errno == EINTR));
178 g_free (buffer);
179 if (out_str)
180 *out_str = g_string_free (out, FALSE);
182 if (err_str)
183 *err_str = g_string_free (err, FALSE);
185 return 0;
188 static gboolean
189 create_pipe (int *fds, GError **gerror)
191 if (pipe (fds) == -1) {
192 set_error ("%s", "Error creating pipe.");
193 return FALSE;
195 return TRUE;
198 static int
199 write_all (int fd, const void *vbuf, size_t n)
201 const char *buf = (const char *) vbuf;
202 size_t nwritten = 0;
203 int w;
205 do {
206 do {
207 w = write (fd, buf + nwritten, n - nwritten);
208 } while (w == -1 && errno == EINTR);
210 if (w == -1)
211 return -1;
213 nwritten += w;
214 } while (nwritten < n);
216 return nwritten;
218 #endif /* !defined (G_OS_WIN32) && defined (HAVE_FORK) && defined (HAVE_EXECV) */
220 #if !defined(G_OS_WIN32) && defined(HAVE_GETDTABLESIZE)
222 eg_getdtablesize (void)
224 #ifdef HAVE_GETRLIMIT
225 struct rlimit limit;
226 int res;
228 res = getrlimit (RLIMIT_NOFILE, &limit);
229 g_assert (res == 0);
230 return limit.rlim_cur;
231 #else
232 return getdtablesize ();
233 #endif
235 #else
237 eg_getdtablesize (void)
239 g_error ("Should not be called");
241 #endif
243 gboolean
244 g_spawn_command_line_sync (const gchar *command_line,
245 gchar **standard_output,
246 gchar **standard_error,
247 gint *exit_status,
248 GError **gerror)
250 #ifdef G_OS_WIN32
251 return TRUE;
252 #elif !defined (HAVE_FORK) || !defined (HAVE_EXECV)
253 fprintf (stderr, "g_spawn_command_line_sync not supported on this platform\n");
254 return FALSE;
255 #else
256 pid_t pid;
257 gchar **argv;
258 gint argc;
259 int stdout_pipe [2] = { -1, -1 };
260 int stderr_pipe [2] = { -1, -1 };
261 int status;
262 int res;
264 if (!g_shell_parse_argv (command_line, &argc, &argv, gerror))
265 return FALSE;
267 if (standard_output && !create_pipe (stdout_pipe, gerror))
268 return FALSE;
270 if (standard_error && !create_pipe (stderr_pipe, gerror)) {
271 if (standard_output) {
272 CLOSE_PIPE (stdout_pipe);
274 return FALSE;
277 pid = fork ();
278 if (pid == 0) {
279 gint i;
281 if (standard_output) {
282 close (stdout_pipe [0]);
283 dup2 (stdout_pipe [1], STDOUT_FILENO);
286 if (standard_error) {
287 close (stderr_pipe [0]);
288 dup2 (stderr_pipe [1], STDERR_FILENO);
290 for (i = eg_getdtablesize () - 1; i >= 3; i--)
291 close (i);
293 /* G_SPAWN_SEARCH_PATH is always enabled for g_spawn_command_line_sync */
294 if (!g_path_is_absolute (argv [0])) {
295 gchar *arg0;
297 arg0 = g_find_program_in_path (argv [0]);
298 if (arg0 == NULL) {
299 exit (1);
301 //g_free (argv [0]);
302 argv [0] = arg0;
304 execv (argv [0], argv);
305 exit (1); /* TODO: What now? */
308 g_strfreev (argv);
309 if (standard_output)
310 close (stdout_pipe [1]);
312 if (standard_error)
313 close (stderr_pipe [1]);
315 if (standard_output || standard_error) {
316 res = read_pipes (stdout_pipe [0], standard_output, stderr_pipe [0], standard_error, gerror);
317 if (res) {
318 waitpid (pid, &status, WNOHANG); /* avoid zombie */
319 return FALSE;
323 NO_INTR (res, waitpid (pid, &status, 0));
325 /* TODO: What if error? */
326 if (WIFEXITED (status) && exit_status) {
327 *exit_status = WEXITSTATUS (status);
329 return TRUE;
330 #endif
334 * This is the only use we have in mono/metadata
335 !g_spawn_async_with_pipes (NULL, (char**)addr_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &child_pid, &ch_in, &ch_out, NULL, NULL)
337 gboolean
338 g_spawn_async_with_pipes (const gchar *working_directory,
339 gchar **argv,
340 gchar **envp,
341 GSpawnFlags flags,
342 GSpawnChildSetupFunc child_setup,
343 gpointer user_data,
344 GPid *child_pid,
345 gint *standard_input,
346 gint *standard_output,
347 gint *standard_error,
348 GError **gerror)
350 #ifdef G_OS_WIN32
351 return TRUE;
352 #elif !defined (HAVE_FORK) || !defined (HAVE_EXECVE)
353 fprintf (stderr, "g_spawn_async_with_pipes is not supported on this platform\n");
354 return FALSE;
355 #else
356 pid_t pid;
357 int info_pipe [2];
358 int in_pipe [2] = { -1, -1 };
359 int out_pipe [2] = { -1, -1 };
360 int err_pipe [2] = { -1, -1 };
361 int status;
363 g_return_val_if_fail (argv != NULL, FALSE); /* Only mandatory arg */
365 if (!create_pipe (info_pipe, gerror))
366 return FALSE;
368 if (standard_output && !create_pipe (out_pipe, gerror)) {
369 CLOSE_PIPE (info_pipe);
370 return FALSE;
373 if (standard_error && !create_pipe (err_pipe, gerror)) {
374 CLOSE_PIPE (info_pipe);
375 CLOSE_PIPE (out_pipe);
376 return FALSE;
379 if (standard_input && !create_pipe (in_pipe, gerror)) {
380 CLOSE_PIPE (info_pipe);
381 CLOSE_PIPE (out_pipe);
382 CLOSE_PIPE (err_pipe);
383 return FALSE;
386 pid = fork ();
387 if (pid == -1) {
388 CLOSE_PIPE (info_pipe);
389 CLOSE_PIPE (out_pipe);
390 CLOSE_PIPE (err_pipe);
391 CLOSE_PIPE (in_pipe);
392 set_error ("%s", "Error in fork ()");
393 return FALSE;
396 if (pid == 0) {
397 /* No zombie left behind */
398 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
399 pid = fork ();
402 if (pid != 0) {
403 exit (pid == -1 ? 1 : 0);
404 } else {
405 gint i;
406 int fd;
407 gchar *arg0;
408 gchar **actual_args;
409 gint unused;
411 close (info_pipe [0]);
412 close (in_pipe [1]);
413 close (out_pipe [0]);
414 close (err_pipe [0]);
416 /* when exec* succeeds, we want to close this fd, which will return
417 * a 0 read on the parent. We're not supposed to keep it open forever.
418 * If exec fails, we still can write the error to it before closing.
420 fcntl (info_pipe [1], F_SETFD, FD_CLOEXEC);
422 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
423 pid = getpid ();
424 NO_INTR (unused, write_all (info_pipe [1], &pid, sizeof (pid_t)));
427 if (working_directory && chdir (working_directory) == -1) {
428 int err = errno;
429 NO_INTR (unused, write_all (info_pipe [1], &err, sizeof (int)));
430 exit (0);
433 if (standard_output) {
434 dup2 (out_pipe [1], STDOUT_FILENO);
435 } else if ((flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0) {
436 fd = open ("/dev/null", O_WRONLY);
437 dup2 (fd, STDOUT_FILENO);
440 if (standard_error) {
441 dup2 (err_pipe [1], STDERR_FILENO);
442 } else if ((flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0) {
443 fd = open ("/dev/null", O_WRONLY);
444 dup2 (fd, STDERR_FILENO);
447 if (standard_input) {
448 dup2 (in_pipe [0], STDIN_FILENO);
449 } else if ((flags & G_SPAWN_CHILD_INHERITS_STDIN) == 0) {
450 fd = open ("/dev/null", O_RDONLY);
451 dup2 (fd, STDIN_FILENO);
454 if ((flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN) != 0) {
455 for (i = eg_getdtablesize () - 1; i >= 3; i--)
456 close (i);
459 actual_args = ((flags & G_SPAWN_FILE_AND_ARGV_ZERO) == 0) ? argv : argv + 1;
460 if (envp == NULL)
461 envp = environ;
463 if (child_setup)
464 child_setup (user_data);
466 arg0 = argv [0];
467 if (!g_path_is_absolute (arg0) || (flags & G_SPAWN_SEARCH_PATH) != 0) {
468 arg0 = g_find_program_in_path (argv [0]);
469 if (arg0 == NULL) {
470 int err = ENOENT;
471 write_all (info_pipe [1], &err, sizeof (int));
472 exit (0);
476 execve (arg0, actual_args, envp);
477 int const err = errno;
478 write_all (info_pipe [1], &err, sizeof (int));
479 exit (0);
481 } else if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
482 int w;
483 /* Wait for the first child if two are created */
484 NO_INTR (w, waitpid (pid, &status, 0));
485 if (status == 1 || w == -1) {
486 CLOSE_PIPE (info_pipe);
487 CLOSE_PIPE (out_pipe);
488 CLOSE_PIPE (err_pipe);
489 CLOSE_PIPE (in_pipe);
490 set_error ("Error in fork (): %d", status);
491 return FALSE;
494 close (info_pipe [1]);
495 close (in_pipe [0]);
496 close (out_pipe [1]);
497 close (err_pipe [1]);
499 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
500 int x;
501 NO_INTR (x, read (info_pipe [0], &pid, sizeof (pid_t))); /* if we read < sizeof (pid_t)... */
504 if (child_pid) {
505 *child_pid = pid;
508 if (read (info_pipe [0], &status, sizeof (int)) != 0) {
509 close (info_pipe [0]);
510 close (in_pipe [0]);
511 close (out_pipe [1]);
512 close (err_pipe [1]);
513 set_error_status (status, "Error in exec (%d -> %s)", status, strerror (status));
514 return FALSE;
517 close (info_pipe [0]);
518 if (standard_input)
519 *standard_input = in_pipe [1];
520 if (standard_output)
521 *standard_output = out_pipe [0];
522 if (standard_error)
523 *standard_error = err_pipe [0];
524 return TRUE;
525 #endif