~ubuntu-branches/ubuntu/utopic/glib2.0/utopic

« back to all changes in this revision

Viewing changes to glib/gspawn-win32-helper.c

Tags: upstream-2.12.12
ImportĀ upstreamĀ versionĀ 2.12.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
30
static void
 
31
write_err_and_exit (gint fd,
 
32
                    gint msg)
 
33
{
 
34
  gint en = errno;
 
35
  
 
36
  write (fd, &msg, sizeof(msg));
 
37
  write (fd, &en, sizeof(en));
 
38
  
 
39
  _exit (1);
 
40
}
 
41
 
 
42
#ifdef __GNUC__
 
43
#  ifndef _stdcall
 
44
#    define _stdcall  __attribute__((stdcall))
 
45
#  endif
 
46
#endif
 
47
 
 
48
/* We build gspawn-win32-helper.exe as a Windows GUI application
 
49
 * to avoid any temporarily flashing console windows in case
 
50
 * the gspawn function is invoked by a GUI program. Thus, no main()
 
51
 * but a WinMain(). We do, however, still use argc and argv tucked
 
52
 * away in the global __argc and __argv by the C runtime startup code.
 
53
 */
 
54
 
 
55
/* Info peeked from mingw runtime's source code. __wgetmainargs() is a
 
56
 * function to get the program's argv in wide char format.
 
57
 */
 
58
 
 
59
typedef struct {
 
60
  int newmode;
 
61
} _startupinfo;
 
62
 
 
63
extern void __wgetmainargs(int *argc,
 
64
                           wchar_t ***wargv,
 
65
                           wchar_t ***wenviron,
 
66
                           int expand_wildcards,
 
67
                           _startupinfo *startupinfo);
 
68
 
 
69
/* Copy of protect_argv that handles wchar_t strings */
 
70
 
 
71
static gint
 
72
protect_wargv (wchar_t  **wargv,
 
73
               wchar_t ***new_wargv)
 
74
{
 
75
  gint i;
 
76
  gint argc = 0;
 
77
  
 
78
  while (wargv[argc])
 
79
    ++argc;
 
80
  *new_wargv = g_new (wchar_t *, argc+1);
 
81
 
 
82
  /* Quote each argv element if necessary, so that it will get
 
83
   * reconstructed correctly in the C runtime startup code.  Note that
 
84
   * the unquoting algorithm in the C runtime is really weird, and
 
85
   * rather different than what Unix shells do. See stdargv.c in the C
 
86
   * runtime sources (in the Platform SDK, in src/crt).
 
87
   *
 
88
   * Note that an new_wargv[0] constructed by this function should
 
89
   * *not* be passed as the filename argument to a _wspawn* or _wexec*
 
90
   * family function. That argument should be the real file name
 
91
   * without any quoting.
 
92
   */
 
93
  for (i = 0; i < argc; i++)
 
94
    {
 
95
      wchar_t *p = wargv[i];
 
96
      wchar_t *q;
 
97
      gint len = 0;
 
98
      gboolean need_dblquotes = FALSE;
 
99
      while (*p)
 
100
        {
 
101
          if (*p == ' ' || *p == '\t')
 
102
            need_dblquotes = TRUE;
 
103
          else if (*p == '"')
 
104
            len++;
 
105
          else if (*p == '\\')
 
106
            {
 
107
              wchar_t *pp = p;
 
108
              while (*pp && *pp == '\\')
 
109
                pp++;
 
110
              if (*pp == '"')
 
111
                len++;
 
112
            }
 
113
          len++;
 
114
          p++;
 
115
        }
 
116
 
 
117
      q = (*new_wargv)[i] = g_new (wchar_t, len + need_dblquotes*2 + 1);
 
118
      p = wargv[i];
 
119
 
 
120
      if (need_dblquotes)
 
121
        *q++ = '"';
 
122
 
 
123
      while (*p)
 
124
        {
 
125
          if (*p == '"')
 
126
            *q++ = '\\';
 
127
          else if (*p == '\\')
 
128
            {
 
129
              wchar_t *pp = p;
 
130
              while (*pp && *pp == '\\')
 
131
                pp++;
 
132
              if (*pp == '"')
 
133
                *q++ = '\\';
 
134
            }
 
135
          *q++ = *p;
 
136
          p++;
 
137
        }
 
138
 
 
139
      if (need_dblquotes)
 
140
        *q++ = '"';
 
141
      *q++ = '\0';
 
142
    }
 
143
  (*new_wargv)[argc] = NULL;
 
144
 
 
145
  return argc;
 
146
}
 
