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