Changes GC.cs
[mono-project.git] / mono / eglib / gspawn.c
blob9be865af3d691252a6356bdc990f7afc1a783f71
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 #ifndef G_OS_WIN32
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 #ifdef _MSC_VER
139 #pragma warning(push)
140 #pragma warning(disable:4389)
141 #endif
143 FD_ZERO (&rfds);
144 if (!out_closed && outfd >= 0)
145 FD_SET (outfd, &rfds);
146 if (!err_closed && errfd >= 0)
147 FD_SET (errfd, &rfds);
149 #ifdef _MSC_VER
150 #pragma warning(pop)
151 #endif
153 res = select (MAX (outfd, errfd) + 1, &rfds, NULL, NULL, NULL);
154 if (res > 0) {
155 if (buffer == NULL)
156 buffer = g_malloc (1024);
157 if (!out_closed && FD_ISSET (outfd, &rfds)) {
158 nread = safe_read (outfd, buffer, 1024, gerror);
159 if (nread < 0) {
160 close (errfd);
161 close (outfd);
162 return -1;
164 g_string_append_len (out, buffer, nread);
165 if (nread <= 0) {
166 out_closed = TRUE;
167 close (outfd);
171 if (!err_closed && FD_ISSET (errfd, &rfds)) {
172 nread = safe_read (errfd, buffer, 1024, gerror);
173 if (nread < 0) {
174 close (errfd);
175 close (outfd);
176 return -1;
178 g_string_append_len (err, buffer, nread);
179 if (nread <= 0) {
180 err_closed = TRUE;
181 close (errfd);
185 } while (res > 0 || (res == -1 && errno == EINTR));
187 g_free (buffer);
188 if (out_str)
189 *out_str = g_string_free (out, FALSE);
191 if (err_str)
192 *err_str = g_string_free (err, FALSE);
194 return 0;
197 static gboolean
198 create_pipe (int *fds, GError **gerror)
200 if (pipe (fds) == -1) {
201 set_error ("%s", "Error creating pipe.");
202 return FALSE;
204 return TRUE;
206 #endif /* G_OS_WIN32 */
208 static int
209 write_all (int fd, const void *vbuf, size_t n)
211 const char *buf = (const char *) vbuf;
212 size_t nwritten = 0;
213 int w;
215 do {
216 do {
217 w = write (fd, buf + nwritten, n - nwritten);
218 } while (w == -1 && errno == EINTR);
220 if (w == -1)
221 return -1;
223 nwritten += w;
224 } while (nwritten < n);
226 return nwritten;
229 #if !defined(G_OS_WIN32) && defined(HAVE_GETDTABLESIZE)
231 eg_getdtablesize (void)
233 #ifdef HAVE_GETRLIMIT
234 struct rlimit limit;
235 int res;
237 res = getrlimit (RLIMIT_NOFILE, &limit);
238 g_assert (res == 0);
239 return limit.rlim_cur;
240 #else
241 return getdtablesize ();
242 #endif
244 #else
246 eg_getdtablesize (void)
248 g_error ("Should not be called");
250 #endif
252 gboolean
253 g_spawn_command_line_sync (const gchar *command_line,
254 gchar **standard_output,
255 gchar **standard_error,
256 gint *exit_status,
257 GError **gerror)
259 #ifdef G_OS_WIN32
260 #elif !defined (HAVE_FORK) || !defined (HAVE_EXECV)
261 fprintf (stderr, "g_spawn_command_line_sync not supported on this platform\n");
262 return FALSE;
263 #else
264 pid_t pid;
265 gchar **argv;
266 gint argc;
267 int stdout_pipe [2] = { -1, -1 };
268 int stderr_pipe [2] = { -1, -1 };
269 int status;
270 int res;
272 if (!g_shell_parse_argv (command_line, &argc, &argv, gerror))
273 return FALSE;
275 if (standard_output && !create_pipe (stdout_pipe, gerror))
276 return FALSE;
278 if (standard_error && !create_pipe (stderr_pipe, gerror)) {
279 if (standard_output) {
280 CLOSE_PIPE (stdout_pipe);
282 return FALSE;
285 pid = fork ();
286 if (pid == 0) {
287 gint i;
289 if (standard_output) {
290 close (stdout_pipe [0]);
291 dup2 (stdout_pipe [1], STDOUT_FILENO);
294 if (standard_error) {
295 close (stderr_pipe [0]);
296 dup2 (stderr_pipe [1], STDERR_FILENO);
298 for (i = eg_getdtablesize () - 1; i >= 3; i--)
299 close (i);
301 /* G_SPAWN_SEARCH_PATH is always enabled for g_spawn_command_line_sync */
302 if (!g_path_is_absolute (argv [0])) {
303 gchar *arg0;
305 arg0 = g_find_program_in_path (argv [0]);
306 if (arg0 == NULL) {
307 exit (1);
309 //g_free (argv [0]);
310 argv [0] = arg0;
312 execv (argv [0], argv);
313 exit (1); /* TODO: What now? */
316 g_strfreev (argv);
317 if (standard_output)
318 close (stdout_pipe [1]);
320 if (standard_error)
321 close (stderr_pipe [1]);
323 if (standard_output || standard_error) {
324 res = read_pipes (stdout_pipe [0], standard_output, stderr_pipe [0], standard_error, gerror);
325 if (res) {
326 waitpid (pid, &status, WNOHANG); /* avoid zombie */
327 return FALSE;
331 NO_INTR (res, waitpid (pid, &status, 0));
333 /* TODO: What if error? */
334 if (WIFEXITED (status) && exit_status) {
335 *exit_status = WEXITSTATUS (status);
337 #endif
338 return TRUE;
342 * This is the only use we have in mono/metadata
343 !g_spawn_async_with_pipes (NULL, (char**)addr_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &child_pid, &ch_in, &ch_out, NULL, NULL)
345 gboolean
346 g_spawn_async_with_pipes (const gchar *working_directory,
347 gchar **argv,
348 gchar **envp,
349 GSpawnFlags flags,
350 GSpawnChildSetupFunc child_setup,
351 gpointer user_data,
352 GPid *child_pid,
353 gint *standard_input,
354 gint *standard_output,
355 gint *standard_error,
356 GError **gerror)
358 #ifdef G_OS_WIN32
359 #elif !defined (HAVE_FORK) || !defined (HAVE_EXECVE)
360 fprintf (stderr, "g_spawn_async_with_pipes is not supported on this platform\n");
361 return FALSE;
362 #else
363 pid_t pid;
364 int info_pipe [2];
365 int in_pipe [2] = { -1, -1 };
366 int out_pipe [2] = { -1, -1 };
367 int err_pipe [2] = { -1, -1 };
368 int status;
370 g_return_val_if_fail (argv != NULL, FALSE); /* Only mandatory arg */
372 if (!create_pipe (info_pipe, gerror))
373 return FALSE;
375 if (standard_output && !create_pipe (out_pipe, gerror)) {
376 CLOSE_PIPE (info_pipe);
377 return FALSE;
380 if (standard_error && !create_pipe (err_pipe, gerror)) {
381 CLOSE_PIPE (info_pipe);
382 CLOSE_PIPE (out_pipe);
383 return FALSE;
386 if (standard_input && !create_pipe (in_pipe, gerror)) {
387 CLOSE_PIPE (info_pipe);
388 CLOSE_PIPE (out_pipe);
389 CLOSE_PIPE (err_pipe);
390 return FALSE;
393 pid = fork ();
394 if (pid == -1) {
395 CLOSE_PIPE (info_pipe);
396 CLOSE_PIPE (out_pipe);
397 CLOSE_PIPE (err_pipe);
398 CLOSE_PIPE (in_pipe);
399 set_error ("%s", "Error in fork ()");
400 return FALSE;
403 if (pid == 0) {
404 /* No zombie left behind */
405 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
406 pid = fork ();
409 if (pid != 0) {
410 exit (pid == -1 ? 1 : 0);
411 } else {
412 gint i;
413 int fd;
414 gchar *arg0;
415 gchar **actual_args;
416 gint unused;
418 close (info_pipe [0]);
419 close (in_pipe [1]);
420 close (out_pipe [0]);
421 close (err_pipe [0]);
423 /* when exec* succeeds, we want to close this fd, which will return
424 * a 0 read on the parent. We're not supposed to keep it open forever.
425 * If exec fails, we still can write the error to it before closing.
427 fcntl (info_pipe [1], F_SETFD, FD_CLOEXEC);
429 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
430 pid = getpid ();
431 NO_INTR (unused, write_all (info_pipe [1], &pid, sizeof (pid_t)));
434 if (working_directory && chdir (working_directory) == -1) {
435 int err = errno;
436 NO_INTR (unused, write_all (info_pipe [1], &err, sizeof (int)));
437 exit (0);
440 if (standard_output) {
441 dup2 (out_pipe [1], STDOUT_FILENO);
442 } else if ((flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0) {
443 fd = open ("/dev/null", O_WRONLY);
444 dup2 (fd, STDOUT_FILENO);
447 if (standard_error) {
448 dup2 (err_pipe [1], STDERR_FILENO);
449 } else if ((flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0) {
450 fd = open ("/dev/null", O_WRONLY);
451 dup2 (fd, STDERR_FILENO);
454 if (standard_input) {
455 dup2 (in_pipe [0], STDIN_FILENO);
456 } else if ((flags & G_SPAWN_CHILD_INHERITS_STDIN) == 0) {
457 fd = open ("/dev/null", O_RDONLY);
458 dup2 (fd, STDIN_FILENO);
461 if ((flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN) != 0) {
462 for (i = eg_getdtablesize () - 1; i >= 3; i--)
463 close (i);
466 actual_args = ((flags & G_SPAWN_FILE_AND_ARGV_ZERO) == 0) ? argv : argv + 1;
467 if (envp == NULL)
468 envp = environ;
470 if (child_setup)
471 child_setup (user_data);
473 arg0 = argv [0];
474 if (!g_path_is_absolute (arg0) || (flags & G_SPAWN_SEARCH_PATH) != 0) {
475 arg0 = g_find_program_in_path (argv [0]);
476 if (arg0 == NULL) {
477 int err = ENOENT;
478 write_all (info_pipe [1], &err, sizeof (int));
479 exit (0);
483 execve (arg0, actual_args, envp);
484 int const err = errno;
485 write_all (info_pipe [1], &err, sizeof (int));
486 exit (0);
488 } else if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
489 int w;
490 /* Wait for the first child if two are created */
491 NO_INTR (w, waitpid (pid, &status, 0));
492 if (status == 1 || w == -1) {
493 CLOSE_PIPE (info_pipe);
494 CLOSE_PIPE (out_pipe);
495 CLOSE_PIPE (err_pipe);
496 CLOSE_PIPE (in_pipe);
497 set_error ("Error in fork (): %d", status);
498 return FALSE;
501 close (info_pipe [1]);
502 close (in_pipe [0]);
503 close (out_pipe [1]);
504 close (err_pipe [1]);
506 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
507 int x;
508 NO_INTR (x, read (info_pipe [0], &pid, sizeof (pid_t))); /* if we read < sizeof (pid_t)... */
511 if (child_pid) {
512 *child_pid = pid;
515 if (read (info_pipe [0], &status, sizeof (int)) != 0) {
516 close (info_pipe [0]);
517 close (in_pipe [0]);
518 close (out_pipe [1]);
519 close (err_pipe [1]);
520 set_error_status (status, "Error in exec (%d -> %s)", status, strerror (status));
521 return FALSE;
524 close (info_pipe [0]);
525 if (standard_input)
526 *standard_input = in_pipe [1];
527 if (standard_output)
528 *standard_output = out_pipe [0];
529 if (standard_error)
530 *standard_error = err_pipe [0];
531 #endif
532 return TRUE;