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

Revision 21369, 6.6 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21368, which included commits to RCS files with non-trunk default branches.
Line 
1/* gspawn-win32-helper.c - Helper program for process launching on Win32.
2 *
3 *  Copyright 2000 Red Hat, Inc.
4 *  Copyright 2000 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#include "config.h"
23
24#undef G_LOG_DOMAIN
25#include "glib.h"
26#define GSPAWN_HELPER
27#include "gspawn-win32.c"       /* For shared definitions */
28
29
30static GString *debugstring;
31
32static void
33write_err_and_exit (gint fd,
34                    gint msg)
35{
36  gint en = errno;
37 
38  if (debug)
39    {
40      debugstring = g_string_new (NULL);
41      g_string_append (debugstring,
42                       g_strdup_printf ("writing error code %d and errno %d",
43                                        msg, en));
44      MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
45    }
46
47  write (fd, &msg, sizeof(msg));
48  write (fd, &en, sizeof(en));
49 
50  _exit (1);
51}
52
53#ifdef __GNUC__
54#  ifndef _stdcall
55#    define _stdcall  __attribute__((stdcall))
56#  endif
57#endif
58
59/* We build gspawn-win32-helper.exe as a Windows GUI application
60 * to avoid any temporarily flashing console windows in case
61 * the gspawn function is invoked by a GUI program. Thus, no main()
62 * but a WinMain(). We do, however, still use argc and argv tucked
63 * away in the global __argc and __argv by the C runtime startup code.
64 */
65
66int _stdcall
67WinMain (struct HINSTANCE__ *hInstance,
68         struct HINSTANCE__ *hPrevInstance,
69         char               *lpszCmdLine,
70         int                 nCmdShow)
71{
72  int child_err_report_fd;
73  int i;
74  int fd;
75  int mode;
76  int handle;
77  int saved_errno;
78  int no_error = CHILD_NO_ERROR;
79  int zero = 0;
80  gint file_and_argv_zero = 0;
81  gchar **new_argv;
82
83  SETUP_DEBUG();
84
85  if (debug)
86    {
87      debugstring = g_string_new (NULL);
88
89      g_string_append (debugstring,
90                       g_strdup_printf ("g-spawn-win32-helper: "
91                                        "argc = %d, argv: ",
92                                        __argc));
93      for (i = 0; i < __argc; i++)
94        {
95          if (i > 0)
96            g_string_append (debugstring, " ");
97          g_string_append (debugstring, __argv[i]);
98        }
99     
100      MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
101    }
102
103  g_assert (__argc >= ARG_COUNT);
104
105  /* argv[ARG_CHILD_ERR_REPORT] is the file descriptor onto which
106   * write error messages.
107   */
108  child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]);
109
110  /* Hack to implement G_SPAWN_FILE_AND_ARGV_ZERO */
111  if (__argv[ARG_CHILD_ERR_REPORT][strlen (__argv[ARG_CHILD_ERR_REPORT]) - 1] == '#')
112    file_and_argv_zero = 1;
113
114  /* argv[ARG_STDIN..ARG_STDERR] are the file descriptors that should
115   * be dup2'd to stdin, stdout and stderr, '-' if the corresponding
116   * std* should be let alone, and 'z' if it should be connected to
117   * the bit bucket NUL:.
118   */
119  if (__argv[ARG_STDIN][0] == '-')
120    ; /* Nothing */
121  else if (__argv[ARG_STDIN][0] == 'z')
122    {
123      fd = open ("NUL:", O_RDONLY);
124      if (fd != 0)
125        {
126          dup2 (fd, 0);
127          close (fd);
128        }
129    }
130  else
131    {
132      fd = atoi (__argv[ARG_STDIN]);
133      if (fd != 0)
134        {
135          dup2 (fd, 0);
136          close (fd);
137        }
138    }
139
140  if (__argv[ARG_STDOUT][0] == '-')
141    ; /* Nothing */
142  else if (__argv[ARG_STDOUT][0] == 'z')
143    {
144      fd = open ("NUL:", O_WRONLY);
145      if (fd != 1)
146        {
147          dup2 (fd, 1);
148          close (fd);
149        }
150    }
151  else
152    {
153      fd = atoi (__argv[ARG_STDOUT]);
154      if (fd != 1)
155        {
156          dup2 (fd, 1);
157          close (fd);
158        }
159    }
160
161  if (__argv[ARG_STDERR][0] == '-')
162    ; /* Nothing */
163  else if (__argv[ARG_STDERR][0] == 'z')
164    {
165      fd = open ("NUL:", O_WRONLY);
166      if (fd != 2)
167        {
168          dup2 (fd, 2);
169          close (fd);
170        }
171    }
172  else
173    {
174      fd = atoi (__argv[ARG_STDERR]);
175      if (fd != 2)
176        {
177          dup2 (fd, 2);
178          close (fd);
179        }
180    }
181
182  /* __argv[ARG_WORKING_DIRECTORY] is the directory in which to run the
183   * process.  If "-", don't change directory.
184   */
185  if (__argv[ARG_WORKING_DIRECTORY][0] == '-' &&
186      __argv[ARG_WORKING_DIRECTORY][1] == 0)
187    ; /* Nothing */
188  else if (chdir (__argv[ARG_WORKING_DIRECTORY]) < 0)
189    write_err_and_exit (child_err_report_fd,
190                        CHILD_CHDIR_FAILED);
191
192  /* __argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3
193   *  upwards should be closed
194   */
195
196  if (__argv[ARG_CLOSE_DESCRIPTORS][0] == 'y')
197    for (i = 3; i < 1000; i++)  /* FIXME real limit? */
198      if (i != child_err_report_fd)
199        close (i);
200
201  /* __argv[ARG_WAIT] is "w" to wait for the program to exit */
202
203  if (__argv[ARG_WAIT][0] == 'w')
204    mode = P_WAIT;
205  else
206    mode = P_NOWAIT;
207
208  /* __argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */
209
210  /* __argv[ARG_PROGRAM] is program file to run,
211   * __argv[ARG_PROGRAM+1]... is its __argv.
212   */
213
214  protect_argv (__argv, &new_argv);
215
216  /* For the program name passed to spawnv(), don't use the quoted
217   * version. */
218
219  if (debug)
220    {
221      debugstring = g_string_new (NULL);
222      g_string_append (debugstring,
223                       g_strdup_printf ("calling %s %s mode=%s argv: ",
224                                        (__argv[ARG_USE_PATH][0] == 'y' ?
225                                         "spawnvp" : "spawnv"),
226                                        __argv[ARG_PROGRAM],
227                                        (mode == P_WAIT ?
228                                         "P_WAIT" : "P_NOWAIT")));
229      i = ARG_PROGRAM + 1 + file_and_argv_zero;
230      while (new_argv[i])
231        {
232          g_string_append (debugstring, new_argv[i++]);
233          if (new_argv[i])
234            g_string_append (debugstring, " ");
235        }
236      MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
237    }
238
239  if (new_argv[ARG_USE_PATH][0] == 'y')
240    handle = spawnvp (mode, __argv[ARG_PROGRAM], new_argv + ARG_PROGRAM + file_and_argv_zero);
241  else
242    handle = spawnv (mode, __argv[ARG_PROGRAM], new_argv + ARG_PROGRAM + file_and_argv_zero);
243
244  saved_errno = errno;
245
246  if (debug)
247    {
248      debugstring = g_string_new (NULL);
249      g_string_append (debugstring,
250                       g_strdup_printf ("%s returned %#x",
251                                        (__argv[ARG_USE_PATH][0] == 'y' ?
252                                         "spawnvp" : "spawnv"),
253                                        handle));
254      MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
255    }
256
257  if (handle == -1 && saved_errno != 0)
258    write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
259
260  write (child_err_report_fd, &no_error, sizeof (no_error));
261  if (mode == P_NOWAIT)
262    write (child_err_report_fd, &handle, sizeof (handle));
263  else
264    write (child_err_report_fd, &zero, sizeof (zero));
265  return 0;
266}
267
Note: See TracBrowser for help on using the repository browser.