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