147
 
 
148
int _stdcall
 
149
WinMain (struct HINSTANCE__ *hInstance,
 
150
         struct HINSTANCE__ *hPrevInstance,
 
151
         char               *lpszCmdLine,
 
152
         int                 nCmdShow)
 
153
{
 
154
  int child_err_report_fd;
 
155
  int i;
 
156
  int fd;
 
157
  int mode;
 
158
  int handle;
 
159
  int saved_errno;
 
160
  int no_error = CHILD_NO_ERROR;
 
161
  int zero = 0;
 
162
  gint argv_zero_offset = ARG_PROGRAM;
 
163
  gchar **new_argv;
 
164
  wchar_t **new_wargv;
 
165
  int argc;
 
166
  wchar_t **wargv, **wenvp;
 
167
  _startupinfo si = { 0 };
 
168
 
 
169
  g_assert (__argc >= ARG_COUNT);
 
170
 
 
171
  if (G_WIN32_HAVE_WIDECHAR_API ())
 
172
    {
 
173
      /* Fetch the wide-char argument vector */
 
174
      __wgetmainargs (&argc, &wargv, &wenvp, 0, &si);
 
175
 
 
176
      /* We still have the system codepage args in __argv. We can look
 
177
       * at the first args in which gspawn-win32.c passes us flags and
 
178
       * fd numbers in __argv, as we know those are just ASCII anyway.
 
179
       */
 
180
      g_assert (argc == __argc);
 
181
    }
 
182
 
 
183
  /* argv[ARG_CHILD_ERR_REPORT] is the file descriptor number onto
 
184
   * which write error messages.
 
185
   */
 
186
  child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]);
 
187
 
 
188
  /* Hack to implement G_SPAWN_FILE_AND_ARGV_ZERO. If
 
189
   * argv[ARG_CHILD_ERR_REPORT] is suffixed with a '#' it means we get
 
190
   * the program to run and its argv[0] separately.
 
191
   */
 
192
  if (__argv[ARG_CHILD_ERR_REPORT][strlen (__argv[ARG_CHILD_ERR_REPORT]) - 1] == '#')
 
193
    argv_zero_offset++;
 
194
 
 
195
  /* argv[ARG_STDIN..ARG_STDERR] are the file descriptor numbers that
 
196
   * should be dup2'd to 0, 1 and 2. '-' if the corresponding fd
 
197
   * should be left alone, and 'z' if it should be connected to the
 
198
   * bit bucket NUL:.
 
199
   */
 
200
  if (__argv[ARG_STDIN][0] == '-')
 
201
    ; /* Nothing */
 
202
  else if (__argv[ARG_STDIN][0] == 'z')
 
203
    {
 
204
      fd = open ("NUL:", O_RDONLY);
 
205
      if (fd != 0)
 
206
        {
 
207
          dup2 (fd, 0);
 
208
          close (fd);
 
209
        }
 
210
    }
 
211
  else
 
212
    {
 
213
      fd = atoi (__argv[ARG_STDIN]);
 
214
      if (fd != 0)
 
215
        {
 
216
          dup2 (fd, 0);
 
217
          close (fd);
 
218
        }
 
219
    }
 
220
 
 
221
  if (__argv[ARG_STDOUT][0] == '-')
 
222
    ; /* Nothing */
 
223
  else if (__argv[ARG_STDOUT][0] == 'z')
 
224
    {
 
225
      fd = open ("NUL:", O_WRONLY);
 
226
      if (fd != 1)
 
227
        {
 
228
          dup2 (fd, 1);
 
229
          close (fd);
 
230
        }
 
231
    }
 
232
  else
 
233
    {
 
234
      fd = atoi (__argv[ARG_STDOUT]);
 
235
      if (fd != 1)
 
236
        {
 
237
          dup2 (fd, 1);
 
238
          close (fd);
 
239
        }
 
240
    }
 
