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