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

Generated by: LCOV version 2.0-1