Branch data Line data Source code
1 : : #include "glib-private.h"
2 : : #include <gio/gio.h>
3 : : #include <string.h>
4 : :
5 : : #ifdef G_OS_UNIX
6 : : #include <sys/wait.h>
7 : : #include <glib-unix.h>
8 : : #include <gio/gunixinputstream.h>
9 : : #include <gio/gunixoutputstream.h>
10 : : #include <gio/gfiledescriptorbased.h>
11 : : #include <unistd.h>
12 : : #include <fcntl.h>
13 : : #endif
14 : :
15 : : #ifdef __linux__
16 : : #include <sys/ptrace.h>
17 : : #endif
18 : :
19 : : /* We write 2^1 + 2^2 ... + 2^10 or 2047 copies of "Hello World!\n"
20 : : * ultimately
21 : : */
22 : : #define TOTAL_HELLOS 2047
23 : : #define HELLO_WORLD "hello world!\n"
24 : :
25 : : #ifdef G_OS_WIN32
26 : : #define LINEEND "\r\n"
27 : : #define EXEEXT ".exe"
28 : : #define SPLICELEN (TOTAL_HELLOS * (strlen (HELLO_WORLD) + 1)) /* because \r */
29 : : #else
30 : : #define LINEEND "\n"
31 : : #define EXEEXT
32 : : #define SPLICELEN (TOTAL_HELLOS * strlen (HELLO_WORLD))
33 : : #endif
34 : :
35 : :
36 : :
37 : : #ifdef G_OS_WIN32
38 : : #define TESTPROG "gsubprocess-testprog.exe"
39 : : #else
40 : : #define TESTPROG "gsubprocess-testprog"
41 : : #endif
42 : :
43 : : static GPtrArray *
44 : : get_test_subprocess_args (const char *mode,
45 : : ...) G_GNUC_NULL_TERMINATED;
46 : :
47 : : static GPtrArray *
48 : 80 : get_test_subprocess_args (const char *mode,
49 : : ...)
50 : : {
51 : : GPtrArray *ret;
52 : : char *path;
53 : : va_list args;
54 : : gpointer arg;
55 : :
56 : 80 : ret = g_ptr_array_new_with_free_func (g_free);
57 : :
58 : 80 : path = g_test_build_filename (G_TEST_BUILT, TESTPROG, NULL);
59 : 80 : g_ptr_array_add (ret, path);
60 : 80 : g_ptr_array_add (ret, g_strdup (mode));
61 : :
62 : 80 : va_start (args, mode);
63 : 97 : while ((arg = va_arg (args, gpointer)) != NULL)
64 : 17 : g_ptr_array_add (ret, g_strdup (arg));
65 : 80 : va_end (args);
66 : :
67 : 80 : g_ptr_array_add (ret, NULL);
68 : 80 : return ret;
69 : : }
70 : :
71 : : static void
72 : 1 : test_noop (void)
73 : : {
74 : 1 : GError *local_error = NULL;
75 : 1 : GError **error = &local_error;
76 : : GPtrArray *args;
77 : : GSubprocess *proc;
78 : :
79 : 1 : args = get_test_subprocess_args ("noop", NULL);
80 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
81 : 1 : g_ptr_array_free (args, TRUE);
82 : 1 : g_assert_no_error (local_error);
83 : :
84 : 1 : g_subprocess_wait_check (proc, NULL, error);
85 : 1 : g_assert_no_error (local_error);
86 : 1 : g_assert_true (g_subprocess_get_successful (proc));
87 : :
88 : 1 : g_object_unref (proc);
89 : 1 : }
90 : :
91 : : static void
92 : 1 : check_ready (GObject *source,
93 : : GAsyncResult *res,
94 : : gpointer user_data)
95 : : {
96 : : gboolean ret;
97 : 1 : GError *error = NULL;
98 : :
99 : 1 : ret = g_subprocess_wait_check_finish (G_SUBPROCESS (source),
100 : : res,
101 : : &error);
102 : 1 : g_assert_true (ret);
103 : 1 : g_assert_no_error (error);
104 : :
105 : 1 : g_object_unref (source);
106 : 1 : }
107 : :
108 : : static void
109 : 1 : test_noop_all_to_null (void)
110 : : {
111 : 1 : GError *local_error = NULL;
112 : 1 : GError **error = &local_error;
113 : : GPtrArray *args;
114 : : GSubprocess *proc;
115 : :
116 : 1 : args = get_test_subprocess_args ("noop", NULL);
117 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata,
118 : : G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_SILENCE,
119 : : error);
120 : 1 : g_ptr_array_free (args, TRUE);
121 : 1 : g_assert_no_error (local_error);
122 : :
123 : 1 : g_subprocess_wait_check_async (proc, NULL, check_ready, NULL);
124 : 1 : }
125 : :
126 : : static void
127 : 1 : test_noop_no_wait (void)
128 : : {
129 : 1 : GError *local_error = NULL;
130 : 1 : GError **error = &local_error;
131 : : GPtrArray *args;
132 : : GSubprocess *proc;
133 : :
134 : 1 : args = get_test_subprocess_args ("noop", NULL);
135 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
136 : 1 : g_ptr_array_free (args, TRUE);
137 : 1 : g_assert_no_error (local_error);
138 : :
139 : 1 : g_object_unref (proc);
140 : 1 : }
141 : :
142 : : static void
143 : 1 : test_noop_stdin_inherit (void)
144 : : {
145 : 1 : GError *local_error = NULL;
146 : 1 : GError **error = &local_error;
147 : : GPtrArray *args;
148 : : GSubprocess *proc;
149 : :
150 : 1 : args = get_test_subprocess_args ("noop", NULL);
151 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_STDIN_INHERIT, error);
152 : 1 : g_ptr_array_free (args, TRUE);
153 : 1 : g_assert_no_error (local_error);
154 : :
155 : 1 : g_subprocess_wait_check (proc, NULL, error);
156 : 1 : g_assert_no_error (local_error);
157 : :
158 : 1 : g_object_unref (proc);
159 : 1 : }
160 : :
161 : : #ifdef G_OS_UNIX
162 : : static void
163 : 1 : test_search_path (void)
164 : : {
165 : 1 : GError *local_error = NULL;
166 : 1 : GError **error = &local_error;
167 : : GSubprocess *proc;
168 : :
169 : 1 : proc = g_subprocess_new (G_SUBPROCESS_FLAGS_NONE, error, "true", NULL);
170 : 1 : g_assert_no_error (local_error);
171 : :
172 : 1 : g_subprocess_wait_check (proc, NULL, error);
173 : 1 : g_assert_no_error (local_error);
174 : :
175 : 1 : g_object_unref (proc);
176 : 1 : }
177 : :
178 : : static void
179 : 1 : test_search_path_from_envp (void)
180 : : {
181 : 1 : GError *local_error = NULL;
182 : 1 : GError **error = &local_error;
183 : : GSubprocessLauncher *launcher;
184 : : GSubprocess *proc;
185 : : const char *path;
186 : :
187 : 1 : path = g_test_get_dir (G_TEST_BUILT);
188 : :
189 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP);
190 : 1 : g_subprocess_launcher_setenv (launcher, "PATH", path, TRUE);
191 : :
192 : 1 : proc = g_subprocess_launcher_spawn (launcher, error, TESTPROG, "exit1", NULL);
193 : 1 : g_assert_no_error (local_error);
194 : 1 : g_object_unref (launcher);
195 : :
196 : 1 : g_subprocess_wait_check (proc, NULL, error);
197 : 1 : g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
198 : 1 : g_clear_error (error);
199 : :
200 : 1 : g_object_unref (proc);
201 : 1 : }
202 : : #endif
203 : :
204 : : static void
205 : 1 : test_exit1 (void)
206 : : {
207 : 1 : GError *local_error = NULL;
208 : 1 : GError **error = &local_error;
209 : : GPtrArray *args;
210 : : GSubprocess *proc;
211 : :
212 : 1 : args = get_test_subprocess_args ("exit1", NULL);
213 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
214 : 1 : g_ptr_array_free (args, TRUE);
215 : 1 : g_assert_no_error (local_error);
216 : :
217 : 1 : g_subprocess_wait_check (proc, NULL, error);
218 : 1 : g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
219 : 1 : g_clear_error (error);
220 : :
221 : 1 : g_object_unref (proc);
222 : 1 : }
223 : :
224 : : typedef struct {
225 : : GMainLoop *loop;
226 : : GCancellable *cancellable;
227 : : gboolean cb_called;
228 : : } TestExit1CancelData;
229 : :
230 : : static gboolean
231 : 2 : test_exit1_cancel_idle_quit_cb (gpointer user_data)
232 : : {
233 : 2 : GMainLoop *loop = user_data;
234 : 2 : g_main_loop_quit (loop);
235 : 2 : return G_SOURCE_REMOVE;
236 : : }
237 : :
238 : : static void
239 : 1 : test_exit1_cancel_wait_check_cb (GObject *source,
240 : : GAsyncResult *result,
241 : : gpointer user_data)
242 : : {
243 : 1 : GSubprocess *subprocess = G_SUBPROCESS (source);
244 : 1 : TestExit1CancelData *data = user_data;
245 : : gboolean ret;
246 : 1 : GError *error = NULL;
247 : :
248 : 1 : g_assert_false (data->cb_called);
249 : 1 : data->cb_called = TRUE;
250 : :
251 : 1 : ret = g_subprocess_wait_check_finish (subprocess, result, &error);
252 : 1 : g_assert_false (ret);
253 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
254 : 1 : g_clear_error (&error);
255 : :
256 : 1 : g_idle_add (test_exit1_cancel_idle_quit_cb, data->loop);
257 : 1 : }
258 : :
259 : : static void
260 : 1 : test_exit1_cancel (void)
261 : : {
262 : 1 : GError *local_error = NULL;
263 : 1 : GError **error = &local_error;
264 : : GPtrArray *args;
265 : : GSubprocess *proc;
266 : 1 : TestExit1CancelData data = { 0 };
267 : :
268 : 1 : g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=786456");
269 : :
270 : 1 : args = get_test_subprocess_args ("exit1", NULL);
271 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
272 : 1 : g_ptr_array_free (args, TRUE);
273 : 1 : g_assert_no_error (local_error);
274 : :
275 : 1 : data.loop = g_main_loop_new (NULL, FALSE);
276 : 1 : data.cancellable = g_cancellable_new ();
277 : 1 : g_subprocess_wait_check_async (proc, data.cancellable, test_exit1_cancel_wait_check_cb, &data);
278 : :
279 : 1 : g_subprocess_wait_check (proc, NULL, error);
280 : 1 : g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
281 : 1 : g_clear_error (error);
282 : :
283 : 1 : g_cancellable_cancel (data.cancellable);
284 : 1 : g_main_loop_run (data.loop);
285 : :
286 : 1 : g_object_unref (proc);
287 : 1 : g_main_loop_unref (data.loop);
288 : 1 : g_clear_object (&data.cancellable);
289 : 1 : }
290 : :
291 : : static void
292 : 1 : test_exit1_cancel_in_cb_wait_check_cb (GObject *source,
293 : : GAsyncResult *result,
294 : : gpointer user_data)
295 : : {
296 : 1 : GSubprocess *subprocess = G_SUBPROCESS (source);
297 : 1 : TestExit1CancelData *data = user_data;
298 : : gboolean ret;
299 : 1 : GError *error = NULL;
300 : :
301 : 1 : g_assert_false (data->cb_called);
302 : 1 : data->cb_called = TRUE;
303 : :
304 : 1 : ret = g_subprocess_wait_check_finish (subprocess, result, &error);
305 : 1 : g_assert_false (ret);
306 : 1 : g_assert_error (error, G_SPAWN_EXIT_ERROR, 1);
307 : 1 : g_clear_error (&error);
308 : :
309 : 1 : g_cancellable_cancel (data->cancellable);
310 : :
311 : 1 : g_idle_add (test_exit1_cancel_idle_quit_cb, data->loop);
312 : 1 : }
313 : :
314 : : static void
315 : 1 : test_exit1_cancel_in_cb (void)
316 : : {
317 : 1 : GError *local_error = NULL;
318 : 1 : GError **error = &local_error;
319 : : GPtrArray *args;
320 : : GSubprocess *proc;
321 : 1 : TestExit1CancelData data = { 0 };
322 : :
323 : 1 : g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=786456");
324 : :
325 : 1 : args = get_test_subprocess_args ("exit1", NULL);
326 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
327 : 1 : g_ptr_array_free (args, TRUE);
328 : 1 : g_assert_no_error (local_error);
329 : :
330 : 1 : data.loop = g_main_loop_new (NULL, FALSE);
331 : 1 : data.cancellable = g_cancellable_new ();
332 : 1 : g_subprocess_wait_check_async (proc, data.cancellable, test_exit1_cancel_in_cb_wait_check_cb, &data);
333 : :
334 : 1 : g_subprocess_wait_check (proc, NULL, error);
335 : 1 : g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
336 : 1 : g_clear_error (error);
337 : :
338 : 1 : g_main_loop_run (data.loop);
339 : :
340 : 1 : g_object_unref (proc);
341 : 1 : g_main_loop_unref (data.loop);
342 : 1 : g_clear_object (&data.cancellable);
343 : 1 : }
344 : :
345 : : static gchar *
346 : 5 : splice_to_string (GInputStream *stream,
347 : : GError **error)
348 : : {
349 : 5 : GMemoryOutputStream *buffer = NULL;
350 : 5 : char *ret = NULL;
351 : :
352 : 5 : buffer = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
353 : 5 : if (g_output_stream_splice ((GOutputStream*)buffer, stream, 0, NULL, error) < 0)
354 : 0 : goto out;
355 : :
356 : 5 : if (!g_output_stream_write ((GOutputStream*)buffer, "\0", 1, NULL, error))
357 : 0 : goto out;
358 : :
359 : 5 : if (!g_output_stream_close ((GOutputStream*)buffer, NULL, error))
360 : 0 : goto out;
361 : :
362 : 5 : ret = g_memory_output_stream_steal_data (buffer);
363 : 5 : out:
364 : 5 : g_clear_object (&buffer);
365 : 5 : return ret;
366 : : }
367 : :
368 : : static void
369 : 1 : test_echo1 (void)
370 : : {
371 : 1 : GError *local_error = NULL;
372 : 1 : GError **error = &local_error;
373 : : GSubprocess *proc;
374 : : GPtrArray *args;
375 : : GInputStream *stdout_stream;
376 : : gchar *result;
377 : :
378 : 1 : args = get_test_subprocess_args ("echo", "hello", "world!", NULL);
379 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_STDOUT_PIPE, error);
380 : 1 : g_ptr_array_free (args, TRUE);
381 : 1 : g_assert_no_error (local_error);
382 : :
383 : 1 : stdout_stream = g_subprocess_get_stdout_pipe (proc);
384 : :
385 : 1 : result = splice_to_string (stdout_stream, error);
386 : 1 : g_assert_no_error (local_error);
387 : :
388 : 1 : g_assert_cmpstr (result, ==, "hello" LINEEND "world!" LINEEND);
389 : :
390 : 1 : g_free (result);
391 : 1 : g_object_unref (proc);
392 : 1 : }
393 : :
394 : : #ifdef G_OS_UNIX
395 : : static void
396 : 1 : test_echo_merged (void)
397 : : {
398 : 1 : GError *local_error = NULL;
399 : 1 : GError **error = &local_error;
400 : : GSubprocess *proc;
401 : : GPtrArray *args;
402 : : GInputStream *stdout_stream;
403 : : gchar *result;
404 : :
405 : 1 : args = get_test_subprocess_args ("echo-stdout-and-stderr", "merge", "this", NULL);
406 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata,
407 : : G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_MERGE,
408 : : error);
409 : 1 : g_ptr_array_free (args, TRUE);
410 : 1 : g_assert_no_error (local_error);
411 : :
412 : 1 : stdout_stream = g_subprocess_get_stdout_pipe (proc);
413 : 1 : result = splice_to_string (stdout_stream, error);
414 : 1 : g_assert_no_error (local_error);
415 : :
416 : 1 : g_assert_cmpstr (result, ==, "merge\nmerge\nthis\nthis\n");
417 : :
418 : 1 : g_free (result);
419 : 1 : g_object_unref (proc);
420 : 1 : }
421 : : #endif
422 : :
423 : : typedef struct {
424 : : guint events_pending;
425 : : GMainLoop *loop;
426 : : } TestCatData;
427 : :
428 : : static void
429 : 2 : test_cat_on_input_splice_complete (GObject *object,
430 : : GAsyncResult *result,
431 : : gpointer user_data)
432 : : {
433 : 2 : TestCatData *data = user_data;
434 : 2 : GError *error = NULL;
435 : :
436 : 2 : (void)g_output_stream_splice_finish ((GOutputStream*)object, result, &error);
437 : 2 : g_assert_no_error (error);
438 : :
439 : 2 : data->events_pending--;
440 : 2 : if (data->events_pending == 0)
441 : 1 : g_main_loop_quit (data->loop);
442 : 2 : }
443 : :
444 : : static void
445 : 1 : test_cat_utf8 (void)
446 : : {
447 : 1 : GError *local_error = NULL;
448 : 1 : GError **error = &local_error;
449 : : GSubprocess *proc;
450 : : GPtrArray *args;
451 : : GBytes *input_buf;
452 : : GBytes *output_buf;
453 : 1 : GInputStream *input_buf_stream = NULL;
454 : 1 : GOutputStream *output_buf_stream = NULL;
455 : 1 : GOutputStream *stdin_stream = NULL;
456 : 1 : GInputStream *stdout_stream = NULL;
457 : : TestCatData data;
458 : :
459 : 1 : memset (&data, 0, sizeof (data));
460 : 1 : data.loop = g_main_loop_new (NULL, TRUE);
461 : :
462 : 1 : args = get_test_subprocess_args ("cat", NULL);
463 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata,
464 : : G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
465 : : error);
466 : 1 : g_ptr_array_free (args, TRUE);
467 : 1 : g_assert_no_error (local_error);
468 : :
469 : 1 : stdin_stream = g_subprocess_get_stdin_pipe (proc);
470 : 1 : stdout_stream = g_subprocess_get_stdout_pipe (proc);
471 : :
472 : 1 : input_buf = g_bytes_new_static ("hello, world!", strlen ("hello, world!"));
473 : 1 : input_buf_stream = g_memory_input_stream_new_from_bytes (input_buf);
474 : 1 : g_bytes_unref (input_buf);
475 : :
476 : 1 : output_buf_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
477 : :
478 : 1 : g_output_stream_splice_async (stdin_stream, input_buf_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
479 : : G_PRIORITY_DEFAULT, NULL, test_cat_on_input_splice_complete,
480 : : &data);
481 : 1 : data.events_pending++;
482 : 1 : g_output_stream_splice_async (output_buf_stream, stdout_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
483 : : G_PRIORITY_DEFAULT, NULL, test_cat_on_input_splice_complete,
484 : : &data);
485 : 1 : data.events_pending++;
486 : :
487 : 1 : g_main_loop_run (data.loop);
488 : :
489 : 1 : g_subprocess_wait_check (proc, NULL, error);
490 : 1 : g_assert_no_error (local_error);
491 : :
492 : 1 : output_buf = g_memory_output_stream_steal_as_bytes ((GMemoryOutputStream*)output_buf_stream);
493 : :
494 : 1 : g_assert_cmpmem (g_bytes_get_data (output_buf, NULL),
495 : : g_bytes_get_size (output_buf),
496 : : "hello, world!", 13);
497 : :
498 : 1 : g_bytes_unref (output_buf);
499 : 1 : g_main_loop_unref (data.loop);
500 : 1 : g_object_unref (input_buf_stream);
501 : 1 : g_object_unref (output_buf_stream);
502 : 1 : g_object_unref (proc);
503 : 1 : }
504 : :
505 : : static gpointer
506 : 1 : cancel_soon (gpointer user_data)
507 : : {
508 : 1 : GCancellable *cancellable = user_data;
509 : :
510 : 1 : g_usleep (G_TIME_SPAN_SECOND);
511 : 1 : g_cancellable_cancel (cancellable);
512 : 1 : g_object_unref (cancellable);
513 : :
514 : 1 : return NULL;
515 : : }
516 : :
517 : : static void
518 : 1 : test_cat_eof (void)
519 : : {
520 : : GCancellable *cancellable;
521 : 1 : GError *error = NULL;
522 : : GSubprocess *cat;
523 : : gboolean result;
524 : : gchar buffer;
525 : : gssize s;
526 : :
527 : : #ifdef G_OS_WIN32
528 : : g_test_skip ("This test has not been ported to Win32");
529 : : return;
530 : : #endif
531 : :
532 : : /* Spawn 'cat' */
533 : 1 : cat = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "cat", NULL);
534 : 1 : g_assert_no_error (error);
535 : 1 : g_assert_nonnull (cat);
536 : :
537 : : /* Make sure that reading stdout blocks (until we cancel) */
538 : 1 : cancellable = g_cancellable_new ();
539 : 1 : g_thread_unref (g_thread_new ("cancel thread", cancel_soon, g_object_ref (cancellable)));
540 : 1 : s = g_input_stream_read (g_subprocess_get_stdout_pipe (cat), &buffer, sizeof buffer, cancellable, &error);
541 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
542 : 1 : g_assert_cmpint (s, ==, -1);
543 : 1 : g_object_unref (cancellable);
544 : 1 : g_clear_error (&error);
545 : :
546 : : /* Close the stream (EOF on cat's stdin) */
547 : 1 : result = g_output_stream_close (g_subprocess_get_stdin_pipe (cat), NULL, &error);
548 : 1 : g_assert_no_error (error);
549 : 1 : g_assert_true (result);
550 : :
551 : : /* Now check that reading cat's stdout gets us an EOF (since it quit) */
552 : 1 : s = g_input_stream_read (g_subprocess_get_stdout_pipe (cat), &buffer, sizeof buffer, NULL, &error);
553 : 1 : g_assert_no_error (error);
554 : 1 : g_assert_false (s);
555 : :
556 : : /* Check that the process has exited as a result of the EOF */
557 : 1 : result = g_subprocess_wait (cat, NULL, &error);
558 : 1 : g_assert_no_error (error);
559 : 1 : g_assert_true (g_subprocess_get_if_exited (cat));
560 : 1 : g_assert_cmpint (g_subprocess_get_exit_status (cat), ==, 0);
561 : 1 : g_assert_true (result);
562 : :
563 : 1 : g_object_unref (cat);
564 : 1 : }
565 : :
566 : : typedef struct {
567 : : guint events_pending;
568 : : gboolean caught_error;
569 : : GError *error;
570 : : GMainLoop *loop;
571 : :
572 : : gint counter;
573 : : GOutputStream *first_stdin;
574 : : } TestMultiSpliceData;
575 : :
576 : : static void
577 : 3 : on_one_multi_splice_done (GObject *obj,
578 : : GAsyncResult *res,
579 : : gpointer user_data)
580 : : {
581 : 3 : TestMultiSpliceData *data = user_data;
582 : :
583 : 3 : if (!data->caught_error)
584 : : {
585 : 3 : if (g_output_stream_splice_finish ((GOutputStream*)obj, res, &data->error) < 0)
586 : 0 : data->caught_error = TRUE;
587 : : }
588 : :
589 : 3 : data->events_pending--;
590 : 3 : if (data->events_pending == 0)
591 : 1 : g_main_loop_quit (data->loop);
592 : 3 : }
593 : :
594 : : static gboolean
595 : 12 : on_idle_multisplice (gpointer user_data)
596 : : {
597 : 12 : TestMultiSpliceData *data = user_data;
598 : :
599 : 12 : if (data->counter >= TOTAL_HELLOS || data->caught_error)
600 : : {
601 : 1 : if (!g_output_stream_close (data->first_stdin, NULL, &data->error))
602 : 0 : data->caught_error = TRUE;
603 : 1 : data->events_pending--;
604 : 1 : if (data->events_pending == 0)
605 : : {
606 : 0 : g_main_loop_quit (data->loop);
607 : : }
608 : 1 : return FALSE;
609 : : }
610 : : else
611 : : {
612 : : int i;
613 : 2058 : for (i = 0; i < data->counter; i++)
614 : : {
615 : : gsize bytes_written;
616 : 2047 : if (!g_output_stream_write_all (data->first_stdin, HELLO_WORLD,
617 : : strlen (HELLO_WORLD), &bytes_written,
618 : : NULL, &data->error))
619 : : {
620 : 0 : data->caught_error = TRUE;
621 : 0 : return FALSE;
622 : : }
623 : : }
624 : 11 : data->counter *= 2;
625 : 11 : return TRUE;
626 : : }
627 : : }
628 : :
629 : : static void
630 : 3 : on_subprocess_exited (GObject *object,
631 : : GAsyncResult *result,
632 : : gpointer user_data)
633 : : {
634 : 3 : GSubprocess *subprocess = G_SUBPROCESS (object);
635 : 3 : TestMultiSpliceData *data = user_data;
636 : 3 : GError *error = NULL;
637 : :
638 : 3 : if (!g_subprocess_wait_finish (subprocess, result, &error))
639 : : {
640 : 0 : if (!data->caught_error)
641 : : {
642 : 0 : data->caught_error = TRUE;
643 : 0 : g_propagate_error (&data->error, error);
644 : : }
645 : : }
646 : 3 : g_spawn_check_wait_status (g_subprocess_get_status (subprocess), &error);
647 : 3 : g_assert_no_error (error);
648 : 3 : data->events_pending--;
649 : 3 : if (data->events_pending == 0)
650 : 0 : g_main_loop_quit (data->loop);
651 : 3 : }
652 : :
653 : : static void
654 : 1 : test_multi_1 (void)
655 : : {
656 : 1 : GError *local_error = NULL;
657 : 1 : GError **error = &local_error;
658 : : GPtrArray *args;
659 : : GSubprocessLauncher *launcher;
660 : : GSubprocess *first;
661 : : GSubprocess *second;
662 : : GSubprocess *third;
663 : : GOutputStream *first_stdin;
664 : : GInputStream *first_stdout;
665 : : GOutputStream *second_stdin;
666 : : GInputStream *second_stdout;
667 : : GOutputStream *third_stdin;
668 : : GInputStream *third_stdout;
669 : : GOutputStream *membuf;
670 : : TestMultiSpliceData data;
671 : 1 : int splice_flags = G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET;
672 : :
673 : 1 : args = get_test_subprocess_args ("cat", NULL);
674 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE);
675 : 1 : first = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
676 : 1 : g_assert_no_error (local_error);
677 : 1 : second = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
678 : 1 : g_assert_no_error (local_error);
679 : 1 : third = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
680 : 1 : g_assert_no_error (local_error);
681 : :
682 : 1 : g_ptr_array_free (args, TRUE);
683 : :
684 : 1 : membuf = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
685 : :
686 : 1 : first_stdin = g_subprocess_get_stdin_pipe (first);
687 : 1 : first_stdout = g_subprocess_get_stdout_pipe (first);
688 : 1 : second_stdin = g_subprocess_get_stdin_pipe (second);
689 : 1 : second_stdout = g_subprocess_get_stdout_pipe (second);
690 : 1 : third_stdin = g_subprocess_get_stdin_pipe (third);
691 : 1 : third_stdout = g_subprocess_get_stdout_pipe (third);
692 : :
693 : 1 : memset (&data, 0, sizeof (data));
694 : 1 : data.loop = g_main_loop_new (NULL, TRUE);
695 : 1 : data.counter = 1;
696 : 1 : data.first_stdin = first_stdin;
697 : :
698 : 1 : data.events_pending++;
699 : 1 : g_output_stream_splice_async (second_stdin, first_stdout, splice_flags, G_PRIORITY_DEFAULT,
700 : : NULL, on_one_multi_splice_done, &data);
701 : 1 : data.events_pending++;
702 : 1 : g_output_stream_splice_async (third_stdin, second_stdout, splice_flags, G_PRIORITY_DEFAULT,
703 : : NULL, on_one_multi_splice_done, &data);
704 : 1 : data.events_pending++;
705 : 1 : g_output_stream_splice_async (membuf, third_stdout, splice_flags, G_PRIORITY_DEFAULT,
706 : : NULL, on_one_multi_splice_done, &data);
707 : :
708 : 1 : data.events_pending++;
709 : 1 : g_timeout_add (250, on_idle_multisplice, &data);
710 : :
711 : 1 : data.events_pending++;
712 : 1 : g_subprocess_wait_async (first, NULL, on_subprocess_exited, &data);
713 : 1 : data.events_pending++;
714 : 1 : g_subprocess_wait_async (second, NULL, on_subprocess_exited, &data);
715 : 1 : data.events_pending++;
716 : 1 : g_subprocess_wait_async (third, NULL, on_subprocess_exited, &data);
717 : :
718 : 1 : g_main_loop_run (data.loop);
719 : :
720 : 1 : g_assert_false (data.caught_error);
721 : 1 : g_assert_no_error (data.error);
722 : :
723 : 1 : g_assert_cmpint (g_memory_output_stream_get_data_size ((GMemoryOutputStream*)membuf), ==, SPLICELEN);
724 : :
725 : 1 : g_main_loop_unref (data.loop);
726 : 1 : g_object_unref (membuf);
727 : 1 : g_object_unref (launcher);
728 : 1 : g_object_unref (first);
729 : 1 : g_object_unref (second);
730 : 1 : g_object_unref (third);
731 : 1 : }
732 : :
733 : : typedef struct {
734 : : GSubprocessFlags flags;
735 : : gboolean is_utf8;
736 : : gboolean running;
737 : : GError *error;
738 : : } TestAsyncCommunicateData;
739 : :
740 : : static void
741 : 13 : on_communicate_complete (GObject *proc,
742 : : GAsyncResult *result,
743 : : gpointer user_data)
744 : : {
745 : 13 : TestAsyncCommunicateData *data = user_data;
746 : 13 : GBytes *stdout_bytes = NULL, *stderr_bytes = NULL;
747 : 13 : char *stdout_str = NULL, *stderr_str = NULL;
748 : : const guint8 *stdout_data;
749 : : gsize stdout_len;
750 : :
751 : 13 : data->running = FALSE;
752 : 13 : if (data->is_utf8)
753 : 7 : (void) g_subprocess_communicate_utf8_finish ((GSubprocess*)proc, result,
754 : : &stdout_str, &stderr_str, &data->error);
755 : : else
756 : 6 : (void) g_subprocess_communicate_finish ((GSubprocess*)proc, result,
757 : : &stdout_bytes, &stderr_bytes, &data->error);
758 : 13 : if (data->error)
759 : 1 : return;
760 : :
761 : 12 : if (data->flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
762 : : {
763 : 6 : if (data->is_utf8)
764 : : {
765 : 3 : g_assert_nonnull (stdout_str);
766 : 3 : stdout_data = (guint8*)stdout_str;
767 : 3 : stdout_len = strlen (stdout_str);
768 : : }
769 : : else
770 : : {
771 : 3 : g_assert_nonnull (stdout_bytes);
772 : 3 : stdout_data = g_bytes_get_data (stdout_bytes, &stdout_len);
773 : : }
774 : :
775 : 6 : g_assert_cmpmem (stdout_data, stdout_len, "# hello world" LINEEND, 13 + strlen (LINEEND));
776 : : }
777 : : else
778 : : {
779 : 6 : g_assert_null (stdout_str);
780 : 6 : g_assert_null (stdout_bytes);
781 : : }
782 : :
783 : 12 : if (data->flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
784 : : {
785 : 4 : if (data->is_utf8)
786 : 2 : g_assert_nonnull (stderr_str);
787 : : else
788 : 2 : g_assert_nonnull (stderr_bytes);
789 : : }
790 : : else
791 : : {
792 : 8 : g_assert_null (stderr_str);
793 : 8 : g_assert_null (stderr_bytes);
794 : : }
795 : :
796 : 12 : g_clear_pointer (&stdout_bytes, g_bytes_unref);
797 : 12 : g_clear_pointer (&stderr_bytes, g_bytes_unref);
798 : 12 : g_free (stdout_str);
799 : 12 : g_free (stderr_str);
800 : : }
801 : :
802 : : /* Test g_subprocess_communicate_async() works correctly with a variety of flags,
803 : : * as passed in via @test_data. */
804 : : static void
805 : 6 : test_communicate_async (gconstpointer test_data)
806 : : {
807 : 6 : GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
808 : 6 : GError *error = NULL;
809 : : GPtrArray *args;
810 : 6 : TestAsyncCommunicateData data = { flags, 0, 0, NULL };
811 : : GSubprocess *proc;
812 : 6 : GCancellable *cancellable = NULL;
813 : : GBytes *input;
814 : : const char *hellostring;
815 : :
816 : 6 : args = get_test_subprocess_args ("cat", NULL);
817 : 6 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
818 : 6 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
819 : : &error);
820 : 6 : g_assert_no_error (error);
821 : 6 : g_ptr_array_free (args, TRUE);
822 : :
823 : : /* Include a leading hash and trailing newline so that if this gets onto the
824 : : * test’s stdout, it doesn’t mess up TAP output. */
825 : 6 : hellostring = "# hello world\n";
826 : 6 : input = g_bytes_new_static (hellostring, strlen (hellostring));
827 : :
828 : 6 : g_subprocess_communicate_async (proc, input,
829 : : cancellable,
830 : : on_communicate_complete,
831 : : &data);
832 : :
833 : 6 : data.running = TRUE;
834 : 57 : while (data.running)
835 : 51 : g_main_context_iteration (NULL, TRUE);
836 : :
837 : 6 : g_assert_no_error (data.error);
838 : :
839 : 6 : g_bytes_unref (input);
840 : 6 : g_object_unref (proc);
841 : 6 : }
842 : :
843 : : /* Test g_subprocess_communicate() works correctly with a variety of flags,
844 : : * as passed in via @test_data. */
845 : : static void
846 : 6 : test_communicate (gconstpointer test_data)
847 : : {
848 : 6 : GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
849 : 6 : GError *error = NULL;
850 : : GPtrArray *args;
851 : : GSubprocess *proc;
852 : 6 : GCancellable *cancellable = NULL;
853 : : GBytes *input;
854 : : const gchar *hellostring;
855 : : GBytes *stdout_bytes, *stderr_bytes;
856 : : const gchar *stdout_data;
857 : : gsize stdout_len;
858 : :
859 : 6 : args = get_test_subprocess_args ("cat", NULL);
860 : 6 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
861 : 6 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
862 : : &error);
863 : 6 : g_assert_no_error (error);
864 : 6 : g_ptr_array_free (args, TRUE);
865 : :
866 : : /* Include a leading hash and trailing newline so that if this gets onto the
867 : : * test’s stdout, it doesn’t mess up TAP output. */
868 : 6 : hellostring = "# hello world\n";
869 : 6 : input = g_bytes_new_static (hellostring, strlen (hellostring));
870 : :
871 : 6 : g_subprocess_communicate (proc, input, cancellable, &stdout_bytes, &stderr_bytes, &error);
872 : 6 : g_assert_no_error (error);
873 : :
874 : 6 : if (flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
875 : : {
876 : 3 : stdout_data = g_bytes_get_data (stdout_bytes, &stdout_len);
877 : 3 : g_assert_cmpmem (stdout_data, stdout_len, "# hello world" LINEEND, 13 + strlen (LINEEND));
878 : : }
879 : : else
880 : 3 : g_assert_null (stdout_bytes);
881 : 6 : if (flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
882 : 2 : g_assert_nonnull (stderr_bytes);
883 : : else
884 : 4 : g_assert_null (stderr_bytes);
885 : :
886 : 6 : g_bytes_unref (input);
887 : 6 : g_clear_pointer (&stdout_bytes, g_bytes_unref);
888 : 6 : g_clear_pointer (&stderr_bytes, g_bytes_unref);
889 : 6 : g_object_unref (proc);
890 : 6 : }
891 : :
892 : : typedef struct {
893 : : GSubprocess *proc;
894 : : GCancellable *cancellable;
895 : : gboolean is_utf8;
896 : : gboolean running;
897 : : GError *error;
898 : : } TestCancelledCommunicateData;
899 : :
900 : : static gboolean
901 : 12 : on_test_communicate_cancelled_idle (gpointer user_data)
902 : : {
903 : 12 : TestCancelledCommunicateData *data = user_data;
904 : : GBytes *input;
905 : : const gchar *hellostring;
906 : 12 : GBytes *stdout_bytes = NULL, *stderr_bytes = NULL;
907 : 12 : gchar *stdout_buf = NULL, *stderr_buf = NULL;
908 : :
909 : : /* Include a leading hash and trailing newline so that if this gets onto the
910 : : * test’s stdout, it doesn’t mess up TAP output. */
911 : 12 : hellostring = "# hello world\n";
912 : 12 : input = g_bytes_new_static (hellostring, strlen (hellostring));
913 : :
914 : 12 : if (data->is_utf8)
915 : 6 : g_subprocess_communicate_utf8 (data->proc, hellostring, data->cancellable,
916 : : &stdout_buf, &stderr_buf, &data->error);
917 : : else
918 : 6 : g_subprocess_communicate (data->proc, input, data->cancellable, &stdout_bytes,
919 : : &stderr_bytes, &data->error);
920 : :
921 : 12 : data->running = FALSE;
922 : :
923 : 12 : if (data->is_utf8)
924 : : {
925 : 6 : g_assert_null (stdout_buf);
926 : 6 : g_assert_null (stderr_buf);
927 : : }
928 : : else
929 : : {
930 : 6 : g_assert_null (stdout_bytes);
931 : 6 : g_assert_null (stderr_bytes);
932 : : }
933 : :
934 : 12 : g_bytes_unref (input);
935 : :
936 : 12 : return G_SOURCE_REMOVE;
937 : : }
938 : :
939 : : /* Test g_subprocess_communicate() can be cancelled correctly */
940 : : static void
941 : 6 : test_communicate_cancelled (gconstpointer test_data)
942 : : {
943 : 6 : GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
944 : : GPtrArray *args;
945 : : GSubprocess *proc;
946 : 6 : GCancellable *cancellable = NULL;
947 : 6 : GError *error = NULL;
948 : 6 : TestCancelledCommunicateData data = { 0 };
949 : :
950 : 6 : args = get_test_subprocess_args ("cat", NULL);
951 : 6 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
952 : 6 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
953 : : &error);
954 : 6 : g_assert_no_error (error);
955 : 6 : g_ptr_array_free (args, TRUE);
956 : :
957 : 6 : cancellable = g_cancellable_new ();
958 : :
959 : 6 : data.proc = proc;
960 : 6 : data.cancellable = cancellable;
961 : 6 : data.error = error;
962 : :
963 : 6 : g_cancellable_cancel (cancellable);
964 : 6 : g_idle_add (on_test_communicate_cancelled_idle, &data);
965 : :
966 : 6 : data.running = TRUE;
967 : 12 : while (data.running)
968 : 6 : g_main_context_iteration (NULL, TRUE);
969 : :
970 : 6 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
971 : 6 : g_clear_error (&data.error);
972 : :
973 : 6 : g_object_unref (cancellable);
974 : 6 : g_object_unref (proc);
975 : 6 : }
976 : :
977 : : static void
978 : 12 : on_communicate_cancelled_complete (GObject *proc,
979 : : GAsyncResult *result,
980 : : gpointer user_data)
981 : : {
982 : 12 : TestAsyncCommunicateData *data = user_data;
983 : 12 : GBytes *stdout_bytes = NULL, *stderr_bytes = NULL;
984 : 12 : char *stdout_str = NULL, *stderr_str = NULL;
985 : :
986 : 12 : data->running = FALSE;
987 : 12 : if (data->is_utf8)
988 : 6 : (void) g_subprocess_communicate_utf8_finish ((GSubprocess*)proc, result,
989 : : &stdout_str, &stderr_str, &data->error);
990 : : else
991 : 6 : (void) g_subprocess_communicate_finish ((GSubprocess*)proc, result,
992 : : &stdout_bytes, &stderr_bytes, &data->error);
993 : :
994 : 12 : if (data->is_utf8)
995 : : {
996 : 6 : g_assert_null (stdout_str);
997 : 6 : g_assert_null (stderr_str);
998 : : }
999 : : else
1000 : : {
1001 : 6 : g_assert_null (stdout_bytes);
1002 : 6 : g_assert_null (stderr_bytes);
1003 : : }
1004 : 12 : }
1005 : :
1006 : : /* Test g_subprocess_communicate_async() can be cancelled correctly,
1007 : : * as passed in via @test_data. */
1008 : : static void
1009 : 6 : test_communicate_cancelled_async (gconstpointer test_data)
1010 : : {
1011 : 6 : GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
1012 : 6 : GError *error = NULL;
1013 : : GPtrArray *args;
1014 : 6 : TestAsyncCommunicateData data = { 0 };
1015 : : GSubprocess *proc;
1016 : 6 : GCancellable *cancellable = NULL;
1017 : : GBytes *input;
1018 : : const char *hellostring;
1019 : :
1020 : 6 : args = get_test_subprocess_args ("cat", NULL);
1021 : 6 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
1022 : 6 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1023 : : &error);
1024 : 6 : g_assert_no_error (error);
1025 : 6 : g_ptr_array_free (args, TRUE);
1026 : :
1027 : : /* Include a leading hash and trailing newline so that if this gets onto the
1028 : : * test’s stdout, it doesn’t mess up TAP output. */
1029 : 6 : hellostring = "# hello world\n";
1030 : 6 : input = g_bytes_new_static (hellostring, strlen (hellostring));
1031 : :
1032 : 6 : cancellable = g_cancellable_new ();
1033 : :
1034 : 6 : g_subprocess_communicate_async (proc, input,
1035 : : cancellable,
1036 : : on_communicate_cancelled_complete,
1037 : : &data);
1038 : :
1039 : 6 : g_cancellable_cancel (cancellable);
1040 : :
1041 : 6 : data.running = TRUE;
1042 : 24 : while (data.running)
1043 : 18 : g_main_context_iteration (NULL, TRUE);
1044 : :
1045 : 6 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1046 : 6 : g_clear_error (&data.error);
1047 : :
1048 : 6 : g_bytes_unref (input);
1049 : 6 : g_object_unref (cancellable);
1050 : 6 : g_object_unref (proc);
1051 : 6 : }
1052 : :
1053 : : /* Test g_subprocess_communicate_utf8_async() works correctly with a variety of
1054 : : * flags, as passed in via @test_data. */
1055 : : static void
1056 : 6 : test_communicate_utf8_async (gconstpointer test_data)
1057 : : {
1058 : 6 : GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
1059 : 6 : GError *error = NULL;
1060 : : GPtrArray *args;
1061 : 6 : TestAsyncCommunicateData data = { flags, 0, 0, NULL };
1062 : : GSubprocess *proc;
1063 : 6 : GCancellable *cancellable = NULL;
1064 : :
1065 : 6 : args = get_test_subprocess_args ("cat", NULL);
1066 : 6 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
1067 : 6 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1068 : : &error);
1069 : 6 : g_assert_no_error (error);
1070 : 6 : g_ptr_array_free (args, TRUE);
1071 : :
1072 : 6 : data.is_utf8 = TRUE;
1073 : 6 : g_subprocess_communicate_utf8_async (proc, "# hello world\n",
1074 : : cancellable,
1075 : : on_communicate_complete,
1076 : : &data);
1077 : :
1078 : 6 : data.running = TRUE;
1079 : 57 : while (data.running)
1080 : 51 : g_main_context_iteration (NULL, TRUE);
1081 : :
1082 : 6 : g_assert_no_error (data.error);
1083 : :
1084 : 6 : g_object_unref (proc);
1085 : 6 : }
1086 : :
1087 : : /* Test g_subprocess_communicate_utf8_async() can be cancelled correctly. */
1088 : : static void
1089 : 6 : test_communicate_utf8_cancelled_async (gconstpointer test_data)
1090 : : {
1091 : 6 : GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
1092 : 6 : GError *error = NULL;
1093 : : GPtrArray *args;
1094 : 6 : TestAsyncCommunicateData data = { flags, 0, 0, NULL };
1095 : : GSubprocess *proc;
1096 : 6 : GCancellable *cancellable = NULL;
1097 : :
1098 : 6 : args = get_test_subprocess_args ("cat", NULL);
1099 : 6 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
1100 : 6 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1101 : : &error);
1102 : 6 : g_assert_no_error (error);
1103 : 6 : g_ptr_array_free (args, TRUE);
1104 : :
1105 : 6 : cancellable = g_cancellable_new ();
1106 : 6 : data.is_utf8 = TRUE;
1107 : 6 : g_subprocess_communicate_utf8_async (proc, "# hello world\n",
1108 : : cancellable,
1109 : : on_communicate_cancelled_complete,
1110 : : &data);
1111 : :
1112 : 6 : g_cancellable_cancel (cancellable);
1113 : :
1114 : 6 : data.running = TRUE;
1115 : 24 : while (data.running)
1116 : 18 : g_main_context_iteration (NULL, TRUE);
1117 : :
1118 : 6 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1119 : 6 : g_clear_error (&data.error);
1120 : :
1121 : 6 : g_object_unref (cancellable);
1122 : 6 : g_object_unref (proc);
1123 : 6 : }
1124 : :
1125 : : /* Test g_subprocess_communicate_utf8() works correctly with a variety of flags,
1126 : : * as passed in via @test_data. */
1127 : : static void
1128 : 6 : test_communicate_utf8 (gconstpointer test_data)
1129 : : {
1130 : 6 : GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
1131 : 6 : GError *error = NULL;
1132 : : GPtrArray *args;
1133 : : GSubprocess *proc;
1134 : 6 : GCancellable *cancellable = NULL;
1135 : : const gchar *stdin_buf;
1136 : : gchar *stdout_buf, *stderr_buf;
1137 : :
1138 : 6 : args = get_test_subprocess_args ("cat", NULL);
1139 : 6 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
1140 : 6 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1141 : : &error);
1142 : 6 : g_assert_no_error (error);
1143 : 6 : g_ptr_array_free (args, TRUE);
1144 : :
1145 : : /* Include a leading hash and trailing newline so that if this gets onto the
1146 : : * test’s stdout, it doesn’t mess up TAP output. */
1147 : 6 : stdin_buf = "# hello world\n";
1148 : :
1149 : 6 : g_subprocess_communicate_utf8 (proc, stdin_buf, cancellable, &stdout_buf, &stderr_buf, &error);
1150 : 6 : g_assert_no_error (error);
1151 : :
1152 : 6 : if (flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
1153 : 3 : g_assert_cmpstr (stdout_buf, ==, "# hello world" LINEEND);
1154 : : else
1155 : 3 : g_assert_null (stdout_buf);
1156 : 6 : if (flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
1157 : 2 : g_assert_nonnull (stderr_buf);
1158 : 4 : else g_assert_null (stderr_buf);
1159 : :
1160 : 6 : g_free (stdout_buf);
1161 : 6 : g_free (stderr_buf);
1162 : 6 : g_object_unref (proc);
1163 : 6 : }
1164 : :
1165 : : /* Test g_subprocess_communicate_utf8() can be cancelled correctly */
1166 : : static void
1167 : 6 : test_communicate_utf8_cancelled (gconstpointer test_data)
1168 : : {
1169 : 6 : GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
1170 : : GPtrArray *args;
1171 : : GSubprocess *proc;
1172 : 6 : GCancellable *cancellable = NULL;
1173 : 6 : GError *error = NULL;
1174 : 6 : TestCancelledCommunicateData data = { 0 };
1175 : :
1176 : 6 : args = get_test_subprocess_args ("cat", NULL);
1177 : 6 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
1178 : 6 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1179 : : &error);
1180 : 6 : g_assert_no_error (error);
1181 : 6 : g_ptr_array_free (args, TRUE);
1182 : :
1183 : 6 : cancellable = g_cancellable_new ();
1184 : :
1185 : 6 : data.proc = proc;
1186 : 6 : data.cancellable = cancellable;
1187 : 6 : data.error = error;
1188 : :
1189 : 6 : g_cancellable_cancel (cancellable);
1190 : 6 : g_idle_add (on_test_communicate_cancelled_idle, &data);
1191 : :
1192 : 6 : data.is_utf8 = TRUE;
1193 : 6 : data.running = TRUE;
1194 : 18 : while (data.running)
1195 : 12 : g_main_context_iteration (NULL, TRUE);
1196 : :
1197 : 6 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1198 : 6 : g_clear_error (&data.error);
1199 : :
1200 : 6 : g_object_unref (cancellable);
1201 : 6 : g_object_unref (proc);
1202 : 6 : }
1203 : :
1204 : : static void
1205 : 1 : test_communicate_nothing (void)
1206 : : {
1207 : 1 : GError *error = NULL;
1208 : : GPtrArray *args;
1209 : : GSubprocess *proc;
1210 : 1 : GCancellable *cancellable = NULL;
1211 : : gchar *stdout_buf;
1212 : :
1213 : 1 : args = get_test_subprocess_args ("cat", NULL);
1214 : 1 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
1215 : : G_SUBPROCESS_FLAGS_STDIN_PIPE
1216 : : | G_SUBPROCESS_FLAGS_STDOUT_PIPE
1217 : : | G_SUBPROCESS_FLAGS_STDERR_MERGE,
1218 : : &error);
1219 : 1 : g_assert_no_error (error);
1220 : 1 : g_ptr_array_free (args, TRUE);
1221 : :
1222 : 1 : g_subprocess_communicate_utf8 (proc, "", cancellable, &stdout_buf, NULL, &error);
1223 : 1 : g_assert_no_error (error);
1224 : :
1225 : 1 : g_assert_cmpstr (stdout_buf, ==, "");
1226 : :
1227 : 1 : g_free (stdout_buf);
1228 : :
1229 : 1 : g_object_unref (proc);
1230 : 1 : }
1231 : :
1232 : : static void
1233 : 1 : test_communicate_utf8_async_invalid (void)
1234 : : {
1235 : 1 : GSubprocessFlags flags = G_SUBPROCESS_FLAGS_STDOUT_PIPE;
1236 : 1 : GError *error = NULL;
1237 : : GPtrArray *args;
1238 : 1 : TestAsyncCommunicateData data = { flags, 0, 0, NULL };
1239 : : GSubprocess *proc;
1240 : 1 : GCancellable *cancellable = NULL;
1241 : :
1242 : 1 : args = get_test_subprocess_args ("cat", NULL);
1243 : 1 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
1244 : 1 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1245 : : &error);
1246 : 1 : g_assert_no_error (error);
1247 : 1 : g_ptr_array_free (args, TRUE);
1248 : :
1249 : 1 : data.is_utf8 = TRUE;
1250 : 1 : g_subprocess_communicate_utf8_async (proc, "\xFF\xFF",
1251 : : cancellable,
1252 : : on_communicate_complete,
1253 : : &data);
1254 : :
1255 : 1 : data.running = TRUE;
1256 : 12 : while (data.running)
1257 : 11 : g_main_context_iteration (NULL, TRUE);
1258 : :
1259 : 1 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_FAILED);
1260 : 1 : g_error_free (data.error);
1261 : :
1262 : 1 : g_object_unref (proc);
1263 : 1 : }
1264 : :
1265 : : /* Test that invalid UTF-8 received using g_subprocess_communicate_utf8()
1266 : : * results in an error. */
1267 : : static void
1268 : 1 : test_communicate_utf8_invalid (void)
1269 : : {
1270 : 1 : GSubprocessFlags flags = G_SUBPROCESS_FLAGS_STDOUT_PIPE;
1271 : 1 : GError *local_error = NULL;
1272 : : gboolean ret;
1273 : : GPtrArray *args;
1274 : 1 : gchar *stdout_str = NULL, *stderr_str = NULL;
1275 : : GSubprocess *proc;
1276 : :
1277 : 1 : args = get_test_subprocess_args ("cat", NULL);
1278 : 1 : proc = g_subprocess_newv ((const gchar* const*)args->pdata,
1279 : 1 : G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1280 : : &local_error);
1281 : 1 : g_assert_no_error (local_error);
1282 : 1 : g_ptr_array_free (args, TRUE);
1283 : :
1284 : 1 : ret = g_subprocess_communicate_utf8 (proc, "\xFF\xFF", NULL,
1285 : : &stdout_str, &stderr_str, &local_error);
1286 : 1 : g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_FAILED);
1287 : 1 : g_error_free (local_error);
1288 : 1 : g_assert_false (ret);
1289 : :
1290 : 1 : g_assert_null (stdout_str);
1291 : 1 : g_assert_null (stderr_str);
1292 : :
1293 : 1 : g_object_unref (proc);
1294 : 1 : }
1295 : :
1296 : : static void
1297 : 1 : send_terminate (gpointer user_data)
1298 : : {
1299 : 1 : GSubprocess *proc = user_data;
1300 : :
1301 : 1 : g_subprocess_force_exit (proc);
1302 : 1 : }
1303 : :
1304 : : static void
1305 : 2 : on_request_quit_exited (GObject *object,
1306 : : GAsyncResult *result,
1307 : : gpointer user_data)
1308 : : {
1309 : 2 : GSubprocess *subprocess = G_SUBPROCESS (object);
1310 : 2 : GError *error = NULL;
1311 : :
1312 : 2 : g_subprocess_wait_finish (subprocess, result, &error);
1313 : 2 : g_assert_no_error (error);
1314 : : #ifdef G_OS_UNIX
1315 : 2 : g_assert_true (g_subprocess_get_if_signaled (subprocess));
1316 : 2 : g_assert_cmpint (g_subprocess_get_term_sig (subprocess), ==, 9);
1317 : : #endif
1318 : 2 : g_spawn_check_wait_status (g_subprocess_get_status (subprocess), &error);
1319 : 2 : g_assert_nonnull (error);
1320 : 2 : g_clear_error (&error);
1321 : :
1322 : 2 : g_main_loop_quit ((GMainLoop*)user_data);
1323 : 2 : }
1324 : :
1325 : : static void
1326 : 1 : test_terminate (void)
1327 : : {
1328 : 1 : GError *local_error = NULL;
1329 : 1 : GError **error = &local_error;
1330 : : GSubprocess *proc;
1331 : : GPtrArray *args;
1332 : : GMainLoop *loop;
1333 : : const gchar *id;
1334 : :
1335 : 1 : args = get_test_subprocess_args ("sleep-forever", NULL);
1336 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
1337 : 1 : g_ptr_array_free (args, TRUE);
1338 : 1 : g_assert_no_error (local_error);
1339 : :
1340 : 1 : id = g_subprocess_get_identifier (proc);
1341 : 1 : g_assert_nonnull (id);
1342 : :
1343 : 1 : loop = g_main_loop_new (NULL, TRUE);
1344 : :
1345 : 1 : g_subprocess_wait_async (proc, NULL, on_request_quit_exited, loop);
1346 : :
1347 : 1 : g_timeout_add_seconds_once (3, send_terminate, proc);
1348 : :
1349 : 1 : g_main_loop_run (loop);
1350 : :
1351 : 1 : g_main_loop_unref (loop);
1352 : 1 : g_object_unref (proc);
1353 : 1 : }
1354 : :
1355 : : #ifdef G_OS_UNIX
1356 : : static void
1357 : 1 : send_signal (gpointer user_data)
1358 : : {
1359 : 1 : GSubprocess *proc = user_data;
1360 : :
1361 : 1 : g_subprocess_send_signal (proc, SIGKILL);
1362 : 1 : }
1363 : :
1364 : : static void
1365 : 1 : test_signal (void)
1366 : : {
1367 : 1 : GError *local_error = NULL;
1368 : 1 : GError **error = &local_error;
1369 : : GSubprocess *proc;
1370 : : GPtrArray *args;
1371 : : GMainLoop *loop;
1372 : :
1373 : 1 : args = get_test_subprocess_args ("sleep-forever", NULL);
1374 : 1 : proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
1375 : 1 : g_ptr_array_free (args, TRUE);
1376 : 1 : g_assert_no_error (local_error);
1377 : :
1378 : 1 : loop = g_main_loop_new (NULL, TRUE);
1379 : :
1380 : 1 : g_subprocess_wait_async (proc, NULL, on_request_quit_exited, loop);
1381 : :
1382 : 1 : g_timeout_add_seconds_once (3, send_signal, proc);
1383 : :
1384 : 1 : g_main_loop_run (loop);
1385 : :
1386 : 1 : g_main_loop_unref (loop);
1387 : 1 : g_object_unref (proc);
1388 : 1 : }
1389 : : #endif
1390 : :
1391 : : static void
1392 : 1 : test_env (void)
1393 : : {
1394 : 1 : GError *local_error = NULL;
1395 : 1 : GError **error = &local_error;
1396 : : GSubprocessLauncher *launcher;
1397 : : GSubprocess *proc;
1398 : : GPtrArray *args;
1399 : : GInputStream *stdout_stream;
1400 : : gchar *result;
1401 : 1 : gchar *envp[] = { NULL, "ONE=1", "TWO=1", "THREE=3", "FOUR=1", NULL };
1402 : : gchar **split;
1403 : :
1404 : 1 : envp[0] = g_strdup_printf ("PATH=%s", g_getenv ("PATH"));
1405 : 1 : args = get_test_subprocess_args ("env", NULL);
1406 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
1407 : 1 : g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
1408 : 1 : g_subprocess_launcher_set_environ (launcher, envp);
1409 : 1 : g_subprocess_launcher_setenv (launcher, "TWO", "2", TRUE);
1410 : 1 : g_subprocess_launcher_setenv (launcher, "THREE", "1", FALSE);
1411 : 1 : g_subprocess_launcher_unsetenv (launcher, "FOUR");
1412 : :
1413 : 1 : g_assert_null (g_subprocess_launcher_getenv (launcher, "FOUR"));
1414 : :
1415 : 1 : proc = g_subprocess_launcher_spawn (launcher, error, args->pdata[0], "env", NULL);
1416 : 1 : g_ptr_array_free (args, TRUE);
1417 : 1 : g_assert_no_error (local_error);
1418 : 1 : g_free (envp[0]);
1419 : :
1420 : 1 : stdout_stream = g_subprocess_get_stdout_pipe (proc);
1421 : :
1422 : 1 : result = splice_to_string (stdout_stream, error);
1423 : 1 : split = g_strsplit (result, LINEEND, -1);
1424 : 1 : g_assert_cmpstr (g_environ_getenv (split, "ONE"), ==, "1");
1425 : 1 : g_assert_cmpstr (g_environ_getenv (split, "TWO"), ==, "2");
1426 : 1 : g_assert_cmpstr (g_environ_getenv (split, "THREE"), ==, "3");
1427 : 1 : g_assert_null (g_environ_getenv (split, "FOUR"));
1428 : :
1429 : 1 : g_strfreev (split);
1430 : 1 : g_free (result);
1431 : 1 : g_object_unref (proc);
1432 : 1 : g_object_unref (launcher);
1433 : 1 : }
1434 : :
1435 : : /* Test that explicitly inheriting and modifying the parent process’
1436 : : * environment works. */
1437 : : static void
1438 : 1 : test_env_inherit (void)
1439 : : {
1440 : 1 : GError *local_error = NULL;
1441 : 1 : GError **error = &local_error;
1442 : : GSubprocessLauncher *launcher;
1443 : : GSubprocess *proc;
1444 : : GPtrArray *args;
1445 : : GInputStream *stdout_stream;
1446 : : gchar *result;
1447 : : gchar **split;
1448 : :
1449 : 1 : g_setenv ("TEST_ENV_INHERIT1", "1", TRUE);
1450 : 1 : g_setenv ("TEST_ENV_INHERIT2", "2", TRUE);
1451 : :
1452 : 1 : args = get_test_subprocess_args ("env", NULL);
1453 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
1454 : 1 : g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
1455 : 1 : g_subprocess_launcher_set_environ (launcher, NULL);
1456 : 1 : g_subprocess_launcher_setenv (launcher, "TWO", "2", TRUE);
1457 : 1 : g_subprocess_launcher_unsetenv (launcher, "TEST_ENV_INHERIT1");
1458 : :
1459 : 1 : g_assert_null (g_subprocess_launcher_getenv (launcher, "TEST_ENV_INHERIT1"));
1460 : 1 : g_assert_cmpstr (g_subprocess_launcher_getenv (launcher, "TEST_ENV_INHERIT2"), ==, "2");
1461 : 1 : g_assert_cmpstr (g_subprocess_launcher_getenv (launcher, "TWO"), ==, "2");
1462 : :
1463 : 1 : proc = g_subprocess_launcher_spawn (launcher, error, args->pdata[0], "env", NULL);
1464 : 1 : g_ptr_array_free (args, TRUE);
1465 : 1 : g_assert_no_error (local_error);
1466 : :
1467 : 1 : stdout_stream = g_subprocess_get_stdout_pipe (proc);
1468 : :
1469 : 1 : result = splice_to_string (stdout_stream, error);
1470 : 1 : split = g_strsplit (result, LINEEND, -1);
1471 : 1 : g_assert_null (g_environ_getenv (split, "TEST_ENV_INHERIT1"));
1472 : 1 : g_assert_cmpstr (g_environ_getenv (split, "TEST_ENV_INHERIT2"), ==, "2");
1473 : 1 : g_assert_cmpstr (g_environ_getenv (split, "TWO"), ==, "2");
1474 : :
1475 : 1 : g_strfreev (split);
1476 : 1 : g_free (result);
1477 : 1 : g_object_unref (proc);
1478 : 1 : g_object_unref (launcher);
1479 : 1 : }
1480 : :
1481 : : static void
1482 : 1 : test_cwd (void)
1483 : : {
1484 : 1 : GError *local_error = NULL;
1485 : : GSubprocessLauncher *launcher;
1486 : : GSubprocess *proc;
1487 : : GPtrArray *args;
1488 : : GInputStream *stdout_stream;
1489 : : gchar *result;
1490 : : gsize result_len;
1491 : 1 : const gchar *tmpdir = g_get_tmp_dir ();
1492 : 1 : gchar *tmpdir_basename = NULL, *result_basename = NULL;
1493 : :
1494 : 1 : args = get_test_subprocess_args ("cwd", NULL);
1495 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
1496 : 1 : g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
1497 : 1 : g_subprocess_launcher_set_cwd (launcher, tmpdir);
1498 : :
1499 : 1 : proc = g_subprocess_launcher_spawnv (launcher, (const char * const *)args->pdata, &local_error);
1500 : 1 : g_ptr_array_free (args, TRUE);
1501 : 1 : g_assert_no_error (local_error);
1502 : :
1503 : 1 : stdout_stream = g_subprocess_get_stdout_pipe (proc);
1504 : :
1505 : 1 : result = splice_to_string (stdout_stream, &local_error);
1506 : 1 : g_assert_no_error (local_error);
1507 : 1 : result_len = strlen (result);
1508 : :
1509 : : /* The result should end with a line ending */
1510 : 1 : g_assert_cmpstr (result + result_len - strlen (LINEEND), ==, LINEEND);
1511 : :
1512 : : /* Not sure if the testprog guarantees to return an absolute path for the cwd,
1513 : : * so only compare the basenames. */
1514 : 1 : tmpdir_basename = g_path_get_basename (tmpdir);
1515 : 1 : result_basename = g_path_get_basename (g_strstrip (result));
1516 : 1 : g_assert_cmpstr (tmpdir_basename, ==, result_basename);
1517 : 1 : g_free (tmpdir_basename);
1518 : 1 : g_free (result_basename);
1519 : :
1520 : 1 : g_free (result);
1521 : 1 : g_object_unref (proc);
1522 : 1 : g_object_unref (launcher);
1523 : 1 : }
1524 : : #ifdef G_OS_UNIX
1525 : :
1526 : : static void
1527 : 1 : test_subprocess_launcher_close (void)
1528 : : {
1529 : 1 : GError *local_error = NULL;
1530 : 1 : GError **error = &local_error;
1531 : : GSubprocessLauncher *launcher;
1532 : : GSubprocess *proc;
1533 : : GPtrArray *args;
1534 : : int fd, fd2;
1535 : : gboolean is_open;
1536 : :
1537 : : /* Open two arbitrary FDs. One of them, @fd, will be transferred to the
1538 : : * launcher, and the other’s FD integer will be used as its target FD, giving
1539 : : * the mapping `fd → fd2` if a child process were to be spawned.
1540 : : *
1541 : : * The launcher will then be closed, which should close @fd but *not* @fd2,
1542 : : * as the value of @fd2 is only valid as an FD in a child process. (A child
1543 : : * process is not actually spawned in this test.)
1544 : : */
1545 : 1 : fd = dup (0);
1546 : 1 : fd2 = dup (0);
1547 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
1548 : 1 : g_subprocess_launcher_take_fd (launcher, fd, fd2);
1549 : :
1550 : 1 : is_open = fcntl (fd, F_GETFD) != -1;
1551 : 1 : g_assert_true (is_open);
1552 : 1 : is_open = fcntl (fd2, F_GETFD) != -1;
1553 : 1 : g_assert_true (is_open);
1554 : :
1555 : 1 : g_subprocess_launcher_close (launcher);
1556 : :
1557 : 1 : is_open = fcntl (fd, F_GETFD) != -1;
1558 : 1 : g_assert_false (is_open);
1559 : 1 : is_open = fcntl (fd2, F_GETFD) != -1;
1560 : 1 : g_assert_true (is_open);
1561 : :
1562 : : /* Now test that actually trying to spawn the child gives %G_IO_ERROR_CLOSED,
1563 : : * as g_subprocess_launcher_close() has been called. */
1564 : 1 : args = get_test_subprocess_args ("cat", NULL);
1565 : 1 : proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
1566 : 1 : g_ptr_array_free (args, TRUE);
1567 : 1 : g_assert_null (proc);
1568 : 1 : g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_CLOSED);
1569 : 1 : g_clear_error (error);
1570 : :
1571 : 1 : close (fd2);
1572 : 1 : g_object_unref (launcher);
1573 : 1 : }
1574 : :
1575 : : static void
1576 : 1 : test_stdout_file (void)
1577 : : {
1578 : 1 : GError *local_error = NULL;
1579 : 1 : GError **error = &local_error;
1580 : : GSubprocessLauncher *launcher;
1581 : : GSubprocess *proc;
1582 : : GPtrArray *args;
1583 : : GFile *tmpfile;
1584 : : GFileIOStream *iostream;
1585 : : GOutputStream *stdin_stream;
1586 : 1 : const char *test_data = "this is some test data\n";
1587 : : char *tmp_contents;
1588 : : char *tmp_file_path;
1589 : :
1590 : 1 : tmpfile = g_file_new_tmp ("gsubprocessXXXXXX", &iostream, error);
1591 : 1 : g_assert_no_error (local_error);
1592 : 1 : g_clear_object (&iostream);
1593 : :
1594 : 1 : tmp_file_path = g_file_get_path (tmpfile);
1595 : :
1596 : 1 : args = get_test_subprocess_args ("cat", NULL);
1597 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE);
1598 : 1 : g_subprocess_launcher_set_stdout_file_path (launcher, tmp_file_path);
1599 : 1 : proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
1600 : 1 : g_ptr_array_free (args, TRUE);
1601 : 1 : g_assert_no_error (local_error);
1602 : :
1603 : 1 : stdin_stream = g_subprocess_get_stdin_pipe (proc);
1604 : :
1605 : 1 : g_output_stream_write_all (stdin_stream, test_data, strlen (test_data), NULL, NULL, error);
1606 : 1 : g_assert_no_error (local_error);
1607 : :
1608 : 1 : g_output_stream_close (stdin_stream, NULL, error);
1609 : 1 : g_assert_no_error (local_error);
1610 : :
1611 : 1 : g_subprocess_wait_check (proc, NULL, error);
1612 : :
1613 : 1 : g_object_unref (launcher);
1614 : 1 : g_object_unref (proc);
1615 : :
1616 : 1 : g_file_load_contents (tmpfile, NULL, &tmp_contents, NULL, NULL, error);
1617 : 1 : g_assert_no_error (local_error);
1618 : :
1619 : 1 : g_assert_cmpstr (test_data, ==, tmp_contents);
1620 : 1 : g_free (tmp_contents);
1621 : :
1622 : 1 : (void) g_file_delete (tmpfile, NULL, NULL);
1623 : 1 : g_object_unref (tmpfile);
1624 : 1 : g_free (tmp_file_path);
1625 : 1 : }
1626 : :
1627 : : static void
1628 : 1 : test_stdout_fd (void)
1629 : : {
1630 : 1 : GError *local_error = NULL;
1631 : 1 : GError **error = &local_error;
1632 : : GSubprocessLauncher *launcher;
1633 : : GSubprocess *proc;
1634 : : GPtrArray *args;
1635 : : GFile *tmpfile;
1636 : : GFileIOStream *iostream;
1637 : : GFileDescriptorBased *descriptor_stream;
1638 : : GOutputStream *stdin_stream;
1639 : 1 : const char *test_data = "this is some test data\n";
1640 : : char *tmp_contents;
1641 : :
1642 : 1 : tmpfile = g_file_new_tmp ("gsubprocessXXXXXX", &iostream, error);
1643 : 1 : g_assert_no_error (local_error);
1644 : :
1645 : 1 : args = get_test_subprocess_args ("cat", NULL);
1646 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE);
1647 : 1 : descriptor_stream = G_FILE_DESCRIPTOR_BASED (g_io_stream_get_output_stream (G_IO_STREAM (iostream)));
1648 : 1 : g_subprocess_launcher_take_stdout_fd (launcher, dup (g_file_descriptor_based_get_fd (descriptor_stream)));
1649 : 1 : proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
1650 : 1 : g_ptr_array_free (args, TRUE);
1651 : 1 : g_assert_no_error (local_error);
1652 : :
1653 : 1 : g_clear_object (&iostream);
1654 : :
1655 : 1 : stdin_stream = g_subprocess_get_stdin_pipe (proc);
1656 : :
1657 : 1 : g_output_stream_write_all (stdin_stream, test_data, strlen (test_data), NULL, NULL, error);
1658 : 1 : g_assert_no_error (local_error);
1659 : :
1660 : 1 : g_output_stream_close (stdin_stream, NULL, error);
1661 : 1 : g_assert_no_error (local_error);
1662 : :
1663 : 1 : g_subprocess_wait_check (proc, NULL, error);
1664 : :
1665 : 1 : g_object_unref (launcher);
1666 : 1 : g_object_unref (proc);
1667 : :
1668 : 1 : g_file_load_contents (tmpfile, NULL, &tmp_contents, NULL, NULL, error);
1669 : 1 : g_assert_no_error (local_error);
1670 : :
1671 : 1 : g_assert_cmpstr (test_data, ==, tmp_contents);
1672 : 1 : g_free (tmp_contents);
1673 : :
1674 : 1 : (void) g_file_delete (tmpfile, NULL, NULL);
1675 : 1 : g_object_unref (tmpfile);
1676 : 1 : }
1677 : :
1678 : : static void
1679 : 1 : child_setup (gpointer user_data)
1680 : : {
1681 : 1 : dup2 (GPOINTER_TO_INT (user_data), 1);
1682 : 1 : }
1683 : :
1684 : : static void
1685 : 1 : test_child_setup (void)
1686 : : {
1687 : 1 : GError *local_error = NULL;
1688 : 1 : GError **error = &local_error;
1689 : : GSubprocessLauncher *launcher;
1690 : : GSubprocess *proc;
1691 : : GPtrArray *args;
1692 : : GFile *tmpfile;
1693 : : GFileIOStream *iostream;
1694 : : GOutputStream *stdin_stream;
1695 : 1 : const char *test_data = "this is some test data\n";
1696 : : char *tmp_contents;
1697 : : int fd;
1698 : :
1699 : 1 : tmpfile = g_file_new_tmp ("gsubprocessXXXXXX", &iostream, error);
1700 : 1 : g_assert_no_error (local_error);
1701 : :
1702 : 1 : fd = g_file_descriptor_based_get_fd (G_FILE_DESCRIPTOR_BASED (g_io_stream_get_output_stream (G_IO_STREAM (iostream))));
1703 : :
1704 : 1 : args = get_test_subprocess_args ("cat", NULL);
1705 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE);
1706 : 1 : g_subprocess_launcher_set_child_setup (launcher, child_setup, GINT_TO_POINTER (fd), NULL);
1707 : 1 : proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
1708 : 1 : g_ptr_array_free (args, TRUE);
1709 : 1 : g_assert_no_error (local_error);
1710 : :
1711 : 1 : g_clear_object (&iostream);
1712 : :
1713 : 1 : stdin_stream = g_subprocess_get_stdin_pipe (proc);
1714 : :
1715 : 1 : g_output_stream_write_all (stdin_stream, test_data, strlen (test_data), NULL, NULL, error);
1716 : 1 : g_assert_no_error (local_error);
1717 : :
1718 : 1 : g_output_stream_close (stdin_stream, NULL, error);
1719 : 1 : g_assert_no_error (local_error);
1720 : :
1721 : 1 : g_subprocess_wait_check (proc, NULL, error);
1722 : :
1723 : 1 : g_object_unref (launcher);
1724 : 1 : g_object_unref (proc);
1725 : :
1726 : 1 : g_file_load_contents (tmpfile, NULL, &tmp_contents, NULL, NULL, error);
1727 : 1 : g_assert_no_error (local_error);
1728 : :
1729 : 1 : g_assert_cmpstr (test_data, ==, tmp_contents);
1730 : 1 : g_free (tmp_contents);
1731 : :
1732 : 1 : (void) g_file_delete (tmpfile, NULL, NULL);
1733 : 1 : g_object_unref (tmpfile);
1734 : 1 : }
1735 : :
1736 : : static void
1737 : 3 : do_test_pass_fd (GSubprocessFlags flags,
1738 : : GSpawnChildSetupFunc child_setup)
1739 : : {
1740 : 3 : GError *local_error = NULL;
1741 : 3 : GError **error = &local_error;
1742 : : GInputStream *child_input;
1743 : : GDataInputStream *child_datainput;
1744 : : GSubprocessLauncher *launcher;
1745 : : GSubprocess *proc;
1746 : : GPtrArray *args;
1747 : : int basic_pipefds[2];
1748 : : int needdup_pipefds[2];
1749 : : char *buf;
1750 : : gsize len;
1751 : : char *basic_fd_str;
1752 : : char *needdup_fd_str;
1753 : :
1754 : 3 : g_unix_open_pipe (basic_pipefds, O_CLOEXEC, error);
1755 : 3 : g_assert_no_error (local_error);
1756 : 3 : g_unix_open_pipe (needdup_pipefds, O_CLOEXEC, error);
1757 : 3 : g_assert_no_error (local_error);
1758 : :
1759 : 3 : basic_fd_str = g_strdup_printf ("%d", basic_pipefds[1]);
1760 : 3 : needdup_fd_str = g_strdup_printf ("%d", needdup_pipefds[1] + 1);
1761 : :
1762 : 3 : args = get_test_subprocess_args ("write-to-fds", basic_fd_str, needdup_fd_str, NULL);
1763 : 3 : launcher = g_subprocess_launcher_new (flags);
1764 : 3 : g_subprocess_launcher_take_fd (launcher, basic_pipefds[1], basic_pipefds[1]);
1765 : 3 : g_subprocess_launcher_take_fd (launcher, needdup_pipefds[1], needdup_pipefds[1] + 1);
1766 : 3 : if (child_setup != NULL)
1767 : 1 : g_subprocess_launcher_set_child_setup (launcher, child_setup, NULL, NULL);
1768 : 3 : proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
1769 : 3 : g_ptr_array_free (args, TRUE);
1770 : 3 : g_assert_no_error (local_error);
1771 : :
1772 : 3 : g_free (basic_fd_str);
1773 : 3 : g_free (needdup_fd_str);
1774 : :
1775 : 3 : child_input = g_unix_input_stream_new (basic_pipefds[0], TRUE);
1776 : 3 : child_datainput = g_data_input_stream_new (child_input);
1777 : 3 : buf = g_data_input_stream_read_line_utf8 (child_datainput, &len, NULL, error);
1778 : 3 : g_assert_no_error (local_error);
1779 : 3 : g_assert_cmpstr (buf, ==, "hello world");
1780 : 3 : g_object_unref (child_datainput);
1781 : 3 : g_object_unref (child_input);
1782 : 3 : g_free (buf);
1783 : :
1784 : 3 : child_input = g_unix_input_stream_new (needdup_pipefds[0], TRUE);
1785 : 3 : child_datainput = g_data_input_stream_new (child_input);
1786 : 3 : buf = g_data_input_stream_read_line_utf8 (child_datainput, &len, NULL, error);
1787 : 3 : g_assert_no_error (local_error);
1788 : 3 : g_assert_cmpstr (buf, ==, "hello world");
1789 : 3 : g_free (buf);
1790 : 3 : g_object_unref (child_datainput);
1791 : 3 : g_object_unref (child_input);
1792 : :
1793 : 3 : g_object_unref (launcher);
1794 : 3 : g_object_unref (proc);
1795 : 3 : }
1796 : :
1797 : : static void
1798 : 1 : test_pass_fd (void)
1799 : : {
1800 : 1 : do_test_pass_fd (G_SUBPROCESS_FLAGS_NONE, NULL);
1801 : 1 : }
1802 : :
1803 : : static void
1804 : 3 : empty_child_setup (gpointer user_data)
1805 : : {
1806 : 3 : }
1807 : :
1808 : : static void
1809 : 1 : test_pass_fd_empty_child_setup (void)
1810 : : {
1811 : : /* Using a child setup function forces gspawn to use fork/exec
1812 : : * rather than posix_spawn.
1813 : : */
1814 : 1 : do_test_pass_fd (G_SUBPROCESS_FLAGS_NONE, empty_child_setup);
1815 : 1 : }
1816 : :
1817 : : static void
1818 : 1 : test_pass_fd_inherit_fds (void)
1819 : : {
1820 : : /* Try to test the optimized posix_spawn codepath instead of
1821 : : * fork/exec. Currently this requires using INHERIT_FDS since gspawn's
1822 : : * posix_spawn codepath does not currently handle closing
1823 : : * non-inherited fds. Note that using INHERIT_FDS means our testing of
1824 : : * g_subprocess_launcher_take_fd() is less-comprehensive than when
1825 : : * using G_SUBPROCESS_FLAGS_NONE.
1826 : : */
1827 : 1 : do_test_pass_fd (G_SUBPROCESS_FLAGS_INHERIT_FDS, NULL);
1828 : 1 : }
1829 : :
1830 : : static void
1831 : 8 : do_test_fd_conflation (GSubprocessFlags flags,
1832 : : GSpawnChildSetupFunc child_setup,
1833 : : gboolean test_child_err_report_fd)
1834 : : {
1835 : 8 : char success_message[] = "Yay success!";
1836 : 8 : GError *error = NULL;
1837 : : GOutputStream *output_stream;
1838 : : GSubprocessLauncher *launcher;
1839 : : GSubprocess *proc;
1840 : : GPtrArray *args;
1841 : : int unused_pipefds[2];
1842 : : int pipefds[2];
1843 : : int fd_to_pass_to_child;
1844 : : gsize bytes_written;
1845 : : gboolean success;
1846 : : char *fd_str;
1847 : :
1848 : : /* This test must run in a new process because it is extremely sensitive to
1849 : : * order of opened fds.
1850 : : */
1851 : 8 : if (!g_test_subprocess ())
1852 : : {
1853 : 4 : g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_INHERIT_STDOUT | G_TEST_SUBPROCESS_INHERIT_STDERR);
1854 : 4 : g_test_trap_assert_passed ();
1855 : 4 : return;
1856 : : }
1857 : :
1858 : 4 : g_unix_open_pipe (unused_pipefds, O_CLOEXEC, &error);
1859 : 4 : g_assert_no_error (error);
1860 : :
1861 : 4 : g_unix_open_pipe (pipefds, O_CLOEXEC, &error);
1862 : 4 : g_assert_no_error (error);
1863 : :
1864 : : /* The fds should be sequential since we are in a new process. */
1865 : 4 : g_assert_cmpint (unused_pipefds[0] /* 3 */, ==, unused_pipefds[1] - 1);
1866 : 4 : g_assert_cmpint (unused_pipefds[1] /* 4 */, ==, pipefds[0] - 1);
1867 : 4 : g_assert_cmpint (pipefds[0] /* 5 */, ==, pipefds[1] /* 6 */ - 1);
1868 : :
1869 : : /* Because GSubprocess allows arbitrary remapping of fds, it has to be careful
1870 : : * to avoid fd conflation issues, e.g. it should properly handle 5 -> 4 and
1871 : : * 4 -> 5 at the same time. GIO previously attempted to handle this by naively
1872 : : * dup'ing the source fds, but this was not good enough because it was
1873 : : * possible that the dup'ed result could still conflict with one of the target
1874 : : * fds. For example:
1875 : : *
1876 : : * source_fd 5 -> target_fd 9, source_fd 3 -> target_fd 7
1877 : : *
1878 : : * dup(5) -> dup returns 8
1879 : : * dup(3) -> dup returns 9
1880 : : *
1881 : : * After dup'ing, we wind up with: 8 -> 9, 9 -> 7. That means that after we
1882 : : * dup2(8, 9), we have clobbered fd 9 before we dup2(9, 7). The end result is
1883 : : * we have remapped 5 -> 9 as expected, but then remapped 5 -> 7 instead of
1884 : : * 3 -> 7 as the application intended.
1885 : : *
1886 : : * This issue has been fixed in the simplest way possible, by passing a
1887 : : * minimum fd value when using F_DUPFD_CLOEXEC that is higher than any of the
1888 : : * target fds, to guarantee all source fds are different than all target fds,
1889 : : * eliminating any possibility of conflation.
1890 : : *
1891 : : * Anyway, that is why we have the unused_pipefds here. We need to open fds in
1892 : : * a certain order in order to trick older GSubprocess into conflating the
1893 : : * fds. The primary goal of this test is to ensure this particular conflation
1894 : : * issue is not reintroduced. See glib#2503.
1895 : : *
1896 : : * This test also has an alternate mode of operation where it instead tests
1897 : : * for conflation with gspawn's child_err_report_fd, glib#2506.
1898 : : *
1899 : : * Be aware this test is necessarily extremely fragile. To reproduce these
1900 : : * bugs, it relies on internals of gspawn and gmain that will likely change
1901 : : * in the future, eventually causing this test to no longer test the bugs
1902 : : * it was originally designed to test. That is OK! If the test fails, at
1903 : : * least you know *something* is wrong.
1904 : : */
1905 : 4 : if (test_child_err_report_fd)
1906 : 1 : fd_to_pass_to_child = pipefds[1] + 2 /* 8 */;
1907 : : else
1908 : 3 : fd_to_pass_to_child = pipefds[1] + 3 /* 9 */;
1909 : :
1910 : 4 : launcher = g_subprocess_launcher_new (flags);
1911 : 4 : g_subprocess_launcher_take_fd (launcher, pipefds[0] /* 5 */, fd_to_pass_to_child);
1912 : 4 : g_subprocess_launcher_take_fd (launcher, unused_pipefds[0] /* 3 */, pipefds[1] + 1 /* 7 */);
1913 : 4 : if (child_setup != NULL)
1914 : 2 : g_subprocess_launcher_set_child_setup (launcher, child_setup, NULL, NULL);
1915 : 4 : fd_str = g_strdup_printf ("%d", fd_to_pass_to_child);
1916 : 4 : args = get_test_subprocess_args ("read-from-fd", fd_str, NULL);
1917 : 4 : proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, &error);
1918 : 4 : g_assert_no_error (error);
1919 : 4 : g_assert_nonnull (proc);
1920 : 4 : g_ptr_array_free (args, TRUE);
1921 : 4 : g_object_unref (launcher);
1922 : 4 : g_free (fd_str);
1923 : :
1924 : : /* Close the read ends of the pipes. */
1925 : 4 : close (unused_pipefds[0]);
1926 : 4 : close (pipefds[0]);
1927 : :
1928 : : /* Also close the write end of the unused pipe. */
1929 : 4 : close (unused_pipefds[1]);
1930 : :
1931 : : /* If doing our normal test:
1932 : : *
1933 : : * So now pipefds[0] should be inherited into the subprocess as
1934 : : * pipefds[1] + 2, and unused_pipefds[0] should be inherited as
1935 : : * pipefds[1] + 1. We will write to pipefds[1] and the subprocess will verify
1936 : : * that it reads the expected data. But older broken GIO will accidentally
1937 : : * clobber pipefds[1] + 2 with pipefds[1] + 1! This will cause the subprocess
1938 : : * to hang trying to read from the wrong pipe.
1939 : : *
1940 : : * If testing conflation with child_err_report_fd:
1941 : : *
1942 : : * We are actually already done. The real test succeeded if we made it this
1943 : : * far without hanging while spawning the child. But let's continue with our
1944 : : * write and read anyway, to ensure things are good.
1945 : : */
1946 : 4 : output_stream = g_unix_output_stream_new (pipefds[1], TRUE);
1947 : 4 : success = g_output_stream_write_all (output_stream,
1948 : : success_message, sizeof (success_message),
1949 : : &bytes_written,
1950 : : NULL,
1951 : : &error);
1952 : 4 : g_assert_no_error (error);
1953 : 4 : g_assert_cmpint (bytes_written, ==, sizeof (success_message));
1954 : 4 : g_assert_true (success);
1955 : 4 : g_object_unref (output_stream);
1956 : :
1957 : 4 : success = g_subprocess_wait_check (proc, NULL, &error);
1958 : 4 : g_assert_no_error (error);
1959 : 4 : g_object_unref (proc);
1960 : : }
1961 : :
1962 : : static void
1963 : 2 : test_fd_conflation (void)
1964 : : {
1965 : 2 : do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, NULL, FALSE);
1966 : 2 : }
1967 : :
1968 : : static void
1969 : 2 : test_fd_conflation_empty_child_setup (void)
1970 : : {
1971 : : /* Using a child setup function forces gspawn to use fork/exec
1972 : : * rather than posix_spawn.
1973 : : */
1974 : 2 : do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, empty_child_setup, FALSE);
1975 : 2 : }
1976 : :
1977 : : static void
1978 : 2 : test_fd_conflation_inherit_fds (void)
1979 : : {
1980 : : /* Try to test the optimized posix_spawn codepath instead of
1981 : : * fork/exec. Currently this requires using INHERIT_FDS since gspawn's
1982 : : * posix_spawn codepath does not currently handle closing
1983 : : * non-inherited fds.
1984 : : */
1985 : 2 : do_test_fd_conflation (G_SUBPROCESS_FLAGS_INHERIT_FDS, NULL, FALSE);
1986 : 2 : }
1987 : :
1988 : : static void
1989 : 2 : test_fd_conflation_child_err_report_fd (void)
1990 : : {
1991 : : /* Using a child setup function forces gspawn to use fork/exec
1992 : : * rather than posix_spawn.
1993 : : */
1994 : 2 : do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, empty_child_setup, TRUE);
1995 : 2 : }
1996 : :
1997 : : #ifdef __linux__
1998 : :
1999 : : /* Handle ptrace events on @main_child, and assert that when it exits, it does
2000 : : * so with status %EXIT_SUCCESS, rather than signalling. Other than that, this
2001 : : * just calls %PTRACE_CONT for all trace events. */
2002 : : static void
2003 : 1 : trace_children (pid_t main_child)
2004 : : {
2005 : : int wstatus;
2006 : :
2007 : 1 : g_assert_no_errno (waitpid (main_child, &wstatus, 0));
2008 : 1 : g_assert_no_errno (ptrace (PTRACE_SETOPTIONS, main_child, NULL,
2009 : : (PTRACE_O_TRACEFORK |
2010 : : #ifdef HAVE_PTRACE_O_EXITKILL
2011 : : PTRACE_O_EXITKILL |
2012 : : #endif
2013 : : PTRACE_O_TRACEVFORK |
2014 : : PTRACE_O_TRACECLONE |
2015 : : PTRACE_O_TRACEEXEC)));
2016 : 1 : g_assert_no_errno (ptrace (PTRACE_CONT, main_child, NULL, 0));
2017 : :
2018 : : while (TRUE)
2019 : 11 : {
2020 : : pid_t pid;
2021 : : int wstatus;
2022 : : int stop_signum;
2023 : : int ptrace_event;
2024 : :
2025 : 12 : pid = waitpid (-1, &wstatus, 0);
2026 : 12 : if (pid == -1 && errno == ECHILD)
2027 : 0 : break;
2028 : :
2029 : 12 : g_assert_cmpint (errno, ==, 0);
2030 : 12 : g_assert_cmpint (pid, >=, 0);
2031 : :
2032 : 12 : if (WIFSTOPPED (wstatus))
2033 : 8 : stop_signum = WSTOPSIG (wstatus);
2034 : : else
2035 : 4 : stop_signum = 0;
2036 : :
2037 : 12 : switch (stop_signum)
2038 : : {
2039 : 4 : case SIGTRAP:
2040 : 4 : ptrace_event = (wstatus >> 16) & 0xffff;
2041 : 4 : switch (ptrace_event)
2042 : : {
2043 : 0 : case 0:
2044 : 0 : g_assert_no_errno (ptrace (PTRACE_CONT, pid, NULL, stop_signum));
2045 : 0 : break;
2046 : 4 : default:
2047 : 4 : g_assert_no_errno (ptrace (PTRACE_CONT, pid, NULL, 0));
2048 : 4 : break;
2049 : : }
2050 : 4 : break;
2051 : 3 : case SIGSTOP:
2052 : 3 : g_assert_no_errno (ptrace (PTRACE_CONT, pid, NULL, 0));
2053 : 3 : break;
2054 : 5 : default:
2055 : 5 : if (!WIFEXITED (wstatus) && !WIFSIGNALED (wstatus))
2056 : 1 : g_assert_no_errno (ptrace (PTRACE_CONT, pid, NULL, stop_signum));
2057 : 5 : break;
2058 : : }
2059 : :
2060 : 12 : if (pid == main_child)
2061 : : {
2062 : 5 : g_assert_false (WIFSIGNALED (wstatus));
2063 : 5 : if (WIFEXITED (wstatus))
2064 : : {
2065 : 1 : g_assert_cmpint (WEXITSTATUS (wstatus), ==, EXIT_SUCCESS);
2066 : 1 : break;
2067 : : }
2068 : : }
2069 : : }
2070 : 1 : }
2071 : :
2072 : : #endif /* __linux__ */
2073 : :
2074 : : static void
2075 : 1 : test_exit_status_trapped (void)
2076 : : {
2077 : : #ifndef _GLIB_ADDRESS_SANITIZER
2078 : :
2079 : : #ifdef __linux__
2080 : 1 : GPtrArray *args = NULL;
2081 : : pid_t test_child;
2082 : : #endif
2083 : :
2084 : 1 : g_test_summary ("Test that exit status is reported correctly for ptrace()d child processes");
2085 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3433");
2086 : :
2087 : : #ifdef __linux__
2088 : : /* Call fork() directly here, rather than using #GSubprocess, so that we can
2089 : : * safely call waitpid() on it ourselves without interfering with the internals
2090 : : * of #GSubprocess.
2091 : : * See https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3433#note_1749055 */
2092 : 1 : args = get_test_subprocess_args ("sleep-and-kill", NULL);
2093 : 1 : test_child = fork ();
2094 : 2 : if (test_child == 0)
2095 : : {
2096 : : /* Between fork() and exec() we can only call async-signal-safe functions. */
2097 : 1 : if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) < 0)
2098 : 0 : abort ();
2099 : :
2100 : 1 : g_assert_no_errno (execvp (args->pdata[0], (char * const *) args->pdata));
2101 : : }
2102 : :
2103 : 2 : trace_children (test_child);
2104 : :
2105 : 1 : g_clear_pointer (&args, g_ptr_array_unref);
2106 : : #else
2107 : : g_test_skip ("ptrace() support for this test is only tested on Linux");
2108 : : #endif
2109 : :
2110 : : #else /* if defined (_GLIB_ADDRESS_SANITIZER) */
2111 : :
2112 : : g_test_skip ("LeakSanitizer does not work under ptrace");
2113 : : (void) trace_children;
2114 : :
2115 : : #endif /* _GLIB_ADDRESS_SANITIZER */
2116 : 1 : }
2117 : :
2118 : : #endif /* G_OS_UNIX */
2119 : :
2120 : : static void
2121 : 1 : test_launcher_environment (void)
2122 : : {
2123 : : GSubprocessLauncher *launcher;
2124 : 1 : GError *error = NULL;
2125 : : GSubprocess *proc;
2126 : : GPtrArray *args;
2127 : : gchar *out;
2128 : :
2129 : 1 : g_setenv ("A", "B", TRUE);
2130 : 1 : g_setenv ("C", "D", TRUE);
2131 : :
2132 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
2133 : :
2134 : : /* unset a variable */
2135 : 1 : g_subprocess_launcher_unsetenv (launcher, "A");
2136 : :
2137 : : /* and set a different one */
2138 : 1 : g_subprocess_launcher_setenv (launcher, "E", "F", TRUE);
2139 : :
2140 : 1 : args = get_test_subprocess_args ("printenv", "A", "C", "E", NULL);
2141 : 1 : proc = g_subprocess_launcher_spawnv (launcher, (const gchar **) args->pdata, &error);
2142 : 1 : g_assert_no_error (error);
2143 : 1 : g_assert_nonnull (proc);
2144 : :
2145 : 1 : g_subprocess_communicate_utf8 (proc, NULL, NULL, &out, NULL, &error);
2146 : 1 : g_assert_no_error (error);
2147 : :
2148 : 1 : g_assert_cmpstr (out, ==, "C=D" LINEEND "E=F" LINEEND);
2149 : 1 : g_free (out);
2150 : :
2151 : 1 : g_object_unref (proc);
2152 : 1 : g_object_unref (launcher);
2153 : 1 : g_ptr_array_unref (args);
2154 : 1 : }
2155 : :
2156 : : int
2157 : 5 : main (int argc, char **argv)
2158 : : {
2159 : : const struct
2160 : : {
2161 : : const gchar *subtest;
2162 : : GSubprocessFlags flags;
2163 : : }
2164 : 5 : flags_vectors[] =
2165 : : {
2166 : : { "", G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_MERGE },
2167 : : { "/no-pipes", G_SUBPROCESS_FLAGS_NONE },
2168 : : { "/separate-stderr", G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE },
2169 : : { "/stdout-only", G_SUBPROCESS_FLAGS_STDOUT_PIPE },
2170 : : { "/stderr-only", G_SUBPROCESS_FLAGS_STDERR_PIPE },
2171 : : { "/stdout-silence", G_SUBPROCESS_FLAGS_STDOUT_SILENCE },
2172 : : };
2173 : : gsize i;
2174 : :
2175 : 5 : g_test_init (&argc, &argv, NULL);
2176 : :
2177 : 5 : g_test_add_func ("/gsubprocess/noop", test_noop);
2178 : 5 : g_test_add_func ("/gsubprocess/noop-all-to-null", test_noop_all_to_null);
2179 : 5 : g_test_add_func ("/gsubprocess/noop-no-wait", test_noop_no_wait);
2180 : 5 : g_test_add_func ("/gsubprocess/noop-stdin-inherit", test_noop_stdin_inherit);
2181 : : #ifdef G_OS_UNIX
2182 : 5 : g_test_add_func ("/gsubprocess/search-path", test_search_path);
2183 : 5 : g_test_add_func ("/gsubprocess/search-path-from-envp", test_search_path_from_envp);
2184 : 5 : g_test_add_func ("/gsubprocess/signal", test_signal);
2185 : : #endif
2186 : 5 : g_test_add_func ("/gsubprocess/exit1", test_exit1);
2187 : 5 : g_test_add_func ("/gsubprocess/exit1/cancel", test_exit1_cancel);
2188 : 5 : g_test_add_func ("/gsubprocess/exit1/cancel_in_cb", test_exit1_cancel_in_cb);
2189 : 5 : g_test_add_func ("/gsubprocess/echo1", test_echo1);
2190 : : #ifdef G_OS_UNIX
2191 : 5 : g_test_add_func ("/gsubprocess/echo-merged", test_echo_merged);
2192 : : #endif
2193 : 5 : g_test_add_func ("/gsubprocess/cat-utf8", test_cat_utf8);
2194 : 5 : g_test_add_func ("/gsubprocess/cat-eof", test_cat_eof);
2195 : 5 : g_test_add_func ("/gsubprocess/multi1", test_multi_1);
2196 : :
2197 : : /* Add various tests for g_subprocess_communicate() with different flags. */
2198 : 35 : for (i = 0; i < G_N_ELEMENTS (flags_vectors); i++)
2199 : : {
2200 : 30 : gchar *test_path = NULL;
2201 : :
2202 : 30 : test_path = g_strdup_printf ("/gsubprocess/communicate%s", flags_vectors[i].subtest);
2203 : 30 : g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
2204 : : test_communicate);
2205 : 30 : g_free (test_path);
2206 : :
2207 : 30 : test_path = g_strdup_printf ("/gsubprocess/communicate/cancelled%s", flags_vectors[i].subtest);
2208 : 30 : g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
2209 : : test_communicate_cancelled);
2210 : 30 : g_free (test_path);
2211 : :
2212 : 30 : test_path = g_strdup_printf ("/gsubprocess/communicate/async%s", flags_vectors[i].subtest);
2213 : 30 : g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
2214 : : test_communicate_async);
2215 : 30 : g_free (test_path);
2216 : :
2217 : 30 : test_path = g_strdup_printf ("/gsubprocess/communicate/async/cancelled%s", flags_vectors[i].subtest);
2218 : 30 : g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
2219 : : test_communicate_cancelled_async);
2220 : 30 : g_free (test_path);
2221 : :
2222 : 30 : test_path = g_strdup_printf ("/gsubprocess/communicate/utf8%s", flags_vectors[i].subtest);
2223 : 30 : g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
2224 : : test_communicate_utf8);
2225 : 30 : g_free (test_path);
2226 : :
2227 : 30 : test_path = g_strdup_printf ("/gsubprocess/communicate/utf8/cancelled%s", flags_vectors[i].subtest);
2228 : 30 : g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
2229 : : test_communicate_utf8_cancelled);
2230 : 30 : g_free (test_path);
2231 : :
2232 : 30 : test_path = g_strdup_printf ("/gsubprocess/communicate/utf8/async%s", flags_vectors[i].subtest);
2233 : 30 : g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
2234 : : test_communicate_utf8_async);
2235 : 30 : g_free (test_path);
2236 : :
2237 : 30 : test_path = g_strdup_printf ("/gsubprocess/communicate/utf8/async/cancelled%s", flags_vectors[i].subtest);
2238 : 30 : g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
2239 : : test_communicate_utf8_cancelled_async);
2240 : 30 : g_free (test_path);
2241 : : }
2242 : :
2243 : 5 : g_test_add_func ("/gsubprocess/communicate/utf8/async/invalid", test_communicate_utf8_async_invalid);
2244 : 5 : g_test_add_func ("/gsubprocess/communicate/utf8/invalid", test_communicate_utf8_invalid);
2245 : 5 : g_test_add_func ("/gsubprocess/communicate/nothing", test_communicate_nothing);
2246 : 5 : g_test_add_func ("/gsubprocess/terminate", test_terminate);
2247 : 5 : g_test_add_func ("/gsubprocess/env", test_env);
2248 : 5 : g_test_add_func ("/gsubprocess/env/inherit", test_env_inherit);
2249 : 5 : g_test_add_func ("/gsubprocess/cwd", test_cwd);
2250 : : #ifdef G_OS_UNIX
2251 : 5 : g_test_add_func ("/gsubprocess/launcher-close", test_subprocess_launcher_close);
2252 : 5 : g_test_add_func ("/gsubprocess/stdout-file", test_stdout_file);
2253 : 5 : g_test_add_func ("/gsubprocess/stdout-fd", test_stdout_fd);
2254 : 5 : g_test_add_func ("/gsubprocess/child-setup", test_child_setup);
2255 : 5 : g_test_add_func ("/gsubprocess/pass-fd/basic", test_pass_fd);
2256 : 5 : g_test_add_func ("/gsubprocess/pass-fd/empty-child-setup", test_pass_fd_empty_child_setup);
2257 : 5 : g_test_add_func ("/gsubprocess/pass-fd/inherit-fds", test_pass_fd_inherit_fds);
2258 : 5 : g_test_add_func ("/gsubprocess/fd-conflation/basic", test_fd_conflation);
2259 : 5 : g_test_add_func ("/gsubprocess/fd-conflation/empty-child-setup", test_fd_conflation_empty_child_setup);
2260 : 5 : g_test_add_func ("/gsubprocess/fd-conflation/inherit-fds", test_fd_conflation_inherit_fds);
2261 : 5 : g_test_add_func ("/gsubprocess/fd-conflation/child-err-report-fd", test_fd_conflation_child_err_report_fd);
2262 : 5 : g_test_add_func ("/gsubprocess/exit-status/trapped", test_exit_status_trapped);
2263 : : #endif
2264 : 5 : g_test_add_func ("/gsubprocess/launcher-environment", test_launcher_environment);
2265 : :
2266 : 5 : return g_test_run ();
2267 : : }
|