Branch data Line data Source code
1 : : /*
2 : : * Copyright 2021 Collabora Ltd.
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this library; if not, see
18 : : * <http://www.gnu.org/licenses/>.
19 : : */
20 : :
21 : : #include <glib.h>
22 : :
23 : : #ifdef G_OS_UNIX
24 : : #include <sys/types.h>
25 : : #include <sys/wait.h>
26 : : #endif
27 : :
28 : : static gboolean
29 : 7 : skip_win32 (void)
30 : : {
31 : : #ifdef G_OS_WIN32
32 : : g_test_skip ("The test manipulate PATH, and breaks DLL lookups.");
33 : : return TRUE;
34 : : #else
35 : 7 : return FALSE;
36 : : #endif
37 : : }
38 : :
39 : : static void
40 : 1 : test_do_not_search (void)
41 : : {
42 : 1 : GPtrArray *argv = g_ptr_array_new_with_free_func (g_free);
43 : 1 : gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL);
44 : 1 : gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL);
45 : 1 : gchar **envp = g_get_environ ();
46 : 1 : gchar *out = NULL;
47 : 1 : gchar *err = NULL;
48 : 1 : GError *error = NULL;
49 : 1 : int wait_status = -1;
50 : :
51 : 1 : g_test_summary ("Without G_SPAWN_SEARCH_PATH, spawn-test-helper "
52 : : "means ./spawn-test-helper.");
53 : :
54 [ - + ]: 1 : if (skip_win32 ())
55 : 0 : return;
56 : :
57 : 1 : envp = g_environ_setenv (envp, "PATH", subdir, TRUE);
58 : :
59 : 1 : g_ptr_array_add (argv,
60 : 1 : g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL));
61 : 1 : g_ptr_array_add (argv, g_strdup ("--"));
62 : 1 : g_ptr_array_add (argv, g_strdup ("spawn-test-helper"));
63 : 1 : g_ptr_array_add (argv, NULL);
64 : :
65 : 1 : g_spawn_sync (here,
66 : 1 : (char **) argv->pdata,
67 : : envp,
68 : : G_SPAWN_DEFAULT,
69 : : NULL, /* child setup */
70 : : NULL, /* user data */
71 : : &out,
72 : : &err,
73 : : &wait_status,
74 : : &error);
75 : 1 : g_assert_no_error (error);
76 : :
77 : 1 : g_test_message ("%s", out);
78 : 1 : g_test_message ("%s", err);
79 : 1 : g_assert_nonnull (strstr (err, "this is spawn-test-helper from glib/tests"));
80 : :
81 : : #ifdef G_OS_UNIX
82 : 1 : g_assert_true (WIFEXITED (wait_status));
83 : 1 : g_assert_cmpint (WEXITSTATUS (wait_status), ==, 0);
84 : : #endif
85 : :
86 : 1 : g_strfreev (envp);
87 : 1 : g_free (here);
88 : 1 : g_free (subdir);
89 : 1 : g_free (out);
90 : 1 : g_free (err);
91 : 1 : g_ptr_array_unref (argv);
92 : : }
93 : :
94 : : static void
95 : 1 : test_search_path (void)
96 : : {
97 : 1 : GPtrArray *argv = g_ptr_array_new_with_free_func (g_free);
98 : 1 : gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL);
99 : 1 : gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL);
100 : 1 : gchar **envp = g_get_environ ();
101 : 1 : gchar *out = NULL;
102 : 1 : gchar *err = NULL;
103 : 1 : GError *error = NULL;
104 : 1 : int wait_status = -1;
105 : :
106 : 1 : g_test_summary ("With G_SPAWN_SEARCH_PATH, spawn-test-helper "
107 : : "means $PATH/spawn-test-helper.");
108 : :
109 [ - + ]: 1 : if (skip_win32 ())
110 : 0 : return;
111 : :
112 : 1 : envp = g_environ_setenv (envp, "PATH", subdir, TRUE);
113 : :
114 : 1 : g_ptr_array_add (argv,
115 : 1 : g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL));
116 : 1 : g_ptr_array_add (argv, g_strdup ("--search-path"));
117 : 1 : g_ptr_array_add (argv, g_strdup ("--"));
118 : 1 : g_ptr_array_add (argv, g_strdup ("spawn-test-helper"));
119 : 1 : g_ptr_array_add (argv, NULL);
120 : :
121 : 1 : g_spawn_sync (here,
122 : 1 : (char **) argv->pdata,
123 : : envp,
124 : : G_SPAWN_DEFAULT,
125 : : NULL, /* child setup */
126 : : NULL, /* user data */
127 : : &out,
128 : : &err,
129 : : &wait_status,
130 : : &error);
131 : 1 : g_assert_no_error (error);
132 : :
133 : 1 : g_test_message ("%s", out);
134 : 1 : g_test_message ("%s", err);
135 : 1 : g_assert_nonnull (strstr (err, "this is spawn-test-helper from path-test-subdir"));
136 : :
137 : : #ifdef G_OS_UNIX
138 : 1 : g_assert_true (WIFEXITED (wait_status));
139 : 1 : g_assert_cmpint (WEXITSTATUS (wait_status), ==, 5);
140 : : #endif
141 : :
142 : 1 : g_strfreev (envp);
143 : 1 : g_free (here);
144 : 1 : g_free (subdir);
145 : 1 : g_free (out);
146 : 1 : g_free (err);
147 : 1 : g_ptr_array_unref (argv);
148 : : }
149 : :
150 : : static void
151 : 1 : test_search_path_from_envp (void)
152 : : {
153 : 1 : GPtrArray *argv = g_ptr_array_new_with_free_func (g_free);
154 : 1 : gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL);
155 : 1 : gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL);
156 : 1 : gchar **envp = g_get_environ ();
157 : 1 : gchar *out = NULL;
158 : 1 : gchar *err = NULL;
159 : 1 : GError *error = NULL;
160 : 1 : int wait_status = -1;
161 : :
162 : 1 : g_test_summary ("With G_SPAWN_SEARCH_PATH_FROM_ENVP, spawn-test-helper "
163 : : "means $PATH/spawn-test-helper with $PATH from envp.");
164 : :
165 [ - + ]: 1 : if (skip_win32 ())
166 : 0 : return;
167 : :
168 : 1 : envp = g_environ_setenv (envp, "PATH", here, TRUE);
169 : :
170 : 1 : g_ptr_array_add (argv,
171 : 1 : g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL));
172 : 1 : g_ptr_array_add (argv, g_strdup ("--search-path-from-envp"));
173 : 1 : g_ptr_array_add (argv, g_strdup ("--set-path-in-envp"));
174 : 1 : g_ptr_array_add (argv, g_strdup (subdir));
175 : 1 : g_ptr_array_add (argv, g_strdup ("--"));
176 : 1 : g_ptr_array_add (argv, g_strdup ("spawn-test-helper"));
177 : 1 : g_ptr_array_add (argv, NULL);
178 : :
179 : 1 : g_spawn_sync (here,
180 : 1 : (char **) argv->pdata,
181 : : envp,
182 : : G_SPAWN_DEFAULT,
183 : : NULL, /* child setup */
184 : : NULL, /* user data */
185 : : &out,
186 : : &err,
187 : : &wait_status,
188 : : &error);
189 : 1 : g_assert_no_error (error);
190 : :
191 : 1 : g_test_message ("%s", out);
192 : 1 : g_test_message ("%s", err);
193 : 1 : g_assert_nonnull (strstr (err, "this is spawn-test-helper from path-test-subdir"));
194 : :
195 : : #ifdef G_OS_UNIX
196 : 1 : g_assert_true (WIFEXITED (wait_status));
197 : 1 : g_assert_cmpint (WEXITSTATUS (wait_status), ==, 5);
198 : : #endif
199 : :
200 : 1 : g_strfreev (envp);
201 : 1 : g_free (here);
202 : 1 : g_free (subdir);
203 : 1 : g_free (out);
204 : 1 : g_free (err);
205 : 1 : g_ptr_array_unref (argv);
206 : : }
207 : :
208 : : static void
209 : 1 : test_search_path_ambiguous (void)
210 : : {
211 : 1 : GPtrArray *argv = g_ptr_array_new_with_free_func (g_free);
212 : 1 : gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL);
213 : 1 : gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL);
214 : 1 : gchar **envp = g_get_environ ();
215 : 1 : gchar *out = NULL;
216 : 1 : gchar *err = NULL;
217 : 1 : GError *error = NULL;
218 : 1 : int wait_status = -1;
219 : :
220 : 1 : g_test_summary ("With G_SPAWN_SEARCH_PATH and G_SPAWN_SEARCH_PATH_FROM_ENVP, "
221 : : "the latter wins.");
222 : :
223 [ - + ]: 1 : if (skip_win32 ())
224 : 0 : return;
225 : :
226 : 1 : envp = g_environ_setenv (envp, "PATH", here, TRUE);
227 : :
228 : 1 : g_ptr_array_add (argv,
229 : 1 : g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL));
230 : 1 : g_ptr_array_add (argv, g_strdup ("--search-path"));
231 : 1 : g_ptr_array_add (argv, g_strdup ("--search-path-from-envp"));
232 : 1 : g_ptr_array_add (argv, g_strdup ("--set-path-in-envp"));
233 : 1 : g_ptr_array_add (argv, g_strdup (subdir));
234 : 1 : g_ptr_array_add (argv, g_strdup ("--"));
235 : 1 : g_ptr_array_add (argv, g_strdup ("spawn-test-helper"));
236 : 1 : g_ptr_array_add (argv, NULL);
237 : :
238 : 1 : g_spawn_sync (here,
239 : 1 : (char **) argv->pdata,
240 : : envp,
241 : : G_SPAWN_DEFAULT,
242 : : NULL, /* child setup */
243 : : NULL, /* user data */
244 : : &out,
245 : : &err,
246 : : &wait_status,
247 : : &error);
248 : 1 : g_assert_no_error (error);
249 : :
250 : 1 : g_test_message ("%s", out);
251 : 1 : g_test_message ("%s", err);
252 : 1 : g_assert_nonnull (strstr (err, "this is spawn-test-helper from path-test-subdir"));
253 : :
254 : : #ifdef G_OS_UNIX
255 : 1 : g_assert_true (WIFEXITED (wait_status));
256 : 1 : g_assert_cmpint (WEXITSTATUS (wait_status), ==, 5);
257 : : #endif
258 : :
259 : 1 : g_strfreev (envp);
260 : 1 : g_free (here);
261 : 1 : g_free (subdir);
262 : 1 : g_free (out);
263 : 1 : g_free (err);
264 : 1 : g_ptr_array_unref (argv);
265 : : }
266 : :
267 : : static void
268 : 1 : test_search_path_fallback_in_environ (void)
269 : : {
270 : 1 : GPtrArray *argv = g_ptr_array_new_with_free_func (g_free);
271 : 1 : gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL);
272 : 1 : gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL);
273 : 1 : gchar **envp = g_get_environ ();
274 : 1 : gchar *out = NULL;
275 : 1 : gchar *err = NULL;
276 : 1 : GError *error = NULL;
277 : 1 : int wait_status = -1;
278 : :
279 : 1 : g_test_summary ("With G_SPAWN_SEARCH_PATH but no PATH, a fallback is used.");
280 : :
281 [ - + ]: 1 : if (skip_win32 ())
282 : 0 : return;
283 : :
284 : : /* We can't make a meaningful assertion about what the fallback *is*,
285 : : * but we can assert that it *includes* the current working directory. */
286 : :
287 [ + - - + ]: 2 : if (g_file_test ("/usr/bin/spawn-test-helper", G_FILE_TEST_IS_EXECUTABLE) ||
288 : 1 : g_file_test ("/bin/spawn-test-helper", G_FILE_TEST_IS_EXECUTABLE))
289 : : {
290 : 0 : g_test_skip ("Not testing fallback with unknown spawn-test-helper "
291 : : "executable in /usr/bin:/bin");
292 : 0 : return;
293 : : }
294 : :
295 : 1 : envp = g_environ_unsetenv (envp, "PATH");
296 : :
297 : 1 : g_ptr_array_add (argv,
298 : 1 : g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL));
299 : 1 : g_ptr_array_add (argv, g_strdup ("--search-path"));
300 : 1 : g_ptr_array_add (argv, g_strdup ("--set-path-in-envp"));
301 : 1 : g_ptr_array_add (argv, g_strdup (subdir));
302 : 1 : g_ptr_array_add (argv, g_strdup ("--"));
303 : 1 : g_ptr_array_add (argv, g_strdup ("spawn-test-helper"));
304 : 1 : g_ptr_array_add (argv, NULL);
305 : :
306 : 1 : g_spawn_sync (here,
307 : 1 : (char **) argv->pdata,
308 : : envp,
309 : : G_SPAWN_DEFAULT,
310 : : NULL, /* child setup */
311 : : NULL, /* user data */
312 : : &out,
313 : : &err,
314 : : &wait_status,
315 : : &error);
316 : 1 : g_assert_no_error (error);
317 : :
318 : 1 : g_test_message ("%s", out);
319 : 1 : g_test_message ("%s", err);
320 : 1 : g_assert_nonnull (strstr (err, "this is spawn-test-helper from glib/tests"));
321 : :
322 : : #ifdef G_OS_UNIX
323 : 1 : g_assert_true (WIFEXITED (wait_status));
324 : 1 : g_assert_cmpint (WEXITSTATUS (wait_status), ==, 0);
325 : : #endif
326 : :
327 : 1 : g_strfreev (envp);
328 : 1 : g_free (here);
329 : 1 : g_free (subdir);
330 : 1 : g_free (out);
331 : 1 : g_free (err);
332 : 1 : g_ptr_array_unref (argv);
333 : : }
334 : :
335 : : static void
336 : 1 : test_search_path_fallback_in_envp (void)
337 : : {
338 : 1 : GPtrArray *argv = g_ptr_array_new_with_free_func (g_free);
339 : 1 : gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL);
340 : 1 : gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL);
341 : 1 : gchar **envp = g_get_environ ();
342 : 1 : gchar *out = NULL;
343 : 1 : gchar *err = NULL;
344 : 1 : GError *error = NULL;
345 : 1 : int wait_status = -1;
346 : :
347 : 1 : g_test_summary ("With G_SPAWN_SEARCH_PATH_FROM_ENVP but no PATH, a fallback is used.");
348 : : /* We can't make a meaningful assertion about what the fallback *is*,
349 : : * but we can assert that it *includes* the current working directory. */
350 : :
351 [ - + ]: 1 : if (skip_win32 ())
352 : 0 : return;
353 : :
354 [ + - - + ]: 2 : if (g_file_test ("/usr/bin/spawn-test-helper", G_FILE_TEST_IS_EXECUTABLE) ||
355 : 1 : g_file_test ("/bin/spawn-test-helper", G_FILE_TEST_IS_EXECUTABLE))
356 : : {
357 : 0 : g_test_skip ("Not testing fallback with unknown spawn-test-helper "
358 : : "executable in /usr/bin:/bin");
359 : 0 : return;
360 : : }
361 : :
362 : 1 : envp = g_environ_setenv (envp, "PATH", subdir, TRUE);
363 : :
364 : 1 : g_ptr_array_add (argv,
365 : 1 : g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL));
366 : 1 : g_ptr_array_add (argv, g_strdup ("--search-path-from-envp"));
367 : 1 : g_ptr_array_add (argv, g_strdup ("--unset-path-in-envp"));
368 : 1 : g_ptr_array_add (argv, g_strdup ("--"));
369 : 1 : g_ptr_array_add (argv, g_strdup ("spawn-test-helper"));
370 : 1 : g_ptr_array_add (argv, NULL);
371 : :
372 : 1 : g_spawn_sync (here,
373 : 1 : (char **) argv->pdata,
374 : : envp,
375 : : G_SPAWN_DEFAULT,
376 : : NULL, /* child setup */
377 : : NULL, /* user data */
378 : : &out,
379 : : &err,
380 : : &wait_status,
381 : : &error);
382 : 1 : g_assert_no_error (error);
383 : :
384 : 1 : g_test_message ("%s", out);
385 : 1 : g_test_message ("%s", err);
386 : 1 : g_assert_nonnull (strstr (err, "this is spawn-test-helper from glib/tests"));
387 : :
388 : : #ifdef G_OS_UNIX
389 : 1 : g_assert_true (WIFEXITED (wait_status));
390 : 1 : g_assert_cmpint (WEXITSTATUS (wait_status), ==, 0);
391 : : #endif
392 : :
393 : 1 : g_strfreev (envp);
394 : 1 : g_free (here);
395 : 1 : g_free (subdir);
396 : 1 : g_free (out);
397 : 1 : g_free (err);
398 : 1 : g_ptr_array_unref (argv);
399 : : }
400 : :
401 : : static void
402 : 1 : test_search_path_heap_allocation (void)
403 : : {
404 : 1 : GPtrArray *argv = g_ptr_array_new_with_free_func (g_free);
405 : : /* Must be longer than the arbitrary 4000 byte limit for stack allocation
406 : : * in gspawn.c */
407 : : char placeholder[4096];
408 : 1 : gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL);
409 : 1 : gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL);
410 : 1 : gchar *long_dir = NULL;
411 : 1 : gchar *long_path = NULL;
412 : 1 : gchar **envp = g_get_environ ();
413 : 1 : gchar *out = NULL;
414 : 1 : gchar *err = NULL;
415 : 1 : GError *error = NULL;
416 : 1 : int wait_status = -1;
417 : : gsize i;
418 : :
419 [ - + ]: 1 : if (skip_win32 ())
420 : 0 : return;
421 : :
422 : 1 : memset (placeholder, '_', sizeof (placeholder) - 1);
423 : 1 : placeholder[sizeof (placeholder) - 1] = '\0';
424 : : /* Force search_path_buffer to be heap-allocated */
425 : 1 : long_dir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", placeholder, NULL);
426 : 1 : long_path = g_strjoin (G_SEARCHPATH_SEPARATOR_S, subdir, long_dir, NULL);
427 : 1 : envp = g_environ_setenv (envp, "PATH", long_path, TRUE);
428 : 1 : g_free (long_path);
429 : 1 : g_free (long_dir);
430 : :
431 : 1 : g_ptr_array_add (argv,
432 : 1 : g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL));
433 : 1 : g_ptr_array_add (argv, g_strdup ("--search-path"));
434 : 1 : g_ptr_array_add (argv, g_strdup ("--"));
435 : 1 : g_ptr_array_add (argv, g_strdup ("spawn-test-helper"));
436 : :
437 : : /* Add enough arguments to make argv longer than the arbitrary 4000 byte
438 : : * limit for stack allocation in gspawn.c.
439 : : * This assumes sizeof (char *) >= 4. */
440 [ + + ]: 1002 : for (i = 0; i < 1001; i++)
441 : 1001 : g_ptr_array_add (argv, g_strdup ("_"));
442 : :
443 : 1 : g_ptr_array_add (argv, NULL);
444 : :
445 : 1 : g_spawn_sync (here,
446 : 1 : (char **) argv->pdata,
447 : : envp,
448 : : G_SPAWN_DEFAULT,
449 : : NULL, /* child setup */
450 : : NULL, /* user data */
451 : : &out,
452 : : &err,
453 : : &wait_status,
454 : : &error);
455 : 1 : g_assert_no_error (error);
456 : :
457 : 1 : g_test_message ("%s", out);
458 : 1 : g_test_message ("%s", err);
459 : 1 : g_assert_nonnull (strstr (err, "this is spawn-test-helper from path-test-subdir"));
460 : :
461 : : #ifdef G_OS_UNIX
462 : 1 : g_assert_true (WIFEXITED (wait_status));
463 : 1 : g_assert_cmpint (WEXITSTATUS (wait_status), ==, 5);
464 : : #endif
465 : :
466 : 1 : g_strfreev (envp);
467 : 1 : g_free (here);
468 : 1 : g_free (subdir);
469 : 1 : g_free (out);
470 : 1 : g_free (err);
471 : 1 : g_ptr_array_unref (argv);
472 : : }
473 : :
474 : : int
475 : 1 : main (int argc,
476 : : char **argv)
477 : : {
478 : 1 : g_test_init (&argc, &argv, NULL);
479 : :
480 : 1 : g_test_add_func ("/spawn/do-not-search", test_do_not_search);
481 : 1 : g_test_add_func ("/spawn/search-path", test_search_path);
482 : 1 : g_test_add_func ("/spawn/search-path-from-envp", test_search_path_from_envp);
483 : 1 : g_test_add_func ("/spawn/search-path-ambiguous", test_search_path_ambiguous);
484 : 1 : g_test_add_func ("/spawn/search-path-heap-allocation",
485 : : test_search_path_heap_allocation);
486 : 1 : g_test_add_func ("/spawn/search-path-fallback-in-environ",
487 : : test_search_path_fallback_in_environ);
488 : 1 : g_test_add_func ("/spawn/search-path-fallback-in-envp",
489 : : test_search_path_fallback_in_envp);
490 : :
491 : 1 : return g_test_run ();
492 : : }
|