Cygwin support contributed by Stefan Ondrejicka <ondrej@idata.sk>.
[platform/upstream/glib.git] / glib / gspawn-win32-helper.c
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 #undef G_LOG_DOMAIN
23 #include "glib.h"
24 #define GSPAWN_HELPER
25 #include "gspawn-win32.c"       /* For shared definitions */
26
27 static void
28 write_err_and_exit (gint fd,
29                     gint msg)
30 {
31   gint en = errno;
32   
33   write (fd, &msg, sizeof(msg));
34   write (fd, &en, sizeof(en));
35   
36   _exit (1);
37 }
38
39 static void
40 write_no_error (gint fd)
41 {
42   gint msg = CHILD_NO_ERROR;
43   gint en = 0;
44
45   write (fd, &msg, sizeof(msg));
46   write (fd, &en, sizeof(en));
47 }
48
49 #ifdef __GNUC__
50 #  ifndef _stdcall
51 #    define _stdcall  __attribute__((stdcall))
52 #  endif
53 #endif
54
55 /* We build gspawn-win32-helper.exe as a Windows GUI application
56  * to avoid any temporarily flashing console windows in case
57  * the gspawn function is invoked by a GUI program. Thus, no main()
58  * but a WinMain(). We do, however, still use argc and argv tucked
59  * away in the global __argc and __argv by the C runtime startup code.
60  */
61
62 int _stdcall
63 WinMain (struct HINSTANCE__ *hInstance,
64          struct HINSTANCE__ *hPrevInstance,
65          char               *lpszCmdLine,
66          int                 nCmdShow)
67 {
68   int child_err_report_fd;
69   int i;
70   int fd;
71   int mode;
72   GString *debugstring;
73
74   SETUP_DEBUG();
75
76   if (debug)
77     {
78       debugstring = g_string_new ("");
79
80       g_string_append (debugstring,
81                        g_strdup_printf ("g-spawn-win32-helper: "
82                                         "argc = %d, argv: ",
83                                         __argc));
84       for (i = 0; i < __argc; i++)
85         {
86           if (i > 0)
87             g_string_append (debugstring, " ");
88           g_string_append (debugstring, __argv[i]);
89         }
90       
91       MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
92     }
93
94   g_assert (__argc >= ARG_COUNT);
95
96   /* argv[ARG_CHILD_ERR_REPORT] is the file descriptor onto which
97    * write error messages.
98    */
99   child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]);
100
101   /* argv[ARG_STDIN..ARG_STDERR] are the file descriptors that should
102    * be dup2'd to stdin, stdout and stderr, '-' if the corresponding
103    * std* should be let alone, and 'z' if it should be connected to
104    * the bit bucket NUL:.
105    */
106   if (__argv[ARG_STDIN][0] == '-')
107     ; /* Nothing */
108   else if (__argv[ARG_STDIN][0] == 'z')
109     {
110       fd = open ("NUL:", O_RDONLY);
111       if (fd != 0)
112         {
113           dup2 (fd, 0);
114           close (fd);
115         }
116     }
117   else
118     {
119       fd = atoi (__argv[ARG_STDIN]);
120       if (fd != 0)
121         {
122           dup2 (fd, 0);
123           close (fd);
124         }
125     }
126
127   if (__argv[ARG_STDOUT][0] == '-')
128     ; /* Nothing */
129   else if (__argv[ARG_STDOUT][0] == 'z')
130     {
131       fd = open ("NUL:", O_WRONLY);
132       if (fd != 1)
133         {
134           dup2 (fd, 1);
135           close (fd);
136         }
137     }
138   else
139     {
140       fd = atoi (__argv[ARG_STDOUT]);
141       if (fd != 1)
142         {
143           dup2 (fd, 1);
144           close (fd);
145         }
146     }
147
148   if (__argv[ARG_STDERR][0] == '-')
149     ; /* Nothing */
150   else if (__argv[ARG_STDERR][0] == 'z')
151     {
152       fd = open ("NUL:", O_WRONLY);
153       if (fd != 2)
154         {
155           dup2 (fd, 2);
156           close (fd);
157         }
158     }
159   else
160     {
161       fd = atoi (__argv[ARG_STDERR]);
162       if (fd != 2)
163         {
164           dup2 (fd, 2);
165           close (fd);
166         }
167     }
168
169   /* __argv[ARG_WORKING_DIRECTORY] is the directory in which to run the
170    * process.  If "-", don't change directory.
171    */
172   if (__argv[ARG_WORKING_DIRECTORY][0] == '-' &&
173       __argv[ARG_WORKING_DIRECTORY][1] == 0)
174     ; /* Nothing */
175   else if (chdir (__argv[ARG_WORKING_DIRECTORY]) < 0)
176     write_err_and_exit (child_err_report_fd,
177                         CHILD_CHDIR_FAILED);
178
179   /* __argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3
180    *  upwards should be closed
181    */
182
183   if (__argv[ARG_CLOSE_DESCRIPTORS][0] == 'y')
184     for (i = 3; i < 1000; i++)  /* FIXME real limit? */
185       if (i != child_err_report_fd)
186         close (i);
187
188   /* __argv[ARG_WAIT] is "w" to wait for the program to exit */
189
190   if (__argv[ARG_WAIT][0] == 'w')
191     mode = P_WAIT;
192   else
193     mode = P_NOWAIT;
194
195   /* __argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */
196
197   /* __argv[ARG_PROGRAM] is program file to run,
198    * __argv[ARG_PROGRAM+1]... is its __argv.
199    */
200
201   if (debug)
202     {
203       debugstring = g_string_new ("");
204       g_string_append (debugstring,
205                        g_strdup_printf ("calling %s on program %s, __argv: ",
206                                         (__argv[ARG_USE_PATH][0] == 'y' ?
207                                          "spawnvp" : "spawnv"),
208                                         __argv[ARG_PROGRAM]));
209       i = ARG_PROGRAM+1;
210       while (__argv[i])
211         g_string_append (debugstring, __argv[i++]);
212       MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
213     }
214
215   if (__argv[ARG_USE_PATH][0] == 'y')
216     {
217       if (spawnvp (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM) < 0)
218         write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
219     }
220   else
221     {
222       if (spawnv (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM) < 0)
223         write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
224     }
225
226   return 0;
227 }
228