LCOV - code coverage report
Current view: top level - glib/glib - gspawn.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 527 725 72.7 %
Date: 2024-04-23 05:16:05 Functions: 25 29 86.2 %
Branches: 318 497 64.0 %

           Branch data     Line data    Source code
       1                 :            : /* gspawn.c - Process launching
       2                 :            :  *
       3                 :            :  *  Copyright 2000 Red Hat, Inc.
       4                 :            :  *  g_execvpe implementation based on GNU libc execvp:
       5                 :            :  *   Copyright 1991, 92, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
       6                 :            :  *
       7                 :            :  * SPDX-License-Identifier: LGPL-2.1-or-later
       8                 :            :  *
       9                 :            :  * This library is free software; you can redistribute it and/or
      10                 :            :  * modify it under the terms of the GNU Lesser General Public
      11                 :            :  * License as published by the Free Software Foundation; either
      12                 :            :  * version 2.1 of the License, or (at your option) any later version.
      13                 :            :  *
      14                 :            :  * This library is distributed in the hope that it will be useful,
      15                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17                 :            :  * Lesser General Public License for more details.
      18                 :            :  *
      19                 :            :  * You should have received a copy of the GNU Lesser General Public License
      20                 :            :  * along with this library; if not, see <http://www.gnu.org/licenses/>.
      21                 :            :  */
      22                 :            : 
      23                 :            : #include "config.h"
      24                 :            : 
      25                 :            : #include <sys/time.h>
      26                 :            : #include <sys/types.h>
      27                 :            : #include <sys/wait.h>
      28                 :            : #include <unistd.h>
      29                 :            : #include <errno.h>
      30                 :            : #include <fcntl.h>
      31                 :            : #include <signal.h>
      32                 :            : #include <string.h>
      33                 :            : #include <stdlib.h>   /* for fdwalk */
      34                 :            : #include <dirent.h>
      35                 :            : #include <unistd.h>
      36                 :            : 
      37                 :            : #ifdef HAVE_SPAWN_H
      38                 :            : #include <spawn.h>
      39                 :            : #endif /* HAVE_SPAWN_H */
      40                 :            : 
      41                 :            : #ifdef HAVE_CRT_EXTERNS_H
      42                 :            : #include <crt_externs.h> /* for _NSGetEnviron */
      43                 :            : #endif
      44                 :            : 
      45                 :            : #ifdef HAVE_SYS_SELECT_H
      46                 :            : #include <sys/select.h>
      47                 :            : #endif /* HAVE_SYS_SELECT_H */
      48                 :            : 
      49                 :            : #ifdef HAVE_SYS_RESOURCE_H
      50                 :            : #include <sys/resource.h>
      51                 :            : #endif /* HAVE_SYS_RESOURCE_H */
      52                 :            : 
      53                 :            : #if defined(__linux__) || defined(__DragonFly__)
      54                 :            : #include <sys/syscall.h>  /* for syscall and SYS_getdents64 */
      55                 :            : #endif
      56                 :            : 
      57                 :            : #include "gspawn.h"
      58                 :            : #include "gspawn-private.h"
      59                 :            : #include "gthread.h"
      60                 :            : #include "gtrace-private.h"
      61                 :            : #include "glib/gstdio.h"
      62                 :            : 
      63                 :            : #include "genviron.h"
      64                 :            : #include "gmem.h"
      65                 :            : #include "gshell.h"
      66                 :            : #include "gstring.h"
      67                 :            : #include "gstrfuncs.h"
      68                 :            : #include "gtestutils.h"
      69                 :            : #include "gutils.h"
      70                 :            : #include "glibintl.h"
      71                 :            : #include "glib-unix.h"
      72                 :            : 
      73                 :            : #if defined(__APPLE__) && defined(HAVE_LIBPROC_H)
      74                 :            : #include <libproc.h>
      75                 :            : #include <sys/proc_info.h>
      76                 :            : #endif
      77                 :            : 
      78                 :            : #define INHERITS_OR_NULL_STDIN  (G_SPAWN_STDIN_FROM_DEV_NULL | G_SPAWN_CHILD_INHERITS_STDIN)
      79                 :            : #define INHERITS_OR_NULL_STDOUT (G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_CHILD_INHERITS_STDOUT)
      80                 :            : #define INHERITS_OR_NULL_STDERR (G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_CHILD_INHERITS_STDERR)
      81                 :            : 
      82                 :            : #define IS_STD_FILENO(_fd) ((_fd >= STDIN_FILENO) && (_fd <= STDERR_FILENO))
      83                 :            : #define IS_VALID_FILENO(_fd) (_fd >= 0)
      84                 :            : 
      85                 :            : /* posix_spawn() is assumed the fastest way to spawn, but glibc's
      86                 :            :  * implementation was buggy before glibc 2.24, so avoid it on old versions.
      87                 :            :  */
      88                 :            : #ifdef HAVE_POSIX_SPAWN
      89                 :            : #ifdef __GLIBC__
      90                 :            : 
      91                 :            : #if __GLIBC_PREREQ(2,24)
      92                 :            : #define POSIX_SPAWN_AVAILABLE
      93                 :            : #endif
      94                 :            : 
      95                 :            : #else /* !__GLIBC__ */
      96                 :            : /* Assume that all non-glibc posix_spawn implementations are fine. */
      97                 :            : #define POSIX_SPAWN_AVAILABLE
      98                 :            : #endif /* __GLIBC__ */
      99                 :            : #endif /* HAVE_POSIX_SPAWN */
     100                 :            : 
     101                 :            : #ifdef HAVE__NSGETENVIRON
     102                 :            : #define environ (*_NSGetEnviron())
     103                 :            : #else
     104                 :            : extern char **environ;
     105                 :            : #endif
     106                 :            : 
     107                 :            : #ifndef O_CLOEXEC
     108                 :            : #define O_CLOEXEC 0
     109                 :            : #else
     110                 :            : #define HAVE_O_CLOEXEC 1
     111                 :            : #endif
     112                 :            : 
     113                 :            : static gint g_execute (const gchar  *file,
     114                 :            :                        gchar       **argv,
     115                 :            :                        gchar       **argv_buffer,
     116                 :            :                        gsize         argv_buffer_len,
     117                 :            :                        gchar       **envp,
     118                 :            :                        const gchar  *search_path,
     119                 :            :                        gchar        *search_path_buffer,
     120                 :            :                        gsize         search_path_buffer_len);
     121                 :            : 
     122                 :            : static gboolean fork_exec (gboolean              intermediate_child,
     123                 :            :                            const gchar          *working_directory,
     124                 :            :                            const gchar * const  *argv,
     125                 :            :                            const gchar * const  *envp,
     126                 :            :                            gboolean              close_descriptors,
     127                 :            :                            gboolean              search_path,
     128                 :            :                            gboolean              search_path_from_envp,
     129                 :            :                            gboolean              stdout_to_null,
     130                 :            :                            gboolean              stderr_to_null,
     131                 :            :                            gboolean              child_inherits_stdin,
     132                 :            :                            gboolean              file_and_argv_zero,
     133                 :            :                            gboolean              cloexec_pipes,
     134                 :            :                            GSpawnChildSetupFunc  child_setup,
     135                 :            :                            gpointer              user_data,
     136                 :            :                            GPid                 *child_pid,
     137                 :            :                            gint                 *stdin_pipe_out,
     138                 :            :                            gint                 *stdout_pipe_out,
     139                 :            :                            gint                 *stderr_pipe_out,
     140                 :            :                            gint                  stdin_fd,
     141                 :            :                            gint                  stdout_fd,
     142                 :            :                            gint                  stderr_fd,
     143                 :            :                            const gint           *source_fds,
     144                 :            :                            const gint           *target_fds,
     145                 :            :                            gsize                 n_fds,
     146                 :            :                            GError              **error);
     147                 :            : 
     148         [ +  + ]:         31 : G_DEFINE_QUARK (g-exec-error-quark, g_spawn_error)
     149         [ +  + ]:         64 : G_DEFINE_QUARK (g-spawn-exit-error-quark, g_spawn_exit_error)
     150                 :            : 
     151                 :            : /**
     152                 :            :  * g_spawn_async:
     153                 :            :  * @working_directory: (type filename) (nullable): child's current working
     154                 :            :  *     directory, or %NULL to inherit parent's
     155                 :            :  * @argv: (array zero-terminated=1) (element-type filename):
     156                 :            :  *     child's argument vector
     157                 :            :  * @envp: (array zero-terminated=1) (element-type filename) (nullable):
     158                 :            :  *     child's environment, or %NULL to inherit parent's
     159                 :            :  * @flags: flags from #GSpawnFlags
     160                 :            :  * @child_setup: (scope async) (closure user_data) (nullable): function to run
     161                 :            :  *     in the child just before `exec()`
     162                 :            :  * @user_data: user data for @child_setup
     163                 :            :  * @child_pid: (out) (optional): return location for child process reference, or %NULL
     164                 :            :  * @error: return location for error
     165                 :            :  *
     166                 :            :  * Executes a child program asynchronously.
     167                 :            :  * 
     168                 :            :  * See g_spawn_async_with_pipes() for a full description; this function
     169                 :            :  * simply calls the g_spawn_async_with_pipes() without any pipes.
     170                 :            :  *
     171                 :            :  * You should call g_spawn_close_pid() on the returned child process
     172                 :            :  * reference when you don't need it any more.
     173                 :            :  * 
     174                 :            :  * If you are writing a GTK application, and the program you are spawning is a
     175                 :            :  * graphical application too, then to ensure that the spawned program opens its
     176                 :            :  * windows on the right screen, you may want to use #GdkAppLaunchContext,
     177                 :            :  * #GAppLaunchContext, or set the %DISPLAY environment variable.
     178                 :            :  *
     179                 :            :  * Note that the returned @child_pid on Windows is a handle to the child
     180                 :            :  * process and not its identifier. Process handles and process identifiers
     181                 :            :  * are different concepts on Windows.
     182                 :            :  *
     183                 :            :  * Returns: %TRUE on success, %FALSE if error is set
     184                 :            :  **/
     185                 :            : gboolean
     186                 :         38 : g_spawn_async (const gchar          *working_directory,
     187                 :            :                gchar               **argv,
     188                 :            :                gchar               **envp,
     189                 :            :                GSpawnFlags           flags,
     190                 :            :                GSpawnChildSetupFunc  child_setup,
     191                 :            :                gpointer              user_data,
     192                 :            :                GPid                 *child_pid,
     193                 :            :                GError              **error)
     194                 :            : {
     195                 :         38 :   return g_spawn_async_with_pipes (working_directory,
     196                 :            :                                    argv, envp,
     197                 :            :                                    flags,
     198                 :            :                                    child_setup,
     199                 :            :                                    user_data,
     200                 :            :                                    child_pid,
     201                 :            :                                    NULL, NULL, NULL,
     202                 :            :                                    error);
     203                 :            : }
     204                 :            : 
     205                 :            : /* Some versions of OS X define READ_OK in public headers */
     206                 :            : #undef READ_OK
     207                 :            : 
     208                 :            : typedef enum
     209                 :            : {
     210                 :            :   READ_FAILED = 0, /* FALSE */
     211                 :            :   READ_OK,
     212                 :            :   READ_EOF
     213                 :            : } ReadResult;
     214                 :            : 
     215                 :            : static ReadResult
     216                 :        624 : read_data (GString *str,
     217                 :            :            gint     fd,
     218                 :            :            GError **error)
     219                 :            : {
     220                 :            :   gssize bytes;
     221                 :            :   gchar buf[4096];
     222                 :            : 
     223                 :        624 :  again:
     224                 :        624 :   bytes = read (fd, buf, 4096);
     225                 :            : 
     226         [ +  + ]:        624 :   if (bytes == 0)
     227                 :        292 :     return READ_EOF;
     228         [ +  - ]:        332 :   else if (bytes > 0)
     229                 :            :     {
     230                 :            :       g_string_append_len (str, buf, bytes);
     231                 :        332 :       return READ_OK;
     232                 :            :     }
     233         [ #  # ]:          0 :   else if (errno == EINTR)
     234                 :          0 :     goto again;
     235                 :            :   else
     236                 :            :     {
     237                 :          0 :       int errsv = errno;
     238                 :            : 
     239                 :          0 :       g_set_error (error,
     240                 :            :                    G_SPAWN_ERROR,
     241                 :            :                    G_SPAWN_ERROR_READ,
     242                 :            :                    _("Failed to read data from child process (%s)"),
     243                 :            :                    g_strerror (errsv));
     244                 :            : 
     245                 :          0 :       return READ_FAILED;
     246                 :            :     }
     247                 :            : }
     248                 :            : 
     249                 :            : /**
     250                 :            :  * g_spawn_sync:
     251                 :            :  * @working_directory: (type filename) (nullable): child's current working
     252                 :            :  *     directory, or %NULL to inherit parent's
     253                 :            :  * @argv: (array zero-terminated=1) (element-type filename):
     254                 :            :  *     child's argument vector, which must be non-empty and %NULL-terminated
     255                 :            :  * @envp: (array zero-terminated=1) (element-type filename) (nullable):
     256                 :            :  *     child's environment, or %NULL to inherit parent's
     257                 :            :  * @flags: flags from #GSpawnFlags
     258                 :            :  * @child_setup: (scope call) (closure user_data) (nullable): function to run
     259                 :            :  *     in the child just before `exec()`
     260                 :            :  * @user_data: user data for @child_setup
     261                 :            :  * @standard_output: (out) (array zero-terminated=1) (element-type guint8) (optional): return location for child output, or %NULL
     262                 :            :  * @standard_error: (out) (array zero-terminated=1) (element-type guint8) (optional): return location for child error messages, or %NULL
     263                 :            :  * @wait_status: (out) (optional): return location for child wait status, as returned by waitpid(), or %NULL
     264                 :            :  * @error: return location for error, or %NULL
     265                 :            :  *
     266                 :            :  * Executes a child synchronously (waits for the child to exit before returning).
     267                 :            :  *
     268                 :            :  * All output from the child is stored in @standard_output and @standard_error,
     269                 :            :  * if those parameters are non-%NULL. Note that you must set the  
     270                 :            :  * %G_SPAWN_STDOUT_TO_DEV_NULL and %G_SPAWN_STDERR_TO_DEV_NULL flags when
     271                 :            :  * passing %NULL for @standard_output and @standard_error.
     272                 :            :  *
     273                 :            :  * If @wait_status is non-%NULL, the platform-specific status of
     274                 :            :  * the child is stored there; see the documentation of
     275                 :            :  * g_spawn_check_wait_status() for how to use and interpret this.
     276                 :            :  * On Unix platforms, note that it is usually not equal
     277                 :            :  * to the integer passed to `exit()` or returned from `main()`.
     278                 :            :  *
     279                 :            :  * Note that it is invalid to pass %G_SPAWN_DO_NOT_REAP_CHILD in
     280                 :            :  * @flags, and on POSIX platforms, the same restrictions as for
     281                 :            :  * g_child_watch_source_new() apply.
     282                 :            :  *
     283                 :            :  * If an error occurs, no data is returned in @standard_output,
     284                 :            :  * @standard_error, or @wait_status.
     285                 :            :  *
     286                 :            :  * This function calls g_spawn_async_with_pipes() internally; see that
     287                 :            :  * function for full details on the other parameters and details on
     288                 :            :  * how these functions work on Windows.
     289                 :            :  * 
     290                 :            :  * Returns: %TRUE on success, %FALSE if an error was set
     291                 :            :  */
     292                 :            : gboolean
     293                 :        296 : g_spawn_sync (const gchar          *working_directory,
     294                 :            :               gchar               **argv,
     295                 :            :               gchar               **envp,
     296                 :            :               GSpawnFlags           flags,
     297                 :            :               GSpawnChildSetupFunc  child_setup,
     298                 :            :               gpointer              user_data,
     299                 :            :               gchar               **standard_output,
     300                 :            :               gchar               **standard_error,
     301                 :            :               gint                 *wait_status,
     302                 :            :               GError              **error)     
     303                 :            : {
     304                 :        296 :   gint outpipe = -1;
     305                 :        296 :   gint errpipe = -1;
     306                 :            :   GPid pid;
     307                 :            :   gint ret;
     308                 :        296 :   GString *outstr = NULL;
     309                 :        296 :   GString *errstr = NULL;
     310                 :            :   gboolean failed;
     311                 :            :   gint status;
     312                 :            :   
     313                 :        296 :   g_return_val_if_fail (argv != NULL, FALSE);
     314                 :        296 :   g_return_val_if_fail (argv[0] != NULL, FALSE);
     315                 :        296 :   g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
     316                 :        296 :   g_return_val_if_fail (standard_output == NULL ||
     317                 :            :                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
     318                 :        296 :   g_return_val_if_fail (standard_error == NULL ||
     319                 :            :                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
     320                 :            :   
     321                 :            :   /* Just to ensure segfaults if callers try to use
     322                 :            :    * these when an error is reported.
     323                 :            :    */
     324         [ +  + ]:        296 :   if (standard_output)
     325                 :        217 :     *standard_output = NULL;
     326                 :            : 
     327         [ +  + ]:        296 :   if (standard_error)
     328                 :         76 :     *standard_error = NULL;
     329                 :            :   
     330   [ +  +  +  +  :        592 :   if (!fork_exec (FALSE,
                   +  + ]
     331                 :            :                   working_directory,
     332                 :            :                   (const gchar * const *) argv,
     333                 :            :                   (const gchar * const *) envp,
     334                 :        296 :                   !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
     335                 :        296 :                   (flags & G_SPAWN_SEARCH_PATH) != 0,
     336                 :        296 :                   (flags & G_SPAWN_SEARCH_PATH_FROM_ENVP) != 0,
     337                 :        296 :                   (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
     338                 :        296 :                   (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
     339                 :        296 :                   (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
     340                 :        296 :                   (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
     341                 :        296 :                   (flags & G_SPAWN_CLOEXEC_PIPES) != 0,
     342                 :            :                   child_setup,
     343                 :            :                   user_data,
     344                 :            :                   &pid,
     345                 :            :                   NULL,
     346                 :            :                   standard_output ? &outpipe : NULL,
     347                 :            :                   standard_error ? &errpipe : NULL,
     348                 :            :                   -1, -1, -1,
     349                 :            :                   NULL, NULL, 0,
     350                 :            :                   error))
     351                 :          6 :     return FALSE;
     352                 :            : 
     353                 :            :   /* Read data from child. */
     354                 :            :   
     355                 :        290 :   failed = FALSE;
     356                 :            : 
     357         [ +  + ]:        290 :   if (outpipe >= 0)
     358                 :            :     {
     359                 :        216 :       outstr = g_string_new (NULL);
     360                 :            :     }
     361                 :            :       
     362         [ +  + ]:        290 :   if (errpipe >= 0)
     363                 :            :     {
     364                 :         76 :       errstr = g_string_new (NULL);
     365                 :            :     }
     366                 :            : 
     367                 :            :   /* Read data until we get EOF on both pipes. */
     368         [ +  - ]:        859 :   while (!failed &&
     369         [ +  + ]:        859 :          (outpipe >= 0 ||
     370         [ +  + ]:        308 :           errpipe >= 0))
     371                 :            :     {
     372                 :            :       /* Any negative FD in the array is ignored, so we can use a fixed length.
     373                 :            :        * We can use UNIX FDs here without worrying about Windows HANDLEs because
     374                 :            :        * the Windows implementation is entirely in gspawn-win32.c. */
     375                 :        569 :       GPollFD fds[] =
     376                 :            :         {
     377                 :            :           { outpipe, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 },
     378                 :            :           { errpipe, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 },
     379                 :            :         };
     380                 :            : 
     381                 :        569 :       ret = g_poll (fds, G_N_ELEMENTS (fds), -1  /* no timeout */);
     382                 :            : 
     383         [ -  + ]:        569 :       if (ret < 0)
     384                 :            :         {
     385                 :          0 :           int errsv = errno;
     386                 :            : 
     387         [ #  # ]:          0 :           if (errno == EINTR)
     388                 :          0 :             continue;
     389                 :            : 
     390                 :          0 :           failed = TRUE;
     391                 :            : 
     392                 :          0 :           g_set_error (error,
     393                 :            :                        G_SPAWN_ERROR,
     394                 :            :                        G_SPAWN_ERROR_READ,
     395                 :            :                        _("Unexpected error in reading data from a child process (%s)"),
     396                 :            :                        g_strerror (errsv));
     397                 :            :               
     398                 :          0 :           break;
     399                 :            :         }
     400                 :            : 
     401   [ +  +  +  + ]:        569 :       if (outpipe >= 0 && fds[0].revents != 0)
     402                 :            :         {
     403      [ -  +  + ]:        524 :           switch (read_data (outstr, outpipe, error))
     404                 :            :             {
     405                 :          0 :             case READ_FAILED:
     406                 :          0 :               failed = TRUE;
     407                 :          0 :               break;
     408                 :        216 :             case READ_EOF:
     409                 :        216 :               g_clear_fd (&outpipe, NULL);
     410                 :        216 :               break;
     411                 :        308 :             default:
     412                 :        308 :               break;
     413                 :            :             }
     414                 :            : 
     415         [ -  + ]:        524 :           if (failed)
     416                 :          0 :             break;
     417                 :            :         }
     418                 :            : 
     419   [ +  +  +  + ]:        569 :       if (errpipe >= 0 && fds[1].revents != 0)
     420                 :            :         {
     421      [ -  +  + ]:        100 :           switch (read_data (errstr, errpipe, error))
     422                 :            :             {
     423                 :          0 :             case READ_FAILED:
     424                 :          0 :               failed = TRUE;
     425                 :          0 :               break;
     426                 :         76 :             case READ_EOF:
     427                 :         76 :               g_clear_fd (&errpipe, NULL);
     428                 :         76 :               break;
     429                 :         24 :             default:
     430                 :         24 :               break;
     431                 :            :             }
     432                 :            : 
     433         [ -  + ]:        100 :           if (failed)
     434                 :          0 :             break;
     435                 :            :         }
     436                 :            :     }
     437                 :            : 
     438                 :            :   /* These should only be open still if we had an error.  */
     439                 :        290 :   g_clear_fd (&outpipe, NULL);
     440                 :        290 :   g_clear_fd (&errpipe, NULL);
     441                 :            : 
     442                 :            :   /* Wait for child to exit, even if we have
     443                 :            :    * an error pending.
     444                 :            :    */
     445                 :        290 :  again:
     446                 :            :       
     447                 :        290 :   ret = waitpid (pid, &status, 0);
     448                 :            : 
     449         [ -  + ]:        290 :   if (ret < 0)
     450                 :            :     {
     451         [ #  # ]:          0 :       if (errno == EINTR)
     452                 :          0 :         goto again;
     453         [ #  # ]:          0 :       else if (errno == ECHILD)
     454                 :            :         {
     455         [ #  # ]:          0 :           if (wait_status)
     456                 :            :             {
     457                 :          0 :               g_warning ("In call to g_spawn_sync(), wait status of a child process was requested but ECHILD was received by waitpid(). See the documentation of g_child_watch_source_new() for possible causes.");
     458                 :            :             }
     459                 :            :           else
     460                 :            :             {
     461                 :            :               /* We don't need the wait status. */
     462                 :            :             }
     463                 :            :         }
     464                 :            :       else
     465                 :            :         {
     466         [ #  # ]:          0 :           if (!failed) /* avoid error pileups */
     467                 :            :             {
     468                 :          0 :               int errsv = errno;
     469                 :            : 
     470                 :          0 :               failed = TRUE;
     471                 :            :                   
     472                 :          0 :               g_set_error (error,
     473                 :            :                            G_SPAWN_ERROR,
     474                 :            :                            G_SPAWN_ERROR_READ,
     475                 :            :                            _("Unexpected error in waitpid() (%s)"),
     476                 :            :                            g_strerror (errsv));
     477                 :            :             }
     478                 :            :         }
     479                 :            :     }
     480                 :            :   
     481         [ -  + ]:        290 :   if (failed)
     482                 :            :     {
     483         [ #  # ]:          0 :       if (outstr)
     484                 :          0 :         g_string_free (outstr, TRUE);
     485         [ #  # ]:          0 :       if (errstr)
     486                 :          0 :         g_string_free (errstr, TRUE);
     487                 :            : 
     488                 :          0 :       return FALSE;
     489                 :            :     }
     490                 :            :   else
     491                 :            :     {
     492         [ +  + ]:        290 :       if (wait_status)
     493                 :        254 :         *wait_status = status;
     494                 :            :       
     495         [ +  + ]:        290 :       if (standard_output)        
     496                 :        216 :         *standard_output = g_string_free (outstr, FALSE);
     497                 :            : 
     498         [ +  + ]:        290 :       if (standard_error)
     499                 :         76 :         *standard_error = g_string_free (errstr, FALSE);
     500                 :            : 
     501                 :        290 :       return TRUE;
     502                 :            :     }
     503                 :            : }
     504                 :            : 
     505                 :            : /**
     506                 :            :  * g_spawn_async_with_pipes:
     507                 :            :  * @working_directory: (type filename) (nullable): child's current working
     508                 :            :  *     directory, or %NULL to inherit parent's, in the GLib file name encoding
     509                 :            :  * @argv: (array zero-terminated=1) (element-type filename): child's argument
     510                 :            :  *     vector, in the GLib file name encoding; it must be non-empty and %NULL-terminated
     511                 :            :  * @envp: (array zero-terminated=1) (element-type filename) (nullable):
     512                 :            :  *     child's environment, or %NULL to inherit parent's, in the GLib file
     513                 :            :  *     name encoding
     514                 :            :  * @flags: flags from #GSpawnFlags
     515                 :            :  * @child_setup: (scope async) (closure user_data) (nullable): function to run
     516                 :            :  *     in the child just before `exec()`
     517                 :            :  * @user_data: user data for @child_setup
     518                 :            :  * @child_pid: (out) (optional): return location for child process ID, or %NULL
     519                 :            :  * @standard_input: (out) (optional): return location for file descriptor to write to child's stdin, or %NULL
     520                 :            :  * @standard_output: (out) (optional): return location for file descriptor to read child's stdout, or %NULL
     521                 :            :  * @standard_error: (out) (optional): return location for file descriptor to read child's stderr, or %NULL
     522                 :            :  * @error: return location for error
     523                 :            :  *
     524                 :            :  * Identical to g_spawn_async_with_pipes_and_fds() but with `n_fds` set to zero,
     525                 :            :  * so no FD assignments are used.
     526                 :            :  *
     527                 :            :  * Returns: %TRUE on success, %FALSE if an error was set
     528                 :            :  */
     529                 :            : gboolean
     530                 :        430 : g_spawn_async_with_pipes (const gchar          *working_directory,
     531                 :            :                           gchar               **argv,
     532                 :            :                           gchar               **envp,
     533                 :            :                           GSpawnFlags           flags,
     534                 :            :                           GSpawnChildSetupFunc  child_setup,
     535                 :            :                           gpointer              user_data,
     536                 :            :                           GPid                 *child_pid,
     537                 :            :                           gint                 *standard_input,
     538                 :            :                           gint                 *standard_output,
     539                 :            :                           gint                 *standard_error,
     540                 :            :                           GError              **error)
     541                 :            : {
     542                 :        430 :   return g_spawn_async_with_pipes_and_fds (working_directory,
     543                 :            :                                            (const gchar * const *) argv,
     544                 :            :                                            (const gchar * const *) envp,
     545                 :            :                                            flags,
     546                 :            :                                            child_setup, user_data,
     547                 :            :                                            -1, -1, -1,
     548                 :            :                                            NULL, NULL, 0,
     549                 :            :                                            child_pid,
     550                 :            :                                            standard_input,
     551                 :            :                                            standard_output,
     552                 :            :                                            standard_error,
     553                 :            :                                            error);
     554                 :            : }
     555                 :            : 
     556                 :            : /**
     557                 :            :  * g_spawn_async_with_pipes_and_fds:
     558                 :            :  * @working_directory: (type filename) (nullable): child's current working
     559                 :            :  *     directory, or %NULL to inherit parent's, in the GLib file name encoding
     560                 :            :  * @argv: (array zero-terminated=1) (element-type filename): child's argument
     561                 :            :  *     vector, in the GLib file name encoding; it must be non-empty and %NULL-terminated
     562                 :            :  * @envp: (array zero-terminated=1) (element-type filename) (nullable):
     563                 :            :  *     child's environment, or %NULL to inherit parent's, in the GLib file
     564                 :            :  *     name encoding
     565                 :            :  * @flags: flags from #GSpawnFlags
     566                 :            :  * @child_setup: (scope async) (closure user_data) (nullable): function to run
     567                 :            :  *     in the child just before `exec()`
     568                 :            :  * @user_data: user data for @child_setup
     569                 :            :  * @stdin_fd: file descriptor to use for child's stdin, or `-1`
     570                 :            :  * @stdout_fd: file descriptor to use for child's stdout, or `-1`
     571                 :            :  * @stderr_fd: file descriptor to use for child's stderr, or `-1`
     572                 :            :  * @source_fds: (array length=n_fds) (nullable): array of FDs from the parent
     573                 :            :  *    process to make available in the child process
     574                 :            :  * @target_fds: (array length=n_fds) (nullable): array of FDs to remap
     575                 :            :  *    @source_fds to in the child process
     576                 :            :  * @n_fds: number of FDs in @source_fds and @target_fds
     577                 :            :  * @child_pid_out: (out) (optional): return location for child process ID, or %NULL
     578                 :            :  * @stdin_pipe_out: (out) (optional): return location for file descriptor to write to child's stdin, or %NULL
     579                 :            :  * @stdout_pipe_out: (out) (optional): return location for file descriptor to read child's stdout, or %NULL
     580                 :            :  * @stderr_pipe_out: (out) (optional): return location for file descriptor to read child's stderr, or %NULL
     581                 :            :  * @error: return location for error
     582                 :            :  *
     583                 :            :  * Executes a child program asynchronously (your program will not
     584                 :            :  * block waiting for the child to exit).
     585                 :            :  *
     586                 :            :  * The child program is specified by the only argument that must be
     587                 :            :  * provided, @argv. @argv should be a %NULL-terminated array of strings,
     588                 :            :  * to be passed as the argument vector for the child. The first string
     589                 :            :  * in @argv is of course the name of the program to execute. By default,
     590                 :            :  * the name of the program must be a full path. If @flags contains the
     591                 :            :  * %G_SPAWN_SEARCH_PATH flag, the `PATH` environment variable is used to
     592                 :            :  * search for the executable. If @flags contains the
     593                 :            :  * %G_SPAWN_SEARCH_PATH_FROM_ENVP flag, the `PATH` variable from @envp
     594                 :            :  * is used to search for the executable. If both the
     595                 :            :  * %G_SPAWN_SEARCH_PATH and %G_SPAWN_SEARCH_PATH_FROM_ENVP flags are
     596                 :            :  * set, the `PATH` variable from @envp takes precedence over the
     597                 :            :  * environment variable.
     598                 :            :  *
     599                 :            :  * If the program name is not a full path and %G_SPAWN_SEARCH_PATH flag
     600                 :            :  * is not used, then the program will be run from the current directory
     601                 :            :  * (or @working_directory, if specified); this might be unexpected or even
     602                 :            :  * dangerous in some cases when the current directory is world-writable.
     603                 :            :  *
     604                 :            :  * On Windows, note that all the string or string vector arguments to
     605                 :            :  * this function and the other `g_spawn*()` functions are in UTF-8, the
     606                 :            :  * GLib file name encoding. Unicode characters that are not part of
     607                 :            :  * the system codepage passed in these arguments will be correctly
     608                 :            :  * available in the spawned program only if it uses wide character API
     609                 :            :  * to retrieve its command line. For C programs built with Microsoft's
     610                 :            :  * tools it is enough to make the program have a `wmain()` instead of
     611                 :            :  * `main()`. `wmain()` has a wide character argument vector as parameter.
     612                 :            :  *
     613                 :            :  * At least currently, mingw doesn't support `wmain()`, so if you use
     614                 :            :  * mingw to develop the spawned program, it should call
     615                 :            :  * g_win32_get_command_line() to get arguments in UTF-8.
     616                 :            :  *
     617                 :            :  * On Windows the low-level child process creation API `CreateProcess()`
     618                 :            :  * doesn't use argument vectors, but a command line. The C runtime
     619                 :            :  * library's `spawn*()` family of functions (which g_spawn_async_with_pipes()
     620                 :            :  * eventually calls) paste the argument vector elements together into
     621                 :            :  * a command line, and the C runtime startup code does a corresponding
     622                 :            :  * reconstruction of an argument vector from the command line, to be
     623                 :            :  * passed to `main()`. Complications arise when you have argument vector
     624                 :            :  * elements that contain spaces or double quotes. The `spawn*()` functions
     625                 :            :  * don't do any quoting or escaping, but on the other hand the startup
     626                 :            :  * code does do unquoting and unescaping in order to enable receiving
     627                 :            :  * arguments with embedded spaces or double quotes. To work around this
     628                 :            :  * asymmetry, g_spawn_async_with_pipes() will do quoting and escaping on
     629                 :            :  * argument vector elements that need it before calling the C runtime
     630                 :            :  * `spawn()` function.
     631                 :            :  *
     632                 :            :  * The returned @child_pid on Windows is a handle to the child
     633                 :            :  * process, not its identifier. Process handles and process
     634                 :            :  * identifiers are different concepts on Windows.
     635                 :            :  *
     636                 :            :  * @envp is a %NULL-terminated array of strings, where each string
     637                 :            :  * has the form `KEY=VALUE`. This will become the child's environment.
     638                 :            :  * If @envp is %NULL, the child inherits its parent's environment.
     639                 :            :  *
     640                 :            :  * @flags should be the bitwise OR of any flags you want to affect the
     641                 :            :  * function's behaviour. The %G_SPAWN_DO_NOT_REAP_CHILD means that the
     642                 :            :  * child will not automatically be reaped; you must use a child watch
     643                 :            :  * (g_child_watch_add()) to be notified about the death of the child process,
     644                 :            :  * otherwise it will stay around as a zombie process until this process exits.
     645                 :            :  * Eventually you must call g_spawn_close_pid() on the @child_pid, in order to
     646                 :            :  * free resources which may be associated with the child process. (On Unix,
     647                 :            :  * using a child watch is equivalent to calling waitpid() or handling
     648                 :            :  * the `SIGCHLD` signal manually. On Windows, calling g_spawn_close_pid()
     649                 :            :  * is equivalent to calling `CloseHandle()` on the process handle returned
     650                 :            :  * in @child_pid). See g_child_watch_add().
     651                 :            :  *
     652                 :            :  * Open UNIX file descriptors marked as `FD_CLOEXEC` will be automatically
     653                 :            :  * closed in the child process. %G_SPAWN_LEAVE_DESCRIPTORS_OPEN means that
     654                 :            :  * other open file descriptors will be inherited by the child; otherwise all
     655                 :            :  * descriptors except stdin/stdout/stderr will be closed before calling `exec()`
     656                 :            :  * in the child. %G_SPAWN_SEARCH_PATH means that @argv[0] need not be an
     657                 :            :  * absolute path, it will be looked for in the `PATH` environment
     658                 :            :  * variable. %G_SPAWN_SEARCH_PATH_FROM_ENVP means need not be an
     659                 :            :  * absolute path, it will be looked for in the `PATH` variable from
     660                 :            :  * @envp. If both %G_SPAWN_SEARCH_PATH and %G_SPAWN_SEARCH_PATH_FROM_ENVP
     661                 :            :  * are used, the value from @envp takes precedence over the environment.
     662                 :            :  *
     663                 :            :  * %G_SPAWN_CHILD_INHERITS_STDIN means that the child will inherit the parent's
     664                 :            :  * standard input (by default, the child's standard input is attached to
     665                 :            :  * `/dev/null`). %G_SPAWN_STDIN_FROM_DEV_NULL explicitly imposes the default
     666                 :            :  * behavior. Both flags cannot be enabled at the same time and, in both cases,
     667                 :            :  * the @stdin_pipe_out argument is ignored.
     668                 :            :  *
     669                 :            :  * %G_SPAWN_STDOUT_TO_DEV_NULL means that the child's standard output
     670                 :            :  * will be discarded (by default, it goes to the same location as the parent's
     671                 :            :  * standard output). %G_SPAWN_CHILD_INHERITS_STDOUT explicitly imposes the
     672                 :            :  * default behavior. Both flags cannot be enabled at the same time and, in
     673                 :            :  * both cases, the @stdout_pipe_out argument is ignored.
     674                 :            :  *
     675                 :            :  * %G_SPAWN_STDERR_TO_DEV_NULL means that the child's standard error
     676                 :            :  * will be discarded (by default, it goes to the same location as the parent's
     677                 :            :  * standard error). %G_SPAWN_CHILD_INHERITS_STDERR explicitly imposes the
     678                 :            :  * default behavior. Both flags cannot be enabled at the same time and, in
     679                 :            :  * both cases, the @stderr_pipe_out argument is ignored.
     680                 :            :  *
     681                 :            :  * It is valid to pass the same FD in multiple parameters (e.g. you can pass
     682                 :            :  * a single FD for both @stdout_fd and @stderr_fd, and include it in
     683                 :            :  * @source_fds too).
     684                 :            :  *
     685                 :            :  * @source_fds and @target_fds allow zero or more FDs from this process to be
     686                 :            :  * remapped to different FDs in the spawned process. If @n_fds is greater than
     687                 :            :  * zero, @source_fds and @target_fds must both be non-%NULL and the same length.
     688                 :            :  * Each FD in @source_fds is remapped to the FD number at the same index in
     689                 :            :  * @target_fds. The source and target FD may be equal to simply propagate an FD
     690                 :            :  * to the spawned process. FD remappings are processed after standard FDs, so
     691                 :            :  * any target FDs which equal @stdin_fd, @stdout_fd or @stderr_fd will overwrite
     692                 :            :  * them in the spawned process.
     693                 :            :  *
     694                 :            :  * @source_fds is supported on Windows since 2.72.
     695                 :            :  *
     696                 :            :  * %G_SPAWN_FILE_AND_ARGV_ZERO means that the first element of @argv is
     697                 :            :  * the file to execute, while the remaining elements are the actual
     698                 :            :  * argument vector to pass to the file. Normally g_spawn_async_with_pipes()
     699                 :            :  * uses @argv[0] as the file to execute, and passes all of @argv to the child.
     700                 :            :  *
     701                 :            :  * @child_setup and @user_data are a function and user data. On POSIX
     702                 :            :  * platforms, the function is called in the child after GLib has
     703                 :            :  * performed all the setup it plans to perform (including creating
     704                 :            :  * pipes, closing file descriptors, etc.) but before calling `exec()`.
     705                 :            :  * That is, @child_setup is called just before calling `exec()` in the
     706                 :            :  * child. Obviously actions taken in this function will only affect
     707                 :            :  * the child, not the parent.
     708                 :            :  *
     709                 :            :  * On Windows, there is no separate `fork()` and `exec()` functionality.
     710                 :            :  * Child processes are created and run with a single API call,
     711                 :            :  * `CreateProcess()`. There is no sensible thing @child_setup
     712                 :            :  * could be used for on Windows so it is ignored and not called.
     713                 :            :  *
     714                 :            :  * If non-%NULL, @child_pid will on Unix be filled with the child's
     715                 :            :  * process ID. You can use the process ID to send signals to the child,
     716                 :            :  * or to use g_child_watch_add() (or `waitpid()`) if you specified the
     717                 :            :  * %G_SPAWN_DO_NOT_REAP_CHILD flag. On Windows, @child_pid will be
     718                 :            :  * filled with a handle to the child process only if you specified the
     719                 :            :  * %G_SPAWN_DO_NOT_REAP_CHILD flag. You can then access the child
     720                 :            :  * process using the Win32 API, for example wait for its termination
     721                 :            :  * with the `WaitFor*()` functions, or examine its exit code with
     722                 :            :  * `GetExitCodeProcess()`. You should close the handle with `CloseHandle()`
     723                 :            :  * or g_spawn_close_pid() when you no longer need it.
     724                 :            :  *
     725                 :            :  * If non-%NULL, the @stdin_pipe_out, @stdout_pipe_out, @stderr_pipe_out
     726                 :            :  * locations will be filled with file descriptors for writing to the child's
     727                 :            :  * standard input or reading from its standard output or standard error.
     728                 :            :  * The caller of g_spawn_async_with_pipes() must close these file descriptors
     729                 :            :  * when they are no longer in use. If these parameters are %NULL, the
     730                 :            :  * corresponding pipe won't be created.
     731                 :            :  *
     732                 :            :  * If @stdin_pipe_out is %NULL, the child's standard input is attached to
     733                 :            :  * `/dev/null` unless %G_SPAWN_CHILD_INHERITS_STDIN is set.
     734                 :            :  *
     735                 :            :  * If @stderr_pipe_out is NULL, the child's standard error goes to the same
     736                 :            :  * location as the parent's standard error unless %G_SPAWN_STDERR_TO_DEV_NULL
     737                 :            :  * is set.
     738                 :            :  *
     739                 :            :  * If @stdout_pipe_out is NULL, the child's standard output goes to the same
     740                 :            :  * location as the parent's standard output unless %G_SPAWN_STDOUT_TO_DEV_NULL
     741                 :            :  * is set.
     742                 :            :  *
     743                 :            :  * @error can be %NULL to ignore errors, or non-%NULL to report errors.
     744                 :            :  * If an error is set, the function returns %FALSE. Errors are reported
     745                 :            :  * even if they occur in the child (for example if the executable in
     746                 :            :  * `@argv[0]` is not found). Typically the `message` field of returned
     747                 :            :  * errors should be displayed to users. Possible errors are those from
     748                 :            :  * the %G_SPAWN_ERROR domain.
     749                 :            :  *
     750                 :            :  * If an error occurs, @child_pid, @stdin_pipe_out, @stdout_pipe_out,
     751                 :            :  * and @stderr_pipe_out will not be filled with valid values.
     752                 :            :  *
     753                 :            :  * If @child_pid is not %NULL and an error does not occur then the returned
     754                 :            :  * process reference must be closed using g_spawn_close_pid().
     755                 :            :  *
     756                 :            :  * On modern UNIX platforms, GLib can use an efficient process launching
     757                 :            :  * codepath driven internally by `posix_spawn()`. This has the advantage of
     758                 :            :  * avoiding the fork-time performance costs of cloning the parent process
     759                 :            :  * address space, and avoiding associated memory overcommit checks that are
     760                 :            :  * not relevant in the context of immediately executing a distinct process.
     761                 :            :  * This optimized codepath will be used provided that the following conditions
     762                 :            :  * are met:
     763                 :            :  *
     764                 :            :  * 1. %G_SPAWN_DO_NOT_REAP_CHILD is set
     765                 :            :  * 2. %G_SPAWN_LEAVE_DESCRIPTORS_OPEN is set
     766                 :            :  * 3. %G_SPAWN_SEARCH_PATH_FROM_ENVP is not set
     767                 :            :  * 4. @working_directory is %NULL
     768                 :            :  * 5. @child_setup is %NULL
     769                 :            :  * 6. The program is of a recognised binary format, or has a shebang.
     770                 :            :  *    Otherwise, GLib will have to execute the program through the
     771                 :            :  *    shell, which is not done using the optimized codepath.
     772                 :            :  *
     773                 :            :  * If you are writing a GTK application, and the program you are spawning is a
     774                 :            :  * graphical application too, then to ensure that the spawned program opens its
     775                 :            :  * windows on the right screen, you may want to use #GdkAppLaunchContext,
     776                 :            :  * #GAppLaunchContext, or set the `DISPLAY` environment variable.
     777                 :            :  *
     778                 :            :  * Returns: %TRUE on success, %FALSE if an error was set
     779                 :            :  *
     780                 :            :  * Since: 2.68
     781                 :            :  */
     782                 :            : gboolean
     783                 :        579 : g_spawn_async_with_pipes_and_fds (const gchar           *working_directory,
     784                 :            :                                   const gchar * const   *argv,
     785                 :            :                                   const gchar * const   *envp,
     786                 :            :                                   GSpawnFlags            flags,
     787                 :            :                                   GSpawnChildSetupFunc   child_setup,
     788                 :            :                                   gpointer               user_data,
     789                 :            :                                   gint                   stdin_fd,
     790                 :            :                                   gint                   stdout_fd,
     791                 :            :                                   gint                   stderr_fd,
     792                 :            :                                   const gint            *source_fds,
     793                 :            :                                   const gint            *target_fds,
     794                 :            :                                   gsize                  n_fds,
     795                 :            :                                   GPid                  *child_pid_out,
     796                 :            :                                   gint                  *stdin_pipe_out,
     797                 :            :                                   gint                  *stdout_pipe_out,
     798                 :            :                                   gint                  *stderr_pipe_out,
     799                 :            :                                   GError               **error)
     800                 :            : {
     801                 :        579 :   g_return_val_if_fail (argv != NULL, FALSE);
     802                 :        579 :   g_return_val_if_fail (argv[0] != NULL, FALSE);
     803                 :            :   /* can’t both inherit and set pipes to /dev/null */
     804                 :        579 :   g_return_val_if_fail ((flags & INHERITS_OR_NULL_STDIN) != INHERITS_OR_NULL_STDIN, FALSE);
     805                 :        579 :   g_return_val_if_fail ((flags & INHERITS_OR_NULL_STDOUT) != INHERITS_OR_NULL_STDOUT, FALSE);
     806                 :        579 :   g_return_val_if_fail ((flags & INHERITS_OR_NULL_STDERR) != INHERITS_OR_NULL_STDERR, FALSE);
     807                 :            :   /* can’t use pipes and stdin/stdout/stderr FDs */
     808                 :        579 :   g_return_val_if_fail (stdin_pipe_out == NULL || stdin_fd < 0, FALSE);
     809                 :        579 :   g_return_val_if_fail (stdout_pipe_out == NULL || stdout_fd < 0, FALSE);
     810                 :        579 :   g_return_val_if_fail (stderr_pipe_out == NULL || stderr_fd < 0, FALSE);
     811                 :            : 
     812         [ +  + ]:        579 :   if ((flags & INHERITS_OR_NULL_STDIN) != 0)
     813                 :          1 :     stdin_pipe_out = NULL;
     814         [ +  + ]:        579 :   if ((flags & INHERITS_OR_NULL_STDOUT) != 0)
     815                 :         34 :     stdout_pipe_out = NULL;
     816         [ +  + ]:        579 :   if ((flags & INHERITS_OR_NULL_STDERR) != 0)
     817                 :         25 :     stderr_pipe_out = NULL;
     818                 :            : 
     819                 :        579 :   return fork_exec (!(flags & G_SPAWN_DO_NOT_REAP_CHILD),
     820                 :            :                     working_directory,
     821                 :            :                     (const gchar * const *) argv,
     822                 :            :                     (const gchar * const *) envp,
     823                 :        579 :                     !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
     824                 :        579 :                     (flags & G_SPAWN_SEARCH_PATH) != 0,
     825                 :        579 :                     (flags & G_SPAWN_SEARCH_PATH_FROM_ENVP) != 0,
     826                 :        579 :                     (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
     827                 :        579 :                     (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
     828                 :        579 :                     (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
     829                 :        579 :                     (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
     830                 :        579 :                     (flags & G_SPAWN_CLOEXEC_PIPES) != 0,
     831                 :            :                     child_setup,
     832                 :            :                     user_data,
     833                 :            :                     child_pid_out,
     834                 :            :                     stdin_pipe_out,
     835                 :            :                     stdout_pipe_out,
     836                 :            :                     stderr_pipe_out,
     837                 :            :                     stdin_fd,
     838                 :            :                     stdout_fd,
     839                 :            :                     stderr_fd,
     840                 :            :                     source_fds,
     841                 :            :                     target_fds,
     842                 :            :                     n_fds,
     843                 :            :                     error);
     844                 :            : }
     845                 :            : 
     846                 :            : /**
     847                 :            :  * g_spawn_async_with_fds:
     848                 :            :  * @working_directory: (type filename) (nullable): child's current working directory, or %NULL to inherit parent's, in the GLib file name encoding
     849                 :            :  * @argv: (array zero-terminated=1): child's argument vector, in the GLib file name encoding;
     850                 :            :  *   it must be non-empty and %NULL-terminated
     851                 :            :  * @envp: (array zero-terminated=1) (nullable): child's environment, or %NULL to inherit parent's, in the GLib file name encoding
     852                 :            :  * @flags: flags from #GSpawnFlags
     853                 :            :  * @child_setup: (scope async) (closure user_data) (nullable): function to run
     854                 :            :  *   in the child just before `exec()`
     855                 :            :  * @user_data: user data for @child_setup
     856                 :            :  * @child_pid: (out) (optional): return location for child process ID, or %NULL
     857                 :            :  * @stdin_fd: file descriptor to use for child's stdin, or `-1`
     858                 :            :  * @stdout_fd: file descriptor to use for child's stdout, or `-1`
     859                 :            :  * @stderr_fd: file descriptor to use for child's stderr, or `-1`
     860                 :            :  * @error: return location for error
     861                 :            :  *
     862                 :            :  * Executes a child program asynchronously.
     863                 :            :  *
     864                 :            :  * Identical to g_spawn_async_with_pipes_and_fds() but with `n_fds` set to zero,
     865                 :            :  * so no FD assignments are used.
     866                 :            :  *
     867                 :            :  * Returns: %TRUE on success, %FALSE if an error was set
     868                 :            :  *
     869                 :            :  * Since: 2.58
     870                 :            :  */
     871                 :            : gboolean
     872                 :         98 : g_spawn_async_with_fds (const gchar          *working_directory,
     873                 :            :                         gchar               **argv,
     874                 :            :                         gchar               **envp,
     875                 :            :                         GSpawnFlags           flags,
     876                 :            :                         GSpawnChildSetupFunc  child_setup,
     877                 :            :                         gpointer              user_data,
     878                 :            :                         GPid                 *child_pid,
     879                 :            :                         gint                  stdin_fd,
     880                 :            :                         gint                  stdout_fd,
     881                 :            :                         gint                  stderr_fd,
     882                 :            :                         GError              **error)
     883                 :            : {
     884                 :         98 :   g_return_val_if_fail (argv != NULL, FALSE);
     885                 :         98 :   g_return_val_if_fail (argv[0] != NULL, FALSE);
     886                 :         98 :   g_return_val_if_fail (stdout_fd < 0 ||
     887                 :            :                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
     888                 :         98 :   g_return_val_if_fail (stderr_fd < 0 ||
     889                 :            :                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
     890                 :            :   /* can't inherit stdin if we have an input pipe. */
     891                 :         98 :   g_return_val_if_fail (stdin_fd < 0 ||
     892                 :            :                         !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
     893                 :            : 
     894                 :         98 :   return fork_exec (!(flags & G_SPAWN_DO_NOT_REAP_CHILD),
     895                 :            :                     working_directory,
     896                 :            :                     (const gchar * const *) argv,
     897                 :            :                     (const gchar * const *) envp,
     898                 :         98 :                     !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
     899                 :         98 :                     (flags & G_SPAWN_SEARCH_PATH) != 0,
     900                 :         98 :                     (flags & G_SPAWN_SEARCH_PATH_FROM_ENVP) != 0,
     901                 :         98 :                     (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
     902                 :         98 :                     (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
     903                 :         98 :                     (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
     904                 :         98 :                     (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
     905                 :         98 :                     (flags & G_SPAWN_CLOEXEC_PIPES) != 0,
     906                 :            :                     child_setup,
     907                 :            :                     user_data,
     908                 :            :                     child_pid,
     909                 :            :                     NULL, NULL, NULL,
     910                 :            :                     stdin_fd,
     911                 :            :                     stdout_fd,
     912                 :            :                     stderr_fd,
     913                 :            :                     NULL, NULL, 0,
     914                 :            :                     error);
     915                 :            : }
     916                 :            : 
     917                 :            : /**
     918                 :            :  * g_spawn_command_line_sync:
     919                 :            :  * @command_line: (type filename): a command line
     920                 :            :  * @standard_output: (out) (array zero-terminated=1) (element-type guint8) (optional): return location for child output
     921                 :            :  * @standard_error: (out) (array zero-terminated=1) (element-type guint8) (optional): return location for child errors
     922                 :            :  * @wait_status: (out) (optional): return location for child wait status, as returned by waitpid()
     923                 :            :  * @error: return location for errors
     924                 :            :  *
     925                 :            :  * A simple version of g_spawn_sync() with little-used parameters
     926                 :            :  * removed, taking a command line instead of an argument vector.
     927                 :            :  *
     928                 :            :  * See g_spawn_sync() for full details.
     929                 :            :  *
     930                 :            :  * The @command_line argument will be parsed by g_shell_parse_argv().
     931                 :            :  *
     932                 :            :  * Unlike g_spawn_sync(), the %G_SPAWN_SEARCH_PATH flag is enabled.
     933                 :            :  * Note that %G_SPAWN_SEARCH_PATH can have security implications, so
     934                 :            :  * consider using g_spawn_sync() directly if appropriate.
     935                 :            :  *
     936                 :            :  * Possible errors are those from g_spawn_sync() and those
     937                 :            :  * from g_shell_parse_argv().
     938                 :            :  *
     939                 :            :  * If @wait_status is non-%NULL, the platform-specific status of
     940                 :            :  * the child is stored there; see the documentation of
     941                 :            :  * g_spawn_check_wait_status() for how to use and interpret this.
     942                 :            :  * On Unix platforms, note that it is usually not equal
     943                 :            :  * to the integer passed to `exit()` or returned from `main()`.
     944                 :            :  * 
     945                 :            :  * On Windows, please note the implications of g_shell_parse_argv()
     946                 :            :  * parsing @command_line. Parsing is done according to Unix shell rules, not 
     947                 :            :  * Windows command interpreter rules.
     948                 :            :  * Space is a separator, and backslashes are
     949                 :            :  * special. Thus you cannot simply pass a @command_line containing
     950                 :            :  * canonical Windows paths, like "c:\\program files\\app\\app.exe", as
     951                 :            :  * the backslashes will be eaten, and the space will act as a
     952                 :            :  * separator. You need to enclose such paths with single quotes, like
     953                 :            :  * "'c:\\program files\\app\\app.exe' 'e:\\folder\\argument.txt'".
     954                 :            :  *
     955                 :            :  * Returns: %TRUE on success, %FALSE if an error was set
     956                 :            :  **/
     957                 :            : gboolean
     958                 :         58 : g_spawn_command_line_sync (const gchar  *command_line,
     959                 :            :                            gchar       **standard_output,
     960                 :            :                            gchar       **standard_error,
     961                 :            :                            gint         *wait_status,
     962                 :            :                            GError      **error)
     963                 :            : {
     964                 :            :   gboolean retval;
     965                 :         58 :   gchar **argv = NULL;
     966                 :            : 
     967                 :         58 :   g_return_val_if_fail (command_line != NULL, FALSE);
     968                 :            :   
     969                 :            :   /* This will return a runtime error if @command_line is the empty string. */
     970         [ -  + ]:         58 :   if (!g_shell_parse_argv (command_line,
     971                 :            :                            NULL, &argv,
     972                 :            :                            error))
     973                 :          0 :     return FALSE;
     974                 :            :   
     975                 :         58 :   retval = g_spawn_sync (NULL,
     976                 :            :                          argv,
     977                 :            :                          NULL,
     978                 :            :                          G_SPAWN_SEARCH_PATH,
     979                 :            :                          NULL,
     980                 :            :                          NULL,
     981                 :            :                          standard_output,
     982                 :            :                          standard_error,
     983                 :            :                          wait_status,
     984                 :            :                          error);
     985                 :         58 :   g_strfreev (argv);
     986                 :            : 
     987                 :         58 :   return retval;
     988                 :            : }
     989                 :            : 
     990                 :            : /**
     991                 :            :  * g_spawn_command_line_async:
     992                 :            :  * @command_line: (type filename): a command line
     993                 :            :  * @error: return location for errors
     994                 :            :  * 
     995                 :            :  * A simple version of g_spawn_async() that parses a command line with
     996                 :            :  * g_shell_parse_argv() and passes it to g_spawn_async().
     997                 :            :  *
     998                 :            :  * Runs a command line in the background. Unlike g_spawn_async(), the
     999                 :            :  * %G_SPAWN_SEARCH_PATH flag is enabled, other flags are not. Note
    1000                 :            :  * that %G_SPAWN_SEARCH_PATH can have security implications, so
    1001                 :            :  * consider using g_spawn_async() directly if appropriate. Possible
    1002                 :            :  * errors are those from g_shell_parse_argv() and g_spawn_async().
    1003                 :            :  * 
    1004                 :            :  * The same concerns on Windows apply as for g_spawn_command_line_sync().
    1005                 :            :  *
    1006                 :            :  * Returns: %TRUE on success, %FALSE if error is set
    1007                 :            :  **/
    1008                 :            : gboolean
    1009                 :         12 : g_spawn_command_line_async (const gchar *command_line,
    1010                 :            :                             GError     **error)
    1011                 :            : {
    1012                 :            :   gboolean retval;
    1013                 :         12 :   gchar **argv = NULL;
    1014                 :            : 
    1015                 :         12 :   g_return_val_if_fail (command_line != NULL, FALSE);
    1016                 :            : 
    1017                 :            :   /* This will return a runtime error if @command_line is the empty string. */
    1018         [ -  + ]:         12 :   if (!g_shell_parse_argv (command_line,
    1019                 :            :                            NULL, &argv,
    1020                 :            :                            error))
    1021                 :          0 :     return FALSE;
    1022                 :            :   
    1023                 :         12 :   retval = g_spawn_async (NULL,
    1024                 :            :                           argv,
    1025                 :            :                           NULL,
    1026                 :            :                           G_SPAWN_SEARCH_PATH,
    1027                 :            :                           NULL,
    1028                 :            :                           NULL,
    1029                 :            :                           NULL,
    1030                 :            :                           error);
    1031                 :         12 :   g_strfreev (argv);
    1032                 :            : 
    1033                 :         12 :   return retval;
    1034                 :            : }
    1035                 :            : 
    1036                 :            : /**
    1037                 :            :  * g_spawn_check_wait_status:
    1038                 :            :  * @wait_status: A platform-specific wait status as returned from g_spawn_sync()
    1039                 :            :  * @error: a #GError
    1040                 :            :  *
    1041                 :            :  * Set @error if @wait_status indicates the child exited abnormally
    1042                 :            :  * (e.g. with a nonzero exit code, or via a fatal signal).
    1043                 :            :  *
    1044                 :            :  * The g_spawn_sync() and g_child_watch_add() family of APIs return the
    1045                 :            :  * status of subprocesses encoded in a platform-specific way.
    1046                 :            :  * On Unix, this is guaranteed to be in the same format waitpid() returns,
    1047                 :            :  * and on Windows it is guaranteed to be the result of GetExitCodeProcess().
    1048                 :            :  *
    1049                 :            :  * Prior to the introduction of this function in GLib 2.34, interpreting
    1050                 :            :  * @wait_status required use of platform-specific APIs, which is problematic
    1051                 :            :  * for software using GLib as a cross-platform layer.
    1052                 :            :  *
    1053                 :            :  * Additionally, many programs simply want to determine whether or not
    1054                 :            :  * the child exited successfully, and either propagate a #GError or
    1055                 :            :  * print a message to standard error. In that common case, this function
    1056                 :            :  * can be used. Note that the error message in @error will contain
    1057                 :            :  * human-readable information about the wait status.
    1058                 :            :  *
    1059                 :            :  * The @domain and @code of @error have special semantics in the case
    1060                 :            :  * where the process has an "exit code", as opposed to being killed by
    1061                 :            :  * a signal. On Unix, this happens if WIFEXITED() would be true of
    1062                 :            :  * @wait_status. On Windows, it is always the case.
    1063                 :            :  *
    1064                 :            :  * The special semantics are that the actual exit code will be the
    1065                 :            :  * code set in @error, and the domain will be %G_SPAWN_EXIT_ERROR.
    1066                 :            :  * This allows you to differentiate between different exit codes.
    1067                 :            :  *
    1068                 :            :  * If the process was terminated by some means other than an exit
    1069                 :            :  * status (for example if it was killed by a signal), the domain will be
    1070                 :            :  * %G_SPAWN_ERROR and the code will be %G_SPAWN_ERROR_FAILED.
    1071                 :            :  *
    1072                 :            :  * This function just offers convenience; you can of course also check
    1073                 :            :  * the available platform via a macro such as %G_OS_UNIX, and use
    1074                 :            :  * WIFEXITED() and WEXITSTATUS() on @wait_status directly. Do not attempt
    1075                 :            :  * to scan or parse the error message string; it may be translated and/or
    1076                 :            :  * change in future versions of GLib.
    1077                 :            :  *
    1078                 :            :  * Prior to version 2.70, g_spawn_check_exit_status() provides the same
    1079                 :            :  * functionality, although under a misleading name.
    1080                 :            :  *
    1081                 :            :  * Returns: %TRUE if child exited successfully, %FALSE otherwise (and
    1082                 :            :  *   @error will be set)
    1083                 :            :  *
    1084                 :            :  * Since: 2.70
    1085                 :            :  */
    1086                 :            : gboolean
    1087                 :        195 : g_spawn_check_wait_status (gint      wait_status,
    1088                 :            :                            GError  **error)
    1089                 :            : {
    1090                 :        195 :   gboolean ret = FALSE;
    1091                 :            : 
    1092         [ +  + ]:        195 :   if (WIFEXITED (wait_status))
    1093                 :            :     {
    1094         [ +  + ]:        189 :       if (WEXITSTATUS (wait_status) != 0)
    1095                 :            :         {
    1096                 :         46 :           g_set_error (error, G_SPAWN_EXIT_ERROR, WEXITSTATUS (wait_status),
    1097                 :            :                        _("Child process exited with code %ld"),
    1098                 :         46 :                        (long) WEXITSTATUS (wait_status));
    1099                 :         46 :           goto out;
    1100                 :            :         }
    1101                 :            :     }
    1102         [ +  - ]:          6 :   else if (WIFSIGNALED (wait_status))
    1103                 :            :     {
    1104                 :          6 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
    1105                 :            :                    _("Child process killed by signal %ld"),
    1106                 :          6 :                    (long) WTERMSIG (wait_status));
    1107                 :          6 :       goto out;
    1108                 :            :     }
    1109         [ #  # ]:          0 :   else if (WIFSTOPPED (wait_status))
    1110                 :            :     {
    1111                 :          0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
    1112                 :            :                    _("Child process stopped by signal %ld"),
    1113                 :          0 :                    (long) WSTOPSIG (wait_status));
    1114                 :          0 :       goto out;
    1115                 :            :     }
    1116                 :            :   else
    1117                 :            :     {
    1118                 :          0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
    1119                 :            :                    _("Child process exited abnormally"));
    1120                 :          0 :       goto out;
    1121                 :            :     }
    1122                 :            : 
    1123                 :        143 :   ret = TRUE;
    1124                 :        195 :  out:
    1125                 :        195 :   return ret;
    1126                 :            : }
    1127                 :            : 
    1128                 :            : /**
    1129                 :            :  * g_spawn_check_exit_status:
    1130                 :            :  * @wait_status: A status as returned from g_spawn_sync()
    1131                 :            :  * @error: a #GError
    1132                 :            :  *
    1133                 :            :  * An old name for g_spawn_check_wait_status(), deprecated because its
    1134                 :            :  * name is misleading.
    1135                 :            :  *
    1136                 :            :  * Despite the name of the function, @wait_status must be the wait status
    1137                 :            :  * as returned by g_spawn_sync(), g_subprocess_get_status(), `waitpid()`,
    1138                 :            :  * etc. On Unix platforms, it is incorrect for it to be the exit status
    1139                 :            :  * as passed to `exit()` or returned by g_subprocess_get_exit_status() or
    1140                 :            :  * `WEXITSTATUS()`.
    1141                 :            :  *
    1142                 :            :  * Returns: %TRUE if child exited successfully, %FALSE otherwise (and
    1143                 :            :  *     @error will be set)
    1144                 :            :  *
    1145                 :            :  * Since: 2.34
    1146                 :            :  *
    1147                 :            :  * Deprecated: 2.70: Use g_spawn_check_wait_status() instead, and check whether your code is conflating wait and exit statuses.
    1148                 :            :  */
    1149                 :            : gboolean
    1150                 :          0 : g_spawn_check_exit_status (gint      wait_status,
    1151                 :            :                            GError  **error)
    1152                 :            : {
    1153                 :          0 :   return g_spawn_check_wait_status (wait_status, error);
    1154                 :            : }
    1155                 :            : 
    1156                 :            : /* This function is called between fork() and exec() and hence must be
    1157                 :            :  * async-signal-safe (see signal-safety(7)). */
    1158                 :            : static gssize
    1159                 :          0 : write_all (gint fd, gconstpointer vbuf, gsize to_write)
    1160                 :            : {
    1161                 :          0 :   gchar *buf = (gchar *) vbuf;
    1162                 :            :   
    1163         [ #  # ]:          0 :   while (to_write > 0)
    1164                 :            :     {
    1165                 :          0 :       gssize count = write (fd, buf, to_write);
    1166         [ #  # ]:          0 :       if (count < 0)
    1167                 :            :         {
    1168         [ #  # ]:          0 :           if (errno != EINTR)
    1169                 :          0 :             return FALSE;
    1170                 :            :         }
    1171                 :            :       else
    1172                 :            :         {
    1173                 :          0 :           to_write -= count;
    1174                 :          0 :           buf += count;
    1175                 :            :         }
    1176                 :            :     }
    1177                 :            :   
    1178                 :          0 :   return TRUE;
    1179                 :            : }
    1180                 :            : 
    1181                 :            : /* This function is called between fork() and exec() and hence must be
    1182                 :            :  * async-signal-safe (see signal-safety(7)). */
    1183                 :            : G_NORETURN
    1184                 :            : static void
    1185                 :          0 : write_err_and_exit (gint fd, gint msg)
    1186                 :            : {
    1187                 :          0 :   gint en = errno;
    1188                 :            :   
    1189                 :          0 :   write_all (fd, &msg, sizeof(msg));
    1190                 :          0 :   write_all (fd, &en, sizeof(en));
    1191                 :            :   
    1192                 :          0 :   _exit (1);
    1193                 :            : }
    1194                 :            : 
    1195                 :            : /* This function is called between fork() and exec() and hence must be
    1196                 :            :  * async-signal-safe (see signal-safety(7)). */
    1197                 :            : static void
    1198                 :       2039 : set_cloexec (int fd)
    1199                 :            : {
    1200                 :       2039 :   fcntl (fd, F_SETFD, FD_CLOEXEC);
    1201                 :       2039 : }
    1202                 :            : 
    1203                 :            : /* This function is called between fork() and exec() and hence must be
    1204                 :            :  * async-signal-safe (see signal-safety(7)). */
    1205                 :            : static void
    1206                 :          2 : unset_cloexec (int fd)
    1207                 :            : {
    1208                 :            :   int flags;
    1209                 :            :   int result;
    1210                 :            : 
    1211                 :          2 :   flags = fcntl (fd, F_GETFD, 0);
    1212                 :            : 
    1213         [ +  - ]:          2 :   if (flags != -1)
    1214                 :            :     {
    1215                 :            :       int errsv;
    1216                 :          2 :       flags &= (~FD_CLOEXEC);
    1217                 :            :       do
    1218                 :            :         {
    1219                 :          2 :           result = fcntl (fd, F_SETFD, flags);
    1220                 :          2 :           errsv = errno;
    1221                 :            :         }
    1222   [ -  +  -  - ]:          2 :       while (result == -1 && errsv == EINTR);
    1223                 :            :     }
    1224                 :          2 : }
    1225                 :            : 
    1226                 :            : /* This function is called between fork() and exec() and hence must be
    1227                 :            :  * async-signal-safe (see signal-safety(7)). */
    1228                 :            : static int
    1229                 :         84 : dupfd_cloexec (int old_fd, int new_fd_min)
    1230                 :            : {
    1231                 :            :   int fd, errsv;
    1232                 :            : #ifdef F_DUPFD_CLOEXEC
    1233                 :            :   do
    1234                 :            :     {
    1235                 :         84 :       fd = fcntl (old_fd, F_DUPFD_CLOEXEC, new_fd_min);
    1236                 :         84 :       errsv = errno;
    1237                 :            :     }
    1238   [ -  +  -  - ]:         84 :   while (fd == -1 && errsv == EINTR);
    1239                 :            : #else
    1240                 :            :   /* OS X Snow Lion and earlier don't have F_DUPFD_CLOEXEC:
    1241                 :            :    * https://bugzilla.gnome.org/show_bug.cgi?id=710962
    1242                 :            :    */
    1243                 :            :   int result, flags;
    1244                 :            :   do
    1245                 :            :     {
    1246                 :            :       fd = fcntl (old_fd, F_DUPFD, new_fd_min);
    1247                 :            :       errsv = errno;
    1248                 :            :     }
    1249                 :            :   while (fd == -1 && errsv == EINTR);
    1250                 :            :   flags = fcntl (fd, F_GETFD, 0);
    1251                 :            :   if (flags != -1)
    1252                 :            :     {
    1253                 :            :       flags |= FD_CLOEXEC;
    1254                 :            :       do
    1255                 :            :         {
    1256                 :            :           result = fcntl (fd, F_SETFD, flags);
    1257                 :            :           errsv = errno;
    1258                 :            :         }
    1259                 :            :       while (result == -1 && errsv == EINTR);
    1260                 :            :     }
    1261                 :            : #endif
    1262                 :         84 :   return fd;
    1263                 :            : }
    1264                 :            : 
    1265                 :            : /* This function is called between fork() and exec() and hence must be
    1266                 :            :  * async-signal-safe (see signal-safety(7)). */
    1267                 :            : static gint
    1268                 :       3117 : safe_dup2 (gint fd1, gint fd2)
    1269                 :            : {
    1270                 :            :   gint ret;
    1271                 :            : 
    1272                 :            :   do
    1273                 :       3117 :     ret = dup2 (fd1, fd2);
    1274   [ -  +  -  -  :       3117 :   while (ret < 0 && (errno == EINTR || errno == EBUSY));
                   -  - ]
    1275                 :            : 
    1276                 :       3117 :   return ret;
    1277                 :            : }
    1278                 :            : 
    1279                 :            : /* This function is called between fork() and exec() and hence must be
    1280                 :            :  * async-signal-safe (see signal-safety(7)). */
    1281                 :            : static gboolean
    1282                 :         16 : relocate_fd_out_of_standard_range (gint *fd)
    1283                 :            : {
    1284                 :         16 :   gint ret = -1;
    1285                 :         16 :   const int min_fileno = STDERR_FILENO + 1;
    1286                 :            : 
    1287                 :            :   do
    1288                 :         16 :     ret = fcntl (*fd, F_DUPFD, min_fileno);
    1289   [ -  +  -  - ]:         16 :   while (ret < 0 && errno == EINTR);
    1290                 :            : 
    1291                 :            :   /* Note we don't need to close the old fd, because the caller is expected
    1292                 :            :    * to close fds in the standard range itself.
    1293                 :            :    */
    1294         [ +  - ]:         16 :   if (ret >= min_fileno)
    1295                 :            :     {
    1296                 :         16 :       *fd = ret;
    1297                 :         16 :       return TRUE;
    1298                 :            :     }
    1299                 :            : 
    1300                 :          0 :   return FALSE;
    1301                 :            : }
    1302                 :            : 
    1303                 :            : /* This function is called between fork() and exec() and hence must be
    1304                 :            :  * async-signal-safe (see signal-safety(7)). */
    1305                 :            : static gint
    1306                 :       1135 : safe_open (const char *path, gint mode)
    1307                 :            : {
    1308                 :            :   gint ret;
    1309                 :            : 
    1310                 :            :   do
    1311                 :       1135 :     ret = open (path, mode);
    1312   [ -  +  -  - ]:       1135 :   while (ret < 0 && errno == EINTR);
    1313                 :            : 
    1314                 :       1135 :   return ret;
    1315                 :            : }
    1316                 :            : 
    1317                 :            : enum
    1318                 :            : {
    1319                 :            :   CHILD_CHDIR_FAILED,
    1320                 :            :   CHILD_EXEC_FAILED,
    1321                 :            :   CHILD_OPEN_FAILED,
    1322                 :            :   CHILD_DUPFD_FAILED,
    1323                 :            :   CHILD_FORK_FAILED,
    1324                 :            :   CHILD_CLOSE_FAILED,
    1325                 :            : };
    1326                 :            : 
    1327                 :            : /* This function is called between fork() and exec() and hence must be
    1328                 :            :  * async-signal-safe (see signal-safety(7)) until it calls exec().
    1329                 :            :  *
    1330                 :            :  * All callers must guarantee that @argv and @argv[0] are non-NULL. */
    1331                 :            : static void
    1332                 :        904 : do_exec (gint                  child_err_report_fd,
    1333                 :            :          gint                  stdin_fd,
    1334                 :            :          gint                  stdout_fd,
    1335                 :            :          gint                  stderr_fd,
    1336                 :            :          gint                 *source_fds,
    1337                 :            :          const gint           *target_fds,
    1338                 :            :          gsize                 n_fds,
    1339                 :            :          const gchar          *working_directory,
    1340                 :            :          const gchar * const  *argv,
    1341                 :            :          gchar               **argv_buffer,
    1342                 :            :          gsize                 argv_buffer_len,
    1343                 :            :          const gchar * const  *envp,
    1344                 :            :          gboolean              close_descriptors,
    1345                 :            :          const gchar          *search_path,
    1346                 :            :          gchar                *search_path_buffer,
    1347                 :            :          gsize                 search_path_buffer_len,
    1348                 :            :          gboolean              stdout_to_null,
    1349                 :            :          gboolean              stderr_to_null,
    1350                 :            :          gboolean              child_inherits_stdin,
    1351                 :            :          gboolean              file_and_argv_zero,
    1352                 :            :          GSpawnChildSetupFunc  child_setup,
    1353                 :            :          gpointer              user_data)
    1354                 :            : {
    1355                 :            :   gsize i;
    1356                 :        904 :   gint max_target_fd = 0;
    1357                 :            : 
    1358   [ +  +  -  + ]:        904 :   if (working_directory && chdir (working_directory) < 0)
    1359                 :          0 :     write_err_and_exit (child_err_report_fd,
    1360                 :            :                         CHILD_CHDIR_FAILED);
    1361                 :            : 
    1362                 :            :   /* It's possible the caller assigned stdin to an fd with a
    1363                 :            :    * file number that is supposed to be reserved for
    1364                 :            :    * stdout or stderr.
    1365                 :            :    *
    1366                 :            :    * If so, move it up out of the standard range, so it doesn't
    1367                 :            :    * cause a conflict.
    1368                 :            :    */
    1369   [ +  +  -  +  :        904 :   if (IS_STD_FILENO (stdin_fd) && stdin_fd != STDIN_FILENO)
                   -  - ]
    1370                 :            :     {
    1371                 :          0 :       int old_fd = stdin_fd;
    1372                 :            : 
    1373         [ #  # ]:          0 :       if (!relocate_fd_out_of_standard_range (&stdin_fd))
    1374                 :          0 :         write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
    1375                 :            : 
    1376         [ #  # ]:          0 :       if (stdout_fd == old_fd)
    1377                 :          0 :         stdout_fd = stdin_fd;
    1378                 :            : 
    1379         [ #  # ]:          0 :       if (stderr_fd == old_fd)
    1380                 :          0 :         stderr_fd = stdin_fd;
    1381                 :            :     }
    1382                 :            : 
    1383                 :            :   /* Redirect pipes as required
    1384                 :            :    *
    1385                 :            :    * There are two cases where we don't need to do the redirection
    1386                 :            :    * 1. Where the associated file descriptor is cleared/invalid
    1387                 :            :    * 2. When the associated file descriptor is already given the
    1388                 :            :    * correct file number.
    1389                 :            :    */
    1390   [ +  +  +  - ]:        904 :   if (IS_VALID_FILENO (stdin_fd) && stdin_fd != STDIN_FILENO)
    1391                 :            :     {
    1392         [ -  + ]:         60 :       if (safe_dup2 (stdin_fd, 0) < 0)
    1393                 :          0 :         write_err_and_exit (child_err_report_fd,
    1394                 :            :                             CHILD_DUPFD_FAILED);
    1395                 :            : 
    1396                 :         60 :       set_cloexec (stdin_fd);
    1397                 :            :     }
    1398         [ +  + ]:        844 :   else if (!child_inherits_stdin)
    1399                 :            :     {
    1400                 :            :       /* Keep process from blocking on a read of stdin */
    1401                 :        843 :       gint read_null = safe_open ("/dev/null", O_RDONLY);
    1402         [ -  + ]:        843 :       if (read_null < 0)
    1403                 :          0 :         write_err_and_exit (child_err_report_fd,
    1404                 :            :                             CHILD_OPEN_FAILED);
    1405         [ -  + ]:        843 :       if (safe_dup2 (read_null, 0) < 0)
    1406                 :          0 :         write_err_and_exit (child_err_report_fd,
    1407                 :            :                             CHILD_DUPFD_FAILED);
    1408                 :        843 :       g_clear_fd (&read_null, NULL);
    1409                 :            :     }
    1410                 :            : 
    1411                 :            :   /* Like with stdin above, it's possible the caller assigned
    1412                 :            :    * stdout to an fd with a file number that's intruding on the
    1413                 :            :    * standard range.
    1414                 :            :    *
    1415                 :            :    * If so, move it out of the way, too.
    1416                 :            :    */
    1417   [ +  +  +  +  :        904 :   if (IS_STD_FILENO (stdout_fd) && stdout_fd != STDOUT_FILENO)
                   +  + ]
    1418                 :            :     {
    1419                 :          4 :       int old_fd = stdout_fd;
    1420                 :            : 
    1421         [ -  + ]:          4 :       if (!relocate_fd_out_of_standard_range (&stdout_fd))
    1422                 :          0 :         write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
    1423                 :            : 
    1424         [ -  + ]:          4 :       if (stderr_fd == old_fd)
    1425                 :          0 :         stderr_fd = stdout_fd;
    1426                 :            :     }
    1427                 :            : 
    1428   [ +  +  +  + ]:        904 :   if (IS_VALID_FILENO (stdout_fd) && stdout_fd != STDOUT_FILENO)
    1429                 :            :     {
    1430         [ -  + ]:        638 :       if (safe_dup2 (stdout_fd, 1) < 0)
    1431                 :          0 :         write_err_and_exit (child_err_report_fd,
    1432                 :            :                             CHILD_DUPFD_FAILED);
    1433                 :            : 
    1434                 :        638 :       set_cloexec (stdout_fd);
    1435                 :            :     }
    1436         [ +  + ]:        266 :   else if (stdout_to_null)
    1437                 :            :     {
    1438                 :         90 :       gint write_null = safe_open ("/dev/null", O_WRONLY);
    1439         [ -  + ]:         90 :       if (write_null < 0)
    1440                 :          0 :         write_err_and_exit (child_err_report_fd,
    1441                 :            :                             CHILD_OPEN_FAILED);
    1442         [ -  + ]:         90 :       if (safe_dup2 (write_null, 1) < 0)
    1443                 :          0 :         write_err_and_exit (child_err_report_fd,
    1444                 :            :                             CHILD_DUPFD_FAILED);
    1445                 :         90 :       g_clear_fd (&write_null, NULL);
    1446                 :            :     }
    1447                 :            : 
    1448   [ +  +  +  +  :        904 :   if (IS_STD_FILENO (stderr_fd) && stderr_fd != STDERR_FILENO)
                   +  + ]
    1449                 :            :     {
    1450         [ -  + ]:         12 :       if (!relocate_fd_out_of_standard_range (&stderr_fd))
    1451                 :          0 :         write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
    1452                 :            :     }
    1453                 :            : 
    1454                 :            :   /* Like with stdin/stdout above, it's possible the caller assigned
    1455                 :            :    * stderr to an fd with a file number that's intruding on the
    1456                 :            :    * standard range.
    1457                 :            :    *
    1458                 :            :    * Make sure it's out of the way, also.
    1459                 :            :    */
    1460   [ +  +  +  + ]:        904 :   if (IS_VALID_FILENO (stderr_fd) && stderr_fd != STDERR_FILENO)
    1461                 :            :     {
    1462         [ -  + ]:        445 :       if (safe_dup2 (stderr_fd, 2) < 0)
    1463                 :          0 :         write_err_and_exit (child_err_report_fd,
    1464                 :            :                             CHILD_DUPFD_FAILED);
    1465                 :            : 
    1466                 :        445 :       set_cloexec (stderr_fd);
    1467                 :            :     }
    1468         [ +  + ]:        459 :   else if (stderr_to_null)
    1469                 :            :     {
    1470                 :        127 :       gint write_null = safe_open ("/dev/null", O_WRONLY);
    1471         [ -  + ]:        127 :       if (write_null < 0)
    1472                 :          0 :         write_err_and_exit (child_err_report_fd,
    1473                 :            :                             CHILD_OPEN_FAILED);
    1474         [ -  + ]:        127 :       if (safe_dup2 (write_null, 2) < 0)
    1475                 :          0 :         write_err_and_exit (child_err_report_fd,
    1476                 :            :                             CHILD_DUPFD_FAILED);
    1477                 :        127 :       g_clear_fd (&write_null, NULL);
    1478                 :            :     }
    1479                 :            : 
    1480                 :            :   /* Close all file descriptors but stdin, stdout and stderr, and any of source_fds,
    1481                 :            :    * before we exec. Note that this includes
    1482                 :            :    * child_err_report_fd, which keeps the parent from blocking
    1483                 :            :    * forever on the other end of that pipe.
    1484                 :            :    */
    1485         [ +  - ]:        904 :   if (close_descriptors)
    1486                 :            :     {
    1487   [ +  +  +  + ]:        904 :       if (child_setup == NULL && n_fds == 0)
    1488                 :            :         {
    1489         [ -  + ]:        896 :           if (safe_dup2 (child_err_report_fd, 3) < 0)
    1490                 :          0 :             write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
    1491                 :        896 :           set_cloexec (3);
    1492         [ -  + ]:        896 :           if (g_closefrom (4) < 0)
    1493                 :          0 :             write_err_and_exit (child_err_report_fd, CHILD_CLOSE_FAILED);
    1494                 :        896 :           child_err_report_fd = 3;
    1495                 :            :         }
    1496                 :            :       else
    1497                 :            :         {
    1498         [ -  + ]:          8 :           if (g_fdwalk_set_cloexec (3) < 0)
    1499                 :          0 :             write_err_and_exit (child_err_report_fd, CHILD_CLOSE_FAILED);
    1500                 :            :         }
    1501                 :            :     }
    1502                 :            :   else
    1503                 :            :     {
    1504                 :            :       /* We need to do child_err_report_fd anyway */
    1505                 :          0 :       set_cloexec (child_err_report_fd);
    1506                 :            :     }
    1507                 :            : 
    1508                 :            :   /*
    1509                 :            :    * Work through the @source_fds and @target_fds mapping.
    1510                 :            :    *
    1511                 :            :    * Based on code originally derived from
    1512                 :            :    * gnome-terminal:src/terminal-screen.c:terminal_screen_child_setup(),
    1513                 :            :    * used under the LGPLv2+ with permission from author. (The code has
    1514                 :            :    * since migrated to vte:src/spawn.cc:SpawnContext::exec and is no longer
    1515                 :            :    * terribly similar to what we have here.)
    1516                 :            :    */
    1517                 :            : 
    1518         [ +  + ]:        904 :   if (n_fds > 0)
    1519                 :            :     {
    1520         [ +  + ]:         26 :       for (i = 0; i < n_fds; i++)
    1521                 :         20 :         max_target_fd = MAX (max_target_fd, target_fds[i]);
    1522                 :            : 
    1523         [ -  + ]:          6 :       if (max_target_fd == G_MAXINT)
    1524                 :            :         {
    1525                 :          0 :           errno = EINVAL;
    1526                 :          0 :           write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
    1527                 :            :         }
    1528                 :            : 
    1529                 :            :       /* If we're doing remapping fd assignments, we need to handle
    1530                 :            :        * the case where the user has specified e.g. 5 -> 4, 4 -> 6.
    1531                 :            :        * We do this by duping all source fds, taking care to ensure the new
    1532                 :            :        * fds are larger than any target fd to avoid introducing new conflicts.
    1533                 :            :        */
    1534         [ +  + ]:         26 :       for (i = 0; i < n_fds; i++)
    1535                 :            :         {
    1536         [ +  + ]:         20 :           if (source_fds[i] != target_fds[i])
    1537                 :            :             {
    1538                 :         18 :               source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1);
    1539         [ -  + ]:         18 :               if (source_fds[i] < 0)
    1540                 :          0 :                 write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
    1541                 :            :             }
    1542                 :            :         }
    1543                 :            : 
    1544         [ +  + ]:         26 :       for (i = 0; i < n_fds; i++)
    1545                 :            :         {
    1546                 :            :           /* For basic fd assignments (where source == target), we can just
    1547                 :            :            * unset FD_CLOEXEC.
    1548                 :            :            */
    1549         [ +  + ]:         20 :           if (source_fds[i] == target_fds[i])
    1550                 :            :             {
    1551                 :          2 :               unset_cloexec (source_fds[i]);
    1552                 :            :             }
    1553                 :            :           else
    1554                 :            :             {
    1555                 :            :               /* If any of the @target_fds conflict with @child_err_report_fd,
    1556                 :            :                * dup it so it doesn’t get conflated.
    1557                 :            :                */
    1558         [ +  + ]:         18 :               if (target_fds[i] == child_err_report_fd)
    1559                 :            :                 {
    1560                 :          2 :                   child_err_report_fd = dupfd_cloexec (child_err_report_fd, max_target_fd + 1);
    1561         [ -  + ]:          2 :                   if (child_err_report_fd < 0)
    1562                 :          0 :                     write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
    1563                 :            :                 }
    1564                 :            : 
    1565         [ -  + ]:         18 :               if (safe_dup2 (source_fds[i], target_fds[i]) < 0)
    1566                 :          0 :                 write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
    1567                 :            : 
    1568                 :         18 :               g_clear_fd (&source_fds[i], NULL);
    1569                 :            :             }
    1570                 :            :         }
    1571                 :            :     }
    1572                 :            : 
    1573                 :            :   /* Call user function just before we exec */
    1574         [ +  + ]:        904 :   if (child_setup)
    1575                 :            :     {
    1576                 :          5 :       (* child_setup) (user_data);
    1577                 :            :     }
    1578                 :            : 
    1579         [ -  + ]:        904 :   g_execute (argv[0],
    1580                 :            :              (gchar **) (file_and_argv_zero ? argv + 1 : argv),
    1581                 :            :              argv_buffer, argv_buffer_len,
    1582                 :            :              (gchar **) envp, search_path, search_path_buffer, search_path_buffer_len);
    1583                 :            : 
    1584                 :            :   /* Exec failed */
    1585                 :          0 :   write_err_and_exit (child_err_report_fd,
    1586                 :            :                       CHILD_EXEC_FAILED);
    1587                 :            : }
    1588                 :            : 
    1589                 :            : static gboolean
    1590                 :       1010 : read_ints (int      fd,
    1591                 :            :            gint*    buf,
    1592                 :            :            gint     n_ints_in_buf,    
    1593                 :            :            gint    *n_ints_read,      
    1594                 :            :            GError **error)
    1595                 :            : {
    1596                 :       1010 :   gsize bytes = 0;    
    1597                 :            :   
    1598                 :            :   while (TRUE)
    1599                 :        115 :     {
    1600                 :            :       gssize chunk;    
    1601                 :            : 
    1602         [ +  + ]:       1125 :       if (bytes >= sizeof(gint)*2)
    1603                 :          9 :         break; /* give up, who knows what happened, should not be
    1604                 :            :                 * possible.
    1605                 :            :                 */
    1606                 :            :           
    1607                 :       1116 :     again:
    1608                 :       1116 :       chunk = read (fd,
    1609                 :            :                     ((gchar*)buf) + bytes,
    1610                 :       1116 :                     sizeof(gint) * n_ints_in_buf - bytes);
    1611   [ -  +  -  - ]:       1116 :       if (chunk < 0 && errno == EINTR)
    1612                 :          0 :         goto again;
    1613                 :            :           
    1614         [ -  + ]:       1116 :       if (chunk < 0)
    1615                 :            :         {
    1616                 :          0 :           int errsv = errno;
    1617                 :            : 
    1618                 :            :           /* Some weird shit happened, bail out */
    1619                 :          0 :           g_set_error (error,
    1620                 :            :                        G_SPAWN_ERROR,
    1621                 :            :                        G_SPAWN_ERROR_FAILED,
    1622                 :            :                        _("Failed to read from child pipe (%s)"),
    1623                 :            :                        g_strerror (errsv));
    1624                 :            : 
    1625                 :          0 :           return FALSE;
    1626                 :            :         }
    1627         [ +  + ]:       1116 :       else if (chunk == 0)
    1628                 :       1001 :         break; /* EOF */
    1629                 :            :       else /* chunk > 0 */
    1630                 :        115 :         bytes += chunk;
    1631                 :            :     }
    1632                 :            : 
    1633                 :       1010 :   *n_ints_read = (gint)(bytes / sizeof(gint));
    1634                 :            : 
    1635                 :       1010 :   return TRUE;
    1636                 :            : }
    1637                 :            : 
    1638                 :            : #ifdef POSIX_SPAWN_AVAILABLE
    1639                 :            : static gboolean
    1640                 :         67 : do_posix_spawn (const gchar * const *argv,
    1641                 :            :                 const gchar * const *envp,
    1642                 :            :                 gboolean    search_path,
    1643                 :            :                 gboolean    stdout_to_null,
    1644                 :            :                 gboolean    stderr_to_null,
    1645                 :            :                 gboolean    child_inherits_stdin,
    1646                 :            :                 gboolean    file_and_argv_zero,
    1647                 :            :                 GPid       *child_pid,
    1648                 :            :                 gint       *child_close_fds,
    1649                 :            :                 gint        stdin_fd,
    1650                 :            :                 gint        stdout_fd,
    1651                 :            :                 gint        stderr_fd,
    1652                 :            :                 const gint *source_fds,
    1653                 :            :                 const gint *target_fds,
    1654                 :            :                 gsize       n_fds)
    1655                 :            : {
    1656                 :            :   pid_t pid;
    1657                 :         67 :   gint *duped_source_fds = NULL;
    1658                 :         67 :   gint max_target_fd = 0;
    1659                 :            :   const gchar * const *argv_pass;
    1660                 :            :   posix_spawnattr_t attr;
    1661                 :            :   posix_spawn_file_actions_t file_actions;
    1662                 :            :   gint parent_close_fds[3];
    1663                 :         67 :   gsize num_parent_close_fds = 0;
    1664                 :         67 :   GSList *child_close = NULL;
    1665                 :            :   GSList *elem;
    1666                 :            :   sigset_t mask;
    1667                 :            :   gsize i;
    1668                 :            :   int r;
    1669                 :            : 
    1670                 :         67 :   g_assert (argv != NULL && argv[0] != NULL);
    1671                 :            : 
    1672         [ -  + ]:         67 :   if (*argv[0] == '\0')
    1673                 :            :     {
    1674                 :            :       /* We check the simple case first. */
    1675                 :          0 :       return ENOENT;
    1676                 :            :     }
    1677                 :            : 
    1678                 :         67 :   r = posix_spawnattr_init (&attr);
    1679         [ -  + ]:         67 :   if (r != 0)
    1680                 :          0 :     return r;
    1681                 :            : 
    1682         [ +  - ]:         67 :   if (child_close_fds)
    1683                 :            :     {
    1684                 :         67 :       int i = -1;
    1685         [ +  + ]:         68 :       while (child_close_fds[++i] != -1)
    1686                 :          1 :         child_close = g_slist_prepend (child_close,
    1687                 :          1 :                                        GINT_TO_POINTER (child_close_fds[i]));
    1688                 :            :     }
    1689                 :            : 
    1690                 :         67 :   r = posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF);
    1691         [ -  + ]:         67 :   if (r != 0)
    1692                 :          0 :     goto out_free_spawnattr;
    1693                 :            : 
    1694                 :            :   /* Reset some signal handlers that we may use */
    1695                 :         67 :   sigemptyset (&mask);
    1696                 :         67 :   sigaddset (&mask, SIGCHLD);
    1697                 :         67 :   sigaddset (&mask, SIGINT);
    1698                 :         67 :   sigaddset (&mask, SIGTERM);
    1699                 :         67 :   sigaddset (&mask, SIGHUP);
    1700                 :            : 
    1701                 :         67 :   r = posix_spawnattr_setsigdefault (&attr, &mask);
    1702         [ -  + ]:         67 :   if (r != 0)
    1703                 :          0 :     goto out_free_spawnattr;
    1704                 :            : 
    1705                 :         67 :   r = posix_spawn_file_actions_init (&file_actions);
    1706         [ -  + ]:         67 :   if (r != 0)
    1707                 :          0 :     goto out_free_spawnattr;
    1708                 :            : 
    1709                 :            :   /* Redirect pipes as required */
    1710                 :            : 
    1711         [ -  + ]:         67 :   if (stdin_fd >= 0)
    1712                 :            :     {
    1713                 :          0 :       r = posix_spawn_file_actions_adddup2 (&file_actions, stdin_fd, 0);
    1714         [ #  # ]:          0 :       if (r != 0)
    1715                 :          0 :         goto out_close_fds;
    1716                 :            : 
    1717         [ #  # ]:          0 :       if (!g_slist_find (child_close, GINT_TO_POINTER (stdin_fd)))
    1718                 :          0 :         child_close = g_slist_prepend (child_close, GINT_TO_POINTER (stdin_fd));
    1719                 :            :     }
    1720         [ +  - ]:         67 :   else if (!child_inherits_stdin)
    1721                 :            :     {
    1722                 :            :       /* Keep process from blocking on a read of stdin */
    1723                 :         67 :       gint read_null = safe_open ("/dev/null", O_RDONLY | O_CLOEXEC);
    1724                 :         67 :       g_assert (read_null != -1);
    1725                 :         67 :       parent_close_fds[num_parent_close_fds++] = read_null;
    1726                 :            : 
    1727                 :            : #ifndef HAVE_O_CLOEXEC
    1728                 :            :       fcntl (read_null, F_SETFD, FD_CLOEXEC);
    1729                 :            : #endif
    1730                 :            : 
    1731                 :         67 :       r = posix_spawn_file_actions_adddup2 (&file_actions, read_null, 0);
    1732         [ -  + ]:         67 :       if (r != 0)
    1733                 :          0 :         goto out_close_fds;
    1734                 :            :     }
    1735                 :            : 
    1736         [ +  + ]:         67 :   if (stdout_fd >= 0)
    1737                 :            :     {
    1738                 :          1 :       r = posix_spawn_file_actions_adddup2 (&file_actions, stdout_fd, 1);
    1739         [ -  + ]:          1 :       if (r != 0)
    1740                 :          0 :         goto out_close_fds;
    1741                 :            : 
    1742         [ +  - ]:          1 :       if (!g_slist_find (child_close, GINT_TO_POINTER (stdout_fd)))
    1743                 :          1 :         child_close = g_slist_prepend (child_close, GINT_TO_POINTER (stdout_fd));
    1744                 :            :     }
    1745         [ +  + ]:         66 :   else if (stdout_to_null)
    1746                 :            :     {
    1747                 :          4 :       gint write_null = safe_open ("/dev/null", O_WRONLY | O_CLOEXEC);
    1748                 :          4 :       g_assert (write_null != -1);
    1749                 :          4 :       parent_close_fds[num_parent_close_fds++] = write_null;
    1750                 :            : 
    1751                 :            : #ifndef HAVE_O_CLOEXEC
    1752                 :            :       fcntl (write_null, F_SETFD, FD_CLOEXEC);
    1753                 :            : #endif
    1754                 :            : 
    1755                 :          4 :       r = posix_spawn_file_actions_adddup2 (&file_actions, write_null, 1);
    1756         [ -  + ]:          4 :       if (r != 0)
    1757                 :          0 :         goto out_close_fds;
    1758                 :            :     }
    1759                 :            : 
    1760         [ -  + ]:         67 :   if (stderr_fd >= 0)
    1761                 :            :     {
    1762                 :          0 :       r = posix_spawn_file_actions_adddup2 (&file_actions, stderr_fd, 2);
    1763         [ #  # ]:          0 :       if (r != 0)
    1764                 :          0 :         goto out_close_fds;
    1765                 :            : 
    1766         [ #  # ]:          0 :       if (!g_slist_find (child_close, GINT_TO_POINTER (stderr_fd)))
    1767                 :          0 :         child_close = g_slist_prepend (child_close, GINT_TO_POINTER (stderr_fd));
    1768                 :            :     }
    1769         [ +  + ]:         67 :   else if (stderr_to_null)
    1770                 :            :     {
    1771                 :          4 :       gint write_null = safe_open ("/dev/null", O_WRONLY | O_CLOEXEC);
    1772                 :          4 :       g_assert (write_null != -1);
    1773                 :          4 :       parent_close_fds[num_parent_close_fds++] = write_null;
    1774                 :            : 
    1775                 :            : #ifndef HAVE_O_CLOEXEC
    1776                 :            :       fcntl (write_null, F_SETFD, FD_CLOEXEC);
    1777                 :            : #endif
    1778                 :            : 
    1779                 :          4 :       r = posix_spawn_file_actions_adddup2 (&file_actions, write_null, 2);
    1780         [ -  + ]:          4 :       if (r != 0)
    1781                 :          0 :         goto out_close_fds;
    1782                 :            :     }
    1783                 :            : 
    1784                 :            :   /* If source_fds[i] != target_fds[i], we need to handle the case
    1785                 :            :    * where the user has specified, e.g., 5 -> 4, 4 -> 6. We do this
    1786                 :            :    * by duping the source fds, taking care to ensure the new fds are
    1787                 :            :    * larger than any target fd to avoid introducing new conflicts.
    1788                 :            :    *
    1789                 :            :    * If source_fds[i] == target_fds[i], then we just need to leak
    1790                 :            :    * the fd into the child process, which we *could* do by temporarily
    1791                 :            :    * unsetting CLOEXEC and then setting it again after we spawn if
    1792                 :            :    * it was originally set. POSIX requires that the addup2 action unset
    1793                 :            :    * CLOEXEC if source and target are identical, so you'd think doing it
    1794                 :            :    * manually wouldn't be needed, but unfortunately as of 2021 many
    1795                 :            :    * libcs still don't do so. Example nonconforming libcs:
    1796                 :            :    *  Bionic: https://android.googlesource.com/platform/bionic/+/f6e5b582604715729b09db3e36a7aeb8c24b36a4/libc/bionic/spawn.cpp#71
    1797                 :            :    *  uclibc-ng: https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/librt/spawn.c?id=7c36bcae09d66bbaa35cbb02253ae0556f42677e#n88
    1798                 :            :    *
    1799                 :            :    * Anyway, unsetting CLOEXEC ourselves would open a small race window
    1800                 :            :    * where the fd could be inherited into a child process if another
    1801                 :            :    * thread spawns something at the same time, because we have not
    1802                 :            :    * called fork() and are multithreaded here. This race is avoidable by
    1803                 :            :    * using dupfd_cloexec, which we already have to do to handle the
    1804                 :            :    * source_fds[i] != target_fds[i] case. So let's always do it!
    1805                 :            :    */
    1806                 :            : 
    1807         [ +  + ]:        131 :   for (i = 0; i < n_fds; i++)
    1808                 :         64 :     max_target_fd = MAX (max_target_fd, target_fds[i]);
    1809                 :            : 
    1810         [ -  + ]:         67 :   if (max_target_fd == G_MAXINT)
    1811                 :          0 :     goto out_close_fds;
    1812                 :            : 
    1813                 :         67 :   duped_source_fds = g_new (gint, n_fds);
    1814         [ +  + ]:        131 :   for (i = 0; i < n_fds; i++)
    1815                 :         64 :     duped_source_fds[i] = -1;  /* initialise in case dupfd_cloexec() fails below */
    1816         [ +  + ]:        131 :   for (i = 0; i < n_fds; i++)
    1817                 :            :     {
    1818                 :         64 :       duped_source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1);
    1819         [ -  + ]:         64 :       if (duped_source_fds[i] < 0)
    1820                 :          0 :         goto out_close_fds;
    1821                 :            :     }
    1822                 :            : 
    1823         [ +  + ]:        131 :   for (i = 0; i < n_fds; i++)
    1824                 :            :     {
    1825                 :         64 :       r = posix_spawn_file_actions_adddup2 (&file_actions, duped_source_fds[i], target_fds[i]);
    1826         [ -  + ]:         64 :       if (r != 0)
    1827                 :          0 :         goto out_close_fds;
    1828                 :            :     }
    1829                 :            : 
    1830                 :            :   /* Intentionally close the fds in the child as the last file action,
    1831                 :            :    * having been careful not to add the same fd to this list twice.
    1832                 :            :    *
    1833                 :            :    * This is important to allow (e.g.) for the same fd to be passed as stdout
    1834                 :            :    * and stderr (we must not close it before we have dupped it in both places,
    1835                 :            :    * and we must not attempt to close it twice).
    1836                 :            :    */
    1837         [ +  + ]:         69 :   for (elem = child_close; elem != NULL; elem = elem->next)
    1838                 :            :     {
    1839                 :          2 :       r = posix_spawn_file_actions_addclose (&file_actions,
    1840                 :          2 :                                              GPOINTER_TO_INT (elem->data));
    1841         [ -  + ]:          2 :       if (r != 0)
    1842                 :          0 :         goto out_close_fds;
    1843                 :            :     }
    1844                 :            : 
    1845         [ -  + ]:         67 :   argv_pass = file_and_argv_zero ? argv + 1 : argv;
    1846         [ +  + ]:         67 :   if (envp == NULL)
    1847                 :         65 :     envp = (const gchar * const *) environ;
    1848                 :            : 
    1849                 :            :   /* Don't search when it contains a slash. */
    1850   [ +  +  -  + ]:         67 :   if (!search_path || strchr (argv[0], '/') != NULL)
    1851                 :          7 :     r = posix_spawn (&pid, argv[0], &file_actions, &attr, (char * const *) argv_pass, (char * const *) envp);
    1852                 :            :   else
    1853                 :         60 :     r = posix_spawnp (&pid, argv[0], &file_actions, &attr, (char * const *) argv_pass, (char * const *) envp);
    1854                 :            : 
    1855   [ -  +  -  + ]:         67 :   if (r == 0 && child_pid != NULL)
    1856                 :         67 :     *child_pid = pid;
    1857                 :            : 
    1858                 :          0 : out_close_fds:
    1859         [ +  + ]:        142 :   for (i = 0; i < num_parent_close_fds; i++)
    1860                 :         75 :     g_clear_fd (&parent_close_fds[i], NULL);
    1861                 :            : 
    1862         [ +  + ]:         67 :   if (duped_source_fds != NULL)
    1863                 :            :     {
    1864         [ +  + ]:        126 :       for (i = 0; i < n_fds; i++)
    1865                 :         64 :         g_clear_fd (&duped_source_fds[i], NULL);
    1866                 :         62 :       g_free (duped_source_fds);
    1867                 :            :     }
    1868                 :            : 
    1869                 :         67 :   posix_spawn_file_actions_destroy (&file_actions);
    1870                 :         67 : out_free_spawnattr:
    1871                 :         67 :   posix_spawnattr_destroy (&attr);
    1872                 :         67 :   g_slist_free (child_close);
    1873                 :            : 
    1874                 :         67 :   return r;
    1875                 :            : }
    1876                 :            : #endif /* POSIX_SPAWN_AVAILABLE */
    1877                 :            : 
    1878                 :            : static gboolean
    1879                 :       2147 : source_fds_collide_with_pipe (const GUnixPipe  *pipefd,
    1880                 :            :                               const int        *source_fds,
    1881                 :            :                               gsize             n_fds,
    1882                 :            :                               GError          **error)
    1883                 :            : {
    1884   [ +  +  -  + ]:       4293 :   return (_g_spawn_invalid_source_fd (pipefd->fds[G_UNIX_PIPE_END_READ], source_fds, n_fds, error) ||
    1885                 :       2146 :           _g_spawn_invalid_source_fd (pipefd->fds[G_UNIX_PIPE_END_WRITE], source_fds, n_fds, error));
    1886                 :            : }
    1887                 :            : 
    1888                 :            : static gboolean
    1889                 :        973 : fork_exec (gboolean              intermediate_child,
    1890                 :            :            const gchar          *working_directory,
    1891                 :            :            const gchar * const  *argv,
    1892                 :            :            const gchar * const  *envp,
    1893                 :            :            gboolean              close_descriptors,
    1894                 :            :            gboolean              search_path,
    1895                 :            :            gboolean              search_path_from_envp,
    1896                 :            :            gboolean              stdout_to_null,
    1897                 :            :            gboolean              stderr_to_null,
    1898                 :            :            gboolean              child_inherits_stdin,
    1899                 :            :            gboolean              file_and_argv_zero,
    1900                 :            :            gboolean              cloexec_pipes,
    1901                 :            :            GSpawnChildSetupFunc  child_setup,
    1902                 :            :            gpointer              user_data,
    1903                 :            :            GPid                 *child_pid,
    1904                 :            :            gint                 *stdin_pipe_out,
    1905                 :            :            gint                 *stdout_pipe_out,
    1906                 :            :            gint                 *stderr_pipe_out,
    1907                 :            :            gint                  stdin_fd,
    1908                 :            :            gint                  stdout_fd,
    1909                 :            :            gint                  stderr_fd,
    1910                 :            :            const gint           *source_fds,
    1911                 :            :            const gint           *target_fds,
    1912                 :            :            gsize                 n_fds,
    1913                 :            :            GError              **error)
    1914                 :            : {
    1915                 :        973 :   GPid pid = -1;
    1916                 :        973 :   GUnixPipe child_err_report_pipe = G_UNIX_PIPE_INIT;
    1917                 :        973 :   GUnixPipe child_pid_report_pipe = G_UNIX_PIPE_INIT;
    1918         [ +  + ]:        973 :   guint pipe_flags = cloexec_pipes ? O_CLOEXEC : 0;
    1919                 :            :   gint status;
    1920                 :            :   const gchar *chosen_search_path;
    1921                 :        973 :   gchar *search_path_buffer = NULL;
    1922                 :        973 :   gchar *search_path_buffer_heap = NULL;
    1923                 :        973 :   gsize search_path_buffer_len = 0;
    1924                 :        973 :   gchar **argv_buffer = NULL;
    1925                 :        973 :   gchar **argv_buffer_heap = NULL;
    1926                 :        973 :   gsize argv_buffer_len = 0;
    1927                 :        973 :   GUnixPipe stdin_pipe = G_UNIX_PIPE_INIT;
    1928                 :        973 :   GUnixPipe stdout_pipe = G_UNIX_PIPE_INIT;
    1929                 :        973 :   GUnixPipe stderr_pipe = G_UNIX_PIPE_INIT;
    1930                 :        973 :   gint child_close_fds[4] = { -1, -1, -1, -1 };
    1931                 :        973 :   gint n_child_close_fds = 0;
    1932                 :        973 :   gint *source_fds_copy = NULL;
    1933                 :            : 
    1934                 :        973 :   g_assert (argv != NULL && argv[0] != NULL);
    1935                 :        973 :   g_assert (stdin_pipe_out == NULL || stdin_fd < 0);
    1936                 :        973 :   g_assert (stdout_pipe_out == NULL || stdout_fd < 0);
    1937                 :        973 :   g_assert (stderr_pipe_out == NULL || stderr_fd < 0);
    1938                 :            : 
    1939                 :            :   /* If pipes have been requested, open them */
    1940         [ +  + ]:        973 :   if (stdin_pipe_out != NULL)
    1941                 :            :     {
    1942         [ -  + ]:         59 :       if (!g_unix_pipe_open (&stdin_pipe, pipe_flags, error))
    1943                 :          0 :         goto cleanup_and_fail;
    1944         [ -  + ]:         59 :       if (source_fds_collide_with_pipe (&stdin_pipe, source_fds, n_fds, error))
    1945                 :          0 :         goto cleanup_and_fail;
    1946                 :         59 :       child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stdin_pipe, G_UNIX_PIPE_END_WRITE);
    1947                 :         59 :       stdin_fd = g_unix_pipe_get (&stdin_pipe, G_UNIX_PIPE_END_READ);
    1948                 :            :     }
    1949                 :            : 
    1950         [ +  + ]:        973 :   if (stdout_pipe_out != NULL)
    1951                 :            :     {
    1952         [ -  + ]:        639 :       if (!g_unix_pipe_open (&stdout_pipe, pipe_flags, error))
    1953                 :          0 :         goto cleanup_and_fail;
    1954         [ -  + ]:        639 :       if (source_fds_collide_with_pipe (&stdout_pipe, source_fds, n_fds, error))
    1955                 :          0 :         goto cleanup_and_fail;
    1956                 :        639 :       child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stdout_pipe, G_UNIX_PIPE_END_READ);
    1957                 :        639 :       stdout_fd = g_unix_pipe_get (&stdout_pipe, G_UNIX_PIPE_END_WRITE);
    1958                 :            :     }
    1959                 :            : 
    1960         [ +  + ]:        973 :   if (stderr_pipe_out != NULL)
    1961                 :            :     {
    1962         [ -  + ]:        435 :       if (!g_unix_pipe_open (&stderr_pipe, pipe_flags, error))
    1963                 :          0 :         goto cleanup_and_fail;
    1964         [ -  + ]:        435 :       if (source_fds_collide_with_pipe (&stderr_pipe, source_fds, n_fds, error))
    1965                 :          0 :         goto cleanup_and_fail;
    1966                 :        435 :       child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stderr_pipe, G_UNIX_PIPE_END_READ);
    1967                 :        435 :       stderr_fd = g_unix_pipe_get (&stderr_pipe, G_UNIX_PIPE_END_WRITE);
    1968                 :            :     }
    1969                 :            : 
    1970                 :        973 :   child_close_fds[n_child_close_fds++] = -1;
    1971                 :            : 
    1972                 :            : #ifdef POSIX_SPAWN_AVAILABLE
    1973   [ +  +  +  +  :        973 :   if (!intermediate_child && working_directory == NULL && !close_descriptors &&
             +  +  +  - ]
    1974         [ +  - ]:         67 :       !search_path_from_envp && child_setup == NULL)
    1975                 :            :     {
    1976                 :            :       g_trace_mark (G_TRACE_CURRENT_TIME, 0,
    1977                 :            :                     "GLib", "posix_spawn",
    1978                 :            :                     "%s", argv[0]);
    1979                 :            : 
    1980                 :         67 :       status = do_posix_spawn (argv,
    1981                 :            :                                envp,
    1982                 :            :                                search_path,
    1983                 :            :                                stdout_to_null,
    1984                 :            :                                stderr_to_null,
    1985                 :            :                                child_inherits_stdin,
    1986                 :            :                                file_and_argv_zero,
    1987                 :            :                                child_pid,
    1988                 :            :                                child_close_fds,
    1989                 :            :                                stdin_fd,
    1990                 :            :                                stdout_fd,
    1991                 :            :                                stderr_fd,
    1992                 :            :                                source_fds,
    1993                 :            :                                target_fds,
    1994                 :            :                                n_fds);
    1995         [ +  - ]:         67 :       if (status == 0)
    1996                 :         67 :         goto success;
    1997                 :            : 
    1998         [ #  # ]:          0 :       if (status != ENOEXEC)
    1999                 :            :         {
    2000                 :          0 :           g_set_error (error,
    2001                 :            :                        G_SPAWN_ERROR,
    2002                 :            :                        G_SPAWN_ERROR_FAILED,
    2003                 :            :                        _("Failed to spawn child process “%s” (%s)"),
    2004                 :            :                        argv[0],
    2005                 :            :                        g_strerror (status));
    2006                 :          0 :           goto cleanup_and_fail;
    2007                 :            :        }
    2008                 :            : 
    2009                 :            :       /* posix_spawn is not intended to support script execution. It does in
    2010                 :            :        * some situations on some glibc versions, but that will be fixed.
    2011                 :            :        * So if it fails with ENOEXEC, we fall through to the regular
    2012                 :            :        * gspawn codepath so that script execution can be attempted,
    2013                 :            :        * per standard gspawn behaviour. */
    2014                 :          0 :       g_debug ("posix_spawn failed (ENOEXEC), fall back to regular gspawn");
    2015                 :            :     }
    2016                 :            :   else
    2017                 :            :     {
    2018                 :            :       g_trace_mark (G_TRACE_CURRENT_TIME, 0,
    2019                 :            :                     "GLib", "fork",
    2020                 :            :                     "posix_spawn avoided %s%s%s%s%s",
    2021                 :            :                     !intermediate_child ? "" : "(automatic reaping requested) ",
    2022                 :            :                     working_directory == NULL ? "" : "(workdir specified) ",
    2023                 :            :                     !close_descriptors ? "" : "(fd close requested) ",
    2024                 :            :                     !search_path_from_envp ? "" : "(using envp for search path) ",
    2025                 :            :                     child_setup == NULL ? "" : "(child_setup specified) ");
    2026                 :            :     }
    2027                 :            : #endif /* POSIX_SPAWN_AVAILABLE */
    2028                 :            : 
    2029                 :            :   /* Choose a search path. This has to be done before calling fork()
    2030                 :            :    * as getenv() isn’t async-signal-safe (see `man 7 signal-safety`). */
    2031                 :        906 :   chosen_search_path = NULL;
    2032         [ +  + ]:        906 :   if (search_path_from_envp)
    2033                 :         36 :     chosen_search_path = g_environ_getenv ((gchar **) envp, "PATH");
    2034   [ +  +  +  + ]:        906 :   if (search_path && chosen_search_path == NULL)
    2035                 :        233 :     chosen_search_path = g_getenv ("PATH");
    2036                 :            : 
    2037   [ +  +  +  +  :        906 :   if ((search_path || search_path_from_envp) && chosen_search_path == NULL)
                   +  + ]
    2038                 :            :     {
    2039                 :            :       /* There is no 'PATH' in the environment.  The default
    2040                 :            :        * * search path in libc is the current directory followed by
    2041                 :            :        * * the path 'confstr' returns for '_CS_PATH'.
    2042                 :            :        * */
    2043                 :            : 
    2044                 :            :       /* In GLib we put . last, for security, and don't use the
    2045                 :            :        * * unportable confstr(); UNIX98 does not actually specify
    2046                 :            :        * * what to search if PATH is unset. POSIX may, dunno.
    2047                 :            :        * */
    2048                 :            : 
    2049                 :          2 :       chosen_search_path = "/bin:/usr/bin:.";
    2050                 :            :     }
    2051                 :            : 
    2052   [ +  +  +  + ]:        906 :   if (search_path || search_path_from_envp)
    2053                 :        269 :     g_assert (chosen_search_path != NULL);
    2054                 :            :   else
    2055                 :        637 :     g_assert (chosen_search_path == NULL);
    2056                 :            : 
    2057                 :            :   /* Allocate a buffer which the fork()ed child can use to assemble potential
    2058                 :            :    * paths for the binary to exec(), combining the argv[0] and elements from
    2059                 :            :    * the chosen_search_path. This can’t be done in the child because malloc()
    2060                 :            :    * (or alloca()) are not async-signal-safe (see `man 7 signal-safety`).
    2061                 :            :    *
    2062                 :            :    * Add 2 for the nul terminator and a leading `/`. */
    2063         [ +  + ]:        906 :   if (chosen_search_path != NULL)
    2064                 :            :     {
    2065                 :        269 :       search_path_buffer_len = strlen (chosen_search_path) + strlen (argv[0]) + 2;
    2066         [ +  + ]:        269 :       if (search_path_buffer_len < 4000)
    2067                 :            :         {
    2068                 :            :           /* Prefer small stack allocations to avoid valgrind leak warnings
    2069                 :            :            * in forked child. The 4000B cutoff is arbitrary. */
    2070                 :        268 :           search_path_buffer = g_alloca (search_path_buffer_len);
    2071                 :            :         }
    2072                 :            :       else
    2073                 :            :         {
    2074                 :          1 :           search_path_buffer_heap = g_malloc (search_path_buffer_len);
    2075                 :          1 :           search_path_buffer = search_path_buffer_heap;
    2076                 :            :         }
    2077                 :            :     }
    2078                 :            : 
    2079   [ +  +  +  + ]:        906 :   if (search_path || search_path_from_envp)
    2080                 :        269 :     g_assert (search_path_buffer != NULL);
    2081                 :            :   else
    2082                 :        637 :     g_assert (search_path_buffer == NULL);
    2083                 :            : 
    2084                 :            :   /* And allocate a buffer which is 2 elements longer than @argv, so that if
    2085                 :            :    * script_execute() has to be called later on, it can build a wrapper argv
    2086                 :            :    * array in this buffer. */
    2087                 :        906 :   argv_buffer_len = g_strv_length ((gchar **) argv) + 2;
    2088         [ +  + ]:        906 :   if (argv_buffer_len < 4000 / sizeof (gchar *))
    2089                 :            :     {
    2090                 :            :       /* Prefer small stack allocations to avoid valgrind leak warnings
    2091                 :            :        * in forked child. The 4000B cutoff is arbitrary. */
    2092                 :        904 :       argv_buffer = g_newa (gchar *, argv_buffer_len);
    2093                 :            :     }
    2094                 :            :   else
    2095                 :            :     {
    2096                 :          2 :       argv_buffer_heap = g_new (gchar *, argv_buffer_len);
    2097                 :          2 :       argv_buffer = argv_buffer_heap;
    2098                 :            :     }
    2099                 :            : 
    2100                 :            :   /* And one to hold a copy of @source_fds for later manipulation in do_exec(). */
    2101                 :        906 :   source_fds_copy = g_new (int, n_fds);
    2102         [ +  + ]:        906 :   if (n_fds > 0)
    2103                 :          7 :     memcpy (source_fds_copy, source_fds, sizeof (*source_fds) * n_fds);
    2104                 :            : 
    2105         [ -  + ]:        906 :   if (!g_unix_pipe_open (&child_err_report_pipe, pipe_flags, error))
    2106                 :          0 :     goto cleanup_and_fail;
    2107         [ +  + ]:        906 :   if (source_fds_collide_with_pipe (&child_err_report_pipe, source_fds, n_fds, error))
    2108                 :          1 :     goto cleanup_and_fail;
    2109                 :            : 
    2110         [ +  + ]:        905 :   if (intermediate_child)
    2111                 :            :     {
    2112         [ -  + ]:        108 :       if (!g_unix_pipe_open (&child_pid_report_pipe, pipe_flags, error))
    2113                 :          0 :         goto cleanup_and_fail;
    2114         [ -  + ]:        108 :       if (source_fds_collide_with_pipe (&child_pid_report_pipe, source_fds, n_fds, error))
    2115                 :          0 :         goto cleanup_and_fail;
    2116                 :            :     }
    2117                 :            :   
    2118                 :        905 :   pid = fork ();
    2119                 :            : 
    2120         [ -  + ]:       1702 :   if (pid < 0)
    2121                 :            :     {
    2122                 :          0 :       int errsv = errno;
    2123                 :            : 
    2124                 :          0 :       g_set_error (error,
    2125                 :            :                    G_SPAWN_ERROR,
    2126                 :            :                    G_SPAWN_ERROR_FORK,
    2127                 :            :                    _("Failed to fork (%s)"),
    2128                 :            :                    g_strerror (errsv));
    2129                 :            : 
    2130                 :          0 :       goto cleanup_and_fail;
    2131                 :            :     }
    2132         [ +  + ]:       1702 :   else if (pid == 0)
    2133                 :            :     {
    2134                 :            :       /* Immediate child. This may or may not be the child that
    2135                 :            :        * actually execs the new process.
    2136                 :            :        */
    2137                 :            : 
    2138                 :            :       /* Reset some signal handlers that we may use */
    2139                 :        797 :       signal (SIGCHLD, SIG_DFL);
    2140                 :        797 :       signal (SIGINT, SIG_DFL);
    2141                 :        797 :       signal (SIGTERM, SIG_DFL);
    2142                 :        797 :       signal (SIGHUP, SIG_DFL);
    2143                 :            :       
    2144                 :            :       /* Be sure we crash if the parent exits
    2145                 :            :        * and we write to the err_report_pipe
    2146                 :            :        */
    2147                 :        797 :       signal (SIGPIPE, SIG_DFL);
    2148                 :            : 
    2149                 :            :       /* Close the parent's end of the pipes;
    2150                 :            :        * not needed in the close_descriptors case,
    2151                 :            :        * though
    2152                 :            :        */
    2153                 :        797 :       g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_READ, NULL);
    2154                 :        797 :       g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_READ, NULL);
    2155         [ +  + ]:        797 :       if (child_close_fds[0] != -1)
    2156                 :            :         {
    2157                 :        674 :            int i = -1;
    2158         [ +  + ]:       1806 :            while (child_close_fds[++i] != -1)
    2159                 :       1132 :              g_clear_fd (&child_close_fds[i], NULL);
    2160                 :            :         }
    2161                 :            :       
    2162         [ -  + ]:        797 :       if (intermediate_child)
    2163                 :            :         {
    2164                 :            :           /* We need to fork an intermediate child that launches the
    2165                 :            :            * final child. The purpose of the intermediate child
    2166                 :            :            * is to exit, so we can waitpid() it immediately.
    2167                 :            :            * Then the grandchild will not become a zombie.
    2168                 :            :            */
    2169                 :            :           GPid grandchild_pid;
    2170                 :            : 
    2171                 :          0 :           grandchild_pid = fork ();
    2172                 :            : 
    2173         [ -  + ]:        107 :           if (grandchild_pid < 0)
    2174                 :            :             {
    2175                 :            :               /* report -1 as child PID */
    2176                 :          0 :               write_all (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE),
    2177                 :            :                          &grandchild_pid, sizeof(grandchild_pid));
    2178                 :            :               
    2179                 :          0 :               write_err_and_exit (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE),
    2180                 :            :                                   CHILD_FORK_FAILED);              
    2181                 :            :             }
    2182         [ +  - ]:        107 :           else if (grandchild_pid == 0)
    2183                 :            :             {
    2184                 :        107 :               g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    2185                 :        107 :               do_exec (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE),
    2186                 :            :                        stdin_fd,
    2187                 :            :                        stdout_fd,
    2188                 :            :                        stderr_fd,
    2189                 :            :                        source_fds_copy,
    2190                 :            :                        target_fds,
    2191                 :            :                        n_fds,
    2192                 :            :                        working_directory,
    2193                 :            :                        argv,
    2194                 :            :                        argv_buffer,
    2195                 :            :                        argv_buffer_len,
    2196                 :            :                        envp,
    2197                 :            :                        close_descriptors,
    2198                 :            :                        chosen_search_path,
    2199                 :            :                        search_path_buffer,
    2200                 :            :                        search_path_buffer_len,
    2201                 :            :                        stdout_to_null,
    2202                 :            :                        stderr_to_null,
    2203                 :            :                        child_inherits_stdin,
    2204                 :            :                        file_and_argv_zero,
    2205                 :            :                        child_setup,
    2206                 :            :                        user_data);
    2207                 :            :             }
    2208                 :            :           else
    2209                 :            :             {
    2210                 :          0 :               write_all (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE),
    2211                 :            :                          &grandchild_pid, sizeof(grandchild_pid));
    2212                 :          0 :               g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    2213                 :            :               
    2214                 :          0 :               _exit (0);
    2215                 :            :             }
    2216                 :            :         }
    2217                 :            :       else
    2218                 :            :         {
    2219                 :            :           /* Just run the child.
    2220                 :            :            */
    2221                 :            : 
    2222                 :        797 :           do_exec (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE),
    2223                 :            :                    stdin_fd,
    2224                 :            :                    stdout_fd,
    2225                 :            :                    stderr_fd,
    2226                 :            :                    source_fds_copy,
    2227                 :            :                    target_fds,
    2228                 :            :                    n_fds,
    2229                 :            :                    working_directory,
    2230                 :            :                    argv,
    2231                 :            :                    argv_buffer,
    2232                 :            :                    argv_buffer_len,
    2233                 :            :                    envp,
    2234                 :            :                    close_descriptors,
    2235                 :            :                    chosen_search_path,
    2236                 :            :                    search_path_buffer,
    2237                 :            :                    search_path_buffer_len,
    2238                 :            :                    stdout_to_null,
    2239                 :            :                    stderr_to_null,
    2240                 :            :                    child_inherits_stdin,
    2241                 :            :                    file_and_argv_zero,
    2242                 :            :                    child_setup,
    2243                 :            :                    user_data);
    2244                 :            :         }
    2245                 :            :     }
    2246                 :            :   else
    2247                 :            :     {
    2248                 :            :       /* Parent */
    2249                 :            :       
    2250                 :            :       gint buf[2];
    2251                 :        905 :       gint n_ints = 0;    
    2252                 :            : 
    2253                 :            :       /* Close the uncared-about ends of the pipes */
    2254                 :        905 :       g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    2255                 :        905 :       g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    2256                 :            : 
    2257                 :            :       /* If we had an intermediate child, reap it */
    2258         [ +  + ]:        905 :       if (intermediate_child)
    2259                 :            :         {
    2260                 :        108 :         wait_again:
    2261         [ -  + ]:        108 :           if (waitpid (pid, &status, 0) < 0)
    2262                 :            :             {
    2263         [ #  # ]:          0 :               if (errno == EINTR)
    2264                 :          0 :                 goto wait_again;
    2265         [ #  # ]:          0 :               else if (errno == ECHILD)
    2266                 :            :                 ; /* do nothing, child already reaped */
    2267                 :            :               else
    2268                 :          0 :                 g_warning ("waitpid() should not fail in 'fork_exec'");
    2269                 :            :             }
    2270                 :            :         }
    2271                 :            :       
    2272                 :            : 
    2273         [ -  + ]:        905 :       if (!read_ints (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_READ),
    2274                 :            :                       buf, 2, &n_ints,
    2275                 :            :                       error))
    2276                 :          9 :         goto cleanup_and_fail;
    2277                 :            :         
    2278         [ +  + ]:        905 :       if (n_ints >= 2)
    2279                 :            :         {
    2280                 :            :           /* Error from the child. */
    2281                 :            : 
    2282   [ -  +  -  +  :          9 :           switch (buf[0])
                -  -  - ]
    2283                 :            :             {
    2284                 :          0 :             case CHILD_CHDIR_FAILED:
    2285                 :          0 :               g_set_error (error,
    2286                 :            :                            G_SPAWN_ERROR,
    2287                 :            :                            G_SPAWN_ERROR_CHDIR,
    2288                 :            :                            _("Failed to change to directory “%s” (%s)"),
    2289                 :            :                            working_directory,
    2290                 :            :                            g_strerror (buf[1]));
    2291                 :            : 
    2292                 :          0 :               break;
    2293                 :            :               
    2294                 :          8 :             case CHILD_EXEC_FAILED:
    2295                 :          8 :               g_set_error (error,
    2296                 :            :                            G_SPAWN_ERROR,
    2297                 :            :                            _g_spawn_exec_err_to_g_error (buf[1]),
    2298                 :            :                            _("Failed to execute child process “%s” (%s)"),
    2299                 :            :                            argv[0],
    2300                 :            :                            g_strerror (buf[1]));
    2301                 :            : 
    2302                 :          8 :               break;
    2303                 :            : 
    2304                 :          0 :             case CHILD_OPEN_FAILED:
    2305                 :          0 :               g_set_error (error,
    2306                 :            :                            G_SPAWN_ERROR,
    2307                 :            :                            G_SPAWN_ERROR_FAILED,
    2308                 :            :                            _("Failed to open file to remap file descriptor (%s)"),
    2309                 :            :                            g_strerror (buf[1]));
    2310                 :          0 :               break;
    2311                 :            : 
    2312                 :          1 :             case CHILD_DUPFD_FAILED:
    2313                 :          1 :               g_set_error (error,
    2314                 :            :                            G_SPAWN_ERROR,
    2315                 :            :                            G_SPAWN_ERROR_FAILED,
    2316                 :            :                            _("Failed to duplicate file descriptor for child process (%s)"),
    2317                 :            :                            g_strerror (buf[1]));
    2318                 :            : 
    2319                 :          1 :               break;
    2320                 :            : 
    2321                 :          0 :             case CHILD_FORK_FAILED:
    2322                 :          0 :               g_set_error (error,
    2323                 :            :                            G_SPAWN_ERROR,
    2324                 :            :                            G_SPAWN_ERROR_FORK,
    2325                 :            :                            _("Failed to fork child process (%s)"),
    2326                 :            :                            g_strerror (buf[1]));
    2327                 :          0 :               break;
    2328                 :            : 
    2329                 :          0 :             case CHILD_CLOSE_FAILED:
    2330                 :          0 :               g_set_error (error,
    2331                 :            :                            G_SPAWN_ERROR,
    2332                 :            :                            G_SPAWN_ERROR_FAILED,
    2333                 :            :                            _("Failed to close file descriptor for child process (%s)"),
    2334                 :            :                            g_strerror (buf[1]));
    2335                 :          0 :               break;
    2336                 :            : 
    2337                 :          0 :             default:
    2338                 :          0 :               g_set_error (error,
    2339                 :            :                            G_SPAWN_ERROR,
    2340                 :            :                            G_SPAWN_ERROR_FAILED,
    2341                 :            :                            _("Unknown error executing child process “%s”"),
    2342                 :            :                            argv[0]);
    2343                 :          0 :               break;
    2344                 :            :             }
    2345                 :            : 
    2346                 :          9 :           goto cleanup_and_fail;
    2347                 :            :         }
    2348                 :            : 
    2349                 :            :       /* Get child pid from intermediate child pipe. */
    2350         [ +  + ]:        896 :       if (intermediate_child)
    2351                 :            :         {
    2352                 :        105 :           n_ints = 0;
    2353                 :            :           
    2354         [ -  + ]:        105 :           if (!read_ints (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_READ),
    2355                 :            :                           buf, 1, &n_ints, error))
    2356                 :          0 :             goto cleanup_and_fail;
    2357                 :            : 
    2358         [ -  + ]:        105 :           if (n_ints < 1)
    2359                 :            :             {
    2360                 :          0 :               int errsv = errno;
    2361                 :            : 
    2362                 :          0 :               g_set_error (error,
    2363                 :            :                            G_SPAWN_ERROR,
    2364                 :            :                            G_SPAWN_ERROR_FAILED,
    2365                 :            :                            _("Failed to read enough data from child pid pipe (%s)"),
    2366                 :            :                            g_strerror (errsv));
    2367                 :          0 :               goto cleanup_and_fail;
    2368                 :            :             }
    2369                 :            :           else
    2370                 :            :             {
    2371                 :            :               /* we have the child pid */
    2372                 :        105 :               pid = buf[0];
    2373                 :            :             }
    2374                 :            :         }
    2375                 :            :       
    2376                 :            :       /* Success against all odds! return the information */
    2377                 :        896 :       g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_READ, NULL);
    2378                 :        896 :       g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_READ, NULL);
    2379                 :            : 
    2380                 :        896 :       g_free (search_path_buffer_heap);
    2381                 :        896 :       g_free (argv_buffer_heap);
    2382                 :        896 :       g_free (source_fds_copy);
    2383                 :            : 
    2384         [ +  + ]:        896 :       if (child_pid)
    2385                 :        885 :         *child_pid = pid;
    2386                 :            : 
    2387                 :        896 :       goto success;
    2388                 :            :     }
    2389                 :            : 
    2390                 :        963 : success:
    2391                 :            :   /* Close the uncared-about ends of the pipes */
    2392                 :        963 :   g_unix_pipe_close (&stdin_pipe, G_UNIX_PIPE_END_READ, NULL);
    2393                 :        963 :   g_unix_pipe_close (&stdout_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    2394                 :        963 :   g_unix_pipe_close (&stderr_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    2395                 :            : 
    2396         [ +  + ]:        963 :   if (stdin_pipe_out != NULL)
    2397                 :         59 :     *stdin_pipe_out = g_unix_pipe_steal (&stdin_pipe, G_UNIX_PIPE_END_WRITE);
    2398                 :            : 
    2399         [ +  + ]:        963 :   if (stdout_pipe_out != NULL)
    2400                 :        638 :     *stdout_pipe_out = g_unix_pipe_steal (&stdout_pipe, G_UNIX_PIPE_END_READ);
    2401                 :            : 
    2402         [ +  + ]:        963 :   if (stderr_pipe_out != NULL)
    2403                 :        435 :     *stderr_pipe_out = g_unix_pipe_steal (&stderr_pipe, G_UNIX_PIPE_END_READ);
    2404                 :            : 
    2405                 :        963 :   return TRUE;
    2406                 :            : 
    2407                 :         10 :  cleanup_and_fail:
    2408                 :            : 
    2409                 :            :   /* There was an error from the Child, reap the child to avoid it being
    2410                 :            :      a zombie.
    2411                 :            :    */
    2412                 :            : 
    2413         [ +  + ]:         10 :   if (pid > 0)
    2414                 :            :   {
    2415                 :          9 :     wait_failed:
    2416         [ +  + ]:          9 :      if (waitpid (pid, NULL, 0) < 0)
    2417                 :            :        {
    2418         [ -  + ]:          3 :           if (errno == EINTR)
    2419                 :          0 :             goto wait_failed;
    2420         [ -  + ]:          3 :           else if (errno == ECHILD)
    2421                 :            :             ; /* do nothing, child already reaped */
    2422                 :            :           else
    2423                 :          0 :             g_warning ("waitpid() should not fail in 'fork_exec'");
    2424                 :            :        }
    2425                 :            :    }
    2426                 :            : 
    2427                 :         10 :   g_unix_pipe_clear (&stdin_pipe);
    2428                 :         10 :   g_unix_pipe_clear (&stdout_pipe);
    2429                 :         10 :   g_unix_pipe_clear (&stderr_pipe);
    2430                 :         10 :   g_unix_pipe_clear (&child_err_report_pipe);
    2431                 :         10 :   g_unix_pipe_clear (&child_pid_report_pipe);
    2432                 :            : 
    2433                 :         10 :   g_clear_pointer (&search_path_buffer_heap, g_free);
    2434                 :         10 :   g_clear_pointer (&argv_buffer_heap, g_free);
    2435                 :         10 :   g_clear_pointer (&source_fds_copy, g_free);
    2436                 :            : 
    2437                 :         10 :   return FALSE;
    2438                 :            : }
    2439                 :            : 
    2440                 :            : /* Based on execvp from GNU C Library */
    2441                 :            : 
    2442                 :            : /* This function is called between fork() and exec() and hence must be
    2443                 :            :  * async-signal-safe (see signal-safety(7)) until it calls exec(). */
    2444                 :            : static gboolean
    2445                 :          0 : script_execute (const gchar *file,
    2446                 :            :                 gchar      **argv,
    2447                 :            :                 gchar      **argv_buffer,
    2448                 :            :                 gsize        argv_buffer_len,
    2449                 :            :                 gchar      **envp)
    2450                 :            : {
    2451                 :            :   /* Count the arguments.  */
    2452                 :          0 :   gsize argc = 0;
    2453         [ #  # ]:          0 :   while (argv[argc])
    2454                 :          0 :     ++argc;
    2455                 :            : 
    2456                 :            :   /* Construct an argument list for the shell. */
    2457         [ #  # ]:          0 :   if (argc + 2 > argv_buffer_len)
    2458                 :          0 :     return FALSE;
    2459                 :            : 
    2460                 :          0 :   argv_buffer[0] = (char *) "/bin/sh";
    2461                 :          0 :   argv_buffer[1] = (char *) file;
    2462         [ #  # ]:          0 :   while (argc > 0)
    2463                 :            :     {
    2464                 :          0 :       argv_buffer[argc + 1] = argv[argc];
    2465                 :          0 :       --argc;
    2466                 :            :     }
    2467                 :            : 
    2468                 :            :   /* Execute the shell. */
    2469         [ #  # ]:          0 :   if (envp)
    2470                 :          0 :     execve (argv_buffer[0], argv_buffer, envp);
    2471                 :            :   else
    2472                 :          0 :     execv (argv_buffer[0], argv_buffer);
    2473                 :            : 
    2474                 :          0 :   return TRUE;
    2475                 :            : }
    2476                 :            : 
    2477                 :            : /* This function is called between fork() and exec() and hence must be
    2478                 :            :  * async-signal-safe (see signal-safety(7)). */
    2479                 :            : static gchar*
    2480                 :        167 : my_strchrnul (const gchar *str, gchar c)
    2481                 :            : {
    2482                 :        167 :   gchar *p = (gchar*) str;
    2483   [ +  +  +  + ]:       5706 :   while (*p && (*p != c))
    2484                 :       5539 :     ++p;
    2485                 :            : 
    2486                 :        167 :   return p;
    2487                 :            : }
    2488                 :            : 
    2489                 :            : /* This function is called between fork() and exec() and hence must be
    2490                 :            :  * async-signal-safe (see signal-safety(7)) until it calls exec(). */
    2491                 :            : static gint
    2492                 :        904 : g_execute (const gchar  *file,
    2493                 :            :            gchar       **argv,
    2494                 :            :            gchar       **argv_buffer,
    2495                 :            :            gsize         argv_buffer_len,
    2496                 :            :            gchar       **envp,
    2497                 :            :            const gchar  *search_path,
    2498                 :            :            gchar        *search_path_buffer,
    2499                 :            :            gsize         search_path_buffer_len)
    2500                 :            : {
    2501   [ +  -  -  + ]:        904 :   if (file == NULL || *file == '\0')
    2502                 :            :     {
    2503                 :            :       /* We check the simple case first. */
    2504                 :          0 :       errno = ENOENT;
    2505                 :          0 :       return -1;
    2506                 :            :     }
    2507                 :            : 
    2508   [ +  +  +  + ]:        904 :   if (search_path == NULL || strchr (file, '/') != NULL)
    2509                 :            :     {
    2510                 :            :       /* Don't search when it contains a slash. */
    2511         [ +  + ]:        823 :       if (envp)
    2512                 :        228 :         execve (file, argv, envp);
    2513                 :            :       else
    2514                 :        595 :         execv (file, argv);
    2515                 :            :       
    2516   [ -  +  -  - ]:        823 :       if (errno == ENOEXEC &&
    2517                 :          0 :           !script_execute (file, argv, argv_buffer, argv_buffer_len, envp))
    2518                 :            :         {
    2519                 :          0 :           errno = ENOMEM;
    2520                 :          0 :           return -1;
    2521                 :            :         }
    2522                 :            :     }
    2523                 :            :   else
    2524                 :            :     {
    2525                 :         81 :       gboolean got_eacces = 0;
    2526                 :            :       const gchar *path, *p;
    2527                 :            :       gchar *name;
    2528                 :            :       gsize len;
    2529                 :            :       gsize pathlen;
    2530                 :            : 
    2531                 :         81 :       path = search_path;
    2532                 :         81 :       len = strlen (file) + 1;
    2533                 :         81 :       pathlen = strlen (path);
    2534                 :         81 :       name = search_path_buffer;
    2535                 :            : 
    2536         [ -  + ]:         81 :       if (search_path_buffer_len < pathlen + len + 1)
    2537                 :            :         {
    2538                 :          0 :           errno = ENOMEM;
    2539                 :          0 :           return -1;
    2540                 :            :         }
    2541                 :            : 
    2542                 :            :       /* Copy the file name at the top, including '\0'  */
    2543                 :         81 :       memcpy (name + pathlen + 1, file, len);
    2544                 :         81 :       name = name + pathlen;
    2545                 :            :       /* And add the slash before the filename  */
    2546                 :         81 :       *name = '/';
    2547                 :            : 
    2548                 :         81 :       p = path;
    2549                 :            :       do
    2550                 :            :         {
    2551                 :            :           char *startp;
    2552                 :            : 
    2553                 :        248 :           path = p;
    2554                 :        248 :           p = my_strchrnul (path, ':');
    2555                 :            : 
    2556         [ -  + ]:        167 :           if (p == path)
    2557                 :            :             /* Two adjacent colons, or a colon at the beginning or the end
    2558                 :            :              * of 'PATH' means to search the current directory.
    2559                 :            :              */
    2560                 :          0 :             startp = name + 1;
    2561                 :            :           else
    2562                 :        167 :             startp = memcpy (name - (p - path), path, p - path);
    2563                 :            : 
    2564                 :            :           /* Try to execute this name.  If it works, execv will not return.  */
    2565         [ +  + ]:        167 :           if (envp)
    2566                 :         15 :             execve (startp, argv, envp);
    2567                 :            :           else
    2568                 :        152 :             execv (startp, argv);
    2569                 :            :           
    2570   [ -  +  -  - ]:        167 :           if (errno == ENOEXEC &&
    2571                 :          0 :               !script_execute (startp, argv, argv_buffer, argv_buffer_len, envp))
    2572                 :            :             {
    2573                 :          0 :               errno = ENOMEM;
    2574                 :          0 :               return -1;
    2575                 :            :             }
    2576                 :            : 
    2577   [ -  +  -  - ]:        167 :           switch (errno)
    2578                 :            :             {
    2579                 :          0 :             case EACCES:
    2580                 :            :               /* Record the we got a 'Permission denied' error.  If we end
    2581                 :            :                * up finding no executable we can use, we want to diagnose
    2582                 :            :                * that we did find one but were denied access.
    2583                 :            :                */
    2584                 :          0 :               got_eacces = TRUE;
    2585                 :            : 
    2586                 :            :               G_GNUC_FALLTHROUGH;
    2587                 :        167 :             case ENOENT:
    2588                 :            : #ifdef ESTALE
    2589                 :            :             case ESTALE:
    2590                 :            : #endif
    2591                 :            : #ifdef ENOTDIR
    2592                 :            :             case ENOTDIR:
    2593                 :            : #endif
    2594                 :            :               /* Those errors indicate the file is missing or not executable
    2595                 :            :                * by us, in which case we want to just try the next path
    2596                 :            :                * directory.
    2597                 :            :                */
    2598                 :        167 :               break;
    2599                 :            : 
    2600                 :          0 :             case ENODEV:
    2601                 :            :             case ETIMEDOUT:
    2602                 :            :               /* Some strange filesystems like AFS return even
    2603                 :            :                * stranger error numbers.  They cannot reasonably mean anything
    2604                 :            :                * else so ignore those, too.
    2605                 :            :                */
    2606                 :          0 :               break;
    2607                 :            : 
    2608                 :          0 :             default:
    2609                 :            :               /* Some other error means we found an executable file, but
    2610                 :            :                * something went wrong executing it; return the error to our
    2611                 :            :                * caller.
    2612                 :            :                */
    2613                 :          0 :               return -1;
    2614                 :            :             }
    2615                 :            :         }
    2616         [ +  - ]:        167 :       while (*p++ != '\0');
    2617                 :            : 
    2618                 :            :       /* We tried every element and none of them worked.  */
    2619         [ #  # ]:          0 :       if (got_eacces)
    2620                 :            :         /* At least one failure was due to permissions, so report that
    2621                 :            :          * error.
    2622                 :            :          */
    2623                 :          0 :         errno = EACCES;
    2624                 :            :     }
    2625                 :            : 
    2626                 :            :   /* Return the error from the last attempt (probably ENOENT).  */
    2627                 :        823 :   return -1;
    2628                 :            : }
    2629                 :            : 
    2630                 :            : /**
    2631                 :            :  * g_spawn_close_pid:
    2632                 :            :  * @pid: The process reference to close
    2633                 :            :  *
    2634                 :            :  * On some platforms, notably Windows, the #GPid type represents a resource
    2635                 :            :  * which must be closed to prevent resource leaking. g_spawn_close_pid()
    2636                 :            :  * is provided for this purpose. It should be used on all platforms, even
    2637                 :            :  * though it doesn't do anything under UNIX.
    2638                 :            :  **/
    2639                 :            : void
    2640                 :        162 : g_spawn_close_pid (GPid pid)
    2641                 :            : {
    2642                 :        162 : }

Generated by: LCOV version 1.14