1 | /* GLIB - Library of useful routines for C programming |
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
20 | * file for a list of people on the GLib Team. See the ChangeLog |
21 | * files for a list of changes. These files are distributed with |
22 | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
23 | */ |
24 | |
25 | #undef G_DISABLE_ASSERT |
26 | #undef G_LOG_DOMAIN |
27 | |
28 | #include <glib.h> |
29 | #include <glib/gstdio.h> |
30 | #include <stdio.h> |
31 | #include <string.h> |
32 | #include <stdlib.h> |
33 | |
34 | #ifdef G_OS_WIN32 |
35 | #include <fcntl.h> |
36 | #include <io.h> |
37 | #define pipe(fds) _pipe(fds, 4096, _O_BINARY) |
38 | #endif |
39 | |
40 | |
41 | static void |
42 | run_tests (const gchar* argv0) |
43 | { |
44 | GError *err = NULL; |
45 | gchar *output = NULL; |
46 | gchar *erroutput = NULL; |
47 | gchar *dirname = g_path_get_dirname (file_name: argv0); |
48 | #ifdef G_OS_WIN32 |
49 | int pipedown[2], pipeup[2]; |
50 | gchar **argv = 0; |
51 | gchar spawn_binary[1000] = {0}; |
52 | gchar full_cmdline[1000] = {0}; |
53 | g_snprintf (spawn_binary, sizeof (spawn_binary), "%s\\spawn-test-win32-gui.exe" , dirname); |
54 | #endif |
55 | g_free (mem: dirname); |
56 | |
57 | err = NULL; |
58 | if (!g_spawn_command_line_sync (command_line: "nonexistent_application foo 'bar baz' blah blah" , |
59 | NULL, NULL, NULL, |
60 | error: &err)) |
61 | { |
62 | g_error_free (error: err); |
63 | } |
64 | else |
65 | { |
66 | g_warning ("no error for sync spawn of nonexistent application" ); |
67 | exit (status: 1); |
68 | } |
69 | |
70 | err = NULL; |
71 | if (!g_spawn_command_line_async (command_line: "nonexistent_application foo bar baz \"blah blah\"" , |
72 | error: &err)) |
73 | { |
74 | g_error_free (error: err); |
75 | } |
76 | else |
77 | { |
78 | g_warning ("no error for async spawn of nonexistent application" ); |
79 | exit (status: 1); |
80 | } |
81 | |
82 | err = NULL; |
83 | #ifdef G_OS_UNIX |
84 | if (!g_spawn_command_line_sync (command_line: "/bin/sh -c 'echo hello'" , |
85 | standard_output: &output, NULL, NULL, |
86 | error: &err)) |
87 | { |
88 | fprintf (stderr, format: "Error: %s\n" , err->message); |
89 | g_error_free (error: err); |
90 | exit (status: 1); |
91 | } |
92 | else |
93 | { |
94 | g_assert (output != NULL); |
95 | |
96 | if (strcmp (s1: output, s2: "hello\n" ) != 0) |
97 | { |
98 | printf (format: "output was '%s', should have been 'hello'\n" , |
99 | output); |
100 | |
101 | exit (status: 1); |
102 | } |
103 | |
104 | g_free (mem: output); |
105 | output = NULL; |
106 | } |
107 | #endif |
108 | /* Running sort synchronously, collecting its output. 'sort' command is selected |
109 | * because it is non-builtin command on both unix and win32 with well-defined stdout behaviour. |
110 | */ |
111 | g_file_set_contents (filename: "spawn-test-created-file.txt" , contents: "line first\nline 2\nline last\n" , length: -1, error: &err); |
112 | g_assert_no_error(err); |
113 | if (!g_spawn_command_line_sync (command_line: "sort spawn-test-created-file.txt" , |
114 | standard_output: &output, standard_error: &erroutput, NULL, |
115 | error: &err)) |
116 | { |
117 | fprintf (stderr, format: "Error: %s\n" , err->message); |
118 | g_error_free (error: err); |
119 | exit (status: 1); |
120 | } |
121 | else |
122 | { |
123 | g_assert (output != NULL); |
124 | g_assert (erroutput != NULL); |
125 | |
126 | if (strstr (haystack: output, needle: "\nline first" ) == 0) |
127 | { |
128 | printf (format: "output was '%s', should have contained 'line first' in second line\n" , |
129 | output); |
130 | |
131 | exit (status: 1); |
132 | } |
133 | if (erroutput[0] != '\0') |
134 | { |
135 | printf (format: "error output was '%s', should have been empty\n" , |
136 | erroutput); |
137 | exit (status: 1); |
138 | } |
139 | |
140 | g_free (mem: output); |
141 | output = NULL; |
142 | g_free (mem: erroutput); |
143 | erroutput = NULL; |
144 | g_unlink (filename: "spawn-test-created-file.txt" ); |
145 | } |
146 | |
147 | if (!g_spawn_command_line_sync (command_line: "sort non-existing-file.txt" , |
148 | NULL, standard_error: &erroutput, NULL, |
149 | error: &err)) |
150 | { |
151 | fprintf (stderr, format: "Error: %s\n" , err->message); |
152 | g_error_free (error: err); |
153 | exit (status: 1); |
154 | } |
155 | else |
156 | { |
157 | g_assert (erroutput != NULL); |
158 | |
159 | if (erroutput[0] == '\0') |
160 | { |
161 | printf (format: "erroutput was empty, expected contain error message about non-existing-file.txt\n" ); |
162 | exit (status: 1); |
163 | } |
164 | g_free (mem: erroutput); |
165 | erroutput = NULL; |
166 | } |
167 | |
168 | #ifdef G_OS_WIN32 |
169 | printf ("Running spawn-test-win32-gui in various ways.\n" ); |
170 | |
171 | printf ("First asynchronously (without wait).\n" ); |
172 | g_snprintf (full_cmdline, sizeof (full_cmdline), "'%s' 1" , spawn_binary); |
173 | if (!g_spawn_command_line_async (full_cmdline, &err)) |
174 | { |
175 | fprintf (stderr, "Error: %s\n" , err->message); |
176 | g_error_free (err); |
177 | exit (1); |
178 | } |
179 | |
180 | printf ("Now synchronously, collecting its output.\n" ); |
181 | g_snprintf (full_cmdline, sizeof (full_cmdline), "'%s' 2" , spawn_binary); |
182 | if (!g_spawn_command_line_sync (full_cmdline, |
183 | &output, &erroutput, NULL, |
184 | &err)) |
185 | { |
186 | fprintf (stderr, "Error: %s\n" , err->message); |
187 | g_error_free (err); |
188 | exit (1); |
189 | } |
190 | else |
191 | { |
192 | g_assert (output != NULL); |
193 | g_assert (erroutput != NULL); |
194 | |
195 | if (strcmp (output, "This is stdout\r\n" ) != 0) |
196 | { |
197 | printf ("output was '%s', should have been 'This is stdout'\n" , |
198 | g_strescape (output, NULL)); |
199 | |
200 | exit (1); |
201 | } |
202 | if (strcmp (erroutput, "This is stderr\r\n" ) != 0) |
203 | { |
204 | printf ("error output was '%s', should have been 'This is stderr'\n" , |
205 | g_strescape (erroutput, NULL)); |
206 | exit (1); |
207 | } |
208 | |
209 | g_free (output); |
210 | output = NULL; |
211 | g_free (erroutput); |
212 | erroutput = NULL; |
213 | } |
214 | |
215 | printf ("Now with G_SPAWN_FILE_AND_ARGV_ZERO.\n" ); |
216 | g_snprintf (full_cmdline, sizeof (full_cmdline), "'%s' this-should-be-argv-zero print_argv0" , spawn_binary); |
217 | if (!g_shell_parse_argv (full_cmdline, NULL, &argv, &err)) |
218 | { |
219 | fprintf (stderr, "Error parsing command line? %s\n" , err->message); |
220 | g_error_free (err); |
221 | exit (1); |
222 | } |
223 | |
224 | if (!g_spawn_sync (NULL, argv, NULL, |
225 | G_SPAWN_FILE_AND_ARGV_ZERO, |
226 | NULL, NULL, &output, NULL, NULL, |
227 | &err)) |
228 | { |
229 | fprintf (stderr, "Error: %s\n" , err->message); |
230 | g_error_free (err); |
231 | exit (1); |
232 | } |
233 | else |
234 | { |
235 | if (strcmp (output, "this-should-be-argv-zero" ) != 0) |
236 | { |
237 | printf ("output was '%s', should have been 'this-should-be-argv-zero'\n" , output); |
238 | exit (1); |
239 | } |
240 | g_free (output); |
241 | output = NULL; |
242 | } |
243 | |
244 | printf ("Now talking to it through pipes.\n" ); |
245 | |
246 | if (pipe (pipedown) < 0 || |
247 | pipe (pipeup) < 0) |
248 | { |
249 | fprintf (stderr, "Could not create pipes\n" ); |
250 | exit (1); |
251 | } |
252 | |
253 | g_snprintf (full_cmdline, sizeof (full_cmdline), "'%s' pipes %d %d" , spawn_binary, pipedown[0], pipeup[1]); |
254 | if (!g_shell_parse_argv (full_cmdline, |
255 | NULL, &argv, |
256 | &err)) |
257 | { |
258 | fprintf (stderr, "Error parsing command line? %s\n" , err->message); |
259 | g_error_free (err); |
260 | exit (1); |
261 | } |
262 | |
263 | if (!g_spawn_async (NULL, argv, NULL, |
264 | G_SPAWN_LEAVE_DESCRIPTORS_OPEN | |
265 | G_SPAWN_DO_NOT_REAP_CHILD, |
266 | NULL, NULL, NULL, |
267 | &err)) |
268 | { |
269 | fprintf (stderr, "Error: %s\n" , err->message); |
270 | g_error_free (err); |
271 | exit (1); |
272 | } |
273 | else |
274 | { |
275 | int k, n; |
276 | char buf[100]; |
277 | |
278 | if ((k = read (pipeup[0], &n, sizeof (n))) != sizeof (n)) |
279 | { |
280 | int errsv = errno; |
281 | if (k == -1) |
282 | fprintf (stderr, "Read error: %s\n" , g_strerror (errsv)); |
283 | else |
284 | fprintf (stderr, "Wanted to read %d bytes, got %d\n" , |
285 | (int)sizeof (n), k); |
286 | exit (1); |
287 | } |
288 | |
289 | if ((k = read (pipeup[0], buf, n)) != n) |
290 | { |
291 | int errsv = errno; |
292 | if (k == -1) |
293 | fprintf (stderr, "Read error: %s\n" , g_strerror (errsv)); |
294 | else |
295 | fprintf (stderr, "Wanted to read %d bytes, got %d\n" , |
296 | n, k); |
297 | exit (1); |
298 | } |
299 | |
300 | n = strlen ("Bye then" ); |
301 | if (write (pipedown[1], &n, sizeof (n)) == -1 || |
302 | write (pipedown[1], "Bye then" , n) == -1) |
303 | { |
304 | int errsv = errno; |
305 | fprintf (stderr, "Write error: %s\n" , g_strerror (errsv)); |
306 | exit (1); |
307 | } |
308 | |
309 | if ((k = read (pipeup[0], &n, sizeof (n))) != sizeof (n)) |
310 | { |
311 | int errsv = errno; |
312 | if (k == -1) |
313 | fprintf (stderr, "Read error: %s\n" , g_strerror (errsv)); |
314 | else |
315 | fprintf (stderr, "Wanted to read %d bytes, got %d\n" , |
316 | (int)sizeof (n), k); |
317 | exit (1); |
318 | } |
319 | if (n != strlen ("See ya" )) |
320 | { |
321 | printf ("child wrote %d bytes, expected %d" , n, (int) strlen ("See ya" )); |
322 | exit (1); |
323 | } |
324 | |
325 | if ((k = read (pipeup[0], buf, n)) != n) |
326 | { |
327 | int errsv = errno; |
328 | if (k == -1) |
329 | fprintf (stderr, "Read error: %s\n" , g_strerror (errsv)); |
330 | else |
331 | fprintf (stderr, "Wanted to read %d bytes, got %d\n" , |
332 | n, k); |
333 | exit (1); |
334 | } |
335 | buf[n] = '\0'; |
336 | if (strcmp (buf, "See ya" ) != 0) |
337 | { |
338 | printf ("output was '%s', should have been 'See ya'\n" , buf); |
339 | exit (1); |
340 | } |
341 | } |
342 | #endif |
343 | } |
344 | |
345 | int |
346 | main (int argc, |
347 | char *argv[]) |
348 | { |
349 | run_tests (argv0: argv[0]); |
350 | |
351 | return 0; |
352 | } |
353 | |