Fix g_dir_open et al for windows.
[mono.git] / eglib / src / gspawn.c
1 /*
2  * Spawning processes.
3  *
4  * Author:
5  *   Gonzalo Paniagua Javier (gonzalo@novell.com
6  *
7  * (C) 2006 Novell, Inc.
8  *
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:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
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.
27  */
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>
34
35 #include <glib.h>
36
37 #ifdef HAVE_UNISTD_H
38 #ifndef __USE_GNU
39 #define __USE_GNU
40 #endif
41 #include <unistd.h>
42 #endif
43
44 #ifdef HAVE_SYS_TIME_H
45 #include <sys/time.h>
46 #endif
47
48 #ifdef HAVE_SYS_WAIT_H
49 #include <sys/wait.h>
50 #endif
51
52 #ifdef G_OS_WIN32
53 #include <io.h>
54 #include <winsock2.h>
55 #define open _open
56 #define close _close
57 #define read _read
58 #define write _write
59 /* windows pipe api details: http://msdn2.microsoft.com/en-us/library/edze9h7e(VS.80).aspx */
60 #define pipe(x) _pipe(x, 256, 0)
61 #endif
62
63 #define set_error(msg, ...) do { if (error != NULL) *error = g_error_new (G_LOG_DOMAIN, 1, msg, __VA_ARGS__); } while (0)
64 #define set_error_cond(cond,msg, ...) do { if ((cond) && error != NULL) *error = g_error_new (G_LOG_DOMAIN, 1, msg, __VA_ARGS__); } while (0)
65 #define set_error_status(status,msg, ...) do { if (error != NULL) *error = g_error_new (G_LOG_DOMAIN, status, msg, __VA_ARGS__); } while (0)
66 #define NO_INTR(var,cmd) do { (var) = (cmd); } while ((var) == -1 && errno == EINTR)
67 #define CLOSE_PIPE(p) do { close (p [0]); close (p [1]); } while (0)
68
69 #if defined(__APPLE__) && !defined (__arm__)
70 /* Apple defines this in crt_externs.h but doesn't provide that header for 
71  * arm-apple-darwin9.  We'll manually define the symbol on Apple as it does
72  * in fact exist on all implementations (so far) 
73  */
74 gchar ***_NSGetEnviron();
75 #define environ (*_NSGetEnviron())
76 #elif defined(_MSC_VER)
77 /* MS defines this in stdlib.h */
78 #else
79 extern char **environ;
80 #endif
81
82 static int
83 safe_read (int fd, gchar *buffer, gint count, GError **error)
84 {
85         int res;
86
87         NO_INTR (res, read (fd, buffer, count));
88         set_error_cond (res == -1, "%s", "Error reading from pipe.");
89         return res;
90 }
91
92 static int
93 read_pipes (int outfd, gchar **out_str, int errfd, gchar **err_str, GError **error)
94 {
95         fd_set rfds;
96         int res;
97         gboolean out_closed;
98         gboolean err_closed;
99         GString *out = NULL;
100         GString *err = NULL;
101         gchar *buffer = NULL;
102         gint nread;
103
104         out_closed = (outfd < 0);
105         err_closed = (errfd < 0);
106         if (out_str) {
107                 *out_str = NULL;
108                 out = g_string_new ("");
109         }       
110
111         if (err_str) {
112                 *err_str = NULL;
113                 err = g_string_new ("");
114         }       
115
116         do {
117                 if (out_closed && err_closed)
118                         break;
119
120 #ifdef _MSC_VER
121 #pragma warning(push)
122 #pragma warning(disable:4389)
123 #endif
124
125                 FD_ZERO (&rfds);
126                 if (!out_closed && outfd >= 0)
127                         FD_SET (outfd, &rfds);
128                 if (!err_closed && errfd >= 0)
129                         FD_SET (errfd, &rfds);
130
131 #ifdef _MSC_VER
132 #pragma warning(pop)
133 #endif
134
135                 res = select (MAX (outfd, errfd) + 1, &rfds, NULL, NULL, NULL);
136                 if (res > 0) {
137                         if (buffer == NULL)
138                                 buffer = g_malloc (1024);
139                         if (!out_closed && FD_ISSET (outfd, &rfds)) {
140                                 nread = safe_read (outfd, buffer, 1024, error);
141                                 if (nread < 0) {
142                                         close (errfd);
143                                         close (outfd);
144                                         return -1;
145                                 }
146                                 g_string_append_len (out, buffer, nread);
147                                 if (nread <= 0) {
148                                         out_closed = TRUE;
149                                         close (outfd);
150                                 }
151                         }
152
153                         if (!err_closed && FD_ISSET (errfd, &rfds)) {
154                                 nread = safe_read (errfd, buffer, 1024, error);
155                                 if (nread < 0) {
156                                         close (errfd);
157                                         close (outfd);
158                                         return -1;
159                                 }
160                                 g_string_append_len (err, buffer, nread);
161                                 if (nread <= 0) {
162                                         err_closed = TRUE;
163                                         close (errfd);
164                                 }
165                         }
166                 }
167         } while (res > 0 || (res == -1 && errno == EINTR));
168
169         g_free (buffer);
170         if (out_str)
171                 *out_str = g_string_free (out, FALSE);
172
173         if (err_str)
174                 *err_str = g_string_free (err, FALSE);
175
176         return 0;
177 }
178
179 static gboolean
180 create_pipe (int *fds, GError **error)
181 {
182         if (pipe (fds) == -1) {
183                 set_error ("%s", "Error creating pipe.");
184                 return FALSE;
185         }
186         return TRUE;
187 }
188
189 gboolean
190 g_spawn_command_line_sync (const gchar *command_line,
191                                 gchar **standard_output,
192                                 gchar **standard_error,
193                                 gint *exit_status,
194                                 GError **error)
195 {
196 #ifdef G_OS_WIN32
197 #else
198         pid_t pid;
199         gchar **argv;
200         gint argc;
201         int stdout_pipe [2] = { -1, -1 };
202         int stderr_pipe [2] = { -1, -1 };
203         int status;
204         int res;
205         
206         if (!g_shell_parse_argv (command_line, &argc, &argv, error))
207                 return FALSE;
208
209         if (standard_output && !create_pipe (stdout_pipe, error))
210                 return FALSE;
211
212         if (standard_error && !create_pipe (stderr_pipe, error)) {
213                 if (standard_output) {
214                         CLOSE_PIPE (stdout_pipe);
215                 }
216                 return FALSE;
217         }
218
219         pid = fork ();
220         if (pid == 0) {
221                 gint i;
222
223                 if (standard_output) {
224                         close (stdout_pipe [0]);
225                         dup2 (stdout_pipe [1], STDOUT_FILENO);
226                 }
227
228                 if (standard_error) {
229                         close (stderr_pipe [0]);
230                         dup2 (stderr_pipe [1], STDERR_FILENO);
231                 }
232                 for (i = getdtablesize () - 1; i >= 3; i--)
233                         close (i);
234
235                 /* G_SPAWN_SEARCH_PATH is always enabled for g_spawn_command_line_sync */
236                 if (!g_path_is_absolute (argv [0])) {
237                         gchar *arg0;
238
239                         arg0 = g_find_program_in_path (argv [0]);
240                         if (arg0 == NULL) {
241                                 exit (1);
242                         }
243                         //g_free (argv [0]);
244                         argv [0] = arg0;
245                 }
246                 execv (argv [0], argv);
247                 exit (1); /* TODO: What now? */
248         }
249
250         g_strfreev (argv);
251         if (standard_output)
252                 close (stdout_pipe [1]);
253
254         if (standard_error)
255                 close (stderr_pipe [1]);
256
257         if (standard_output || standard_error) {
258                 res = read_pipes (stdout_pipe [0], standard_output, stderr_pipe [0], standard_error, error);
259                 if (res) {
260                         waitpid (pid, &status, WNOHANG); /* avoid zombie */
261                         return FALSE;
262                 }
263         }
264
265         NO_INTR (res, waitpid (pid, &status, 0));
266
267         /* TODO: What if error? */
268         if (WIFEXITED (status) && exit_status) {
269                 *exit_status = WEXITSTATUS (status);
270         }
271 #endif
272         return TRUE;
273 }
274
275 /*
276  * This is the only use we have in mono/metadata
277 !g_spawn_async_with_pipes (NULL, (char**)addr_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &child_pid, &ch_in, &ch_out, NULL, NULL)
278 */
279 gboolean
280 g_spawn_async_with_pipes (const gchar *working_directory,
281                         gchar **argv,
282                         gchar **envp,
283                         GSpawnFlags flags,
284                         GSpawnChildSetupFunc child_setup,
285                         gpointer user_data,
286                         GPid *child_pid,
287                         gint *standard_input,
288                         gint *standard_output,
289                         gint *standard_error,
290                         GError **error)
291 {
292 #ifdef G_OS_WIN32
293 #else
294         pid_t pid;
295         int info_pipe [2];
296         int in_pipe [2] = { -1, -1 };
297         int out_pipe [2] = { -1, -1 };
298         int err_pipe [2] = { -1, -1 };
299         int status;
300
301         g_return_val_if_fail (argv != NULL, FALSE); /* Only mandatory arg */
302
303         if (!create_pipe (info_pipe, error))
304                 return FALSE;
305
306         if (standard_output && !create_pipe (out_pipe, error)) {
307                 CLOSE_PIPE (info_pipe);
308                 return FALSE;
309         }
310
311         if (standard_error && !create_pipe (err_pipe, error)) {
312                 CLOSE_PIPE (info_pipe);
313                 CLOSE_PIPE (out_pipe);
314                 return FALSE;
315         }
316
317         if (standard_input && !create_pipe (in_pipe, error)) {
318                 CLOSE_PIPE (info_pipe);
319                 CLOSE_PIPE (out_pipe);
320                 CLOSE_PIPE (err_pipe);
321                 return FALSE;
322         }
323
324         pid = fork ();
325         if (pid == -1) {
326                 CLOSE_PIPE (info_pipe);
327                 CLOSE_PIPE (out_pipe);
328                 CLOSE_PIPE (err_pipe);
329                 CLOSE_PIPE (in_pipe);
330                 set_error ("%s", "Error in fork ()");
331                 return FALSE;
332         }
333
334         if (pid == 0) {
335                 /* No zombie left behind */
336                 if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
337                         pid = fork ();
338                 }
339
340                 if (pid != 0) {
341                         exit (pid == -1 ? 1 : 0);
342                 }  else {
343                         gint i;
344                         int fd;
345                         gchar *arg0;
346                         gchar **actual_args;
347                         gint unused;
348
349                         close (info_pipe [0]);
350                         close (in_pipe [1]);
351                         close (out_pipe [0]);
352                         close (err_pipe [0]);
353
354                         /* when exec* succeeds, we want to close this fd, which will return
355                          * a 0 read on the parent. We're not supposed to keep it open forever.
356                          * If exec fails, we still can write the error to it before closing.
357                          */
358                         fcntl (info_pipe [1], F_SETFD, FD_CLOEXEC);
359
360                         if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
361                                 pid = getpid ();
362                                 NO_INTR (unused, write (info_pipe [1], &pid, sizeof (pid_t)));
363                         }
364
365                         if (working_directory && chdir (working_directory) == -1) {
366                                 int err = errno;
367                                 NO_INTR (unused, write (info_pipe [1], &err, sizeof (int)));
368                                 exit (0);
369                         }
370
371                         if (standard_output) {
372                                 dup2 (out_pipe [1], STDOUT_FILENO);
373                         } else if ((flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0) {
374                                 fd = open ("/dev/null", O_WRONLY);
375                                 dup2 (fd, STDOUT_FILENO);
376                         }
377
378                         if (standard_error) {
379                                 dup2 (err_pipe [1], STDERR_FILENO);
380                         } else if ((flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0) {
381                                 fd = open ("/dev/null", O_WRONLY);
382                                 dup2 (fd, STDERR_FILENO);
383                         }
384
385                         if (standard_input) {
386                                 dup2 (in_pipe [0], STDIN_FILENO);
387                         } else if ((flags & G_SPAWN_CHILD_INHERITS_STDIN) == 0) {
388                                 fd = open ("/dev/null", O_RDONLY);
389                                 dup2 (fd, STDIN_FILENO);
390                         }
391
392                         if ((flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN) != 0) {
393                                 for (i = getdtablesize () - 1; i >= 3; i--)
394                                         close (i);
395                         }
396
397                         actual_args = ((flags & G_SPAWN_FILE_AND_ARGV_ZERO) == 0) ? argv : argv + 1;
398                         if (envp == NULL)
399                                 envp = environ;
400
401                         if (child_setup)
402                                 child_setup (user_data);
403
404                         arg0 = argv [0];
405                         if (!g_path_is_absolute (arg0) || (flags & G_SPAWN_SEARCH_PATH) != 0) {
406                                 arg0 = g_find_program_in_path (argv [0]);
407                                 if (arg0 == NULL) {
408                                         int err = ENOENT;
409                                         write (info_pipe [1], &err, sizeof (int));
410                                         exit (0);
411                                 }
412                         }
413
414                         execve (arg0, actual_args, envp);
415                         write (info_pipe [1], &errno, sizeof (int));
416                         exit (0);
417                 }
418         } else if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
419                 int w;
420                 /* Wait for the first child if two are created */
421                 NO_INTR (w, waitpid (pid, &status, 0));
422                 if (status == 1 || w == -1) {
423                         CLOSE_PIPE (info_pipe);
424                         CLOSE_PIPE (out_pipe);
425                         CLOSE_PIPE (err_pipe);
426                         CLOSE_PIPE (in_pipe);
427                         set_error ("Error in fork (): %d", status);
428                         return FALSE;
429                 }
430         }
431         close (info_pipe [1]);
432         close (in_pipe [0]);
433         close (out_pipe [1]);
434         close (err_pipe [1]);
435
436         if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
437                 int x;
438                 NO_INTR (x, read (info_pipe [0], &pid, sizeof (pid_t))); /* if we read < sizeof (pid_t)... */
439         }
440
441         if (child_pid) {
442                 *child_pid = pid;
443         }
444
445         if (read (info_pipe [0], &status, sizeof (int)) != 0) {
446                 close (info_pipe [0]);
447                 close (in_pipe [0]);
448                 close (out_pipe [1]);
449                 close (err_pipe [1]);
450                 set_error_status (status, "Error in exec (%d -> %s)", status, strerror (status));
451                 return FALSE;
452         }
453
454         close (info_pipe [0]);
455         if (standard_input)
456                 *standard_input = in_pipe [1];
457         if (standard_output)
458                 *standard_output = out_pipe [0];
459         if (standard_error)
460                 *standard_error = err_pipe [0];
461 #endif
462         return TRUE;
463 }
464
465