LCOV - code coverage report
Current view: top level - glib/glib/tests - spawn-test.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 108 109 99.1 %
Date: 2024-03-26 05:16:46 Functions: 3 3 100.0 %
Branches: 47 48 97.9 %

           Branch data     Line data    Source code
       1                 :            : /* GLIB - Library of useful routines for C programming
       2                 :            :  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       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 <http://www.gnu.org/licenses/>.
      18                 :            :  */
      19                 :            : 
      20                 :            : /*
      21                 :            :  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      22                 :            :  * file for a list of people on the GLib Team.  See the ChangeLog
      23                 :            :  * files for a list of changes.  These files are distributed with
      24                 :            :  * GLib at ftp://ftp.gtk.org/pub/gtk/.
      25                 :            :  */
      26                 :            : 
      27                 :            : #include <glib.h>
      28                 :            : #include <glib/gstdio.h>
      29                 :            : 
      30                 :            : #ifdef G_OS_UNIX
      31                 :            : #include <unistd.h>
      32                 :            : #endif
      33                 :            : 
      34                 :            : #ifdef G_OS_WIN32
      35                 :            : #define WIN32_LEAN_AND_MEAN
      36                 :            : #include <windows.h>
      37                 :            : #include <fcntl.h>
      38                 :            : #include <io.h>
      39                 :            : #define pipe(fds) _pipe(fds, 4096, _O_BINARY)
      40                 :            : #endif
      41                 :            : 
      42                 :            : #ifdef G_OS_WIN32
      43                 :            : static gchar *dirname = NULL;
      44                 :            : #endif
      45                 :            : 
      46                 :            : #ifdef G_OS_WIN32
      47                 :            : static char *
      48                 :            : get_system_directory (void)
      49                 :            : {
      50                 :            :   wchar_t path_utf16[MAX_PATH] = {0};
      51                 :            :   char *path = NULL;
      52                 :            : 
      53                 :            :   if (!GetSystemDirectoryW (path_utf16, G_N_ELEMENTS (path_utf16)))
      54                 :            :     g_error ("%s failed with error code %u", "GetSystemWindowsDirectory",
      55                 :            :              (unsigned int) GetLastError ());
      56                 :            : 
      57                 :            :   path = g_utf16_to_utf8 (path_utf16, -1, NULL, NULL, NULL);
      58                 :            :   g_assert_nonnull (path);
      59                 :            : 
      60                 :            :   return path;
      61                 :            : }
      62                 :            : 
      63                 :            : static wchar_t *
      64                 :            : g_wcsdup (const wchar_t *wcs_string)
      65                 :            : {
      66                 :            :   size_t length = wcslen (wcs_string);
      67                 :            : 
      68                 :            :   return g_memdup2 (wcs_string, (length + 1) * sizeof (wchar_t));
      69                 :            : }
      70                 :            : 
      71                 :            : static wchar_t *
      72                 :            : g_wcsndup (const wchar_t *wcs_string,
      73                 :            :            size_t         length)
      74                 :            : {
      75                 :            :   wchar_t *result = NULL;
      76                 :            : 
      77                 :            :   g_assert_true (length < SIZE_MAX);
      78                 :            : 
      79                 :            :   result = g_new (wchar_t, length + 1);
      80                 :            :   memcpy (result, wcs_string, length * sizeof (wchar_t));
      81                 :            :   result[length] = L'\0';
      82                 :            : 
      83                 :            :   return result;
      84                 :            : }
      85                 :            : 
      86                 :            : /**
      87                 :            :  * parse_environment_string:
      88                 :            :  *
      89                 :            :  * @string: source environment string in the form <VARIABLE>=<VALUE>
      90                 :            :  *          (e.g as returned by GetEnvironmentStrings)
      91                 :            :  * @name: (out) (optional) (utf-16) name of the variable
      92                 :            :  * @value: (out) (optional) (utf-16) value of the variable
      93                 :            :  *
      94                 :            :  * Parse environment string in the form <VARIABLE>=<VALUE>, for example
      95                 :            :  * the strings in the environment block returned by GetEnvironmentStrings.
      96                 :            :  *
      97                 :            :  * Returns: %TRUE on success
      98                 :            :  */
      99                 :            : static gboolean
     100                 :            : parse_environment_string (const wchar_t  *string,
     101                 :            :                           wchar_t       **name,
     102                 :            :                           wchar_t       **value)
     103                 :            : {
     104                 :            :   const wchar_t *equal_sign;
     105                 :            : 
     106                 :            :   g_assert_nonnull (string);
     107                 :            :   g_assert_true (name || value);
     108                 :            : 
     109                 :            :   /* On Windows environment variables may have an equal-sign
     110                 :            :    * character as part of their name, but only as the first
     111                 :            :    * character */
     112                 :            :   equal_sign = wcschr (string[0] == L'=' ? (string + 1) : string, L'=');
     113                 :            : 
     114                 :            :   if (name)
     115                 :            :     *name = equal_sign ? g_wcsndup (string, equal_sign - string) : NULL;
     116                 :            : 
     117                 :            :   if (value)
     118                 :            :     *value = equal_sign ? g_wcsdup (equal_sign + 1) : NULL;
     119                 :            : 
     120                 :            :   return (equal_sign != NULL);
     121                 :            : }
     122                 :            : 
     123                 :            : /**
     124                 :            :  * find_cmd_shell_environment_variables:
     125                 :            :  *
     126                 :            :  * Finds all the environment variables related to cmd.exe, which are
     127                 :            :  * usually (but not always) present in a process environment block.
     128                 :            :  * Those environment variables are named "=X:", where X is a drive /
     129                 :            :  * volume letter and are used by cmd.exe to track per-drive current
     130                 :            :  * directories.
     131                 :            :  *
     132                 :            :  * See "What are these strange =C: environment variables?"
     133                 :            :  * https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
     134                 :            :  *
     135                 :            :  * This is used to test a work around for an UCRT issue
     136                 :            :  * https://developercommunity.visualstudio.com/t/UCRT-Crash-in-_wspawne-functions/10262748
     137                 :            :  */
     138                 :            : static GList *
     139                 :            : find_cmd_shell_environment_variables (void)
     140                 :            : {
     141                 :            :   wchar_t *block = NULL;
     142                 :            :   wchar_t *iter = NULL;
     143                 :            :   GList *variables = NULL;
     144                 :            :   size_t len = 0;
     145                 :            : 
     146                 :            :   block = GetEnvironmentStringsW ();
     147                 :            :   if (!block)
     148                 :            :     {
     149                 :            :       DWORD code = GetLastError ();
     150                 :            :       g_error ("%s failed with error code %u",
     151                 :            :                "GetEnvironmentStrings", (unsigned int) code);
     152                 :            :     }
     153                 :            : 
     154                 :            :   iter = block;
     155                 :            : 
     156                 :            :   while ((len = wcslen (iter)))
     157                 :            :     {
     158                 :            :       if (iter[0] == L'=')
     159                 :            :         {
     160                 :            :           wchar_t *variable = NULL;
     161                 :            : 
     162                 :            :           g_assert_true (parse_environment_string (iter, &variable, NULL));
     163                 :            :           g_assert_nonnull (variable);
     164                 :            : 
     165                 :            :           variables = g_list_prepend (variables, variable);
     166                 :            :         }
     167                 :            : 
     168                 :            :       iter += len + 1;
     169                 :            :     }
     170                 :            : 
     171                 :            :   FreeEnvironmentStringsW (block);
     172                 :            : 
     173                 :            :   return variables;
     174                 :            : }
     175                 :            : 
     176                 :            : static void
     177                 :            : remove_environment_variables (GList *list)
     178                 :            : {
     179                 :            :   for (GList *l = list; l; l = l->next)
     180                 :            :     {
     181                 :            :       const wchar_t *variable = (const wchar_t*) l->data;
     182                 :            : 
     183                 :            :       if (!SetEnvironmentVariableW (variable, NULL))
     184                 :            :         {
     185                 :            :           DWORD code = GetLastError ();
     186                 :            :           g_error ("%s failed with error code %u",
     187                 :            :                    "SetEnvironmentVariable", (unsigned int) code);
     188                 :            :         }
     189                 :            :     }
     190                 :            : }
     191                 :            : #endif /* G_OS_WIN32 */
     192                 :            : 
     193                 :            : static void
     194                 :          1 : test_spawn_basics (void)
     195                 :            : {
     196                 :            :   gboolean result;
     197                 :          1 :   GError *err = NULL;
     198                 :          1 :   gchar *output = NULL;
     199                 :          1 :   gchar *erroutput = NULL;
     200                 :            : #ifdef G_OS_WIN32
     201                 :            :   int n;
     202                 :            :   char buf[100];
     203                 :            :   int pipedown[2], pipeup[2];
     204                 :            :   gchar **argv = NULL;
     205                 :            :   gchar **envp = g_get_environ ();
     206                 :            :   gchar *system_directory;
     207                 :            :   gchar spawn_binary[1000] = {0};
     208                 :            :   gchar full_cmdline[1000] = {0};
     209                 :            :   GList *cmd_shell_env_vars = NULL;
     210                 :            :   const LCID old_lcid = GetThreadUILanguage ();
     211                 :            :   const unsigned int initial_cp = GetConsoleOutputCP ();
     212                 :            : 
     213                 :            :   SetConsoleOutputCP (437); /* 437 means en-US codepage */
     214                 :            :   SetThreadUILanguage (MAKELCID (MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT));
     215                 :            :   system_directory = get_system_directory ();
     216                 :            : 
     217                 :            :   g_snprintf (spawn_binary, sizeof (spawn_binary),
     218                 :            :               "%s\\spawn-test-win32-gui.exe", dirname);
     219                 :            : #endif
     220                 :            : 
     221                 :          1 :   err = NULL;
     222                 :            :   result =
     223                 :          1 :     g_spawn_command_line_sync ("nonexistent_application foo 'bar baz' blah blah",
     224                 :            :                                NULL, NULL, NULL, &err);
     225                 :          1 :   g_assert_false (result);
     226                 :          1 :   g_assert_error (err, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
     227                 :          1 :   g_clear_error (&err);
     228                 :            : 
     229                 :          1 :   err = NULL;
     230                 :            :   result =
     231                 :          1 :     g_spawn_command_line_async ("nonexistent_application foo bar baz \"blah blah\"",
     232                 :            :                                 &err);
     233                 :          1 :   g_assert_false (result);
     234                 :          1 :   g_assert_error (err, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
     235                 :          1 :   g_clear_error (&err);
     236                 :            : 
     237                 :          1 :   err = NULL;
     238                 :            : #ifdef G_OS_UNIX
     239                 :          1 :   result = g_spawn_command_line_sync ("/bin/sh -c 'echo hello'",
     240                 :            :                                       &output, NULL, NULL, &err);
     241                 :          1 :   g_assert_no_error (err);
     242                 :          1 :   g_assert_true (result);
     243                 :          1 :   g_assert_cmpstr (output, ==, "hello\n");
     244                 :            : 
     245                 :          1 :   g_free (output);
     246                 :          1 :   output = NULL;
     247                 :            : #endif
     248                 :            : 
     249                 :            :   /* Running sort synchronously, collecting its output. 'sort' command
     250                 :            :    * is selected because it is non-builtin command on both unix and
     251                 :            :    * win32 with well-defined stdout behaviour.
     252                 :            :    * On win32 we use an absolute path to the system-provided sort.exe
     253                 :            :    * because a different sort.exe may be available in PATH. This is
     254                 :            :    * important e.g for the MSYS2 environment, which provides coreutils
     255                 :            :    * sort.exe
     256                 :            :    */
     257                 :          1 :   g_file_set_contents ("spawn-test-created-file.txt",
     258                 :            :                        "line first\nline 2\nline last\n", -1, &err);
     259                 :          1 :   g_assert_no_error(err);
     260                 :            : 
     261                 :            : #ifndef G_OS_WIN32
     262                 :          1 :   result = g_spawn_command_line_sync ("sort spawn-test-created-file.txt",
     263                 :            :                                       &output, &erroutput, NULL, &err);
     264                 :            : #else
     265                 :            :   g_snprintf (full_cmdline, sizeof (full_cmdline),
     266                 :            :               "'%s\\sort.exe' spawn-test-created-file.txt", system_directory);
     267                 :            :   result = g_spawn_command_line_sync (full_cmdline, &output, &erroutput, NULL, &err);
     268                 :            : #endif
     269                 :          1 :   g_assert_no_error (err);
     270                 :          1 :   g_assert_true (result);
     271                 :          1 :   g_assert_nonnull (output);
     272         [ -  + ]:          1 :   if (strchr (output, '\r') != NULL)
     273                 :          0 :     g_assert_cmpstr (output, ==, "line 2\r\nline first\r\nline last\r\n");
     274                 :            :   else
     275                 :          1 :     g_assert_cmpstr (output, ==, "line 2\nline first\nline last\n");
     276                 :          1 :   g_assert_cmpstr (erroutput, ==, "");
     277                 :            : 
     278                 :          1 :   g_free (output);
     279                 :          1 :   output = NULL;
     280                 :          1 :   g_free (erroutput);
     281                 :          1 :   erroutput = NULL;
     282                 :            : 
     283                 :            : #ifndef G_OS_WIN32
     284                 :          1 :   result = g_spawn_command_line_sync ("sort non-existing-file.txt",
     285                 :            :                                       NULL, &erroutput, NULL, &err);
     286                 :            : #else
     287                 :            :   g_snprintf (full_cmdline, sizeof (full_cmdline),
     288                 :            :               "'%s\\sort.exe' non-existing-file.txt", system_directory);
     289                 :            :   result = g_spawn_command_line_sync (full_cmdline, NULL, &erroutput, NULL, &err);
     290                 :            : #endif
     291                 :          1 :   g_assert_no_error (err);
     292                 :          1 :   g_assert_true (result);
     293                 :            : #ifndef G_OS_WIN32
     294                 :            :   /* Test against output of coreutils sort */
     295                 :          1 :   g_assert_true (g_str_has_prefix (erroutput, "sort: "));
     296                 :          1 :   g_assert_nonnull (strstr (erroutput, g_strerror (ENOENT)));
     297                 :            : #else
     298                 :            :   /* Test against output of windows sort */
     299                 :            :   {
     300                 :            :     gchar *file_not_found_message = g_win32_error_message (ERROR_FILE_NOT_FOUND);
     301                 :            :     g_test_message ("sort output: %s\nExpected message: %s", erroutput, file_not_found_message);
     302                 :            :     g_assert_nonnull (strstr (erroutput, file_not_found_message));
     303                 :            :     g_free (file_not_found_message);
     304                 :            :   }
     305                 :            : #endif
     306                 :          1 :   g_free (erroutput);
     307                 :          1 :   erroutput = NULL;
     308                 :          1 :   g_unlink ("spawn-test-created-file.txt");
     309                 :            : 
     310                 :            : #ifdef G_OS_WIN32
     311                 :            :   g_test_message ("Running spawn-test-win32-gui in various ways.");
     312                 :            : 
     313                 :            :   g_test_message ("First asynchronously (without wait).");
     314                 :            :   g_snprintf (full_cmdline, sizeof (full_cmdline), "'%s' 1", spawn_binary);
     315                 :            :   result = g_spawn_command_line_async (full_cmdline, &err);
     316                 :            :   g_assert_no_error (err);
     317                 :            :   g_assert_true (result);
     318                 :            : 
     319                 :            :   g_test_message ("Now synchronously, collecting its output.");
     320                 :            :   g_snprintf (full_cmdline, sizeof (full_cmdline), "'%s' 2", spawn_binary);
     321                 :            :   result =
     322                 :            :     g_spawn_command_line_sync (full_cmdline, &output, &erroutput, NULL, &err);
     323                 :            : 
     324                 :            :   g_assert_no_error (err);
     325                 :            :   g_assert_true (result);
     326                 :            :   g_assert_cmpstr (output, ==, "# This is stdout\r\n");
     327                 :            :   g_assert_cmpstr (erroutput, ==, "This is stderr\r\n");
     328                 :            : 
     329                 :            :   g_free (output);
     330                 :            :   output = NULL;
     331                 :            :   g_free (erroutput);
     332                 :            :   erroutput = NULL;
     333                 :            : 
     334                 :            :   g_test_message ("Now with G_SPAWN_FILE_AND_ARGV_ZERO.");
     335                 :            :   g_snprintf (full_cmdline, sizeof (full_cmdline),
     336                 :            :               "'%s' this-should-be-argv-zero print_argv0", spawn_binary);
     337                 :            :   result = g_shell_parse_argv (full_cmdline, NULL, &argv, &err);
     338                 :            :   g_assert_no_error (err);
     339                 :            :   g_assert_true (result);
     340                 :            : 
     341                 :            :   result = g_spawn_sync (NULL, argv, NULL, G_SPAWN_FILE_AND_ARGV_ZERO,
     342                 :            :                          NULL, NULL, &output, NULL, NULL, &err);
     343                 :            :   g_assert_no_error (err);
     344                 :            :   g_assert_true (result);
     345                 :            :   g_assert_cmpstr (output, ==, "this-should-be-argv-zero");
     346                 :            : 
     347                 :            :   g_free (output);
     348                 :            :   output = NULL;
     349                 :            :   g_free (argv);
     350                 :            :   argv = NULL;
     351                 :            : 
     352                 :            :   g_test_message ("Now talking to it through pipes.");
     353                 :            :   g_assert_cmpint (pipe (pipedown), >=, 0);
     354                 :            :   g_assert_cmpint (pipe (pipeup), >=, 0);
     355                 :            : 
     356                 :            :   g_snprintf (full_cmdline, sizeof (full_cmdline), "'%s' pipes %d %d",
     357                 :            :               spawn_binary, pipedown[0], pipeup[1]);
     358                 :            : 
     359                 :            :   result = g_shell_parse_argv (full_cmdline, NULL, &argv, &err);
     360                 :            :   g_assert_no_error (err);
     361                 :            :   g_assert_true (result);
     362                 :            : 
     363                 :            :   result = g_spawn_async (NULL, argv, NULL,
     364                 :            :                           G_SPAWN_LEAVE_DESCRIPTORS_OPEN |
     365                 :            :                           G_SPAWN_DO_NOT_REAP_CHILD,
     366                 :            :                           NULL, NULL, NULL,
     367                 :            :                           &err);
     368                 :            :   g_assert_no_error (err);
     369                 :            :   g_assert_true (result);
     370                 :            :   g_free (argv);
     371                 :            :   argv = NULL;
     372                 :            : 
     373                 :            :   g_assert_cmpint (read (pipeup[0], &n, sizeof (n)), ==, sizeof (n));
     374                 :            :   g_assert_cmpint (read (pipeup[0], buf, n), ==, n);
     375                 :            : 
     376                 :            :   n = strlen ("Bye then");
     377                 :            :   g_assert_cmpint (write (pipedown[1], &n, sizeof (n)), !=, -1);
     378                 :            :   g_assert_cmpint (write (pipedown[1], "Bye then", n), !=, -1);
     379                 :            : 
     380                 :            :   g_assert_cmpint (read (pipeup[0], &n, sizeof (n)), ==, sizeof (n));
     381                 :            :   g_assert_cmpint (n, ==, strlen ("See ya"));
     382                 :            : 
     383                 :            :   g_assert_cmpint (read (pipeup[0], buf, n), ==, n);
     384                 :            : 
     385                 :            :   buf[n] = '\0';
     386                 :            :   g_assert_cmpstr (buf, ==, "See ya");
     387                 :            : 
     388                 :            :   /* Test workaround for:
     389                 :            :    *
     390                 :            :    * https://developercommunity.visualstudio.com/t/UCRT-Crash-in-_wspawne-functions/10262748
     391                 :            :    */
     392                 :            :   cmd_shell_env_vars = find_cmd_shell_environment_variables ();
     393                 :            :   remove_environment_variables (cmd_shell_env_vars);
     394                 :            : 
     395                 :            :   g_snprintf (full_cmdline, sizeof (full_cmdline),
     396                 :            :               "'%s\\sort.exe' non-existing-file.txt", system_directory);
     397                 :            :   g_assert_true (g_shell_parse_argv (full_cmdline, NULL, &argv, NULL));
     398                 :            :   g_assert_nonnull (argv);
     399                 :            :   g_spawn_sync (NULL, argv, envp, G_SPAWN_DEFAULT,
     400                 :            :                 NULL, NULL, NULL, NULL, NULL, NULL);
     401                 :            :   g_free (argv);
     402                 :            :   argv = NULL;
     403                 :            : #endif
     404                 :            : 
     405                 :            : #ifdef G_OS_WIN32
     406                 :            :   SetThreadUILanguage (old_lcid);
     407                 :            :   SetConsoleOutputCP (initial_cp); /* 437 means en-US codepage */
     408                 :            :   g_list_free_full (cmd_shell_env_vars, g_free);
     409                 :            :   g_strfreev (envp);
     410                 :            :   g_free (system_directory);
     411                 :            : #endif
     412                 :          1 : }
     413                 :            : 
     414                 :            : #ifdef G_OS_UNIX
     415                 :            : static void
     416                 :          1 : test_spawn_stdio_overwrite (void)
     417                 :            : {
     418                 :            :   gboolean result;
     419                 :            :   int ret;
     420                 :          1 :   GError *error = NULL;
     421                 :          1 :   int old_stdin_fd = -1;
     422                 :          1 :   int old_stdout_fd = -1;
     423                 :          1 :   int old_stderr_fd = -1;
     424                 :          1 :   char **envp = g_get_environ ();
     425                 :            :   enum OpenState { OPENED = 0, CLOSED = 1, DONE = 2 } stdin_state, stdout_state, stderr_state, output_return_state, error_return_state;
     426                 :            : 
     427                 :          1 :   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/16");
     428                 :            : 
     429                 :          1 :   old_stdin_fd = dup (STDIN_FILENO);
     430                 :          1 :   old_stdout_fd = dup (STDOUT_FILENO);
     431                 :          1 :   old_stderr_fd = dup (STDERR_FILENO);
     432                 :            : 
     433         [ +  + ]:          3 :   for (output_return_state = OPENED; output_return_state != DONE; output_return_state++)
     434         [ +  + ]:          6 :     for (error_return_state = OPENED; error_return_state != DONE; error_return_state++)
     435         [ +  + ]:         12 :       for (stdin_state = OPENED; stdin_state != DONE; stdin_state++)
     436         [ +  + ]:         24 :         for (stdout_state = OPENED; stdout_state != DONE; stdout_state++)
     437         [ +  + ]:         48 :           for (stderr_state = OPENED; stderr_state != DONE; stderr_state++)
     438                 :            :     {
     439                 :         32 :         char *command_line = NULL;
     440                 :         32 :         char **argv = NULL;
     441                 :         32 :         gchar *standard_output = NULL;
     442                 :         32 :         gchar *standard_error = NULL;
     443                 :            : 
     444   [ +  +  +  +  :         48 :         g_test_message ("Fetching GSpawn result %s%s%s with stdin %s, stdout %s, stderr %s",
          +  +  +  +  +  
                +  +  + ]
     445                 :            :                         output_return_state == OPENED? "output" : "",
     446         [ +  + ]:         16 :                         output_return_state == OPENED && error_return_state == OPENED? " and " : "",
     447                 :            :                         error_return_state == OPENED? "error output" : "",
     448                 :            :                         stdin_state == CLOSED? "already closed" : "open",
     449                 :            :                         stdout_state == CLOSED? "already closed" : "open",
     450                 :            :                         stderr_state == CLOSED? "already closed" : "open");
     451                 :            : 
     452         [ +  + ]:         32 :         if (stdin_state == CLOSED)
     453                 :            :           {
     454                 :         16 :             g_close (STDIN_FILENO, &error);
     455                 :         16 :             g_assert_no_error (error);
     456                 :            :           }
     457                 :            : 
     458         [ +  + ]:         32 :         if (stdout_state == CLOSED)
     459                 :            :           {
     460                 :         16 :             g_close (STDOUT_FILENO, &error);
     461                 :         16 :             g_assert_no_error (error);
     462                 :            :           }
     463                 :            : 
     464         [ +  + ]:         32 :         if (stderr_state == CLOSED)
     465                 :            :           {
     466                 :         16 :             g_close (STDERR_FILENO, &error);
     467                 :         16 :             g_assert_no_error (error);
     468                 :            :           }
     469                 :            : 
     470   [ +  +  +  +  :         48 :         command_line = g_strdup_printf ("/bin/sh -c '%s%s%s'",
                   +  + ]
     471                 :            :                                         output_return_state == OPENED? "echo stdout": "",
     472         [ +  + ]:         16 :                                         output_return_state == OPENED && error_return_state == OPENED? ";" : "",
     473                 :            :                                         error_return_state == OPENED? "echo stderr >&2": "");
     474                 :         32 :         g_shell_parse_argv (command_line, NULL, &argv, &error);
     475                 :         32 :         g_assert_no_error (error);
     476                 :            : 
     477                 :         32 :         g_clear_pointer (&command_line, g_free);
     478                 :            : 
     479   [ +  +  +  + ]:         32 :         result = g_spawn_sync (NULL,
     480                 :            :                                argv, envp, G_SPAWN_SEARCH_PATH_FROM_ENVP,
     481                 :            :                                NULL, NULL,
     482                 :            :                                output_return_state == OPENED? &standard_output : NULL,
     483                 :            :                                error_return_state == OPENED? &standard_error: NULL,
     484                 :            :                                NULL,
     485                 :            :                                &error);
     486                 :         32 :         g_clear_pointer (&argv, g_strfreev);
     487                 :            : 
     488                 :         32 :         ret = dup2 (old_stderr_fd, STDERR_FILENO);
     489                 :         32 :         g_assert_cmpint (ret, ==, STDERR_FILENO);
     490                 :            : 
     491                 :         32 :         ret = dup2 (old_stdout_fd, STDOUT_FILENO);
     492                 :         32 :         g_assert_cmpint (ret, ==, STDOUT_FILENO);
     493                 :            : 
     494                 :         32 :         ret = dup2 (old_stdin_fd, STDIN_FILENO);
     495                 :         32 :         g_assert_cmpint (ret, ==, STDIN_FILENO);
     496                 :            : 
     497                 :         32 :         g_assert_no_error (error);
     498                 :         32 :         g_assert_true (result);
     499                 :            : 
     500         [ +  + ]:         32 :         if (output_return_state == OPENED)
     501                 :            :           {
     502                 :         16 :             g_assert_cmpstr (standard_output, ==, "stdout\n");
     503                 :         16 :             g_clear_pointer (&standard_output, g_free);
     504                 :            :           }
     505                 :            : 
     506         [ +  + ]:         32 :         if (error_return_state == OPENED)
     507                 :            :           {
     508                 :         16 :             g_assert_cmpstr (standard_error, ==, "stderr\n");
     509                 :         16 :             g_clear_pointer (&standard_error, g_free);
     510                 :            :           }
     511                 :            :     }
     512                 :            : 
     513                 :          1 :   g_clear_fd (&old_stdin_fd, &error);
     514                 :          1 :   g_assert_no_error (error);
     515                 :            : 
     516                 :          1 :   g_clear_fd (&old_stdout_fd, &error);
     517                 :          1 :   g_assert_no_error (error);
     518                 :            : 
     519                 :          1 :   g_clear_fd (&old_stderr_fd, &error);
     520                 :          1 :   g_assert_no_error (error);
     521                 :            : 
     522                 :          1 :   g_clear_pointer (&envp, g_strfreev);
     523                 :          1 : }
     524                 :            : #endif
     525                 :            : 
     526                 :            : int
     527                 :          1 : main (int   argc,
     528                 :            :       char *argv[])
     529                 :            : {
     530                 :            :   int ret_val;
     531                 :            : 
     532                 :            : #ifdef G_OS_WIN32
     533                 :            :   dirname = g_path_get_dirname (argv[0]);
     534                 :            : #endif
     535                 :            : 
     536                 :          1 :   g_test_init (&argc, &argv, NULL);
     537                 :            : 
     538                 :          1 :   g_test_add_func ("/spawn/basics", test_spawn_basics);
     539                 :            : #ifdef G_OS_UNIX
     540                 :          1 :   g_test_add_func ("/spawn/stdio-overwrite", test_spawn_stdio_overwrite);
     541                 :            : #endif
     542                 :            : 
     543                 :          1 :   ret_val = g_test_run ();
     544                 :            : 
     545                 :            : #ifdef G_OS_WIN32
     546                 :            :   g_free (dirname);
     547                 :            : #endif
     548                 :          1 :   return ret_val;
     549                 :            : }

Generated by: LCOV version 1.14