LCOV - code coverage report
Current view: top level - glib - gspawn-posix.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 72.0 % 693 499
Test Date: 2026-07-07 05:12:03 Functions: 87.0 % 23 20
Branches: - 0 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                 :             : #elif defined(__FreeBSD__)
     104                 :             : /* FreeBSD has environ in crt rather than libc. Using "extern char** environ"
     105                 :             :  * in the code of a shared library makes it fail to link with -Wl,--no-undefined
     106                 :             :  * See https://reviews.freebsd.org/D30842#840642
     107                 :             :  */
     108                 :             : #include <dlfcn.h>
     109                 :             : #define environ (*((char***)dlsym(RTLD_DEFAULT, "environ")))
     110                 :             : #else
     111                 :             : extern char **environ;
     112                 :             : #endif
     113                 :             : 
     114                 :             : #ifndef O_CLOEXEC
     115                 :             : #define O_CLOEXEC 0
     116                 :             : #else
     117                 :             : #define HAVE_O_CLOEXEC 1
     118                 :             : #endif
     119                 :             : 
     120                 :             : static gint g_execute (const gchar  *file,
     121                 :             :                        gchar       **argv,
     122                 :             :                        gchar       **argv_buffer,
     123                 :             :                        gsize         argv_buffer_len,
     124                 :             :                        gchar       **envp,
     125                 :             :                        const gchar  *search_path,
     126                 :             :                        gchar        *search_path_buffer,
     127                 :             :                        gsize         search_path_buffer_len);
     128                 :             : 
     129                 :             : static gboolean fork_exec (gboolean              intermediate_child,
     130                 :             :                            const gchar          *working_directory,
     131                 :             :                            const gchar * const  *argv,
     132                 :             :                            const gchar * const  *envp,
     133                 :             :                            gboolean              close_descriptors,
     134                 :             :                            gboolean              search_path,
     135                 :             :                            gboolean              search_path_from_envp,
     136                 :             :                            gboolean              stdout_to_null,
     137                 :             :                            gboolean              stderr_to_null,
     138                 :             :                            gboolean              child_inherits_stdin,
     139                 :             :                            gboolean              file_and_argv_zero,
     140                 :             :                            gboolean              cloexec_pipes,
     141                 :             :                            GSpawnChildSetupFunc  child_setup,
     142                 :             :                            gpointer              user_data,
     143                 :             :                            GPid                 *child_pid,
     144                 :             :                            gint                 *stdin_pipe_out,
     145                 :             :                            gint                 *stdout_pipe_out,
     146                 :             :                            gint                 *stderr_pipe_out,
     147                 :             :                            gint                  stdin_fd,
     148                 :             :                            gint                  stdout_fd,
     149                 :             :                            gint                  stderr_fd,
     150                 :             :                            const gint           *source_fds,
     151                 :             :                            const gint           *target_fds,
     152                 :             :                            gsize                 n_fds,
     153                 :             :                            GError              **error);
     154                 :             : 
     155                 :          35 : G_DEFINE_QUARK (g-exec-error-quark, g_spawn_error)
     156                 :          64 : G_DEFINE_QUARK (g-spawn-exit-error-quark, g_spawn_exit_error)
     157                 :             : 
     158                 :             : /* Some versions of OS X define READ_OK in public headers */
     159                 :             : #undef READ_OK
     160                 :             : 
     161                 :             : typedef enum
     162                 :             : {
     163                 :             :   READ_FAILED = 0, /* FALSE */
     164                 :             :   READ_OK,
     165                 :             :   READ_EOF
     166                 :             : } ReadResult;
     167                 :             : 
     168                 :             : static ReadResult
     169                 :         706 : read_data (GString *str,
     170                 :             :            gint     fd,
     171                 :             :            GError **error)
     172                 :             : {
     173                 :             :   gssize bytes;
     174                 :             :   gchar buf[4096];
     175                 :             : 
     176                 :         706 :  again:
     177                 :         706 :   bytes = read (fd, buf, 4096);
     178                 :             : 
     179                 :         706 :   if (bytes == 0)
     180                 :         318 :     return READ_EOF;
     181                 :         388 :   else if (bytes > 0)
     182                 :             :     {
     183                 :             :       g_string_append_len (str, buf, bytes);
     184                 :         388 :       return READ_OK;
     185                 :             :     }
     186                 :           0 :   else if (errno == EINTR)
     187                 :           0 :     goto again;
     188                 :             :   else
     189                 :             :     {
     190                 :           0 :       int errsv = errno;
     191                 :             : 
     192                 :           0 :       g_set_error (error,
     193                 :             :                    G_SPAWN_ERROR,
     194                 :             :                    G_SPAWN_ERROR_READ,
     195                 :             :                    _("Failed to read data from child process (%s)"),
     196                 :             :                    g_strerror (errsv));
     197                 :             : 
     198                 :           0 :       return READ_FAILED;
     199                 :             :     }
     200                 :             : }
     201                 :             : 
     202                 :             : gboolean
     203                 :         322 : g_spawn_sync_impl (const gchar           *working_directory,
     204                 :             :                    gchar                **argv,
     205                 :             :                    gchar                **envp,
     206                 :             :                    GSpawnFlags            flags,
     207                 :             :                    GSpawnChildSetupFunc   child_setup,
     208                 :             :                    gpointer               user_data,
     209                 :             :                    gchar                **standard_output,
     210                 :             :                    gchar                **standard_error,
     211                 :             :                    gint                  *wait_status,
     212                 :             :                    GError               **error)
     213                 :             : {
     214                 :         322 :   gint outpipe = -1;
     215                 :         322 :   gint errpipe = -1;
     216                 :             :   GPid pid;
     217                 :             :   gint ret;
     218                 :         322 :   GString *outstr = NULL;
     219                 :         322 :   GString *errstr = NULL;
     220                 :             :   gboolean failed;
     221                 :             :   gint status;
     222                 :             :   
     223                 :         322 :   g_return_val_if_fail (argv != NULL, FALSE);
     224                 :         322 :   g_return_val_if_fail (argv[0] != NULL, FALSE);
     225                 :         322 :   g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
     226                 :         322 :   g_return_val_if_fail (standard_output == NULL ||
     227                 :             :                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
     228                 :         322 :   g_return_val_if_fail (standard_error == NULL ||
     229                 :             :                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
     230                 :             :   
     231                 :             :   /* Just to ensure segfaults if callers try to use
     232                 :             :    * these when an error is reported.
     233                 :             :    */
     234                 :         322 :   if (standard_output)
     235                 :         243 :     *standard_output = NULL;
     236                 :             : 
     237                 :         322 :   if (standard_error)
     238                 :          76 :     *standard_error = NULL;
     239                 :             :   
     240                 :         644 :   if (!fork_exec (FALSE,
     241                 :             :                   working_directory,
     242                 :             :                   (const gchar * const *) argv,
     243                 :             :                   (const gchar * const *) envp,
     244                 :         322 :                   !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
     245                 :         322 :                   (flags & G_SPAWN_SEARCH_PATH) != 0,
     246                 :         322 :                   (flags & G_SPAWN_SEARCH_PATH_FROM_ENVP) != 0,
     247                 :         322 :                   (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
     248                 :         322 :                   (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
     249                 :         322 :                   (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
     250                 :         322 :                   (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
     251                 :         322 :                   (flags & G_SPAWN_CLOEXEC_PIPES) != 0,
     252                 :             :                   child_setup,
     253                 :             :                   user_data,
     254                 :             :                   &pid,
     255                 :             :                   NULL,
     256                 :             :                   standard_output ? &outpipe : NULL,
     257                 :             :                   standard_error ? &errpipe : NULL,
     258                 :             :                   -1, -1, -1,
     259                 :             :                   NULL, NULL, 0,
     260                 :             :                   error))
     261                 :           6 :     return FALSE;
     262                 :             : 
     263                 :             :   /* Read data from child. */
     264                 :             :   
     265                 :         316 :   failed = FALSE;
     266                 :             : 
     267                 :         316 :   if (outpipe >= 0)
     268                 :             :     {
     269                 :         242 :       outstr = g_string_new (NULL);
     270                 :             :     }
     271                 :             :       
     272                 :         316 :   if (errpipe >= 0)
     273                 :             :     {
     274                 :          76 :       errstr = g_string_new (NULL);
     275                 :             :     }
     276                 :             : 
     277                 :             :   /* Read data until we get EOF on both pipes. */
     278                 :         954 :   while (!failed &&
     279                 :         954 :          (outpipe >= 0 ||
     280                 :         334 :           errpipe >= 0))
     281                 :             :     {
     282                 :             :       /* Any negative FD in the array is ignored, so we can use a fixed length.
     283                 :             :        * We can use UNIX FDs here without worrying about Windows HANDLEs because
     284                 :             :        * the Windows implementation is entirely in gspawn-win32.c. */
     285                 :         638 :       GPollFD fds[] =
     286                 :             :         {
     287                 :             :           { outpipe, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 },
     288                 :             :           { errpipe, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 },
     289                 :             :         };
     290                 :             : 
     291                 :         638 :       ret = g_poll (fds, G_N_ELEMENTS (fds), -1  /* no timeout */);
     292                 :             : 
     293                 :         638 :       if (ret < 0)
     294                 :             :         {
     295                 :           0 :           int errsv = errno;
     296                 :             : 
     297                 :           0 :           if (errno == EINTR)
     298                 :           0 :             continue;
     299                 :             : 
     300                 :           0 :           failed = TRUE;
     301                 :             : 
     302                 :           0 :           g_set_error (error,
     303                 :             :                        G_SPAWN_ERROR,
     304                 :             :                        G_SPAWN_ERROR_READ,
     305                 :             :                        _("Unexpected error in reading data from a child process (%s)"),
     306                 :             :                        g_strerror (errsv));
     307                 :             :               
     308                 :           0 :           break;
     309                 :             :         }
     310                 :             : 
     311                 :         638 :       if (outpipe >= 0 && fds[0].revents != 0)
     312                 :             :         {
     313                 :         606 :           switch (read_data (outstr, outpipe, error))
     314                 :             :             {
     315                 :           0 :             case READ_FAILED:
     316                 :           0 :               failed = TRUE;
     317                 :           0 :               break;
     318                 :         242 :             case READ_EOF:
     319                 :         242 :               g_clear_fd (&outpipe, NULL);
     320                 :         242 :               break;
     321                 :         364 :             default:
     322                 :         364 :               break;
     323                 :             :             }
     324                 :             : 
     325                 :         606 :           if (failed)
     326                 :           0 :             break;
     327                 :             :         }
     328                 :             : 
     329                 :         638 :       if (errpipe >= 0 && fds[1].revents != 0)
     330                 :             :         {
     331                 :         100 :           switch (read_data (errstr, errpipe, error))
     332                 :             :             {
     333                 :           0 :             case READ_FAILED:
     334                 :           0 :               failed = TRUE;
     335                 :           0 :               break;
     336                 :          76 :             case READ_EOF:
     337                 :          76 :               g_clear_fd (&errpipe, NULL);
     338                 :          76 :               break;
     339                 :          24 :             default:
     340                 :          24 :               break;
     341                 :             :             }
     342                 :             : 
     343                 :         100 :           if (failed)
     344                 :           0 :             break;
     345                 :             :         }
     346                 :             :     }
     347                 :             : 
     348                 :             :   /* These should only be open still if we had an error.  */
     349                 :         316 :   g_clear_fd (&outpipe, NULL);
     350                 :         316 :   g_clear_fd (&errpipe, NULL);
     351                 :             : 
     352                 :             :   /* Wait for child to exit, even if we have
     353                 :             :    * an error pending.
     354                 :             :    */
     355                 :         316 :  again:
     356                 :             :       
     357                 :         316 :   ret = waitpid (pid, &status, 0);
     358                 :             : 
     359                 :         316 :   if (ret < 0)
     360                 :             :     {
     361                 :           0 :       if (errno == EINTR)
     362                 :           0 :         goto again;
     363                 :           0 :       else if (errno == ECHILD)
     364                 :             :         {
     365                 :           0 :           if (wait_status)
     366                 :             :             {
     367                 :           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.");
     368                 :             :             }
     369                 :             :           else
     370                 :             :             {
     371                 :             :               /* We don't need the wait status. */
     372                 :             :             }
     373                 :             :         }
     374                 :             :       else
     375                 :             :         {
     376                 :           0 :           if (!failed) /* avoid error pileups */
     377                 :             :             {
     378                 :           0 :               int errsv = errno;
     379                 :             : 
     380                 :           0 :               failed = TRUE;
     381                 :             :                   
     382                 :           0 :               g_set_error (error,
     383                 :             :                            G_SPAWN_ERROR,
     384                 :             :                            G_SPAWN_ERROR_READ,
     385                 :             :                            _("Unexpected error in waitpid() (%s)"),
     386                 :             :                            g_strerror (errsv));
     387                 :             :             }
     388                 :             :         }
     389                 :             :     }
     390                 :             :   
     391                 :         316 :   if (failed)
     392                 :             :     {
     393                 :           0 :       if (outstr)
     394                 :           0 :         g_string_free (outstr, TRUE);
     395                 :           0 :       if (errstr)
     396                 :           0 :         g_string_free (errstr, TRUE);
     397                 :             : 
     398                 :           0 :       return FALSE;
     399                 :             :     }
     400                 :             :   else
     401                 :             :     {
     402                 :         316 :       if (wait_status)
     403                 :         280 :         *wait_status = status;
     404                 :             :       
     405                 :         316 :       if (standard_output)        
     406                 :         242 :         *standard_output = g_string_free (outstr, FALSE);
     407                 :             : 
     408                 :         316 :       if (standard_error)
     409                 :          76 :         *standard_error = g_string_free (errstr, FALSE);
     410                 :             : 
     411                 :         316 :       return TRUE;
     412                 :             :     }
     413                 :             : }
     414                 :             : 
     415                 :             : gboolean
     416                 :         784 : g_spawn_async_with_pipes_and_fds_impl (const gchar           *working_directory,
     417                 :             :                                        const gchar * const   *argv,
     418                 :             :                                        const gchar * const   *envp,
     419                 :             :                                        GSpawnFlags            flags,
     420                 :             :                                        GSpawnChildSetupFunc   child_setup,
     421                 :             :                                        gpointer               user_data,
     422                 :             :                                        gint                   stdin_fd,
     423                 :             :                                        gint                   stdout_fd,
     424                 :             :                                        gint                   stderr_fd,
     425                 :             :                                        const gint            *source_fds,
     426                 :             :                                        const gint            *target_fds,
     427                 :             :                                        gsize                  n_fds,
     428                 :             :                                        GPid                  *child_pid_out,
     429                 :             :                                        gint                  *stdin_pipe_out,
     430                 :             :                                        gint                  *stdout_pipe_out,
     431                 :             :                                        gint                  *stderr_pipe_out,
     432                 :             :                                        GError               **error)
     433                 :             : {
     434                 :         784 :   g_return_val_if_fail (argv != NULL, FALSE);
     435                 :         784 :   g_return_val_if_fail (argv[0] != NULL, FALSE);
     436                 :             :   /* can’t both inherit and set pipes to /dev/null */
     437                 :         784 :   g_return_val_if_fail ((flags & INHERITS_OR_NULL_STDIN) != INHERITS_OR_NULL_STDIN, FALSE);
     438                 :         784 :   g_return_val_if_fail ((flags & INHERITS_OR_NULL_STDOUT) != INHERITS_OR_NULL_STDOUT, FALSE);
     439                 :         784 :   g_return_val_if_fail ((flags & INHERITS_OR_NULL_STDERR) != INHERITS_OR_NULL_STDERR, FALSE);
     440                 :             :   /* can’t use pipes and stdin/stdout/stderr FDs */
     441                 :         784 :   g_return_val_if_fail (stdin_pipe_out == NULL || stdin_fd < 0, FALSE);
     442                 :         784 :   g_return_val_if_fail (stdout_pipe_out == NULL || stdout_fd < 0, FALSE);
     443                 :         784 :   g_return_val_if_fail (stderr_pipe_out == NULL || stderr_fd < 0, FALSE);
     444                 :             : 
     445                 :         784 :   if ((flags & INHERITS_OR_NULL_STDIN) != 0)
     446                 :           4 :     stdin_pipe_out = NULL;
     447                 :         784 :   if ((flags & INHERITS_OR_NULL_STDOUT) != 0)
     448                 :          34 :     stdout_pipe_out = NULL;
     449                 :         784 :   if ((flags & INHERITS_OR_NULL_STDERR) != 0)
     450                 :          25 :     stderr_pipe_out = NULL;
     451                 :             : 
     452                 :         784 :   return fork_exec (!(flags & G_SPAWN_DO_NOT_REAP_CHILD),
     453                 :             :                     working_directory,
     454                 :             :                     (const gchar * const *) argv,
     455                 :             :                     (const gchar * const *) envp,
     456                 :         784 :                     !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
     457                 :         784 :                     (flags & G_SPAWN_SEARCH_PATH) != 0,
     458                 :         784 :                     (flags & G_SPAWN_SEARCH_PATH_FROM_ENVP) != 0,
     459                 :         784 :                     (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
     460                 :         784 :                     (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
     461                 :         784 :                     (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
     462                 :         784 :                     (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
     463                 :         784 :                     (flags & G_SPAWN_CLOEXEC_PIPES) != 0,
     464                 :             :                     child_setup,
     465                 :             :                     user_data,
     466                 :             :                     child_pid_out,
     467                 :             :                     stdin_pipe_out,
     468                 :             :                     stdout_pipe_out,
     469                 :             :                     stderr_pipe_out,
     470                 :             :                     stdin_fd,
     471                 :             :                     stdout_fd,
     472                 :             :                     stderr_fd,
     473                 :             :                     source_fds,
     474                 :             :                     target_fds,
     475                 :             :                     n_fds,
     476                 :             :                     error);
     477                 :             : }
     478                 :             : 
     479                 :             : gboolean
     480                 :         199 : g_spawn_check_wait_status_impl (gint     wait_status,
     481                 :             :                                 GError **error)
     482                 :             : {
     483                 :         199 :   gboolean ret = FALSE;
     484                 :             : 
     485                 :         199 :   if (WIFEXITED (wait_status))
     486                 :             :     {
     487                 :         193 :       if (WEXITSTATUS (wait_status) != 0)
     488                 :             :         {
     489                 :          46 :           g_set_error (error, G_SPAWN_EXIT_ERROR, WEXITSTATUS (wait_status),
     490                 :             :                        _("Child process exited with code %ld"),
     491                 :          46 :                        (long) WEXITSTATUS (wait_status));
     492                 :          46 :           goto out;
     493                 :             :         }
     494                 :             :     }
     495                 :           6 :   else if (WIFSIGNALED (wait_status))
     496                 :             :     {
     497                 :           6 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     498                 :             :                    _("Child process killed by signal %ld"),
     499                 :           6 :                    (long) WTERMSIG (wait_status));
     500                 :           6 :       goto out;
     501                 :             :     }
     502                 :           0 :   else if (WIFSTOPPED (wait_status))
     503                 :             :     {
     504                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     505                 :             :                    _("Child process stopped by signal %ld"),
     506                 :           0 :                    (long) WSTOPSIG (wait_status));
     507                 :           0 :       goto out;
     508                 :             :     }
     509                 :             :   else
     510                 :             :     {
     511                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     512                 :             :                    _("Child process exited abnormally"));
     513                 :           0 :       goto out;
     514                 :             :     }
     515                 :             : 
     516                 :         147 :   ret = TRUE;
     517                 :         199 :  out:
     518                 :         199 :   return ret;
     519                 :             : }
     520                 :             : 
     521                 :             : /* This function is called between fork() and exec() and hence must be
     522                 :             :  * async-signal-safe (see signal-safety(7)). */
     523                 :             : static gssize
     524                 :           0 : write_all (gint fd, gconstpointer vbuf, gsize to_write)
     525                 :             : {
     526                 :           0 :   gchar *buf = (gchar *) vbuf;
     527                 :             :   
     528                 :           0 :   while (to_write > 0)
     529                 :             :     {
     530                 :           0 :       gssize count = write (fd, buf, to_write);
     531                 :           0 :       if (count < 0)
     532                 :             :         {
     533                 :           0 :           if (errno != EINTR)
     534                 :           0 :             return FALSE;
     535                 :             :         }
     536                 :             :       else
     537                 :             :         {
     538                 :           0 :           to_write -= count;
     539                 :           0 :           buf += count;
     540                 :             :         }
     541                 :             :     }
     542                 :             :   
     543                 :           0 :   return TRUE;
     544                 :             : }
     545                 :             : 
     546                 :             : /* This function is called between fork() and exec() and hence must be
     547                 :             :  * async-signal-safe (see signal-safety(7)). */
     548                 :             : G_NORETURN
     549                 :             : static void
     550                 :           0 : write_err_and_exit (gint fd, gint msg)
     551                 :             : {
     552                 :           0 :   gint en = errno;
     553                 :             :   
     554                 :           0 :   write_all (fd, &msg, sizeof(msg));
     555                 :           0 :   write_all (fd, &en, sizeof(en));
     556                 :             : 
     557                 :           0 :   close (fd);
     558                 :             :   
     559                 :           0 :   _exit (1);
     560                 :             : }
     561                 :             : 
     562                 :             : /* This function is called between fork() and exec() and hence must be
     563                 :             :  * async-signal-safe (see signal-safety(7)). */
     564                 :             : static void
     565                 :        2273 : set_cloexec (int fd)
     566                 :             : {
     567                 :        2273 :   fcntl (fd, F_SETFD, FD_CLOEXEC);
     568                 :        2273 : }
     569                 :             : 
     570                 :             : /* This function is called between fork() and exec() and hence must be
     571                 :             :  * async-signal-safe (see signal-safety(7)). */
     572                 :             : static void
     573                 :           2 : unset_cloexec (int fd)
     574                 :             : {
     575                 :             :   int flags;
     576                 :             :   int result;
     577                 :             : 
     578                 :           2 :   flags = fcntl (fd, F_GETFD, 0);
     579                 :             : 
     580                 :           2 :   if (flags != -1)
     581                 :             :     {
     582                 :             :       int errsv;
     583                 :           2 :       flags &= (~FD_CLOEXEC);
     584                 :             :       do
     585                 :             :         {
     586                 :           2 :           result = fcntl (fd, F_SETFD, flags);
     587                 :           2 :           errsv = errno;
     588                 :             :         }
     589                 :           2 :       while (result == -1 && errsv == EINTR);
     590                 :             :     }
     591                 :           2 : }
     592                 :             : 
     593                 :             : /* This function is called between fork() and exec() and hence must be
     594                 :             :  * async-signal-safe (see signal-safety(7)). */
     595                 :             : static int
     596                 :         117 : dupfd_cloexec (int old_fd, int new_fd_min)
     597                 :             : {
     598                 :             :   int fd, errsv;
     599                 :             : #ifdef F_DUPFD_CLOEXEC
     600                 :             :   do
     601                 :             :     {
     602                 :         117 :       fd = fcntl (old_fd, F_DUPFD_CLOEXEC, new_fd_min);
     603                 :         117 :       errsv = errno;
     604                 :             :     }
     605                 :         117 :   while (fd == -1 && errsv == EINTR);
     606                 :             : #else
     607                 :             :   /* OS X Snow Lion and earlier don't have F_DUPFD_CLOEXEC:
     608                 :             :    * https://bugzilla.gnome.org/show_bug.cgi?id=710962
     609                 :             :    */
     610                 :             :   int result, flags;
     611                 :             :   do
     612                 :             :     {
     613                 :             :       fd = fcntl (old_fd, F_DUPFD, new_fd_min);
     614                 :             :       errsv = errno;
     615                 :             :     }
     616                 :             :   while (fd == -1 && errsv == EINTR);
     617                 :             :   flags = fcntl (fd, F_GETFD, 0);
     618                 :             :   if (flags != -1)
     619                 :             :     {
     620                 :             :       flags |= FD_CLOEXEC;
     621                 :             :       do
     622                 :             :         {
     623                 :             :           result = fcntl (fd, F_SETFD, flags);
     624                 :             :           errsv = errno;
     625                 :             :         }
     626                 :             :       while (result == -1 && errsv == EINTR);
     627                 :             :     }
     628                 :             : #endif
     629                 :         117 :   return fd;
     630                 :             : }
     631                 :             : 
     632                 :             : /* This function is called between fork() and exec() and hence must be
     633                 :             :  * async-signal-safe (see signal-safety(7)). */
     634                 :             : static gint
     635                 :        3444 : safe_dup2 (gint fd1, gint fd2)
     636                 :             : {
     637                 :             :   gint ret;
     638                 :             : 
     639                 :             :   do
     640                 :        3444 :     ret = dup2 (fd1, fd2);
     641                 :        3444 :   while (ret < 0 && (errno == EINTR || errno == EBUSY));
     642                 :             : 
     643                 :        3444 :   return ret;
     644                 :             : }
     645                 :             : 
     646                 :             : /* This function is called between fork() and exec() and hence must be
     647                 :             :  * async-signal-safe (see signal-safety(7)). */
     648                 :             : static gboolean
     649                 :          16 : relocate_fd_out_of_standard_range (gint *fd)
     650                 :             : {
     651                 :          16 :   gint ret = -1;
     652                 :          16 :   const int min_fileno = STDERR_FILENO + 1;
     653                 :             : 
     654                 :             :   do
     655                 :          16 :     ret = fcntl (*fd, F_DUPFD, min_fileno);
     656                 :          16 :   while (ret < 0 && errno == EINTR);
     657                 :             : 
     658                 :             :   /* Note we don't need to close the old fd, because the caller is expected
     659                 :             :    * to close fds in the standard range itself.
     660                 :             :    */
     661                 :          16 :   if (ret >= min_fileno)
     662                 :             :     {
     663                 :          16 :       *fd = ret;
     664                 :          16 :       return TRUE;
     665                 :             :     }
     666                 :             : 
     667                 :           0 :   return FALSE;
     668                 :             : }
     669                 :             : 
     670                 :             : /* This function is called between fork() and exec() and hence must be
     671                 :             :  * async-signal-safe (see signal-safety(7)). */
     672                 :             : static gint
     673                 :        1265 : safe_open (const char *path, gint mode)
     674                 :             : {
     675                 :             :   gint ret;
     676                 :             : 
     677                 :             :   do
     678                 :        1265 :     ret = open (path, mode);
     679                 :        1265 :   while (ret < 0 && errno == EINTR);
     680                 :             : 
     681                 :        1265 :   return ret;
     682                 :             : }
     683                 :             : 
     684                 :             : enum
     685                 :             : {
     686                 :             :   CHILD_CHDIR_FAILED,
     687                 :             :   CHILD_EXEC_FAILED,
     688                 :             :   CHILD_OPEN_FAILED,
     689                 :             :   CHILD_DUPFD_FAILED,
     690                 :             :   CHILD_FORK_FAILED,
     691                 :             :   CHILD_CLOSE_FAILED,
     692                 :             : };
     693                 :             : 
     694                 :             : /* This function is called between fork() and exec() and hence must be
     695                 :             :  * async-signal-safe (see signal-safety(7)) until it calls exec().
     696                 :             :  *
     697                 :             :  * All callers must guarantee that @argv and @argv[0] are non-NULL. */
     698                 :             : static void
     699                 :        1004 : do_exec (gint                  child_err_report_fd,
     700                 :             :          gint                  stdin_fd,
     701                 :             :          gint                  stdout_fd,
     702                 :             :          gint                  stderr_fd,
     703                 :             :          gint                 *source_fds,
     704                 :             :          const gint           *target_fds,
     705                 :             :          gsize                 n_fds,
     706                 :             :          const gchar          *working_directory,
     707                 :             :          const gchar * const  *argv,
     708                 :             :          gchar               **argv_buffer,
     709                 :             :          gsize                 argv_buffer_len,
     710                 :             :          const gchar * const  *envp,
     711                 :             :          gboolean              close_descriptors,
     712                 :             :          const gchar          *search_path,
     713                 :             :          gchar                *search_path_buffer,
     714                 :             :          gsize                 search_path_buffer_len,
     715                 :             :          gboolean              stdout_to_null,
     716                 :             :          gboolean              stderr_to_null,
     717                 :             :          gboolean              child_inherits_stdin,
     718                 :             :          gboolean              file_and_argv_zero,
     719                 :             :          GSpawnChildSetupFunc  child_setup,
     720                 :             :          gpointer              user_data)
     721                 :             : {
     722                 :             :   gsize i;
     723                 :        1004 :   gint max_target_fd = 0;
     724                 :             : 
     725                 :        1004 :   if (working_directory && chdir (working_directory) < 0)
     726                 :           0 :     write_err_and_exit (child_err_report_fd,
     727                 :             :                         CHILD_CHDIR_FAILED);
     728                 :             : 
     729                 :             :   /* It's possible the caller assigned stdin to an fd with a
     730                 :             :    * file number that is supposed to be reserved for
     731                 :             :    * stdout or stderr.
     732                 :             :    *
     733                 :             :    * If so, move it up out of the standard range, so it doesn't
     734                 :             :    * cause a conflict.
     735                 :             :    */
     736                 :        1004 :   if (IS_STD_FILENO (stdin_fd) && stdin_fd != STDIN_FILENO)
     737                 :             :     {
     738                 :           0 :       int old_fd = stdin_fd;
     739                 :             : 
     740                 :           0 :       if (!relocate_fd_out_of_standard_range (&stdin_fd))
     741                 :           0 :         write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
     742                 :             : 
     743                 :           0 :       if (stdout_fd == old_fd)
     744                 :           0 :         stdout_fd = stdin_fd;
     745                 :             : 
     746                 :           0 :       if (stderr_fd == old_fd)
     747                 :           0 :         stderr_fd = stdin_fd;
     748                 :             :     }
     749                 :             : 
     750                 :             :   /* Redirect pipes as required
     751                 :             :    *
     752                 :             :    * There are two cases where we don't need to do the redirection
     753                 :             :    * 1. Where the associated file descriptor is cleared/invalid
     754                 :             :    * 2. When the associated file descriptor is already given the
     755                 :             :    * correct file number.
     756                 :             :    */
     757                 :        1004 :   if (IS_VALID_FILENO (stdin_fd) && stdin_fd != STDIN_FILENO)
     758                 :             :     {
     759                 :          60 :       if (safe_dup2 (stdin_fd, 0) < 0)
     760                 :           0 :         write_err_and_exit (child_err_report_fd,
     761                 :             :                             CHILD_DUPFD_FAILED);
     762                 :             : 
     763                 :          60 :       set_cloexec (stdin_fd);
     764                 :             :     }
     765                 :         944 :   else if (!child_inherits_stdin)
     766                 :             :     {
     767                 :             :       /* Keep process from blocking on a read of stdin */
     768                 :         940 :       gint read_null = safe_open ("/dev/null", O_RDONLY);
     769                 :         940 :       if (read_null < 0)
     770                 :           0 :         write_err_and_exit (child_err_report_fd,
     771                 :             :                             CHILD_OPEN_FAILED);
     772                 :         940 :       if (safe_dup2 (read_null, 0) < 0)
     773                 :           0 :         write_err_and_exit (child_err_report_fd,
     774                 :             :                             CHILD_DUPFD_FAILED);
     775                 :         940 :       g_clear_fd (&read_null, NULL);
     776                 :             :     }
     777                 :             : 
     778                 :             :   /* Like with stdin above, it's possible the caller assigned
     779                 :             :    * stdout to an fd with a file number that's intruding on the
     780                 :             :    * standard range.
     781                 :             :    *
     782                 :             :    * If so, move it out of the way, too.
     783                 :             :    */
     784                 :        1004 :   if (IS_STD_FILENO (stdout_fd) && stdout_fd != STDOUT_FILENO)
     785                 :             :     {
     786                 :           4 :       int old_fd = stdout_fd;
     787                 :             : 
     788                 :           4 :       if (!relocate_fd_out_of_standard_range (&stdout_fd))
     789                 :           0 :         write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
     790                 :             : 
     791                 :           4 :       if (stderr_fd == old_fd)
     792                 :           0 :         stderr_fd = stdout_fd;
     793                 :             :     }
     794                 :             : 
     795                 :        1004 :   if (IS_VALID_FILENO (stdout_fd) && stdout_fd != STDOUT_FILENO)
     796                 :             :     {
     797                 :         730 :       if (safe_dup2 (stdout_fd, 1) < 0)
     798                 :           0 :         write_err_and_exit (child_err_report_fd,
     799                 :             :                             CHILD_DUPFD_FAILED);
     800                 :             : 
     801                 :         730 :       set_cloexec (stdout_fd);
     802                 :             :     }
     803                 :         274 :   else if (stdout_to_null)
     804                 :             :     {
     805                 :          90 :       gint write_null = safe_open ("/dev/null", O_WRONLY);
     806                 :          90 :       if (write_null < 0)
     807                 :           0 :         write_err_and_exit (child_err_report_fd,
     808                 :             :                             CHILD_OPEN_FAILED);
     809                 :          90 :       if (safe_dup2 (write_null, 1) < 0)
     810                 :           0 :         write_err_and_exit (child_err_report_fd,
     811                 :             :                             CHILD_DUPFD_FAILED);
     812                 :          90 :       g_clear_fd (&write_null, NULL);
     813                 :             :     }
     814                 :             : 
     815                 :        1004 :   if (IS_STD_FILENO (stderr_fd) && stderr_fd != STDERR_FILENO)
     816                 :             :     {
     817                 :          12 :       if (!relocate_fd_out_of_standard_range (&stderr_fd))
     818                 :           0 :         write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
     819                 :             :     }
     820                 :             : 
     821                 :             :   /* Like with stdin/stdout above, it's possible the caller assigned
     822                 :             :    * stderr to an fd with a file number that's intruding on the
     823                 :             :    * standard range.
     824                 :             :    *
     825                 :             :    * Make sure it's out of the way, also.
     826                 :             :    */
     827                 :        1004 :   if (IS_VALID_FILENO (stderr_fd) && stderr_fd != STDERR_FILENO)
     828                 :             :     {
     829                 :         487 :       if (safe_dup2 (stderr_fd, 2) < 0)
     830                 :           0 :         write_err_and_exit (child_err_report_fd,
     831                 :             :                             CHILD_DUPFD_FAILED);
     832                 :             : 
     833                 :         487 :       set_cloexec (stderr_fd);
     834                 :             :     }
     835                 :         517 :   else if (stderr_to_null)
     836                 :             :     {
     837                 :         127 :       gint write_null = safe_open ("/dev/null", O_WRONLY);
     838                 :         127 :       if (write_null < 0)
     839                 :           0 :         write_err_and_exit (child_err_report_fd,
     840                 :             :                             CHILD_OPEN_FAILED);
     841                 :         127 :       if (safe_dup2 (write_null, 2) < 0)
     842                 :           0 :         write_err_and_exit (child_err_report_fd,
     843                 :             :                             CHILD_DUPFD_FAILED);
     844                 :         127 :       g_clear_fd (&write_null, NULL);
     845                 :             :     }
     846                 :             : 
     847                 :             :   /* Close all file descriptors but stdin, stdout and stderr, and any of source_fds,
     848                 :             :    * before we exec. Note that this includes
     849                 :             :    * child_err_report_fd, which keeps the parent from blocking
     850                 :             :    * forever on the other end of that pipe.
     851                 :             :    */
     852                 :        1004 :   if (close_descriptors)
     853                 :             :     {
     854                 :        1000 :       if (child_setup == NULL && n_fds == 0)
     855                 :             :         {
     856                 :         992 :           if (safe_dup2 (child_err_report_fd, 3) < 0)
     857                 :           0 :             write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
     858                 :         992 :           set_cloexec (3);
     859                 :         992 :           if (g_closefrom (4) < 0)
     860                 :           0 :             write_err_and_exit (child_err_report_fd, CHILD_CLOSE_FAILED);
     861                 :         992 :           child_err_report_fd = 3;
     862                 :             :         }
     863                 :             :       else
     864                 :             :         {
     865                 :           8 :           if (g_fdwalk_set_cloexec (3) < 0)
     866                 :           0 :             write_err_and_exit (child_err_report_fd, CHILD_CLOSE_FAILED);
     867                 :             :         }
     868                 :             :     }
     869                 :             :   else
     870                 :             :     {
     871                 :             :       /* We need to do child_err_report_fd anyway */
     872                 :           4 :       set_cloexec (child_err_report_fd);
     873                 :             :     }
     874                 :             : 
     875                 :             :   /*
     876                 :             :    * Work through the @source_fds and @target_fds mapping.
     877                 :             :    *
     878                 :             :    * Based on code originally derived from
     879                 :             :    * gnome-terminal:src/terminal-screen.c:terminal_screen_child_setup(),
     880                 :             :    * used under the LGPLv2+ with permission from author. (The code has
     881                 :             :    * since migrated to vte:src/spawn.cc:SpawnContext::exec and is no longer
     882                 :             :    * terribly similar to what we have here.)
     883                 :             :    */
     884                 :             : 
     885                 :        1004 :   if (n_fds > 0)
     886                 :             :     {
     887                 :          26 :       for (i = 0; i < n_fds; i++)
     888                 :          20 :         max_target_fd = MAX (max_target_fd, target_fds[i]);
     889                 :             : 
     890                 :           6 :       if (max_target_fd == G_MAXINT)
     891                 :             :         {
     892                 :           0 :           errno = EINVAL;
     893                 :           0 :           write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
     894                 :             :         }
     895                 :             : 
     896                 :             :       /* If we're doing remapping fd assignments, we need to handle
     897                 :             :        * the case where the user has specified e.g. 5 -> 4, 4 -> 6.
     898                 :             :        * We do this by duping all source fds, taking care to ensure the new
     899                 :             :        * fds are larger than any target fd to avoid introducing new conflicts.
     900                 :             :        */
     901                 :          26 :       for (i = 0; i < n_fds; i++)
     902                 :             :         {
     903                 :          20 :           if (source_fds[i] != target_fds[i])
     904                 :             :             {
     905                 :          18 :               source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1);
     906                 :          18 :               if (source_fds[i] < 0)
     907                 :           0 :                 write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
     908                 :             :             }
     909                 :             :         }
     910                 :             : 
     911                 :          26 :       for (i = 0; i < n_fds; i++)
     912                 :             :         {
     913                 :             :           /* For basic fd assignments (where source == target), we can just
     914                 :             :            * unset FD_CLOEXEC.
     915                 :             :            */
     916                 :          20 :           if (source_fds[i] == target_fds[i])
     917                 :             :             {
     918                 :           2 :               unset_cloexec (source_fds[i]);
     919                 :             :             }
     920                 :             :           else
     921                 :             :             {
     922                 :             :               /* If any of the @target_fds conflict with @child_err_report_fd,
     923                 :             :                * dup it so it doesn’t get conflated.
     924                 :             :                */
     925                 :          18 :               if (target_fds[i] == child_err_report_fd)
     926                 :             :                 {
     927                 :           2 :                   int new_child_err_report_fd = dupfd_cloexec (child_err_report_fd, max_target_fd + 1);
     928                 :           2 :                   if (new_child_err_report_fd < 0)
     929                 :           0 :                     write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
     930                 :           2 :                   child_err_report_fd = new_child_err_report_fd;
     931                 :             :                 }
     932                 :             : 
     933                 :          36 :               if (target_fds[i] < 0 ||
     934                 :          18 :                   safe_dup2 (source_fds[i], target_fds[i]) < 0)
     935                 :           0 :                 write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED);
     936                 :             : 
     937                 :          18 :               g_clear_fd (&source_fds[i], NULL);
     938                 :             :             }
     939                 :             :         }
     940                 :             :     }
     941                 :             : 
     942                 :             :   /* Call user function just before we exec */
     943                 :        1004 :   if (child_setup)
     944                 :             :     {
     945                 :           5 :       (* child_setup) (user_data);
     946                 :             :     }
     947                 :             : 
     948                 :        1004 :   g_execute (argv[0],
     949                 :             :              (gchar **) (file_and_argv_zero ? argv + 1 : argv),
     950                 :             :              argv_buffer, argv_buffer_len,
     951                 :             :              (gchar **) envp, search_path, search_path_buffer, search_path_buffer_len);
     952                 :             : 
     953                 :             :   /* Exec failed */
     954                 :           0 :   write_err_and_exit (child_err_report_fd,
     955                 :             :                       CHILD_EXEC_FAILED);
     956                 :             : }
     957                 :             : 
     958                 :             : static gboolean
     959                 :        1113 : read_ints (int      fd,
     960                 :             :            gint*    buf,
     961                 :             :            gint     n_ints_in_buf,    
     962                 :             :            gint    *n_ints_read,      
     963                 :             :            GError **error)
     964                 :             : {
     965                 :        1113 :   gsize bytes = 0;    
     966                 :             :   
     967                 :             :   while (TRUE)
     968                 :         118 :     {
     969                 :             :       gssize chunk;    
     970                 :             : 
     971                 :        1231 :       if (bytes >= sizeof(gint)*2)
     972                 :          10 :         break; /* give up, who knows what happened, should not be
     973                 :             :                 * possible.
     974                 :             :                 */
     975                 :             :           
     976                 :        1221 :     again:
     977                 :        1221 :       chunk = read (fd,
     978                 :             :                     ((gchar*)buf) + bytes,
     979                 :        1221 :                     sizeof(gint) * n_ints_in_buf - bytes);
     980                 :        1221 :       if (chunk < 0 && errno == EINTR)
     981                 :           0 :         goto again;
     982                 :             :           
     983                 :        1221 :       if (chunk < 0)
     984                 :             :         {
     985                 :           0 :           int errsv = errno;
     986                 :             : 
     987                 :             :           /* Some weird shit happened, bail out */
     988                 :           0 :           g_set_error (error,
     989                 :             :                        G_SPAWN_ERROR,
     990                 :             :                        G_SPAWN_ERROR_FAILED,
     991                 :             :                        _("Failed to read from child pipe (%s)"),
     992                 :             :                        g_strerror (errsv));
     993                 :             : 
     994                 :           0 :           return FALSE;
     995                 :             :         }
     996                 :        1221 :       else if (chunk == 0)
     997                 :        1103 :         break; /* EOF */
     998                 :             :       else /* chunk > 0 */
     999                 :         118 :         bytes += chunk;
    1000                 :             :     }
    1001                 :             : 
    1002                 :        1113 :   *n_ints_read = (gint)(bytes / sizeof(gint));
    1003                 :             : 
    1004                 :        1113 :   return TRUE;
    1005                 :             : }
    1006                 :             : 
    1007                 :             : #ifdef POSIX_SPAWN_AVAILABLE
    1008                 :             : static gboolean
    1009                 :         100 : do_posix_spawn (const gchar * const *argv,
    1010                 :             :                 const gchar * const *envp,
    1011                 :             :                 gboolean    search_path,
    1012                 :             :                 gboolean    stdout_to_null,
    1013                 :             :                 gboolean    stderr_to_null,
    1014                 :             :                 gboolean    child_inherits_stdin,
    1015                 :             :                 gboolean    file_and_argv_zero,
    1016                 :             :                 GPid       *child_pid,
    1017                 :             :                 gint       *child_close_fds,
    1018                 :             :                 gint        stdin_fd,
    1019                 :             :                 gint        stdout_fd,
    1020                 :             :                 gint        stderr_fd,
    1021                 :             :                 const gint *source_fds,
    1022                 :             :                 const gint *target_fds,
    1023                 :             :                 gsize       n_fds)
    1024                 :             : {
    1025                 :             :   pid_t pid;
    1026                 :         100 :   gint *duped_source_fds = NULL;
    1027                 :         100 :   gint max_target_fd = 0;
    1028                 :             :   const gchar * const *argv_pass;
    1029                 :             :   posix_spawnattr_t attr;
    1030                 :             :   posix_spawn_file_actions_t file_actions;
    1031                 :             :   gint parent_close_fds[3];
    1032                 :         100 :   gsize num_parent_close_fds = 0;
    1033                 :         100 :   GSList *child_close = NULL;
    1034                 :             :   GSList *elem;
    1035                 :             :   sigset_t mask;
    1036                 :             :   gsize i;
    1037                 :             :   int r;
    1038                 :             : 
    1039                 :         100 :   g_assert (argv != NULL && argv[0] != NULL);
    1040                 :             : 
    1041                 :         100 :   if (*argv[0] == '\0')
    1042                 :             :     {
    1043                 :             :       /* We check the simple case first. */
    1044                 :           0 :       return ENOENT;
    1045                 :             :     }
    1046                 :             : 
    1047                 :         100 :   r = posix_spawnattr_init (&attr);
    1048                 :         100 :   if (r != 0)
    1049                 :           0 :     return r;
    1050                 :             : 
    1051                 :         100 :   if (child_close_fds)
    1052                 :             :     {
    1053                 :         100 :       int i = -1;
    1054                 :         101 :       while (child_close_fds[++i] != -1)
    1055                 :           1 :         child_close = g_slist_prepend (child_close,
    1056                 :           1 :                                        GINT_TO_POINTER (child_close_fds[i]));
    1057                 :             :     }
    1058                 :             : 
    1059                 :         100 :   r = posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF);
    1060                 :         100 :   if (r != 0)
    1061                 :           0 :     goto out_free_spawnattr;
    1062                 :             : 
    1063                 :             :   /* Reset some signal handlers that we may use */
    1064                 :         100 :   sigemptyset (&mask);
    1065                 :         100 :   sigaddset (&mask, SIGCHLD);
    1066                 :         100 :   sigaddset (&mask, SIGINT);
    1067                 :         100 :   sigaddset (&mask, SIGTERM);
    1068                 :         100 :   sigaddset (&mask, SIGHUP);
    1069                 :             : 
    1070                 :         100 :   r = posix_spawnattr_setsigdefault (&attr, &mask);
    1071                 :         100 :   if (r != 0)
    1072                 :           0 :     goto out_free_spawnattr;
    1073                 :             : 
    1074                 :         100 :   r = posix_spawn_file_actions_init (&file_actions);
    1075                 :         100 :   if (r != 0)
    1076                 :           0 :     goto out_free_spawnattr;
    1077                 :             : 
    1078                 :             :   /* Redirect pipes as required */
    1079                 :             : 
    1080                 :         100 :   if (stdin_fd >= 0)
    1081                 :             :     {
    1082                 :           0 :       r = posix_spawn_file_actions_adddup2 (&file_actions, stdin_fd, 0);
    1083                 :           0 :       if (r != 0)
    1084                 :           0 :         goto out_close_fds;
    1085                 :             : 
    1086                 :           0 :       if (!g_slist_find (child_close, GINT_TO_POINTER (stdin_fd)))
    1087                 :           0 :         child_close = g_slist_prepend (child_close, GINT_TO_POINTER (stdin_fd));
    1088                 :             :     }
    1089                 :         100 :   else if (!child_inherits_stdin)
    1090                 :             :     {
    1091                 :             :       /* Keep process from blocking on a read of stdin */
    1092                 :         100 :       gint read_null = safe_open ("/dev/null", O_RDONLY | O_CLOEXEC);
    1093                 :         100 :       g_assert (read_null != -1);
    1094                 :         100 :       parent_close_fds[num_parent_close_fds++] = read_null;
    1095                 :             : 
    1096                 :             : #ifndef HAVE_O_CLOEXEC
    1097                 :             :       fcntl (read_null, F_SETFD, FD_CLOEXEC);
    1098                 :             : #endif
    1099                 :             : 
    1100                 :         100 :       r = posix_spawn_file_actions_adddup2 (&file_actions, read_null, 0);
    1101                 :         100 :       if (r != 0)
    1102                 :           0 :         goto out_close_fds;
    1103                 :             :     }
    1104                 :             : 
    1105                 :         100 :   if (stdout_fd >= 0)
    1106                 :             :     {
    1107                 :           1 :       r = posix_spawn_file_actions_adddup2 (&file_actions, stdout_fd, 1);
    1108                 :           1 :       if (r != 0)
    1109                 :           0 :         goto out_close_fds;
    1110                 :             : 
    1111                 :           1 :       if (!g_slist_find (child_close, GINT_TO_POINTER (stdout_fd)))
    1112                 :           1 :         child_close = g_slist_prepend (child_close, GINT_TO_POINTER (stdout_fd));
    1113                 :             :     }
    1114                 :          99 :   else if (stdout_to_null)
    1115                 :             :     {
    1116                 :           4 :       gint write_null = safe_open ("/dev/null", O_WRONLY | O_CLOEXEC);
    1117                 :           4 :       g_assert (write_null != -1);
    1118                 :           4 :       parent_close_fds[num_parent_close_fds++] = write_null;
    1119                 :             : 
    1120                 :             : #ifndef HAVE_O_CLOEXEC
    1121                 :             :       fcntl (write_null, F_SETFD, FD_CLOEXEC);
    1122                 :             : #endif
    1123                 :             : 
    1124                 :           4 :       r = posix_spawn_file_actions_adddup2 (&file_actions, write_null, 1);
    1125                 :           4 :       if (r != 0)
    1126                 :           0 :         goto out_close_fds;
    1127                 :             :     }
    1128                 :             : 
    1129                 :         100 :   if (stderr_fd >= 0)
    1130                 :             :     {
    1131                 :           0 :       r = posix_spawn_file_actions_adddup2 (&file_actions, stderr_fd, 2);
    1132                 :           0 :       if (r != 0)
    1133                 :           0 :         goto out_close_fds;
    1134                 :             : 
    1135                 :           0 :       if (!g_slist_find (child_close, GINT_TO_POINTER (stderr_fd)))
    1136                 :           0 :         child_close = g_slist_prepend (child_close, GINT_TO_POINTER (stderr_fd));
    1137                 :             :     }
    1138                 :         100 :   else if (stderr_to_null)
    1139                 :             :     {
    1140                 :           4 :       gint write_null = safe_open ("/dev/null", O_WRONLY | O_CLOEXEC);
    1141                 :           4 :       g_assert (write_null != -1);
    1142                 :           4 :       parent_close_fds[num_parent_close_fds++] = write_null;
    1143                 :             : 
    1144                 :             : #ifndef HAVE_O_CLOEXEC
    1145                 :             :       fcntl (write_null, F_SETFD, FD_CLOEXEC);
    1146                 :             : #endif
    1147                 :             : 
    1148                 :           4 :       r = posix_spawn_file_actions_adddup2 (&file_actions, write_null, 2);
    1149                 :           4 :       if (r != 0)
    1150                 :           0 :         goto out_close_fds;
    1151                 :             :     }
    1152                 :             : 
    1153                 :             :   /* If source_fds[i] != target_fds[i], we need to handle the case
    1154                 :             :    * where the user has specified, e.g., 5 -> 4, 4 -> 6. We do this
    1155                 :             :    * by duping the source fds, taking care to ensure the new fds are
    1156                 :             :    * larger than any target fd to avoid introducing new conflicts.
    1157                 :             :    *
    1158                 :             :    * If source_fds[i] == target_fds[i], then we just need to leak
    1159                 :             :    * the fd into the child process, which we *could* do by temporarily
    1160                 :             :    * unsetting CLOEXEC and then setting it again after we spawn if
    1161                 :             :    * it was originally set. POSIX requires that the addup2 action unset
    1162                 :             :    * CLOEXEC if source and target are identical, so you'd think doing it
    1163                 :             :    * manually wouldn't be needed, but unfortunately as of 2021 many
    1164                 :             :    * libcs still don't do so. Example nonconforming libcs:
    1165                 :             :    *  Bionic: https://android.googlesource.com/platform/bionic/+/f6e5b582604715729b09db3e36a7aeb8c24b36a4/libc/bionic/spawn.cpp#71
    1166                 :             :    *  uclibc-ng: https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/librt/spawn.c?id=7c36bcae09d66bbaa35cbb02253ae0556f42677e#n88
    1167                 :             :    *
    1168                 :             :    * Anyway, unsetting CLOEXEC ourselves would open a small race window
    1169                 :             :    * where the fd could be inherited into a child process if another
    1170                 :             :    * thread spawns something at the same time, because we have not
    1171                 :             :    * called fork() and are multithreaded here. This race is avoidable by
    1172                 :             :    * using dupfd_cloexec, which we already have to do to handle the
    1173                 :             :    * source_fds[i] != target_fds[i] case. So let's always do it!
    1174                 :             :    */
    1175                 :             : 
    1176                 :         197 :   for (i = 0; i < n_fds; i++)
    1177                 :          97 :     max_target_fd = MAX (max_target_fd, target_fds[i]);
    1178                 :             : 
    1179                 :         100 :   if (max_target_fd == G_MAXINT)
    1180                 :           0 :     goto out_close_fds;
    1181                 :             : 
    1182                 :         100 :   duped_source_fds = g_new (gint, n_fds);
    1183                 :         197 :   for (i = 0; i < n_fds; i++)
    1184                 :          97 :     duped_source_fds[i] = -1;  /* initialise in case dupfd_cloexec() fails below */
    1185                 :         197 :   for (i = 0; i < n_fds; i++)
    1186                 :             :     {
    1187                 :          97 :       duped_source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1);
    1188                 :          97 :       if (duped_source_fds[i] < 0)
    1189                 :           0 :         goto out_close_fds;
    1190                 :             :     }
    1191                 :             : 
    1192                 :         197 :   for (i = 0; i < n_fds; i++)
    1193                 :             :     {
    1194                 :          97 :       r = posix_spawn_file_actions_adddup2 (&file_actions, duped_source_fds[i], target_fds[i]);
    1195                 :          97 :       if (r != 0)
    1196                 :           0 :         goto out_close_fds;
    1197                 :             :     }
    1198                 :             : 
    1199                 :             :   /* Intentionally close the fds in the child as the last file action,
    1200                 :             :    * having been careful not to add the same fd to this list twice.
    1201                 :             :    *
    1202                 :             :    * This is important to allow (e.g.) for the same fd to be passed as stdout
    1203                 :             :    * and stderr (we must not close it before we have dupped it in both places,
    1204                 :             :    * and we must not attempt to close it twice).
    1205                 :             :    */
    1206                 :         102 :   for (elem = child_close; elem != NULL; elem = elem->next)
    1207                 :             :     {
    1208                 :           2 :       r = posix_spawn_file_actions_addclose (&file_actions,
    1209                 :           2 :                                              GPOINTER_TO_INT (elem->data));
    1210                 :           2 :       if (r != 0)
    1211                 :           0 :         goto out_close_fds;
    1212                 :             :     }
    1213                 :             : 
    1214                 :         100 :   argv_pass = file_and_argv_zero ? argv + 1 : argv;
    1215                 :         100 :   if (envp == NULL)
    1216                 :          98 :     envp = (const gchar * const *) environ;
    1217                 :             : 
    1218                 :             :   /* Don't search when it contains a slash. */
    1219                 :         100 :   if (!search_path || strchr (argv[0], '/') != NULL)
    1220                 :           7 :     r = posix_spawn (&pid, argv[0], &file_actions, &attr, (char * const *) argv_pass, (char * const *) envp);
    1221                 :             :   else
    1222                 :          93 :     r = posix_spawnp (&pid, argv[0], &file_actions, &attr, (char * const *) argv_pass, (char * const *) envp);
    1223                 :             : 
    1224                 :         100 :   if (r == 0 && child_pid != NULL)
    1225                 :         100 :     *child_pid = pid;
    1226                 :             : 
    1227                 :           0 : out_close_fds:
    1228                 :         208 :   for (i = 0; i < num_parent_close_fds; i++)
    1229                 :         108 :     g_clear_fd (&parent_close_fds[i], NULL);
    1230                 :             : 
    1231                 :         100 :   if (duped_source_fds != NULL)
    1232                 :             :     {
    1233                 :         192 :       for (i = 0; i < n_fds; i++)
    1234                 :          97 :         g_clear_fd (&duped_source_fds[i], NULL);
    1235                 :          95 :       g_free (duped_source_fds);
    1236                 :             :     }
    1237                 :             : 
    1238                 :         100 :   posix_spawn_file_actions_destroy (&file_actions);
    1239                 :         100 : out_free_spawnattr:
    1240                 :         100 :   posix_spawnattr_destroy (&attr);
    1241                 :         100 :   g_slist_free (child_close);
    1242                 :             : 
    1243                 :         100 :   return r;
    1244                 :             : }
    1245                 :             : #endif /* POSIX_SPAWN_AVAILABLE */
    1246                 :             : 
    1247                 :             : static gboolean
    1248                 :        2383 : source_fds_collide_with_pipe (const GUnixPipe  *pipefd,
    1249                 :             :                               const int        *source_fds,
    1250                 :             :                               gsize             n_fds,
    1251                 :             :                               GError          **error)
    1252                 :             : {
    1253                 :        4765 :   return (_g_spawn_invalid_source_fd (pipefd->fds[G_UNIX_PIPE_END_READ], source_fds, n_fds, error) ||
    1254                 :        2382 :           _g_spawn_invalid_source_fd (pipefd->fds[G_UNIX_PIPE_END_WRITE], source_fds, n_fds, error));
    1255                 :             : }
    1256                 :             : 
    1257                 :             : static gboolean
    1258                 :        1106 : fork_exec (gboolean              intermediate_child,
    1259                 :             :            const gchar          *working_directory,
    1260                 :             :            const gchar * const  *argv,
    1261                 :             :            const gchar * const  *envp,
    1262                 :             :            gboolean              close_descriptors,
    1263                 :             :            gboolean              search_path,
    1264                 :             :            gboolean              search_path_from_envp,
    1265                 :             :            gboolean              stdout_to_null,
    1266                 :             :            gboolean              stderr_to_null,
    1267                 :             :            gboolean              child_inherits_stdin,
    1268                 :             :            gboolean              file_and_argv_zero,
    1269                 :             :            gboolean              cloexec_pipes,
    1270                 :             :            GSpawnChildSetupFunc  child_setup,
    1271                 :             :            gpointer              user_data,
    1272                 :             :            GPid                 *child_pid,
    1273                 :             :            gint                 *stdin_pipe_out,
    1274                 :             :            gint                 *stdout_pipe_out,
    1275                 :             :            gint                 *stderr_pipe_out,
    1276                 :             :            gint                  stdin_fd,
    1277                 :             :            gint                  stdout_fd,
    1278                 :             :            gint                  stderr_fd,
    1279                 :             :            const gint           *source_fds,
    1280                 :             :            const gint           *target_fds,
    1281                 :             :            gsize                 n_fds,
    1282                 :             :            GError              **error)
    1283                 :             : {
    1284                 :        1106 :   GPid pid = -1;
    1285                 :        1106 :   GUnixPipe child_err_report_pipe = G_UNIX_PIPE_INIT;
    1286                 :        1106 :   GUnixPipe child_pid_report_pipe = G_UNIX_PIPE_INIT;
    1287                 :        1106 :   guint pipe_flags = cloexec_pipes ? O_CLOEXEC : 0;
    1288                 :             :   gint status;
    1289                 :             :   const gchar *chosen_search_path;
    1290                 :        1106 :   gchar *search_path_buffer = NULL;
    1291                 :        1106 :   gchar *search_path_buffer_heap = NULL;
    1292                 :        1106 :   gsize search_path_buffer_len = 0;
    1293                 :        1106 :   gchar **argv_buffer = NULL;
    1294                 :        1106 :   gchar **argv_buffer_heap = NULL;
    1295                 :        1106 :   gsize argv_buffer_len = 0;
    1296                 :        1106 :   GUnixPipe stdin_pipe = G_UNIX_PIPE_INIT;
    1297                 :        1106 :   GUnixPipe stdout_pipe = G_UNIX_PIPE_INIT;
    1298                 :        1106 :   GUnixPipe stderr_pipe = G_UNIX_PIPE_INIT;
    1299                 :        1106 :   gint child_close_fds[4] = { -1, -1, -1, -1 };
    1300                 :        1106 :   gint n_child_close_fds = 0;
    1301                 :        1106 :   gint *source_fds_copy = NULL;
    1302                 :             : 
    1303                 :        1106 :   g_assert (argv != NULL && argv[0] != NULL);
    1304                 :        1106 :   g_assert (stdin_pipe_out == NULL || stdin_fd < 0);
    1305                 :        1106 :   g_assert (stdout_pipe_out == NULL || stdout_fd < 0);
    1306                 :        1106 :   g_assert (stderr_pipe_out == NULL || stderr_fd < 0);
    1307                 :             : 
    1308                 :             :   /* If pipes have been requested, open them */
    1309                 :        1106 :   if (stdin_pipe_out != NULL)
    1310                 :             :     {
    1311                 :          59 :       if (!g_unix_pipe_open (&stdin_pipe, pipe_flags, error))
    1312                 :           0 :         goto cleanup_and_fail;
    1313                 :          59 :       if (source_fds_collide_with_pipe (&stdin_pipe, source_fds, n_fds, error))
    1314                 :           0 :         goto cleanup_and_fail;
    1315                 :          59 :       child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stdin_pipe, G_UNIX_PIPE_END_WRITE);
    1316                 :          59 :       stdin_fd = g_unix_pipe_get (&stdin_pipe, G_UNIX_PIPE_END_READ);
    1317                 :             :     }
    1318                 :             : 
    1319                 :        1106 :   if (stdout_pipe_out != NULL)
    1320                 :             :     {
    1321                 :         731 :       if (!g_unix_pipe_open (&stdout_pipe, pipe_flags, error))
    1322                 :           0 :         goto cleanup_and_fail;
    1323                 :         731 :       if (source_fds_collide_with_pipe (&stdout_pipe, source_fds, n_fds, error))
    1324                 :           0 :         goto cleanup_and_fail;
    1325                 :         731 :       child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stdout_pipe, G_UNIX_PIPE_END_READ);
    1326                 :         731 :       stdout_fd = g_unix_pipe_get (&stdout_pipe, G_UNIX_PIPE_END_WRITE);
    1327                 :             :     }
    1328                 :             : 
    1329                 :        1106 :   if (stderr_pipe_out != NULL)
    1330                 :             :     {
    1331                 :         477 :       if (!g_unix_pipe_open (&stderr_pipe, pipe_flags, error))
    1332                 :           0 :         goto cleanup_and_fail;
    1333                 :         477 :       if (source_fds_collide_with_pipe (&stderr_pipe, source_fds, n_fds, error))
    1334                 :           0 :         goto cleanup_and_fail;
    1335                 :         477 :       child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stderr_pipe, G_UNIX_PIPE_END_READ);
    1336                 :         477 :       stderr_fd = g_unix_pipe_get (&stderr_pipe, G_UNIX_PIPE_END_WRITE);
    1337                 :             :     }
    1338                 :             : 
    1339                 :        1106 :   child_close_fds[n_child_close_fds++] = -1;
    1340                 :             : 
    1341                 :             : #ifdef POSIX_SPAWN_AVAILABLE
    1342                 :        1106 :   if (!intermediate_child && working_directory == NULL && !close_descriptors &&
    1343                 :         100 :       !search_path_from_envp && child_setup == NULL)
    1344                 :             :     {
    1345                 :         100 :       g_trace_mark (G_TRACE_CURRENT_TIME, 0,
    1346                 :             :                     "GLib", "posix_spawn",
    1347                 :             :                     "%s", argv[0]);
    1348                 :             : 
    1349                 :         100 :       status = do_posix_spawn (argv,
    1350                 :             :                                envp,
    1351                 :             :                                search_path,
    1352                 :             :                                stdout_to_null,
    1353                 :             :                                stderr_to_null,
    1354                 :             :                                child_inherits_stdin,
    1355                 :             :                                file_and_argv_zero,
    1356                 :             :                                child_pid,
    1357                 :             :                                child_close_fds,
    1358                 :             :                                stdin_fd,
    1359                 :             :                                stdout_fd,
    1360                 :             :                                stderr_fd,
    1361                 :             :                                source_fds,
    1362                 :             :                                target_fds,
    1363                 :             :                                n_fds);
    1364                 :         100 :       if (status == 0)
    1365                 :         100 :         goto success;
    1366                 :             : 
    1367                 :           0 :       if (status != ENOEXEC)
    1368                 :             :         {
    1369                 :           0 :           g_set_error (error,
    1370                 :             :                        G_SPAWN_ERROR,
    1371                 :             :                        G_SPAWN_ERROR_FAILED,
    1372                 :             :                        _("Failed to spawn child process “%s” (%s)"),
    1373                 :             :                        argv[0],
    1374                 :             :                        g_strerror (status));
    1375                 :           0 :           goto cleanup_and_fail;
    1376                 :             :        }
    1377                 :             : 
    1378                 :             :       /* posix_spawn is not intended to support script execution. It does in
    1379                 :             :        * some situations on some glibc versions, but that will be fixed.
    1380                 :             :        * So if it fails with ENOEXEC, we fall through to the regular
    1381                 :             :        * gspawn codepath so that script execution can be attempted,
    1382                 :             :        * per standard gspawn behaviour. */
    1383                 :           0 :       g_debug ("posix_spawn failed (ENOEXEC), fall back to regular gspawn");
    1384                 :             :     }
    1385                 :             :   else
    1386                 :             :     {
    1387                 :        1006 :       g_trace_mark (G_TRACE_CURRENT_TIME, 0,
    1388                 :             :                     "GLib", "fork",
    1389                 :             :                     "posix_spawn avoided %s%s%s%s%s",
    1390                 :             :                     !intermediate_child ? "" : "(automatic reaping requested) ",
    1391                 :             :                     working_directory == NULL ? "" : "(workdir specified) ",
    1392                 :             :                     !close_descriptors ? "" : "(fd close requested) ",
    1393                 :             :                     !search_path_from_envp ? "" : "(using envp for search path) ",
    1394                 :             :                     child_setup == NULL ? "" : "(child_setup specified) ");
    1395                 :             :     }
    1396                 :             : #endif /* POSIX_SPAWN_AVAILABLE */
    1397                 :             : 
    1398                 :             :   /* Choose a search path. This has to be done before calling fork()
    1399                 :             :    * as getenv() isn’t async-signal-safe (see `man 7 signal-safety`). */
    1400                 :        1006 :   chosen_search_path = NULL;
    1401                 :        1006 :   if (search_path_from_envp)
    1402                 :          36 :     chosen_search_path = g_environ_getenv ((gchar **) envp, "PATH");
    1403                 :        1006 :   if (search_path && chosen_search_path == NULL)
    1404                 :         240 :     chosen_search_path = g_getenv ("PATH");
    1405                 :             : 
    1406                 :        1006 :   if ((search_path || search_path_from_envp) && chosen_search_path == NULL)
    1407                 :             :     {
    1408                 :             :       /* There is no 'PATH' in the environment.  The default
    1409                 :             :        * * search path in libc is the current directory followed by
    1410                 :             :        * * the path 'confstr' returns for '_CS_PATH'.
    1411                 :             :        * */
    1412                 :             : 
    1413                 :             :       /* In GLib we put . last, for security, and don't use the
    1414                 :             :        * * unportable confstr(); UNIX98 does not actually specify
    1415                 :             :        * * what to search if PATH is unset. POSIX may, dunno.
    1416                 :             :        * */
    1417                 :             : 
    1418                 :           2 :       chosen_search_path = "/bin:/usr/bin:.";
    1419                 :             :     }
    1420                 :             : 
    1421                 :        1006 :   if (search_path || search_path_from_envp)
    1422                 :         276 :     g_assert (chosen_search_path != NULL);
    1423                 :             :   else
    1424                 :         730 :     g_assert (chosen_search_path == NULL);
    1425                 :             : 
    1426                 :             :   /* Allocate a buffer which the fork()ed child can use to assemble potential
    1427                 :             :    * paths for the binary to exec(), combining the argv[0] and elements from
    1428                 :             :    * the chosen_search_path. This can’t be done in the child because malloc()
    1429                 :             :    * (or alloca()) are not async-signal-safe (see `man 7 signal-safety`).
    1430                 :             :    *
    1431                 :             :    * Add 2 for the nul terminator and a leading `/`. */
    1432                 :        1006 :   if (chosen_search_path != NULL)
    1433                 :             :     {
    1434                 :         276 :       search_path_buffer_len = strlen (chosen_search_path) + strlen (argv[0]) + 2;
    1435                 :         276 :       if (search_path_buffer_len < 4000)
    1436                 :             :         {
    1437                 :             :           /* Prefer small stack allocations to avoid valgrind leak warnings
    1438                 :             :            * in forked child. The 4000B cutoff is arbitrary. */
    1439                 :         275 :           search_path_buffer = g_alloca (search_path_buffer_len);
    1440                 :             :         }
    1441                 :             :       else
    1442                 :             :         {
    1443                 :           1 :           search_path_buffer_heap = g_malloc (search_path_buffer_len);
    1444                 :           1 :           search_path_buffer = search_path_buffer_heap;
    1445                 :             :         }
    1446                 :             :     }
    1447                 :             : 
    1448                 :        1006 :   if (search_path || search_path_from_envp)
    1449                 :         276 :     g_assert (search_path_buffer != NULL);
    1450                 :             :   else
    1451                 :         730 :     g_assert (search_path_buffer == NULL);
    1452                 :             : 
    1453                 :             :   /* And allocate a buffer which is 2 elements longer than @argv, so that if
    1454                 :             :    * script_execute() has to be called later on, it can build a wrapper argv
    1455                 :             :    * array in this buffer. */
    1456                 :        1006 :   argv_buffer_len = g_strv_length ((gchar **) argv) + 2;
    1457                 :        1006 :   if (argv_buffer_len < 4000 / sizeof (gchar *))
    1458                 :             :     {
    1459                 :             :       /* Prefer small stack allocations to avoid valgrind leak warnings
    1460                 :             :        * in forked child. The 4000B cutoff is arbitrary. */
    1461                 :        1004 :       argv_buffer = g_newa (gchar *, argv_buffer_len);
    1462                 :             :     }
    1463                 :             :   else
    1464                 :             :     {
    1465                 :           2 :       argv_buffer_heap = g_new (gchar *, argv_buffer_len);
    1466                 :           2 :       argv_buffer = argv_buffer_heap;
    1467                 :             :     }
    1468                 :             : 
    1469                 :             :   /* And one to hold a copy of @source_fds for later manipulation in do_exec(). */
    1470                 :        1006 :   source_fds_copy = g_new (int, n_fds);
    1471                 :        1006 :   if (n_fds > 0)
    1472                 :           7 :     memcpy (source_fds_copy, source_fds, sizeof (*source_fds) * n_fds);
    1473                 :             : 
    1474                 :        1006 :   if (!g_unix_pipe_open (&child_err_report_pipe, pipe_flags, error))
    1475                 :           0 :     goto cleanup_and_fail;
    1476                 :        1006 :   if (source_fds_collide_with_pipe (&child_err_report_pipe, source_fds, n_fds, error))
    1477                 :           1 :     goto cleanup_and_fail;
    1478                 :             : 
    1479                 :        1005 :   if (intermediate_child)
    1480                 :             :     {
    1481                 :         110 :       if (!g_unix_pipe_open (&child_pid_report_pipe, pipe_flags, error))
    1482                 :           0 :         goto cleanup_and_fail;
    1483                 :         110 :       if (source_fds_collide_with_pipe (&child_pid_report_pipe, source_fds, n_fds, error))
    1484                 :           0 :         goto cleanup_and_fail;
    1485                 :             :     }
    1486                 :             :   
    1487                 :        1005 :   pid = fork ();
    1488                 :             : 
    1489                 :        1899 :   if (pid < 0)
    1490                 :             :     {
    1491                 :           0 :       int errsv = errno;
    1492                 :             : 
    1493                 :           0 :       g_set_error (error,
    1494                 :             :                    G_SPAWN_ERROR,
    1495                 :             :                    G_SPAWN_ERROR_FORK,
    1496                 :             :                    _("Failed to fork (%s)"),
    1497                 :             :                    g_strerror (errsv));
    1498                 :             : 
    1499                 :           0 :       goto cleanup_and_fail;
    1500                 :             :     }
    1501                 :        1899 :   else if (pid == 0)
    1502                 :             :     {
    1503                 :             :       /* Immediate child. This may or may not be the child that
    1504                 :             :        * actually execs the new process.
    1505                 :             :        */
    1506                 :             : 
    1507                 :             :       /* Reset some signal handlers that we may use */
    1508                 :         894 :       signal (SIGCHLD, SIG_DFL);
    1509                 :         894 :       signal (SIGINT, SIG_DFL);
    1510                 :         894 :       signal (SIGTERM, SIG_DFL);
    1511                 :         894 :       signal (SIGHUP, SIG_DFL);
    1512                 :             :       
    1513                 :             :       /* Be sure we crash if the parent exits
    1514                 :             :        * and we write to the err_report_pipe
    1515                 :             :        */
    1516                 :         894 :       signal (SIGPIPE, SIG_DFL);
    1517                 :             : 
    1518                 :             :       /* Close the parent's end of the pipes;
    1519                 :             :        * not needed in the close_descriptors case,
    1520                 :             :        * though
    1521                 :             :        */
    1522                 :         894 :       g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_READ, NULL);
    1523                 :         894 :       g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_READ, NULL);
    1524                 :         894 :       if (child_close_fds[0] != -1)
    1525                 :             :         {
    1526                 :         766 :            int i = -1;
    1527                 :        2032 :            while (child_close_fds[++i] != -1)
    1528                 :        1266 :              g_clear_fd (&child_close_fds[i], NULL);
    1529                 :             :         }
    1530                 :             :       
    1531                 :         894 :       if (intermediate_child)
    1532                 :             :         {
    1533                 :             :           /* We need to fork an intermediate child that launches the
    1534                 :             :            * final child. The purpose of the intermediate child
    1535                 :             :            * is to exit, so we can waitpid() it immediately.
    1536                 :             :            * Then the grandchild will not become a zombie.
    1537                 :             :            */
    1538                 :             :           GPid grandchild_pid;
    1539                 :             : 
    1540                 :           0 :           grandchild_pid = fork ();
    1541                 :             : 
    1542                 :         110 :           if (grandchild_pid < 0)
    1543                 :             :             {
    1544                 :             :               /* report -1 as child PID */
    1545                 :           0 :               write_all (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE),
    1546                 :             :                          &grandchild_pid, sizeof(grandchild_pid));
    1547                 :             :               
    1548                 :           0 :               write_err_and_exit (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE),
    1549                 :             :                                   CHILD_FORK_FAILED);              
    1550                 :             :             }
    1551                 :         110 :           else if (grandchild_pid == 0)
    1552                 :             :             {
    1553                 :         110 :               g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    1554                 :         110 :               do_exec (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE),
    1555                 :             :                        stdin_fd,
    1556                 :             :                        stdout_fd,
    1557                 :             :                        stderr_fd,
    1558                 :             :                        source_fds_copy,
    1559                 :             :                        target_fds,
    1560                 :             :                        n_fds,
    1561                 :             :                        working_directory,
    1562                 :             :                        argv,
    1563                 :             :                        argv_buffer,
    1564                 :             :                        argv_buffer_len,
    1565                 :             :                        envp,
    1566                 :             :                        close_descriptors,
    1567                 :             :                        chosen_search_path,
    1568                 :             :                        search_path_buffer,
    1569                 :             :                        search_path_buffer_len,
    1570                 :             :                        stdout_to_null,
    1571                 :             :                        stderr_to_null,
    1572                 :             :                        child_inherits_stdin,
    1573                 :             :                        file_and_argv_zero,
    1574                 :             :                        child_setup,
    1575                 :             :                        user_data);
    1576                 :             :             }
    1577                 :             :           else
    1578                 :             :             {
    1579                 :           0 :               write_all (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE),
    1580                 :             :                          &grandchild_pid, sizeof(grandchild_pid));
    1581                 :           0 :               g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    1582                 :             :               
    1583                 :           0 :               _exit (0);
    1584                 :             :             }
    1585                 :             :         }
    1586                 :             :       else
    1587                 :             :         {
    1588                 :             :           /* Just run the child.
    1589                 :             :            */
    1590                 :             : 
    1591                 :         894 :           do_exec (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE),
    1592                 :             :                    stdin_fd,
    1593                 :             :                    stdout_fd,
    1594                 :             :                    stderr_fd,
    1595                 :             :                    source_fds_copy,
    1596                 :             :                    target_fds,
    1597                 :             :                    n_fds,
    1598                 :             :                    working_directory,
    1599                 :             :                    argv,
    1600                 :             :                    argv_buffer,
    1601                 :             :                    argv_buffer_len,
    1602                 :             :                    envp,
    1603                 :             :                    close_descriptors,
    1604                 :             :                    chosen_search_path,
    1605                 :             :                    search_path_buffer,
    1606                 :             :                    search_path_buffer_len,
    1607                 :             :                    stdout_to_null,
    1608                 :             :                    stderr_to_null,
    1609                 :             :                    child_inherits_stdin,
    1610                 :             :                    file_and_argv_zero,
    1611                 :             :                    child_setup,
    1612                 :             :                    user_data);
    1613                 :             :         }
    1614                 :             :     }
    1615                 :             :   else
    1616                 :             :     {
    1617                 :             :       /* Parent */
    1618                 :             :       
    1619                 :             :       gint buf[2];
    1620                 :        1005 :       gint n_ints = 0;    
    1621                 :             : 
    1622                 :             :       /* Close the uncared-about ends of the pipes */
    1623                 :        1005 :       g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    1624                 :        1005 :       g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    1625                 :             : 
    1626                 :             :       /* If we had an intermediate child, reap it */
    1627                 :        1005 :       if (intermediate_child)
    1628                 :             :         {
    1629                 :         110 :         wait_again:
    1630                 :         110 :           if (waitpid (pid, &status, 0) < 0)
    1631                 :             :             {
    1632                 :           0 :               if (errno == EINTR)
    1633                 :           0 :                 goto wait_again;
    1634                 :           0 :               else if (errno == ECHILD)
    1635                 :             :                 ; /* do nothing, child already reaped */
    1636                 :             :               else
    1637                 :           0 :                 g_warning ("waitpid() should not fail in 'fork_exec'");
    1638                 :             :             }
    1639                 :             :         }
    1640                 :             :       
    1641                 :             : 
    1642                 :        1005 :       if (!read_ints (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_READ),
    1643                 :             :                       buf, 2, &n_ints,
    1644                 :             :                       error))
    1645                 :          10 :         goto cleanup_and_fail;
    1646                 :             :         
    1647                 :        1005 :       if (n_ints >= 2)
    1648                 :             :         {
    1649                 :             :           /* Error from the child. */
    1650                 :             : 
    1651                 :          10 :           switch (buf[0])
    1652                 :             :             {
    1653                 :           0 :             case CHILD_CHDIR_FAILED:
    1654                 :           0 :               g_set_error (error,
    1655                 :             :                            G_SPAWN_ERROR,
    1656                 :             :                            G_SPAWN_ERROR_CHDIR,
    1657                 :             :                            _("Failed to change to directory “%s” (%s)"),
    1658                 :             :                            working_directory,
    1659                 :             :                            g_strerror (buf[1]));
    1660                 :             : 
    1661                 :           0 :               break;
    1662                 :             :               
    1663                 :           9 :             case CHILD_EXEC_FAILED:
    1664                 :           9 :               g_set_error (error,
    1665                 :             :                            G_SPAWN_ERROR,
    1666                 :             :                            _g_spawn_exec_err_to_g_error (buf[1]),
    1667                 :             :                            _("Failed to execute child process “%s” (%s)"),
    1668                 :             :                            argv[0],
    1669                 :             :                            g_strerror (buf[1]));
    1670                 :             : 
    1671                 :           9 :               break;
    1672                 :             : 
    1673                 :           0 :             case CHILD_OPEN_FAILED:
    1674                 :           0 :               g_set_error (error,
    1675                 :             :                            G_SPAWN_ERROR,
    1676                 :             :                            G_SPAWN_ERROR_FAILED,
    1677                 :             :                            _("Failed to open file to remap file descriptor (%s)"),
    1678                 :             :                            g_strerror (buf[1]));
    1679                 :           0 :               break;
    1680                 :             : 
    1681                 :           1 :             case CHILD_DUPFD_FAILED:
    1682                 :           1 :               g_set_error (error,
    1683                 :             :                            G_SPAWN_ERROR,
    1684                 :             :                            G_SPAWN_ERROR_FAILED,
    1685                 :             :                            _("Failed to duplicate file descriptor for child process (%s)"),
    1686                 :             :                            g_strerror (buf[1]));
    1687                 :             : 
    1688                 :           1 :               break;
    1689                 :             : 
    1690                 :           0 :             case CHILD_FORK_FAILED:
    1691                 :           0 :               g_set_error (error,
    1692                 :             :                            G_SPAWN_ERROR,
    1693                 :             :                            G_SPAWN_ERROR_FORK,
    1694                 :             :                            _("Failed to fork child process (%s)"),
    1695                 :             :                            g_strerror (buf[1]));
    1696                 :           0 :               break;
    1697                 :             : 
    1698                 :           0 :             case CHILD_CLOSE_FAILED:
    1699                 :           0 :               g_set_error (error,
    1700                 :             :                            G_SPAWN_ERROR,
    1701                 :             :                            G_SPAWN_ERROR_FAILED,
    1702                 :             :                            _("Failed to close file descriptor for child process (%s)"),
    1703                 :             :                            g_strerror (buf[1]));
    1704                 :           0 :               break;
    1705                 :             : 
    1706                 :           0 :             default:
    1707                 :           0 :               g_set_error (error,
    1708                 :             :                            G_SPAWN_ERROR,
    1709                 :             :                            G_SPAWN_ERROR_FAILED,
    1710                 :             :                            _("Unknown error executing child process “%s”"),
    1711                 :             :                            argv[0]);
    1712                 :           0 :               break;
    1713                 :             :             }
    1714                 :             : 
    1715                 :          10 :           goto cleanup_and_fail;
    1716                 :             :         }
    1717                 :             : 
    1718                 :             :       /* Get child pid from intermediate child pipe. */
    1719                 :         995 :       if (intermediate_child)
    1720                 :             :         {
    1721                 :         108 :           n_ints = 0;
    1722                 :             :           
    1723                 :         108 :           if (!read_ints (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_READ),
    1724                 :             :                           buf, 1, &n_ints, error))
    1725                 :           0 :             goto cleanup_and_fail;
    1726                 :             : 
    1727                 :         108 :           if (n_ints < 1)
    1728                 :             :             {
    1729                 :           0 :               int errsv = errno;
    1730                 :             : 
    1731                 :           0 :               g_set_error (error,
    1732                 :             :                            G_SPAWN_ERROR,
    1733                 :             :                            G_SPAWN_ERROR_FAILED,
    1734                 :             :                            _("Failed to read enough data from child pid pipe (%s)"),
    1735                 :             :                            g_strerror (errsv));
    1736                 :           0 :               goto cleanup_and_fail;
    1737                 :             :             }
    1738                 :             :           else
    1739                 :             :             {
    1740                 :             :               /* we have the child pid */
    1741                 :         108 :               pid = buf[0];
    1742                 :             :             }
    1743                 :             :         }
    1744                 :             :       
    1745                 :             :       /* Success against all odds! return the information */
    1746                 :         995 :       g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_READ, NULL);
    1747                 :         995 :       g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_READ, NULL);
    1748                 :             : 
    1749                 :         995 :       g_free (search_path_buffer_heap);
    1750                 :         995 :       g_free (argv_buffer_heap);
    1751                 :         995 :       g_free (source_fds_copy);
    1752                 :             : 
    1753                 :         995 :       if (child_pid)
    1754                 :         984 :         *child_pid = pid;
    1755                 :             : 
    1756                 :         995 :       goto success;
    1757                 :             :     }
    1758                 :             : 
    1759                 :        1095 : success:
    1760                 :             :   /* Close the uncared-about ends of the pipes */
    1761                 :        1095 :   g_unix_pipe_close (&stdin_pipe, G_UNIX_PIPE_END_READ, NULL);
    1762                 :        1095 :   g_unix_pipe_close (&stdout_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    1763                 :        1095 :   g_unix_pipe_close (&stderr_pipe, G_UNIX_PIPE_END_WRITE, NULL);
    1764                 :             : 
    1765                 :        1095 :   if (stdin_pipe_out != NULL)
    1766                 :          59 :     *stdin_pipe_out = g_unix_pipe_steal (&stdin_pipe, G_UNIX_PIPE_END_WRITE);
    1767                 :             : 
    1768                 :        1095 :   if (stdout_pipe_out != NULL)
    1769                 :         730 :     *stdout_pipe_out = g_unix_pipe_steal (&stdout_pipe, G_UNIX_PIPE_END_READ);
    1770                 :             : 
    1771                 :        1095 :   if (stderr_pipe_out != NULL)
    1772                 :         477 :     *stderr_pipe_out = g_unix_pipe_steal (&stderr_pipe, G_UNIX_PIPE_END_READ);
    1773                 :             : 
    1774                 :        1095 :   return TRUE;
    1775                 :             : 
    1776                 :          11 :  cleanup_and_fail:
    1777                 :             : 
    1778                 :             :   /* There was an error from the Child, reap the child to avoid it being
    1779                 :             :      a zombie.
    1780                 :             :    */
    1781                 :             : 
    1782                 :          11 :   if (pid > 0)
    1783                 :             :   {
    1784                 :          10 :     wait_failed:
    1785                 :          10 :      if (waitpid (pid, NULL, 0) < 0)
    1786                 :             :        {
    1787                 :           2 :           if (errno == EINTR)
    1788                 :           0 :             goto wait_failed;
    1789                 :           2 :           else if (errno == ECHILD)
    1790                 :             :             ; /* do nothing, child already reaped */
    1791                 :             :           else
    1792                 :           0 :             g_warning ("waitpid() should not fail in 'fork_exec'");
    1793                 :             :        }
    1794                 :             :    }
    1795                 :             : 
    1796                 :          11 :   g_unix_pipe_clear (&stdin_pipe);
    1797                 :          11 :   g_unix_pipe_clear (&stdout_pipe);
    1798                 :          11 :   g_unix_pipe_clear (&stderr_pipe);
    1799                 :          11 :   g_unix_pipe_clear (&child_err_report_pipe);
    1800                 :          11 :   g_unix_pipe_clear (&child_pid_report_pipe);
    1801                 :             : 
    1802                 :          11 :   g_clear_pointer (&search_path_buffer_heap, g_free);
    1803                 :          11 :   g_clear_pointer (&argv_buffer_heap, g_free);
    1804                 :          11 :   g_clear_pointer (&source_fds_copy, g_free);
    1805                 :             : 
    1806                 :          11 :   return FALSE;
    1807                 :             : }
    1808                 :             : 
    1809                 :             : /* Based on execvp from GNU C Library */
    1810                 :             : 
    1811                 :             : /* This function is called between fork() and exec() and hence must be
    1812                 :             :  * async-signal-safe (see signal-safety(7)) until it calls exec(). */
    1813                 :             : static gboolean
    1814                 :           0 : script_execute (const gchar *file,
    1815                 :             :                 gchar      **argv,
    1816                 :             :                 gchar      **argv_buffer,
    1817                 :             :                 gsize        argv_buffer_len,
    1818                 :             :                 gchar      **envp)
    1819                 :             : {
    1820                 :             :   /* Count the arguments.  */
    1821                 :           0 :   gsize argc = 0;
    1822                 :           0 :   while (argv[argc])
    1823                 :           0 :     ++argc;
    1824                 :             : 
    1825                 :             :   /* Construct an argument list for the shell. */
    1826                 :           0 :   if (argc + 2 > argv_buffer_len)
    1827                 :           0 :     return FALSE;
    1828                 :             : 
    1829                 :           0 :   argv_buffer[0] = (char *) "/bin/sh";
    1830                 :           0 :   argv_buffer[1] = (char *) file;
    1831                 :           0 :   while (argc > 0)
    1832                 :             :     {
    1833                 :           0 :       argv_buffer[argc + 1] = argv[argc];
    1834                 :           0 :       --argc;
    1835                 :             :     }
    1836                 :             : 
    1837                 :             :   /* Execute the shell. */
    1838                 :           0 :   if (envp)
    1839                 :           0 :     execve (argv_buffer[0], argv_buffer, envp);
    1840                 :             :   else
    1841                 :           0 :     execv (argv_buffer[0], argv_buffer);
    1842                 :             : 
    1843                 :           0 :   return TRUE;
    1844                 :             : }
    1845                 :             : 
    1846                 :             : /* This function is called between fork() and exec() and hence must be
    1847                 :             :  * async-signal-safe (see signal-safety(7)). */
    1848                 :             : static gchar*
    1849                 :         173 : my_strchrnul (const gchar *str, gchar c)
    1850                 :             : {
    1851                 :         173 :   gchar *p = (gchar*) str;
    1852                 :        5767 :   while (*p && (*p != c))
    1853                 :        5594 :     ++p;
    1854                 :             : 
    1855                 :         173 :   return p;
    1856                 :             : }
    1857                 :             : 
    1858                 :             : /* This function is called between fork() and exec() and hence must be
    1859                 :             :  * async-signal-safe (see signal-safety(7)) until it calls exec(). */
    1860                 :             : static gint
    1861                 :        1004 : g_execute (const gchar  *file,
    1862                 :             :            gchar       **argv,
    1863                 :             :            gchar       **argv_buffer,
    1864                 :             :            gsize         argv_buffer_len,
    1865                 :             :            gchar       **envp,
    1866                 :             :            const gchar  *search_path,
    1867                 :             :            gchar        *search_path_buffer,
    1868                 :             :            gsize         search_path_buffer_len)
    1869                 :             : {
    1870                 :        1004 :   if (file == NULL || *file == '\0')
    1871                 :             :     {
    1872                 :             :       /* We check the simple case first. */
    1873                 :           0 :       errno = ENOENT;
    1874                 :           0 :       return -1;
    1875                 :             :     }
    1876                 :             : 
    1877                 :        1004 :   if (search_path == NULL || strchr (file, '/') != NULL)
    1878                 :             :     {
    1879                 :             :       /* Don't search when it contains a slash. */
    1880                 :         922 :       if (envp)
    1881                 :         263 :         execve (file, argv, envp);
    1882                 :             :       else
    1883                 :         659 :         execv (file, argv);
    1884                 :             :       
    1885                 :         922 :       if (errno == ENOEXEC &&
    1886                 :           0 :           !script_execute (file, argv, argv_buffer, argv_buffer_len, envp))
    1887                 :             :         {
    1888                 :           0 :           errno = ENOMEM;
    1889                 :           0 :           return -1;
    1890                 :             :         }
    1891                 :             :     }
    1892                 :             :   else
    1893                 :             :     {
    1894                 :          82 :       gboolean got_eacces = 0;
    1895                 :             :       const gchar *path, *p;
    1896                 :             :       gchar *name;
    1897                 :             :       gsize len;
    1898                 :             :       gsize pathlen;
    1899                 :             : 
    1900                 :          82 :       path = search_path;
    1901                 :          82 :       len = strlen (file) + 1;
    1902                 :          82 :       pathlen = strlen (path);
    1903                 :          82 :       name = search_path_buffer;
    1904                 :             : 
    1905                 :          82 :       if (search_path_buffer_len < pathlen + len + 1)
    1906                 :             :         {
    1907                 :           0 :           errno = ENOMEM;
    1908                 :           0 :           return -1;
    1909                 :             :         }
    1910                 :             : 
    1911                 :             :       /* Copy the file name at the top, including '\0'  */
    1912                 :          82 :       memcpy (name + pathlen + 1, file, len);
    1913                 :          82 :       name = name + pathlen;
    1914                 :             :       /* And add the slash before the filename  */
    1915                 :          82 :       *name = '/';
    1916                 :             : 
    1917                 :          82 :       p = path;
    1918                 :             :       do
    1919                 :             :         {
    1920                 :             :           char *startp;
    1921                 :             : 
    1922                 :         255 :           path = p;
    1923                 :         255 :           p = my_strchrnul (path, ':');
    1924                 :             : 
    1925                 :         173 :           if (p == path)
    1926                 :             :             /* Two adjacent colons, or a colon at the beginning or the end
    1927                 :             :              * of 'PATH' means to search the current directory.
    1928                 :             :              */
    1929                 :           0 :             startp = name + 1;
    1930                 :             :           else
    1931                 :         173 :             startp = memcpy (name - (p - path), path, p - path);
    1932                 :             : 
    1933                 :             :           /* Try to execute this name.  If it works, execv will not return.  */
    1934                 :         173 :           if (envp)
    1935                 :          15 :             execve (startp, argv, envp);
    1936                 :             :           else
    1937                 :         158 :             execv (startp, argv);
    1938                 :             :           
    1939                 :         173 :           if (errno == ENOEXEC &&
    1940                 :           0 :               !script_execute (startp, argv, argv_buffer, argv_buffer_len, envp))
    1941                 :             :             {
    1942                 :           0 :               errno = ENOMEM;
    1943                 :           0 :               return -1;
    1944                 :             :             }
    1945                 :             : 
    1946                 :         173 :           switch (errno)
    1947                 :             :             {
    1948                 :           0 :             case EACCES:
    1949                 :             :               /* Record the we got a 'Permission denied' error.  If we end
    1950                 :             :                * up finding no executable we can use, we want to diagnose
    1951                 :             :                * that we did find one but were denied access.
    1952                 :             :                */
    1953                 :           0 :               got_eacces = TRUE;
    1954                 :             : 
    1955                 :             :               G_GNUC_FALLTHROUGH;
    1956                 :         173 :             case ENOENT:
    1957                 :             : #ifdef ESTALE
    1958                 :             :             case ESTALE:
    1959                 :             : #endif
    1960                 :             : #ifdef ENOTDIR
    1961                 :             :             case ENOTDIR:
    1962                 :             : #endif
    1963                 :             :               /* Those errors indicate the file is missing or not executable
    1964                 :             :                * by us, in which case we want to just try the next path
    1965                 :             :                * directory.
    1966                 :             :                */
    1967                 :         173 :               break;
    1968                 :             : 
    1969                 :           0 :             case ENODEV:
    1970                 :             :             case ETIMEDOUT:
    1971                 :             :               /* Some strange filesystems like AFS return even
    1972                 :             :                * stranger error numbers.  They cannot reasonably mean anything
    1973                 :             :                * else so ignore those, too.
    1974                 :             :                */
    1975                 :           0 :               break;
    1976                 :             : 
    1977                 :           0 :             default:
    1978                 :             :               /* Some other error means we found an executable file, but
    1979                 :             :                * something went wrong executing it; return the error to our
    1980                 :             :                * caller.
    1981                 :             :                */
    1982                 :           0 :               return -1;
    1983                 :             :             }
    1984                 :             :         }
    1985                 :         173 :       while (*p++ != '\0');
    1986                 :             : 
    1987                 :             :       /* We tried every element and none of them worked.  */
    1988                 :           0 :       if (got_eacces)
    1989                 :             :         /* At least one failure was due to permissions, so report that
    1990                 :             :          * error.
    1991                 :             :          */
    1992                 :           0 :         errno = EACCES;
    1993                 :             :     }
    1994                 :             : 
    1995                 :             :   /* Return the error from the last attempt (probably ENOENT).  */
    1996                 :         922 :   return -1;
    1997                 :             : }
    1998                 :             : 
    1999                 :             : void
    2000                 :         194 : g_spawn_close_pid_impl (GPid pid)
    2001                 :             : {
    2002                 :             :   /* no-op */
    2003                 :         194 : }
        

Generated by: LCOV version 2.0-1