source: trunk/third/glib2/glib/gspawn-win32.c @ 20721

Revision 20721, 27.7 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20720, which included commits to RCS files with non-trunk default branches.
Line 
1/* gspawn-win32.c - Process launching on Win32
2 *
3 *  Copyright 2000 Red Hat, Inc.
4 *  Copyright 2003 Tor Lillqvist
5 *
6 * GLib is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * GLib is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with GLib; see the file COPYING.LIB.  If not, write
18 * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22/*
23 * Implementation details on Win32.
24 *
25 * - There is no way to set the no-inherit flag for
26 *   a "file descriptor" in the MS C runtime. The flag is there,
27 *   and the dospawn() function uses it, but unfortunately
28 *   this flag can only be set when opening the file.
29 * - As there is no fork(), we cannot reliably change directory
30 *   before starting the child process. (There might be several threads
31 *   running, and the current directory is common for all threads.)
32 *
33 * Thus, we must in most cases use a helper program to handle closing
34 * of (inherited) file descriptors and changing of directory. The
35 * helper process is also needed if the standard input, standard
36 * output, or standard error of the process to be run are supposed to
37 * be redirected somewhere.
38 *
39 * The structure of the source code in this file is a mess, I know.
40 */
41
42/* Define this to get some logging all the time */
43/* #define G_SPAWN_WIN32_DEBUG */
44
45#include <config.h>
46
47#include "glib.h"
48#include "gprintfint.h"
49
50#include <string.h>
51#include <stdlib.h>
52#include <stdio.h>
53
54#include <windows.h>
55#include <errno.h>
56#include <fcntl.h>
57#include <io.h>
58#include <process.h>
59#include <direct.h>
60
61#include "glibintl.h"
62
63#ifdef G_SPAWN_WIN32_DEBUG
64  static int debug = 1;
65  #define SETUP_DEBUG() /* empty */
66
67#else
68  static int debug = -1;
69  #define SETUP_DEBUG()                                 \
70    G_STMT_START                                        \
71      {                                                 \
72        if (debug == -1)                                \
73          {                                             \
74            if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \
75              debug = 1;                                \
76            else                                        \
77              debug = 0;                                \
78          }                                             \
79      }                                                 \
80    G_STMT_END
81#endif
82
83enum
84{
85  CHILD_NO_ERROR,
86  CHILD_CHDIR_FAILED,
87  CHILD_SPAWN_FAILED,
88};
89
90enum {
91  ARG_CHILD_ERR_REPORT = 1,
92  ARG_STDIN,
93  ARG_STDOUT,
94  ARG_STDERR,
95  ARG_WORKING_DIRECTORY,
96  ARG_CLOSE_DESCRIPTORS,
97  ARG_USE_PATH,
98  ARG_WAIT,
99  ARG_PROGRAM,
100  ARG_COUNT = ARG_PROGRAM
101};
102
103/* Return codes from do_spawn() */
104#define DO_SPAWN_ERROR_HELPER -1
105#define DO_SPAWN_OK_NO_HELPER -2
106#define DO_SPAWN_ERROR_NO_HELPER -3
107
108static gint
109protect_argv (gchar  **argv,
110              gchar ***new_argv)
111{
112  gint i;
113  gint argc = 0;
114 
115  while (argv[argc])
116    ++argc;
117  *new_argv = g_new (gchar *, argc+1);
118
119  /* Quote each argv element if necessary, so that it will get
120   * reconstructed correctly in the C runtime startup code.  Note that
121   * the unquoting algorithm in the C runtime is really weird, and
122   * rather different than what Unix shells do. See stdargv.c in the C
123   * runtime sources (in the Platform SDK, in src/crt).
124   *
125   * Note that an new_argv[0] constructed by this function should
126   * *not* be passed as the filename argument to a spawn* or exec*
127   * family function. That argument should be the real file name
128   * without any quoting.
129   */
130  for (i = 0; i < argc; i++)
131    {
132      gchar *p = argv[i];
133      gchar *q;
134      gint len = 0;
135      gboolean need_dblquotes = FALSE;
136      while (*p)
137        {
138          if (*p == ' ' || *p == '\t')
139            need_dblquotes = TRUE;
140          else if (*p == '"')
141            len++;
142          else if (*p == '\\')
143            {
144              gchar *pp = p;
145              while (*pp && *pp == '\\')
146                pp++;
147              if (*pp == '"')
148                len++;
149            }
150          len++;
151          p++;
152        }
153
154      q = (*new_argv)[i] = g_malloc (len + need_dblquotes*2 + 1);
155      p = argv[i];
156
157      if (need_dblquotes)
158        *q++ = '"';
159
160      while (*p)
161        {
162          if (*p == '"')
163            *q++ = '\\';
164          else if (*p == '\\')
165            {
166              gchar *pp = p;
167              while (*pp && *pp == '\\')
168                pp++;
169              if (*pp == '"')
170                *q++ = '\\';
171            }
172          *q++ = *p;
173          p++;
174        }
175
176      if (need_dblquotes)
177        *q++ = '"';
178      *q++ = '\0';
179      /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
180    }
181  (*new_argv)[argc] = NULL;
182
183  return argc;
184}
185
186#ifndef GSPAWN_HELPER
187
188static gboolean make_pipe            (gint                  p[2],
189                                      GError              **error);
190static gboolean do_spawn_with_pipes  (gboolean              dont_wait,
191                                      gboolean              dont_return_handle,
192                                      const gchar          *working_directory,
193                                      gchar               **argv,
194                                      gchar               **envp,
195                                      gboolean              close_descriptors,
196                                      gboolean              search_path,
197                                      gboolean              stdout_to_null,
198                                      gboolean              stderr_to_null,
199                                      gboolean              child_inherits_stdin,
200                                      gboolean              file_and_argv_zero,
201                                      GSpawnChildSetupFunc  child_setup,
202                                      gpointer              user_data,
203                                      GPid                 *child_handle,
204                                      gint                 *standard_input,
205                                      gint                 *standard_output,
206                                      gint                 *standard_error,
207                                      gint                 *exit_status,
208                                      GError              **error);
209
210GQuark
211g_spawn_error_quark (void)
212{
213  static GQuark quark = 0;
214  if (quark == 0)
215    quark = g_quark_from_static_string ("g-exec-error-quark");
216  return quark;
217}
218
219gboolean
220g_spawn_async (const gchar          *working_directory,
221               gchar               **argv,
222               gchar               **envp,
223               GSpawnFlags           flags,
224               GSpawnChildSetupFunc  child_setup,
225               gpointer              user_data,
226               GPid                 *child_handle,
227               GError              **error)
228{
229  g_return_val_if_fail (argv != NULL, FALSE);
230 
231  return g_spawn_async_with_pipes (working_directory,
232                                   argv, envp,
233                                   flags,
234                                   child_setup,
235                                   user_data,
236                                   child_handle,
237                                   NULL, NULL, NULL,
238                                   error);
239}
240
241/* Avoids a danger in threaded situations (calling close()
242 * on a file descriptor twice, and another thread has
243 * re-opened it since the first close)
244 */
245static gint
246close_and_invalidate (gint *fd)
247{
248  gint ret;
249
250  if (*fd < 0)
251    return -1;
252  else
253    {
254      ret = close (*fd);
255      *fd = -1;
256    }
257
258  return ret;
259}
260
261typedef enum
262{
263  READ_FAILED = 0, /* FALSE */
264  READ_OK,
265  READ_EOF
266} ReadResult;
267
268static ReadResult
269read_data (GString     *str,
270           GIOChannel  *iochannel,
271           GError     **error)
272{
273  GIOStatus giostatus;
274  gssize bytes;
275  gchar buf[4096];
276
277 again:
278 
279  giostatus = g_io_channel_read_chars (iochannel, buf, sizeof (buf), &bytes, NULL);
280
281  if (bytes == 0)
282    return READ_EOF;
283  else if (bytes > 0)
284    {
285      g_string_append_len (str, buf, bytes);
286      return READ_OK;
287    }
288  else if (giostatus == G_IO_STATUS_AGAIN)
289    goto again;
290  else if (giostatus == G_IO_STATUS_ERROR)
291    {
292      g_set_error (error,
293                   G_SPAWN_ERROR,
294                   G_SPAWN_ERROR_READ,
295                   _("Failed to read data from child process"));
296     
297      return READ_FAILED;
298    }
299  else
300    return READ_OK;
301}
302
303gboolean
304g_spawn_sync (const gchar          *working_directory,
305              gchar               **argv,
306              gchar               **envp,
307              GSpawnFlags           flags,
308              GSpawnChildSetupFunc  child_setup,
309              gpointer              user_data,
310              gchar               **standard_output,
311              gchar               **standard_error,
312              gint                 *exit_status,
313              GError              **error)     
314{
315  gint outpipe = -1;
316  gint errpipe = -1;
317  GPid pid;
318  GIOChannel *outchannel = NULL;
319  GIOChannel *errchannel = NULL;
320  GPollFD outfd, errfd;
321  GPollFD fds[2];
322  gint nfds;
323  gint outindex = -1;
324  gint errindex = -1;
325  gint ret;
326  GString *outstr = NULL;
327  GString *errstr = NULL;
328  gboolean failed;
329  gint status;
330 
331  g_return_val_if_fail (argv != NULL, FALSE);
332  g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
333  g_return_val_if_fail (standard_output == NULL ||
334                        !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
335  g_return_val_if_fail (standard_error == NULL ||
336                        !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
337 
338  /* Just to ensure segfaults if callers try to use
339   * these when an error is reported.
340   */
341  if (standard_output)
342    *standard_output = NULL;
343
344  if (standard_error)
345    *standard_error = NULL;
346 
347  if (!do_spawn_with_pipes (FALSE,
348                            TRUE,
349                            working_directory,
350                            argv,
351                            envp,
352                            !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
353                            (flags & G_SPAWN_SEARCH_PATH) != 0,
354                            (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
355                            (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
356                            (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
357                            (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
358                            child_setup,
359                            user_data,
360                            &pid,
361                            NULL,
362                            standard_output ? &outpipe : NULL,
363                            standard_error ? &errpipe : NULL,
364                            &status,
365                            error))
366    return FALSE;
367
368  /* Read data from child. */
369 
370  failed = FALSE;
371
372  if (outpipe >= 0)
373    {
374      outstr = g_string_new (NULL);
375      outchannel = g_io_channel_win32_new_fd (outpipe);
376      g_io_channel_set_encoding (outchannel, NULL, NULL);
377      g_io_channel_win32_make_pollfd (outchannel,
378                                      G_IO_IN | G_IO_ERR | G_IO_HUP,
379                                      &outfd);
380    }
381     
382  if (errpipe >= 0)
383    {
384      errstr = g_string_new (NULL);
385      errchannel = g_io_channel_win32_new_fd (errpipe);
386      g_io_channel_set_encoding (errchannel, NULL, NULL);
387      g_io_channel_win32_make_pollfd (errchannel,
388                                      G_IO_IN | G_IO_ERR | G_IO_HUP,
389                                      &errfd);
390    }
391
392  /* Read data until we get EOF on both pipes. */
393  while (!failed &&
394         (outpipe >= 0 ||
395          errpipe >= 0))
396    {
397      nfds = 0;
398      if (outpipe >= 0)
399        {
400          fds[nfds] = outfd;
401          outindex = nfds;
402          nfds++;
403        }
404      if (errpipe >= 0)
405        {
406          fds[nfds] = errfd;
407          errindex = nfds;
408          nfds++;
409        }
410
411      if (debug)
412        g_print ("%s:g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n",
413                 __FILE__, nfds);
414
415      ret = g_io_channel_win32_poll (fds, nfds, -1);
416
417      if (ret < 0)
418        {
419          failed = TRUE;
420
421          g_set_error (error,
422                       G_SPAWN_ERROR,
423                       G_SPAWN_ERROR_READ,
424                       _("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
425             
426          break;
427        }
428
429      if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN))
430        {
431          switch (read_data (outstr, outchannel, error))
432            {
433            case READ_FAILED:
434              if (debug)
435                g_print ("g_spawn_sync: outchannel: READ_FAILED\n");
436              failed = TRUE;
437              break;
438            case READ_EOF:
439              if (debug)
440                g_print ("g_spawn_sync: outchannel: READ_EOF\n");
441              g_io_channel_unref (outchannel);
442              outchannel = NULL;
443              close_and_invalidate (&outpipe);
444              break;
445            default:
446              if (debug)
447                g_print ("g_spawn_sync: outchannel: OK\n");
448              break;
449            }
450
451          if (failed)
452            break;
453        }
454
455      if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN))
456        {
457          switch (read_data (errstr, errchannel, error))
458            {
459            case READ_FAILED:
460              if (debug)
461                g_print ("g_spawn_sync: errchannel: READ_FAILED\n");
462              failed = TRUE;
463              break;
464            case READ_EOF:
465              if (debug)
466                g_print ("g_spawn_sync: errchannel: READ_EOF\n");
467              g_io_channel_unref (errchannel);
468              errchannel = NULL;
469              close_and_invalidate (&errpipe);
470              break;
471            default:
472              if (debug)
473                g_print ("g_spawn_sync: errchannel: OK\n");
474              break;
475            }
476
477          if (failed)
478            break;
479        }
480    }
481
482  /* These should only be open still if we had an error.  */
483 
484  if (outchannel != NULL)
485    g_io_channel_unref (outchannel);
486  if (errchannel != NULL)
487    g_io_channel_unref (errchannel);
488  if (outpipe >= 0)
489    close_and_invalidate (&outpipe);
490  if (errpipe >= 0)
491    close_and_invalidate (&errpipe);
492 
493  g_spawn_close_pid(pid);
494
495  if (failed)
496    {
497      if (outstr)
498        g_string_free (outstr, TRUE);
499      if (errstr)
500        g_string_free (errstr, TRUE);
501
502      return FALSE;
503    }
504  else
505    {
506      if (exit_status)
507        *exit_status = status;
508     
509      if (standard_output)       
510        *standard_output = g_string_free (outstr, FALSE);
511
512      if (standard_error)
513        *standard_error = g_string_free (errstr, FALSE);
514
515      return TRUE;
516    }
517}
518
519gboolean
520g_spawn_async_with_pipes (const gchar          *working_directory,
521                          gchar               **argv,
522                          gchar               **envp,
523                          GSpawnFlags           flags,
524                          GSpawnChildSetupFunc  child_setup,
525                          gpointer              user_data,
526                          GPid                 *child_handle,
527                          gint                 *standard_input,
528                          gint                 *standard_output,
529                          gint                 *standard_error,
530                          GError              **error)
531{
532  g_return_val_if_fail (argv != NULL, FALSE);
533  g_return_val_if_fail (standard_output == NULL ||
534                        !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
535  g_return_val_if_fail (standard_error == NULL ||
536                        !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
537  /* can't inherit stdin if we have an input pipe. */
538  g_return_val_if_fail (standard_input == NULL ||
539                        !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
540 
541  return do_spawn_with_pipes (TRUE,
542                              !(flags & G_SPAWN_DO_NOT_REAP_CHILD),
543                              working_directory,
544                              argv,
545                              envp,
546                              !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
547                              (flags & G_SPAWN_SEARCH_PATH) != 0,
548                              (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
549                              (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
550                              (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
551                              (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
552                              child_setup,
553                              user_data,
554                              child_handle,
555                              standard_input,
556                              standard_output,
557                              standard_error,
558                              NULL,
559                              error);
560}
561
562gboolean
563g_spawn_command_line_sync (const gchar  *command_line,
564                           gchar       **standard_output,
565                           gchar       **standard_error,
566                           gint         *exit_status,
567                           GError      **error)
568{
569  gboolean retval;
570  gchar **argv = 0;
571
572  g_return_val_if_fail (command_line != NULL, FALSE);
573 
574  if (!g_shell_parse_argv (command_line,
575                           NULL, &argv,
576                           error))
577    return FALSE;
578 
579  retval = g_spawn_sync (NULL,
580                         argv,
581                         NULL,
582                         G_SPAWN_SEARCH_PATH,
583                         NULL,
584                         NULL,
585                         standard_output,
586                         standard_error,
587                         exit_status,
588                         error);
589  g_strfreev (argv);
590
591  return retval;
592}
593
594gboolean
595g_spawn_command_line_async (const gchar *command_line,
596                            GError     **error)
597{
598  gboolean retval;
599  gchar **argv = 0;
600
601  g_return_val_if_fail (command_line != NULL, FALSE);
602
603  if (!g_shell_parse_argv (command_line,
604                           NULL, &argv,
605                           error))
606    return FALSE;
607 
608  retval = g_spawn_async (NULL,
609                          argv,
610                          NULL,
611                          G_SPAWN_SEARCH_PATH,
612                          NULL,
613                          NULL,
614                          NULL,
615                          error);
616  g_strfreev (argv);
617
618  return retval;
619}
620
621/* This stinks, code reorg needed. Presumably do_spawn() should be
622 * inserted into its only caller, do_spawn_with_pipes(), and then code
623 * snippets from that function should be split out to separate
624 * functions if necessary.
625 */
626
627static gint shortcut_spawn_retval;
628
629static gint
630do_spawn (gboolean              dont_wait,
631          gint                  child_err_report_fd,
632          gint                  stdin_fd,
633          gint                  stdout_fd,
634          gint                  stderr_fd,
635          const gchar          *working_directory,
636          gchar               **argv,
637          gchar               **envp,
638          gboolean              close_descriptors,
639          gboolean              search_path,
640          gboolean              stdout_to_null,
641          gboolean              stderr_to_null,
642          gboolean              child_inherits_stdin,
643          gboolean              file_and_argv_zero,
644          GSpawnChildSetupFunc  child_setup,
645          gpointer              user_data)
646{
647  gchar **protected_argv;
648  gchar **new_argv;
649  gchar args[ARG_COUNT][10];
650  gint i;
651  int rc;
652  int argc;
653
654  SETUP_DEBUG();
655
656  argc = protect_argv (argv, &protected_argv);
657
658  if (stdin_fd == -1 && stdout_fd == -1 && stderr_fd == -1 &&
659      (working_directory == NULL || !*working_directory) &&
660      !close_descriptors &&
661      !stdout_to_null && !stderr_to_null &&
662      child_inherits_stdin)
663    {
664      /* We can do without the helper process */
665      int mode = dont_wait ? P_NOWAIT : P_WAIT;
666
667      if (debug)
668        g_print ("doing without gspawn-win32-helper\n");
669
670      if (search_path)
671        rc = spawnvp (mode, argv[0], file_and_argv_zero ? protected_argv + 1 : protected_argv);
672      else
673        rc = spawnv (mode, argv[0], file_and_argv_zero ? protected_argv + 1 : protected_argv);
674
675      for (i = 0; i < argc; i++)
676        g_free (protected_argv[i]);
677      g_free (protected_argv);
678     
679      if (rc == -1)
680        {
681          return DO_SPAWN_ERROR_NO_HELPER;
682        }
683      else
684        {
685          shortcut_spawn_retval = rc;
686          return DO_SPAWN_OK_NO_HELPER;
687        }
688    }
689
690  new_argv = g_new (gchar *, argc + 1 + ARG_COUNT);
691
692  new_argv[0] = "gspawn-win32-helper";
693  _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_fd);
694  new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
695
696  if (file_and_argv_zero)
697    {
698      /* Overload ARG_CHILD_ERR_REPORT to also encode the
699       * G_SPAWN_FILE_AND_ARGV_ZERO functionality.
700       */
701      strcat (args[ARG_CHILD_ERR_REPORT], "#");
702    }
703
704  if (stdin_fd >= 0)
705    {
706      _g_sprintf (args[ARG_STDIN], "%d", stdin_fd);
707      new_argv[ARG_STDIN] = args[ARG_STDIN];
708    }
709  else if (child_inherits_stdin)
710    {
711      /* Let stdin be alone */
712      new_argv[ARG_STDIN] = "-";
713    }
714  else
715    {
716      /* Keep process from blocking on a read of stdin */
717      new_argv[ARG_STDIN] = "z";
718    }
719
720  if (stdout_fd >= 0)
721    {
722      _g_sprintf (args[ARG_STDOUT], "%d", stdout_fd);
723      new_argv[ARG_STDOUT] = args[ARG_STDOUT];
724    }
725  else if (stdout_to_null)
726    {
727      new_argv[ARG_STDOUT] = "z";
728    }
729  else
730    {
731      new_argv[ARG_STDOUT] = "-";
732    }
733
734  if (stderr_fd >= 0)
735    {
736      _g_sprintf (args[ARG_STDERR], "%d", stderr_fd);
737      new_argv[ARG_STDERR] = args[ARG_STDERR];
738    }
739  else if (stderr_to_null)
740    {
741      new_argv[ARG_STDERR] = "z";
742    }
743  else
744    {
745      new_argv[ARG_STDERR] = "-";
746    }
747
748  if (working_directory && *working_directory)
749    /* The g_strdup() to lose the constness */
750    new_argv[ARG_WORKING_DIRECTORY] = g_strdup (working_directory);
751  else
752    new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-");
753
754  if (close_descriptors)
755    new_argv[ARG_CLOSE_DESCRIPTORS] = "y";
756  else
757    new_argv[ARG_CLOSE_DESCRIPTORS] = "-";
758
759  if (search_path)
760    new_argv[ARG_USE_PATH] = "y";
761  else
762    new_argv[ARG_USE_PATH] = "-";
763
764  if (dont_wait)
765    new_argv[ARG_WAIT] = "-";
766  else
767    new_argv[ARG_WAIT] = "w";
768
769  for (i = 0; i <= argc; i++)
770    new_argv[ARG_PROGRAM + i] = protected_argv[i];
771
772  /* Call user function just before we execute the helper program,
773   * which executes the program. Dunno what's the usefulness of this.
774   * A child setup function used on Unix probably isn't of much use
775   * as such on Win32, anyhow
776   */
777  if (child_setup)
778    {
779      (* child_setup) (user_data);
780    }
781
782  if (debug)
783    {
784      g_print ("calling gspawn-win32-helper with argv:\n");
785      for (i = 0; i < argc + 1 + ARG_COUNT; i++)
786        g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL"));
787    }
788 
789  if (envp != NULL)
790    /* Let's hope envp hasn't mucked with PATH so that
791     * gspawn-win32-helper.exe isn't found.
792     */
793    rc = spawnvpe (P_NOWAIT, "gspawn-win32-helper", new_argv, envp);
794  else
795    rc = spawnvp (P_NOWAIT, "gspawn-win32-helper", new_argv);
796
797  /* Close the child_err_report_fd and the other process's ends of the
798   * pipes in this process, otherwise the reader will never get
799   * EOF.
800   */
801  close (child_err_report_fd);
802  if (stdin_fd >= 0)
803    close (stdin_fd);
804  if (stdout_fd >= 0)
805    close (stdout_fd);
806  if (stderr_fd >= 0)
807    close (stderr_fd);
808
809  for (i = 0; i < argc; i++)
810    g_free (protected_argv[i]);
811  g_free (protected_argv);
812
813  g_free (new_argv[ARG_WORKING_DIRECTORY]);
814  g_free (new_argv);
815
816  return rc;
817}
818
819static gboolean
820read_ints (int      fd,
821           gint*    buf,
822           gint     n_ints_in_buf,
823           gint    *n_ints_read,
824           GError **error)
825{
826  gint bytes = 0;
827 
828  while (bytes < sizeof(gint)*n_ints_in_buf)
829    {
830      gint chunk;
831
832      if (debug)
833        g_print ("%s:read_ints: trying to read %d bytes from pipe...\n",
834                 __FILE__,
835                 sizeof(gint)*n_ints_in_buf - bytes);
836
837      chunk = read (fd, ((gchar*)buf) + bytes,
838                    sizeof(gint)*n_ints_in_buf - bytes);
839
840      if (debug)
841        g_print ("... got %d bytes\n", chunk);
842         
843      if (chunk < 0)
844        {
845          /* Some weird shit happened, bail out */
846             
847          g_set_error (error,
848                       G_SPAWN_ERROR,
849                       G_SPAWN_ERROR_FAILED,
850                       _("Failed to read from child pipe (%s)"),
851                       g_strerror (errno));
852
853          return FALSE;
854        }
855      else if (chunk == 0)
856        break; /* EOF */
857      else
858        bytes += chunk;
859    }
860
861  *n_ints_read = bytes/sizeof(gint);
862
863  return TRUE;
864}
865
866static gboolean
867do_spawn_with_pipes (gboolean              dont_wait,
868                     gboolean              dont_return_handle,
869                     const gchar          *working_directory,
870                     gchar               **argv,
871                     gchar               **envp,
872                     gboolean              close_descriptors,
873                     gboolean              search_path,
874                     gboolean              stdout_to_null,
875                     gboolean              stderr_to_null,
876                     gboolean              child_inherits_stdin,
877                     gboolean              file_and_argv_zero,
878                     GSpawnChildSetupFunc  child_setup,
879                     gpointer              user_data,
880                     GPid                 *child_handle,
881                     gint                 *standard_input,
882                     gint                 *standard_output,
883                     gint                 *standard_error,
884                     gint                 *exit_status,
885                     GError              **error)     
886{
887  gint stdin_pipe[2] = { -1, -1 };
888  gint stdout_pipe[2] = { -1, -1 };
889  gint stderr_pipe[2] = { -1, -1 };
890  gint child_err_report_pipe[2] = { -1, -1 };
891  gint helper = -1;
892  gint buf[2];
893  gint n_ints = 0;
894 
895  if (!make_pipe (child_err_report_pipe, error))
896    return FALSE;
897
898  if (standard_input && !make_pipe (stdin_pipe, error))
899    goto cleanup_and_fail;
900 
901  if (standard_output && !make_pipe (stdout_pipe, error))
902    goto cleanup_and_fail;
903
904  if (standard_error && !make_pipe (stderr_pipe, error))
905    goto cleanup_and_fail;
906
907  helper = do_spawn (dont_wait,
908                     child_err_report_pipe[1],
909                     stdin_pipe[0],
910                     stdout_pipe[1],
911                     stderr_pipe[1],
912                     working_directory,
913                     argv,
914                     envp,
915                     close_descriptors,
916                     search_path,
917                     stdout_to_null,
918                     stderr_to_null,
919                     child_inherits_stdin,
920                     file_and_argv_zero,
921                     child_setup,
922                     user_data);
923     
924  /* Check if gspawn-win32-helper couldn't be run */
925  if (helper == DO_SPAWN_ERROR_HELPER)
926    {
927      g_set_error (error,
928                   G_SPAWN_ERROR,
929                   G_SPAWN_ERROR_FAILED,
930                   _("Failed to execute helper program"));
931      goto cleanup_and_fail;
932    }
933
934  else if (helper == DO_SPAWN_OK_NO_HELPER)
935    {
936      if (child_handle && dont_wait && !dont_return_handle)
937        *child_handle = (GPid) shortcut_spawn_retval;
938      else if (!dont_wait && exit_status)
939        *exit_status = shortcut_spawn_retval;
940
941      close_and_invalidate (&child_err_report_pipe[0]);
942      close_and_invalidate (&child_err_report_pipe[1]);
943
944      return TRUE;
945    }
946  else if (helper == DO_SPAWN_ERROR_NO_HELPER)
947    {
948      g_set_error (error,
949                   G_SPAWN_ERROR,
950                   G_SPAWN_ERROR_FAILED,
951                   _("Failed to execute child process (%s)"),
952                   g_strerror (errno));
953      helper = -1;
954      goto cleanup_and_fail;
955    }
956
957  if (!read_ints (child_err_report_pipe[0],
958                  buf, 2, &n_ints,
959                  error) ||
960           n_ints != 2)
961    goto cleanup_and_fail;
962       
963  /* Error code from gspawn-win32-helper. */
964  switch (buf[0])
965    {
966    case CHILD_NO_ERROR:
967      if (child_handle && dont_wait && !dont_return_handle)
968        {
969          /* helper is our HANDLE for gspawn-win32-helper. It has
970           * told us the HANDLE of its child. Duplicate that into
971           * a HANDLE valid in this process.
972           */
973          if (!DuplicateHandle ((HANDLE) helper, (HANDLE) buf[1],
974                                GetCurrentProcess (), (LPHANDLE) child_handle,
975                                0, TRUE, DUPLICATE_SAME_ACCESS))
976            *child_handle = 0;
977        }
978      else if (child_handle)
979        *child_handle = 0;
980      break;
981     
982    case CHILD_CHDIR_FAILED:
983      g_set_error (error,
984                   G_SPAWN_ERROR,
985                   G_SPAWN_ERROR_CHDIR,
986                   _("Failed to change to directory '%s' (%s)"),
987                   working_directory,
988                   g_strerror (buf[1]));
989      goto cleanup_and_fail;
990     
991    case CHILD_SPAWN_FAILED:
992      g_set_error (error,
993                   G_SPAWN_ERROR,
994                   G_SPAWN_ERROR_FAILED,
995                   _("Failed to execute child process (%s)"),
996                   g_strerror (buf[1]));
997      goto cleanup_and_fail;
998    }
999
1000  /* Success against all odds! return the information */
1001     
1002  if (standard_input)
1003    *standard_input = stdin_pipe[1];
1004  if (standard_output)
1005    *standard_output = stdout_pipe[0];
1006  if (standard_error)
1007    *standard_error = stderr_pipe[0];
1008  if (exit_status)
1009    *exit_status = buf[1];
1010  CloseHandle ((HANDLE) helper);
1011 
1012  close_and_invalidate (&child_err_report_pipe[0]);
1013
1014  return TRUE;
1015
1016 cleanup_and_fail:
1017  if (helper != -1)
1018    CloseHandle ((HANDLE) helper);
1019  close_and_invalidate (&child_err_report_pipe[0]);
1020  close_and_invalidate (&child_err_report_pipe[1]);
1021  close_and_invalidate (&stdin_pipe[0]);
1022  close_and_invalidate (&stdin_pipe[1]);
1023  close_and_invalidate (&stdout_pipe[0]);
1024  close_and_invalidate (&stdout_pipe[1]);
1025  close_and_invalidate (&stderr_pipe[0]);
1026  close_and_invalidate (&stderr_pipe[1]);
1027
1028  return FALSE;
1029}
1030
1031static gboolean
1032make_pipe (gint     p[2],
1033           GError **error)
1034{
1035  if (pipe (p) < 0)
1036    {
1037      g_set_error (error,
1038                   G_SPAWN_ERROR,
1039                   G_SPAWN_ERROR_FAILED,
1040                   _("Failed to create pipe for communicating with child process (%s)"),
1041                   g_strerror (errno));
1042      return FALSE;
1043    }
1044  else
1045    return TRUE;
1046}
1047#endif /* !GSPAWN_HELPER */
1048
1049void
1050g_spawn_close_pid (GPid pid)
1051{
1052    CloseHandle (pid);
1053}
Note: See TracBrowser for help on using the repository browser.