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

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