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