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