241
 
 
242
  if (__argv[ARG_STDERR][0] == '-')
 
243
    ; /* Nothing */
 
244
  else if (__argv[ARG_STDERR][0] == 'z')
 
245
    {
 
246
      fd = open ("NUL:", O_WRONLY);
 
247
      if (fd != 2)
 
248
        {
 
249
          dup2 (fd, 2);
 
250
          close (fd);
 
251
        }
 
252
    }
 
253
  else
 
254
    {
 
255
      fd = atoi (__argv[ARG_STDERR]);
 
256
      if (fd != 2)
 
257
        {
 
258
          dup2 (fd, 2);
 
259
          close (fd);
 
260
        }
 
261
    }
 
262
 
 
263
  /* __argv[ARG_WORKING_DIRECTORY] is the directory in which to run the
 
264
   * process.  If "-", don't change directory.
 
265
   */
 
266
  if (__argv[ARG_WORKING_DIRECTORY][0] == '-' &&
 
267
      __argv[ARG_WORKING_DIRECTORY][1] == 0)
 
268
    ; /* Nothing */
 
269
  else if ((G_WIN32_HAVE_WIDECHAR_API () &&
 
270
            _wchdir (wargv[ARG_WORKING_DIRECTORY]) < 0) ||
 
271
           (!G_WIN32_HAVE_WIDECHAR_API () &&
 
272
            chdir (__argv[ARG_WORKING_DIRECTORY]) < 0))
 
273
    write_err_and_exit (child_err_report_fd, CHILD_CHDIR_FAILED);
 
274
 
 
275
  /* __argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3
 
276
   *  upwards should be closed
 
277
   */
 
278
  if (__argv[ARG_CLOSE_DESCRIPTORS][0] == 'y')
 
279
    for (i = 3; i < 1000; i++)  /* FIXME real limit? */
 
280
      if (i != child_err_report_fd)
 
281
        close (i);
 
282
 
 
283
  /* __argv[ARG_WAIT] is "w" to wait for the program to exit */
 
284
  if (__argv[ARG_WAIT][0] == 'w')
 
285
    mode = P_WAIT;
 
286
  else
 
287
    mode = P_NOWAIT;
 
288
 
 
289
  /* __argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */
 
290
 
 
291
  /* __argv[ARG_PROGRAM] is executable file to run,
 
292
   * __argv[argv_zero_offset]... is its argv. argv_zero_offset equals
 
293
   * ARG_PROGRAM unless G_SPAWN_FILE_AND_ARGV_ZERO was used, in which
 
294
   * case we have a separate executable name and argv[0].
 
295
   */
 
296
 
 
297
  /* For the program name passed to spawnv(), don't use the quoted
 
298
   * version.
 
299
   */
 
300
  if (G_WIN32_HAVE_WIDECHAR_API ())
 
301
    {
 
302
      protect_wargv (wargv + argv_zero_offset, &new_wargv);
 
303
 
 
304
      if (__argv[ARG_USE_PATH][0] == 'y')
 
305
        handle = _wspawnvp (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv);
 
306
      else
 
307
        handle = _wspawnv (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv);
 
308
    }
 
309
  else
 
310
    {
 
311
      protect_argv (__argv + argv_zero_offset, &new_argv);
 
312
 
 
313
      if (__argv[ARG_USE_PATH][0] == 'y')
 
314
        handle = spawnvp (mode, __argv[ARG_PROGRAM], (const char **) new_argv);
 
315
      else
 
316
        handle = spawnv (mode, __argv[ARG_PROGRAM], (const char **) new_argv);
 
317
    }
 
318
 
 
319
  saved_errno = errno;
 
320
 
 
321
  if (handle == -1 && saved_errno != 0)
 
322
    write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
 
323
 
 
324
  write (child_err_report_fd, &no_error, sizeof (no_error));
 
325
  if (mode == P_NOWAIT)
 
326
    write (child_err_report_fd, &handle, sizeof (handle));
 
327
  else
 
328
    write (child_err_report_fd, &zero, sizeof (zero));
 
329
  return 0;
 
330
}