Added/Updated .gitignore files
[mono.git] / eglib / src / gspawn.c
blob73b456d1a41e0a0bdcbe6ac21795bd07d32586b5
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 #define __USE_GNU
39 #include <unistd.h>
40 #endif
42 #ifdef HAVE_SYS_TIME_H
43 #include <sys/time.h>
44 #endif
46 #ifdef HAVE_SYS_WAIT_H
47 #include <sys/wait.h>
48 #endif
50 #ifdef G_OS_WIN32
51 #include <io.h>
52 #include <winsock2.h>
53 #define open _open
54 #define close _close
55 #define read _read
56 #define write _write
57 /* windows pipe api details: http://msdn2.microsoft.com/en-us/library/edze9h7e(VS.80).aspx */
58 #define pipe(x) _pipe(x, 256, 0)
59 #endif
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)
67 #ifdef __APPLE__
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())
74 #endif
76 static int
77 safe_read (int fd, gchar *buffer, gint count, GError **error)
79 int res;
81 NO_INTR (res, read (fd, buffer, count));
82 set_error_cond (res == -1, "%s", "Error reading from pipe.");
83 return res;
86 static int
87 read_pipes (int outfd, gchar **out_str, int errfd, gchar **err_str, GError **error)
89 fd_set rfds;
90 int res;
91 gboolean out_closed;
92 gboolean err_closed;
93 GString *out = NULL;
94 GString *err = NULL;
95 gchar *buffer = NULL;
96 gint nread;
98 out_closed = (outfd < 0);
99 err_closed = (errfd < 0);
100 if (out_str) {
101 *out_str = NULL;
102 out = g_string_new ("");
105 if (err_str) {
106 *err_str = NULL;
107 err = g_string_new ("");
110 do {
111 if (out_closed && err_closed)
112 break;
114 #ifdef _MSC_VER
115 #pragma warning(push)
116 #pragma warning(disable:4389)
117 #endif
119 FD_ZERO (&rfds);
120 if (!out_closed && outfd >= 0)
121 FD_SET (outfd, &rfds);
122 if (!err_closed && errfd >= 0)
123 FD_SET (errfd, &rfds);
125 #ifdef _MSC_VER
126 #pragma warning(pop)
127 #endif
129 res = select (MAX (outfd, errfd) + 1, &rfds, NULL, NULL, NULL);
130 if (res > 0) {
131 if (buffer == NULL)
132 buffer = g_malloc (1024);
133 if (!out_closed && FD_ISSET (outfd, &rfds)) {
134 nread = safe_read (outfd, buffer, 1024, error);
135 if (nread < 0) {
136 close (errfd);
137 close (outfd);
138 return -1;
140 g_string_append_len (out, buffer, nread);
141 if (nread <= 0) {
142 out_closed = TRUE;
143 close (outfd);
147 if (!err_closed && FD_ISSET (errfd, &rfds)) {
148 nread = safe_read (errfd, buffer, 1024, error);
149 if (nread < 0) {
150 close (errfd);
151 close (outfd);
152 return -1;
154 g_string_append_len (err, buffer, nread);
155 if (nread <= 0) {
156 err_closed = TRUE;
157 close (errfd);
161 } while (res > 0 || (res == -1 && errno == EINTR));
163 g_free (buffer);
164 if (out_str)
165 *out_str = g_string_free (out, FALSE);
167 if (err_str)
168 *err_str = g_string_free (err, FALSE);
170 return 0;
173 static gboolean
174 create_pipe (int *fds, GError **error)
176 if (pipe (fds) == -1) {
177 set_error ("%s", "Error creating pipe.");
178 return FALSE;
180 return TRUE;
183 gboolean
184 g_spawn_command_line_sync (const gchar *command_line,
185 gchar **standard_output,
186 gchar **standard_error,
187 gint *exit_status,
188 GError **error)
190 #ifdef G_OS_WIN32
191 #else
192 pid_t pid;
193 gchar **argv;
194 gint argc;
195 int stdout_pipe [2] = { -1, -1 };
196 int stderr_pipe [2] = { -1, -1 };
197 int status;
198 int res;
200 if (!g_shell_parse_argv (command_line, &argc, &argv, error))
201 return FALSE;
203 if (standard_output && !create_pipe (stdout_pipe, error))
204 return FALSE;
206 if (standard_error && !create_pipe (stderr_pipe, error)) {
207 if (standard_output) {
208 CLOSE_PIPE (stdout_pipe);
210 return FALSE;
213 pid = fork ();
214 if (pid == 0) {
215 gint i;
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--)
227 close (i);
229 /* G_SPAWN_SEARCH_PATH is always enabled for g_spawn_command_line_sync */
230 if (!g_path_is_absolute (argv [0])) {
231 gchar *arg0;
233 arg0 = g_find_program_in_path (argv [0]);
234 if (arg0 == NULL) {
235 exit (1);
237 //g_free (argv [0]);
238 argv [0] = arg0;
240 execv (argv [0], argv);
241 exit (1); /* TODO: What now? */
244 g_strfreev (argv);
245 if (standard_output)
246 close (stdout_pipe [1]);
248 if (standard_error)
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);
253 if (res) {
254 waitpid (pid, &status, WNOHANG); /* avoid zombie */
255 return FALSE;
259 NO_INTR (res, waitpid (pid, &status, 0));
261 /* TODO: What if error? */
262 if (WIFEXITED (status) && exit_status) {
263 *exit_status = WEXITSTATUS (status);
265 #endif
266 return TRUE;
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)
273 gboolean
274 g_spawn_async_with_pipes (const gchar *working_directory,
275 gchar **argv,
276 gchar **envp,
277 GSpawnFlags flags,
278 GSpawnChildSetupFunc child_setup,
279 gpointer user_data,
280 GPid *child_pid,
281 gint *standard_input,
282 gint *standard_output,
283 gint *standard_error,
284 GError **error)
286 #ifdef G_OS_WIN32
287 #else
288 pid_t pid;
289 int info_pipe [2];
290 int in_pipe [2] = { -1, -1 };
291 int out_pipe [2] = { -1, -1 };
292 int err_pipe [2] = { -1, -1 };
293 int status;
295 g_return_val_if_fail (argv != NULL, FALSE); /* Only mandatory arg */
297 if (!create_pipe (info_pipe, error))
298 return FALSE;
300 if (standard_output && !create_pipe (out_pipe, error)) {
301 CLOSE_PIPE (info_pipe);
302 return FALSE;
305 if (standard_error && !create_pipe (err_pipe, error)) {
306 CLOSE_PIPE (info_pipe);
307 CLOSE_PIPE (out_pipe);
308 return FALSE;
311 if (standard_input && !create_pipe (in_pipe, error)) {
312 CLOSE_PIPE (info_pipe);
313 CLOSE_PIPE (out_pipe);
314 CLOSE_PIPE (err_pipe);
315 return FALSE;
318 pid = fork ();
319 if (pid == -1) {
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 ()");
325 return FALSE;
328 if (pid == 0) {
329 /* No zombie left behind */
330 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
331 pid = fork ();
334 if (pid != 0) {
335 exit (pid == -1 ? 1 : 0);
336 } else {
337 gint i;
338 int fd;
339 gchar *arg0;
340 gchar **actual_args;
341 gint unused;
343 close (info_pipe [0]);
344 close (in_pipe [1]);
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) {
355 pid = getpid ();
356 NO_INTR (unused, write (info_pipe [1], &pid, sizeof (pid_t)));
359 if (working_directory && chdir (working_directory) == -1) {
360 int err = errno;
361 NO_INTR (unused, write (info_pipe [1], &err, sizeof (int)));
362 exit (0);
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--)
388 close (i);
391 actual_args = ((flags & G_SPAWN_FILE_AND_ARGV_ZERO) == 0) ? argv : argv + 1;
392 if (envp == NULL)
393 envp = environ;
395 if (child_setup)
396 child_setup (user_data);
398 arg0 = argv [0];
399 if (!g_path_is_absolute (arg0) || (flags & G_SPAWN_SEARCH_PATH) != 0) {
400 arg0 = g_find_program_in_path (argv [0]);
401 if (arg0 == NULL) {
402 int err = ENOENT;
403 write (info_pipe [1], &err, sizeof (int));
404 exit (0);
408 execve (arg0, actual_args, envp);
409 write (info_pipe [1], &errno, sizeof (int));
410 exit (0);
412 } else if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
413 int w;
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);
422 return FALSE;
425 close (info_pipe [1]);
426 close (in_pipe [0]);
427 close (out_pipe [1]);
428 close (err_pipe [1]);
430 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
431 int x;
432 NO_INTR (x, read (info_pipe [0], &pid, sizeof (pid_t))); /* if we read < sizeof (pid_t)... */
435 if (child_pid) {
436 *child_pid = pid;
439 if (read (info_pipe [0], &status, sizeof (int)) != 0) {
440 close (info_pipe [0]);
441 close (in_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));
445 return FALSE;
448 close (info_pipe [0]);
449 if (standard_input)
450 *standard_input = in_pipe [1];
451 if (standard_output)
452 *standard_output = out_pipe [0];
453 if (standard_error)
454 *standard_error = err_pipe [0];
455 #endif
456 return TRUE;