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