2000-10-09 18:24:57 +02:00
/* gspawn.c - Process launching
*
* Copyright 2000 Red Hat , Inc .
* g_execvpe implementation based on GNU libc execvp :
* Copyright 1991 , 92 , 95 , 96 , 97 , 98 , 99 Free Software Foundation , Inc .
*
* GLib is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation ; either version 2 of the
* License , or ( at your option ) any later version .
*
* GLib is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with GLib ; see the file COPYING . LIB . If not , write
* to the Free Software Foundation , Inc . , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*/
2002-12-04 02:27:44 +01:00
# include "config.h"
2002-02-18 00:28:43 +01:00
2000-10-09 18:24:57 +02:00
# include <sys/time.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
# include <signal.h>
# include <string.h>
2006-12-15 06:33:32 +01:00
# include <stdlib.h> /* for fdwalk */
2007-10-16 07:28:10 +02:00
# include <dirent.h>
2000-10-09 18:24:57 +02:00
2000-11-02 12:38:10 +01:00
# ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
# endif /* HAVE_SYS_SELECT_H */
2007-10-16 07:28:10 +02:00
# ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
# endif /* HAVE_SYS_RESOURCE_H */
2010-09-05 06:23:03 +02:00
# include "gspawn.h"
2012-08-28 11:52:24 +02:00
# include "gthread.h"
2013-01-25 18:05:26 +01:00
# include "glib/gstdio.h"
2010-09-05 06:23:03 +02:00
2011-10-16 02:06:32 +02:00
# include "genviron.h"
2010-09-05 06:23:03 +02:00
# include "gmem.h"
2010-09-06 12:43:04 +02:00
# include "gshell.h"
2010-09-05 06:23:03 +02:00
# include "gstring.h"
2010-09-06 12:43:04 +02:00
# include "gstrfuncs.h"
2010-09-05 06:23:03 +02:00
# include "gtestutils.h"
# include "gutils.h"
2001-01-16 03:24:24 +01:00
# include "glibintl.h"
2012-11-10 19:16:29 +01:00
# include "glib-unix.h"
2011-07-06 23:13:05 +02:00
/**
* SECTION : spawn
* @ Short_description : process launching
* @ Title : Spawning Processes
*/
2000-10-09 18:24:57 +02:00
static gint g_execute ( const gchar * file ,
gchar * * argv ,
gchar * * envp ,
2012-05-20 00:01:35 +02:00
gboolean search_path ,
gboolean search_path_from_envp ) ;
2000-10-09 18:24:57 +02:00
static gboolean fork_exec_with_pipes ( gboolean intermediate_child ,
const gchar * working_directory ,
gchar * * argv ,
gchar * * envp ,
gboolean close_descriptors ,
gboolean search_path ,
2012-05-20 00:01:35 +02:00
gboolean search_path_from_envp ,
2000-10-09 18:24:57 +02:00
gboolean stdout_to_null ,
gboolean stderr_to_null ,
gboolean child_inherits_stdin ,
2001-06-08 21:41:51 +02:00
gboolean file_and_argv_zero ,
2012-11-10 19:16:29 +01:00
gboolean cloexec_pipes ,
2000-10-09 18:24:57 +02:00
GSpawnChildSetupFunc child_setup ,
gpointer user_data ,
2004-03-01 21:47:49 +01:00
GPid * child_pid ,
2000-10-09 18:24:57 +02:00
gint * standard_input ,
gint * standard_output ,
gint * standard_error ,
GError * * error ) ;
2012-08-28 19:15:56 +02:00
G_DEFINE_QUARK ( g - exec - error - quark , g_spawn_error )
G_DEFINE_QUARK ( g - spawn - exit - error - quark , g_spawn_exit_error )
2012-07-10 17:27:22 +02:00
2000-10-09 18:24:57 +02:00
/**
* g_spawn_async :
2011-04-03 18:53:04 +02:00
* @ working_directory : ( allow - none ) : child ' s current working directory , or % NULL to inherit parent ' s
* @ argv : ( array zero - terminated = 1 ) : child ' s argument vector
* @ envp : ( array zero - terminated = 1 ) ( allow - none ) : child ' s environment , or % NULL to inherit parent ' s
2000-10-09 18:24:57 +02:00
* @ flags : flags from # GSpawnFlags
2011-04-03 18:53:04 +02:00
* @ child_setup : ( scope async ) ( allow - none ) : function to run in the child just before exec ( )
* @ user_data : ( closure ) : user data for @ child_setup
* @ child_pid : ( out ) ( allow - none ) : return location for child process reference , or % NULL
2000-10-09 18:24:57 +02:00
* @ error : return location for error
*
* See g_spawn_async_with_pipes ( ) for a full description ; this function
* simply calls the g_spawn_async_with_pipes ( ) without any pipes .
2008-06-11 08:57:22 +02:00
*
* You should call g_spawn_close_pid ( ) on the returned child process
* reference when you don ' t need it any more .
2000-10-09 18:24:57 +02:00
*
2014-01-31 20:56:10 +01:00
* If you are writing a GTK + application , and the program you are
* spawning is a graphical application , too , then you may want to
* use gdk_spawn_on_screen ( ) instead to ensure that the spawned program
* opens its windows on the right screen .
2006-12-17 19:49:57 +01:00
*
2014-01-31 20:56:10 +01:00
* Note that the returned @ child_pid on Windows is a handle to the child
* process and not its identifier . Process handles and process identifiers
* are different concepts on Windows .
2008-06-11 08:57:22 +02:00
*
2001-12-16 20:31:36 +01:00
* Return value : % TRUE on success , % FALSE if error is set
2000-10-09 18:24:57 +02:00
* */
gboolean
g_spawn_async ( const gchar * working_directory ,
gchar * * argv ,
gchar * * envp ,
GSpawnFlags flags ,
GSpawnChildSetupFunc child_setup ,
gpointer user_data ,
2004-03-01 21:47:49 +01:00
GPid * child_pid ,
2000-10-09 18:24:57 +02:00
GError * * error )
{
g_return_val_if_fail ( argv ! = NULL , FALSE ) ;
return g_spawn_async_with_pipes ( working_directory ,
argv , envp ,
flags ,
child_setup ,
user_data ,
child_pid ,
NULL , NULL , NULL ,
error ) ;
}
/* Avoids a danger in threaded situations (calling close()
* on a file descriptor twice , and another thread has
* re - opened it since the first close )
*/
2013-01-25 18:05:26 +01:00
static void
2000-10-09 18:24:57 +02:00
close_and_invalidate ( gint * fd )
{
2002-05-20 21:36:58 +02:00
if ( * fd < 0 )
2013-01-25 18:05:26 +01:00
return ;
2002-05-20 21:36:58 +02:00
else
{
2013-01-25 18:05:26 +01:00
( void ) g_close ( * fd , NULL ) ;
2002-05-20 21:36:58 +02:00
* fd = - 1 ;
}
2000-10-09 18:24:57 +02:00
}
2006-12-16 04:36:14 +01:00
/* Some versions of OS X define READ_OK in public headers */
2006-12-16 04:33:23 +01:00
# undef READ_OK
2000-10-09 18:24:57 +02:00
typedef enum
{
READ_FAILED = 0 , /* FALSE */
READ_OK ,
READ_EOF
} ReadResult ;
static ReadResult
read_data ( GString * str ,
gint fd ,
GError * * error )
{
2011-06-15 02:44:15 +02:00
gssize bytes ;
gchar buf [ 4096 ] ;
2000-10-09 18:24:57 +02:00
again :
2003-06-02 20:20:25 +02:00
bytes = read ( fd , buf , 4096 ) ;
2000-10-09 18:24:57 +02:00
if ( bytes = = 0 )
return READ_EOF ;
else if ( bytes > 0 )
{
g_string_append_len ( str , buf , bytes ) ;
return READ_OK ;
}
2011-06-15 02:44:15 +02:00
else if ( errno = = EINTR )
2000-10-09 18:24:57 +02:00
goto again ;
2011-06-15 02:44:15 +02:00
else
2000-10-09 18:24:57 +02:00
{
2009-08-20 15:13:43 +02:00
int errsv = errno ;
2000-10-09 18:24:57 +02:00
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_READ ,
_ ( " Failed to read data from child process (%s) " ) ,
2009-08-20 15:13:43 +02:00
g_strerror ( errsv ) ) ;
2011-06-15 02:44:15 +02:00
2000-10-09 18:24:57 +02:00
return READ_FAILED ;
}
}
/**
* g_spawn_sync :
2011-04-03 18:53:04 +02:00
* @ working_directory : ( allow - none ) : child ' s current working directory , or % NULL to inherit parent ' s
* @ argv : ( array zero - terminated = 1 ) : child ' s argument vector
* @ envp : ( array zero - terminated = 1 ) ( allow - none ) : child ' s environment , or % NULL to inherit parent ' s
* @ flags : flags from # GSpawnFlags
* @ child_setup : ( scope async ) ( allow - none ) : function to run in the child just before exec ( )
* @ user_data : ( closure ) : user data for @ child_setup
2011-06-10 18:58:49 +02:00
* @ standard_output : ( out ) ( array zero - terminated = 1 ) ( element - type guint8 ) ( allow - none ) : return location for child output , or % NULL
* @ standard_error : ( out ) ( array zero - terminated = 1 ) ( element - type guint8 ) ( allow - none ) : return location for child error messages , or % NULL
2011-04-03 18:53:04 +02:00
* @ exit_status : ( out ) ( allow - none ) : return location for child exit status , as returned by waitpid ( ) , or % NULL
2007-11-09 17:45:42 +01:00
* @ error : return location for error , or % NULL
2000-10-09 18:24:57 +02:00
*
* Executes a child synchronously ( waits for the child to exit before returning ) .
* All output from the child is stored in @ standard_output and @ standard_error ,
2007-11-09 17:45:42 +01:00
* if those parameters are non - % NULL . Note that you must set the
* % G_SPAWN_STDOUT_TO_DEV_NULL and % G_SPAWN_STDERR_TO_DEV_NULL flags when
* passing % NULL for @ standard_output and @ standard_error .
2012-07-10 17:27:22 +02:00
*
* If @ exit_status is non - % NULL , the platform - specific exit status of
2013-06-21 20:07:58 +02:00
* the child is stored there ; see the documentation of
2012-07-10 17:27:22 +02:00
* g_spawn_check_exit_status ( ) for how to use and interpret this .
* Note that it is invalid to pass % G_SPAWN_DO_NOT_REAP_CHILD in
* @ flags .
*
* If an error occurs , no data is returned in @ standard_output ,
* @ standard_error , or @ exit_status .
2007-11-09 17:45:42 +01:00
*
2005-08-26 01:28:24 +02:00
* This function calls g_spawn_async_with_pipes ( ) internally ; see that
* function for full details on the other parameters and details on
* how these functions work on Windows .
2000-10-09 18:24:57 +02:00
*
2014-01-31 20:56:10 +01:00
* Return value : % TRUE on success , % FALSE if an error was set
*/
2000-10-09 18:24:57 +02:00
gboolean
g_spawn_sync ( const gchar * working_directory ,
gchar * * argv ,
gchar * * envp ,
GSpawnFlags flags ,
GSpawnChildSetupFunc child_setup ,
gpointer user_data ,
gchar * * standard_output ,
gchar * * standard_error ,
gint * exit_status ,
GError * * error )
{
gint outpipe = - 1 ;
gint errpipe = - 1 ;
2004-03-01 21:47:49 +01:00
GPid pid ;
2000-10-09 18:24:57 +02:00
fd_set fds ;
gint ret ;
GString * outstr = NULL ;
GString * errstr = NULL ;
gboolean failed ;
gint status ;
g_return_val_if_fail ( argv ! = NULL , FALSE ) ;
g_return_val_if_fail ( ! ( flags & G_SPAWN_DO_NOT_REAP_CHILD ) , FALSE ) ;
g_return_val_if_fail ( standard_output = = NULL | |
! ( flags & G_SPAWN_STDOUT_TO_DEV_NULL ) , FALSE ) ;
g_return_val_if_fail ( standard_error = = NULL | |
! ( flags & G_SPAWN_STDERR_TO_DEV_NULL ) , FALSE ) ;
/* Just to ensure segfaults if callers try to use
* these when an error is reported .
*/
if ( standard_output )
* standard_output = NULL ;
if ( standard_error )
* standard_error = NULL ;
if ( ! fork_exec_with_pipes ( FALSE ,
working_directory ,
argv ,
envp ,
! ( flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN ) ,
( flags & G_SPAWN_SEARCH_PATH ) ! = 0 ,
2012-05-20 00:01:35 +02:00
( flags & G_SPAWN_SEARCH_PATH_FROM_ENVP ) ! = 0 ,
2000-10-09 18:24:57 +02:00
( flags & G_SPAWN_STDOUT_TO_DEV_NULL ) ! = 0 ,
( flags & G_SPAWN_STDERR_TO_DEV_NULL ) ! = 0 ,
( flags & G_SPAWN_CHILD_INHERITS_STDIN ) ! = 0 ,
2001-06-08 21:41:51 +02:00
( flags & G_SPAWN_FILE_AND_ARGV_ZERO ) ! = 0 ,
2012-11-10 19:16:29 +01:00
( flags & G_SPAWN_CLOEXEC_PIPES ) ! = 0 ,
2000-10-09 18:24:57 +02:00
child_setup ,
user_data ,
& pid ,
NULL ,
standard_output ? & outpipe : NULL ,
standard_error ? & errpipe : NULL ,
error ) )
return FALSE ;
/* Read data from child. */
failed = FALSE ;
if ( outpipe > = 0 )
{
2003-03-31 00:02:20 +02:00
outstr = g_string_new ( NULL ) ;
2000-10-09 18:24:57 +02:00
}
if ( errpipe > = 0 )
{
2003-03-31 00:02:20 +02:00
errstr = g_string_new ( NULL ) ;
2000-10-09 18:24:57 +02:00
}
/* Read data until we get EOF on both pipes. */
while ( ! failed & &
( outpipe > = 0 | |
errpipe > = 0 ) )
{
ret = 0 ;
FD_ZERO ( & fds ) ;
if ( outpipe > = 0 )
FD_SET ( outpipe , & fds ) ;
if ( errpipe > = 0 )
FD_SET ( errpipe , & fds ) ;
ret = select ( MAX ( outpipe , errpipe ) + 1 ,
& fds ,
NULL , NULL ,
NULL /* no timeout */ ) ;
2011-06-10 16:14:25 +02:00
if ( ret < 0 )
2000-10-09 18:24:57 +02:00
{
2009-08-20 15:13:43 +02:00
int errsv = errno ;
2011-06-10 16:14:25 +02:00
if ( errno = = EINTR )
continue ;
2000-10-09 18:24:57 +02:00
failed = TRUE ;
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_READ ,
_ ( " Unexpected error in select() reading data from a child process (%s) " ) ,
2009-08-20 15:13:43 +02:00
g_strerror ( errsv ) ) ;
2000-10-09 18:24:57 +02:00
break ;
}
if ( outpipe > = 0 & & FD_ISSET ( outpipe , & fds ) )
{
switch ( read_data ( outstr , outpipe , error ) )
{
case READ_FAILED :
failed = TRUE ;
break ;
case READ_EOF :
close_and_invalidate ( & outpipe ) ;
outpipe = - 1 ;
break ;
default :
break ;
}
if ( failed )
break ;
}
if ( errpipe > = 0 & & FD_ISSET ( errpipe , & fds ) )
{
switch ( read_data ( errstr , errpipe , error ) )
{
case READ_FAILED :
failed = TRUE ;
break ;
case READ_EOF :
close_and_invalidate ( & errpipe ) ;
errpipe = - 1 ;
break ;
default :
break ;
}
if ( failed )
break ;
}
}
/* These should only be open still if we had an error. */
if ( outpipe > = 0 )
close_and_invalidate ( & outpipe ) ;
if ( errpipe > = 0 )
close_and_invalidate ( & errpipe ) ;
2013-04-23 19:26:48 +02:00
/* Wait for child to exit, even if we have
* an error pending .
2012-10-29 20:44:16 +01:00
*/
2013-04-23 19:26:48 +02:00
again :
ret = waitpid ( pid , & status , 0 ) ;
if ( ret < 0 )
{
if ( errno = = EINTR )
goto again ;
else if ( errno = = ECHILD )
{
if ( exit_status )
{
g_warning ( " In call to g_spawn_sync(), exit status of a child process was requested but ECHILD was received by waitpid(). Most likely the process is ignoring SIGCHLD, or some other thread is invoking waitpid() with a nonpositive first argument; either behavior can break applications that use g_spawn_sync either directly or indirectly. " ) ;
}
else
{
/* We don't need the exit status. */
}
}
else
{
if ( ! failed ) /* avoid error pileups */
{
int errsv = errno ;
failed = TRUE ;
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_READ ,
_ ( " Unexpected error in waitpid() (%s) " ) ,
g_strerror ( errsv ) ) ;
}
}
}
2000-10-09 18:24:57 +02:00
if ( failed )
{
if ( outstr )
g_string_free ( outstr , TRUE ) ;
if ( errstr )
g_string_free ( errstr , TRUE ) ;
return FALSE ;
}
else
{
if ( exit_status )
* exit_status = status ;
if ( standard_output )
* standard_output = g_string_free ( outstr , FALSE ) ;
if ( standard_error )
* standard_error = g_string_free ( errstr , FALSE ) ;
return TRUE ;
}
}
/**
* g_spawn_async_with_pipes :
2011-04-03 18:53:04 +02:00
* @ working_directory : ( allow - none ) : child ' s current working directory , or % NULL to inherit parent ' s , in the GLib file name encoding
* @ argv : ( array zero - terminated = 1 ) : child ' s argument vector , in the GLib file name encoding
* @ envp : ( array zero - terminated = 1 ) ( allow - none ) : child ' s environment , or % NULL to inherit parent ' s , in the GLib file name encoding
2000-10-09 18:24:57 +02:00
* @ flags : flags from # GSpawnFlags
2011-04-03 18:53:04 +02:00
* @ child_setup : ( scope async ) ( allow - none ) : function to run in the child just before exec ( )
* @ user_data : ( closure ) : user data for @ child_setup
* @ child_pid : ( out ) ( allow - none ) : return location for child process ID , or % NULL
* @ standard_input : ( out ) ( allow - none ) : return location for file descriptor to write to child ' s stdin , or % NULL
* @ standard_output : ( out ) ( allow - none ) : return location for file descriptor to read child ' s stdout , or % NULL
* @ standard_error : ( out ) ( allow - none ) : return location for file descriptor to read child ' s stderr , or % NULL
2000-10-09 18:24:57 +02:00
* @ error : return location for error
*
* Executes a child program asynchronously ( your program will not
* block waiting for the child to exit ) . The child program is
* specified by the only argument that must be provided , @ argv . @ argv
2001-10-01 19:35:18 +02:00
* should be a % NULL - terminated array of strings , to be passed as the
2000-10-09 18:24:57 +02:00
* argument vector for the child . The first string in @ argv is of
* course the name of the program to execute . By default , the name of
2012-05-20 00:01:35 +02:00
* the program must be a full path . If @ flags contains the
* % G_SPAWN_SEARCH_PATH flag , the < envar > PATH < / envar > environment variable
* is used to search for the executable . If @ flags contains the
* % G_SPAWN_SEARCH_PATH_FROM_ENVP flag , the < envar > PATH < / envar > variable from
* @ envp is used to search for the executable .
* If both the % G_SPAWN_SEARCH_PATH and % G_SPAWN_SEARCH_PATH_FROM_ENVP
* flags are set , the < envar > PATH < / envar > variable from @ envp takes precedence
* over the environment variable .
*
2011-08-17 08:57:15 +02:00
* If the program name is not a full path and % G_SPAWN_SEARCH_PATH flag is not
* used , then the program will be run from the current directory ( or
2011-12-14 05:00:16 +01:00
* @ working_directory , if specified ) ; this might be unexpected or even
2011-08-17 08:57:15 +02:00
* dangerous in some cases when the current directory is world - writable .
2000-10-09 18:24:57 +02:00
*
2005-08-26 01:28:24 +02:00
* On Windows , note that all the string or string vector arguments to
* this function and the other g_spawn * ( ) functions are in UTF - 8 , the
* GLib file name encoding . Unicode characters that are not part of
2007-11-07 17:44:21 +01:00
* the system codepage passed in these arguments will be correctly
2005-08-26 01:28:24 +02:00
* available in the spawned program only if it uses wide character API
* to retrieve its command line . For C programs built with Microsoft ' s
* tools it is enough to make the program have a wmain ( ) instead of
* main ( ) . wmain ( ) has a wide character argument vector as parameter .
*
* At least currently , mingw doesn ' t support wmain ( ) , so if you use
* mingw to develop the spawned program , it will have to call the
* undocumented function __wgetmainargs ( ) to get the wide character
* argument vector and environment . See gspawn - win32 - helper . c in the
* GLib sources or init . c in the mingw runtime sources for a prototype
* for that function . Alternatively , you can retrieve the Win32 system
* level wide character command line passed to the spawned program
* using the GetCommandLineW ( ) function .
*
2014-01-31 20:56:10 +01:00
* On Windows the low - level child process creation API CreateProcess ( )
* doesn ' t use argument vectors , but a command line . The C runtime
* library ' s spawn * ( ) family of functions ( which g_spawn_async_with_pipes ( )
* eventually calls ) paste the argument vector elements together into
* a command line , and the C runtime startup code does a corresponding
* reconstruction of an argument vector from the command line , to be
* passed to main ( ) . Complications arise when you have argument vector
* elements that contain spaces of double quotes . The spawn * ( ) functions
* don ' t do any quoting or escaping , but on the other hand the startup
* code does do unquoting and unescaping in order to enable receiving
* arguments with embedded spaces or double quotes . To work around this
* asymmetry , g_spawn_async_with_pipes ( ) will do quoting and escaping on
* argument vector elements that need it before calling the C runtime
2003-07-25 23:32:47 +02:00
* spawn ( ) function .
2003-02-05 00:37:04 +01:00
*
2008-06-11 08:57:22 +02:00
* The returned @ child_pid on Windows is a handle to the child
* process , not its identifier . Process handles and process
* identifiers are different concepts on Windows .
*
2001-10-01 19:35:18 +02:00
* @ envp is a % NULL - terminated array of strings , where each string
2000-10-09 18:24:57 +02:00
* has the form < literal > KEY = VALUE < / literal > . This will become
2001-12-16 20:31:36 +01:00
* the child ' s environment . If @ envp is % NULL , the child inherits its
2000-10-09 18:24:57 +02:00
* parent ' s environment .
*
* @ flags should be the bitwise OR of any flags you want to affect the
2011-09-05 16:29:09 +02:00
* function ' s behaviour . The % G_SPAWN_DO_NOT_REAP_CHILD means that the
* child will not automatically be reaped ; you must use a child watch to
* be notified about the death of the child process . Eventually you must
* call g_spawn_close_pid ( ) on the @ child_pid , in order to free
* resources which may be associated with the child process . ( On Unix ,
* using a child watch is equivalent to calling waitpid ( ) or handling
2014-01-31 20:56:10 +01:00
* the % SIGCHLD signal manually . On Windows , calling g_spawn_close_pid ( )
2011-09-05 16:29:09 +02:00
* is equivalent to calling CloseHandle ( ) on the process handle returned
2014-01-31 20:56:10 +01:00
* in @ child_pid ) . See g_child_watch_add ( ) .
2002-11-18 10:58:39 +01:00
*
2000-10-09 18:24:57 +02:00
* % G_SPAWN_LEAVE_DESCRIPTORS_OPEN means that the parent ' s open file
2014-01-31 20:56:10 +01:00
* descriptors will be inherited by the child ; otherwise all descriptors
* except stdin / stdout / stderr will be closed before calling exec ( ) in the
* child . % G_SPAWN_SEARCH_PATH means that @ argv [ 0 ] need not be an absolute
* path , it will be looked for in the < envar > PATH < / envar > environment
* variable . % G_SPAWN_SEARCH_PATH_FROM_ENVP means need not be an absolute
* path , it will be looked for in the < envar > PATH < / envar > variable from
* @ envp . If both % G_SPAWN_SEARCH_PATH and % G_SPAWN_SEARCH_PATH_FROM_ENVP
* are used , the value from @ envp takes precedence over the environment .
2002-10-12 12:36:45 +02:00
* % G_SPAWN_STDOUT_TO_DEV_NULL means that the child ' s standard output will
2001-12-16 20:31:36 +01:00
* be discarded , instead of going to the same location as the parent ' s
2002-10-12 12:36:45 +02:00
* standard output . If you use this flag , @ standard_output must be % NULL .
2000-10-09 18:24:57 +02:00
* % G_SPAWN_STDERR_TO_DEV_NULL means that the child ' s standard error
2002-10-12 12:36:45 +02:00
* will be discarded , instead of going to the same location as the parent ' s
* standard error . If you use this flag , @ standard_error must be % NULL .
* % G_SPAWN_CHILD_INHERITS_STDIN means that the child will inherit the parent ' s
* standard input ( by default , the child ' s standard input is attached to
* / dev / null ) . If you use this flag , @ standard_input must be % NULL .
2001-06-08 21:41:51 +02:00
* % G_SPAWN_FILE_AND_ARGV_ZERO means that the first element of @ argv is
2014-01-31 20:56:10 +01:00
* the file to execute , while the remaining elements are the actual
* argument vector to pass to the file . Normally g_spawn_async_with_pipes ( )
* uses @ argv [ 0 ] as the file to execute , and passes all of @ argv to the child .
2000-10-09 18:24:57 +02:00
*
Ignore the G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully
2002-11-17 Tor Lillqvist <tml@iki.fi>
* glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully implemented
on Windows, at least not now. Always pass dont_wait as TRUE to
do_spawn_with_pipes(). The semantics of the dont_wait parameter is
very different from the semantics of the intermediate_child
parameter to fork_exec_with_pipes() in the Unix version. This
fixes a serious bug, g_spawn_async() in fact behaved
synchronously.
(do_spawn_with_pipes, do_spawn): Rename from
fork_exec_with_pipes() and do_exec(), those names were from the
Unix bersion, and misleading.
(close_and_invalidate): Don't try to close invalid fds.
* glib/gspawn.c (g_spawn_async_with_pipes): Add warning about
Windows behaviour. There is no fork(), so the child_setup()
function is in fact called in the parent.
* glib/gspawn-win32-helper.c (WinMain): Insert spaces in argv
debugging output.
* tests/spawn-test-win32-gui.c: New file. Test program to be
linked as a GUI application. Behaves differently depending on how
invoked (by spawn-test).
* tests/spawn-test.c (run_tests): On Win32, run the
spawn-test-win32-gui program, too, in several ways, synchronously
and asynchronously.
* tests/Makefile.am: Corresponding change.
2002-11-17 04:52:55 +01:00
* @ child_setup and @ user_data are a function and user data . On POSIX
* platforms , the function is called in the child after GLib has
* performed all the setup it plans to perform ( including creating
2014-01-31 20:56:10 +01:00
* pipes , closing file descriptors , etc . ) but before calling exec ( ) .
* That is , @ child_setup is called just before calling exec ( ) in the
* child . Obviously actions taken in this function will only affect
* the child , not the parent .
*
* On Windows , there is no separate fork ( ) and exec ( ) functionality .
* Child processes are created and run with a single API call ,
* CreateProcess ( ) . There is no sensible thing @ child_setup
2008-09-25 10:05:41 +02:00
* could be used for on Windows so it is ignored and not called .
2000-10-09 18:24:57 +02:00
*
2002-11-18 10:58:39 +01:00
* If non - % NULL , @ child_pid will on Unix be filled with the child ' s
2014-01-31 20:56:10 +01:00
* process ID . You can use the process ID to send signals to the child ,
* or to use g_child_watch_add ( ) ( or waitpid ( ) ) if you specified the
2002-11-18 10:58:39 +01:00
* % G_SPAWN_DO_NOT_REAP_CHILD flag . On Windows , @ child_pid will be
* filled with a handle to the child process only if you specified the
* % G_SPAWN_DO_NOT_REAP_CHILD flag . You can then access the child
* process using the Win32 API , for example wait for its termination
2014-01-31 20:56:10 +01:00
* with the WaitFor * ( ) functions , or examine its exit code with
* GetExitCodeProcess ( ) . You should close the handle with CloseHandle ( )
* or g_spawn_close_pid ( ) when you no longer need it .
2000-10-09 18:24:57 +02:00
*
2001-12-16 20:31:36 +01:00
* If non - % NULL , the @ standard_input , @ standard_output , @ standard_error
2000-10-09 18:24:57 +02:00
* locations will be filled with file descriptors for writing to the child ' s
* standard input or reading from its standard output or standard error .
* The caller of g_spawn_async_with_pipes ( ) must close these file descriptors
2014-01-31 20:56:10 +01:00
* when they are no longer in use . If these parameters are % NULL , the
* corresponding pipe won ' t be created .
2002-10-12 12:36:45 +02:00
*
2006-12-17 19:49:57 +01:00
* If @ standard_input is NULL , the child ' s standard input is attached to
* / dev / null unless % G_SPAWN_CHILD_INHERITS_STDIN is set .
2002-10-12 12:36:45 +02:00
*
2006-12-17 19:49:57 +01:00
* If @ standard_error is NULL , the child ' s standard error goes to the same
* location as the parent ' s standard error unless % G_SPAWN_STDERR_TO_DEV_NULL
* is set .
2002-10-12 12:36:45 +02:00
*
2006-12-17 19:49:57 +01:00
* If @ standard_output is NULL , the child ' s standard output goes to the same
* location as the parent ' s standard output unless % G_SPAWN_STDOUT_TO_DEV_NULL
* is set .
2000-10-09 18:24:57 +02:00
*
2001-12-16 20:31:36 +01:00
* @ error can be % NULL to ignore errors , or non - % NULL to report errors .
2014-01-31 20:56:10 +01:00
* If an error is set , the function returns % FALSE . Errors are reported
* even if they occur in the child ( for example if the executable in
* @ argv [ 0 ] is not found ) . Typically the < literal > message < / literal > field
* of returned errors should be displayed to users . Possible errors are
* those from the # G_SPAWN_ERROR domain .
2000-10-09 18:24:57 +02:00
*
* If an error occurs , @ child_pid , @ standard_input , @ standard_output ,
* and @ standard_error will not be filled with valid values .
2004-03-01 21:47:49 +01:00
*
* If @ child_pid is not % NULL and an error does not occur then the returned
2008-06-11 08:57:22 +02:00
* process reference must be closed using g_spawn_close_pid ( ) .
2006-12-17 19:49:57 +01:00
*
* If you are writing a GTK + application , and the program you
* are spawning is a graphical application , too , then you may
2011-12-14 05:00:16 +01:00
* want to use gdk_spawn_on_screen_with_pipes ( ) instead to ensure that
2008-05-25 21:57:56 +02:00
* the spawned program opens its windows on the right screen .
2000-10-09 18:24:57 +02:00
*
2001-12-16 20:31:36 +01:00
* Return value : % TRUE on success , % FALSE if an error was set
2014-01-31 20:56:10 +01:00
*/
2000-10-09 18:24:57 +02:00
gboolean
g_spawn_async_with_pipes ( const gchar * working_directory ,
gchar * * argv ,
gchar * * envp ,
GSpawnFlags flags ,
GSpawnChildSetupFunc child_setup ,
gpointer user_data ,
2004-03-01 21:47:49 +01:00
GPid * child_pid ,
2000-10-09 18:24:57 +02:00
gint * standard_input ,
gint * standard_output ,
gint * standard_error ,
GError * * error )
{
g_return_val_if_fail ( argv ! = NULL , FALSE ) ;
g_return_val_if_fail ( standard_output = = NULL | |
! ( flags & G_SPAWN_STDOUT_TO_DEV_NULL ) , FALSE ) ;
g_return_val_if_fail ( standard_error = = NULL | |
! ( flags & G_SPAWN_STDERR_TO_DEV_NULL ) , FALSE ) ;
/* can't inherit stdin if we have an input pipe. */
g_return_val_if_fail ( standard_input = = NULL | |
! ( flags & G_SPAWN_CHILD_INHERITS_STDIN ) , FALSE ) ;
return fork_exec_with_pipes ( ! ( flags & G_SPAWN_DO_NOT_REAP_CHILD ) ,
working_directory ,
argv ,
envp ,
! ( flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN ) ,
( flags & G_SPAWN_SEARCH_PATH ) ! = 0 ,
2012-05-20 00:01:35 +02:00
( flags & G_SPAWN_SEARCH_PATH_FROM_ENVP ) ! = 0 ,
2000-10-09 18:24:57 +02:00
( flags & G_SPAWN_STDOUT_TO_DEV_NULL ) ! = 0 ,
( flags & G_SPAWN_STDERR_TO_DEV_NULL ) ! = 0 ,
( flags & G_SPAWN_CHILD_INHERITS_STDIN ) ! = 0 ,
2001-06-08 21:41:51 +02:00
( flags & G_SPAWN_FILE_AND_ARGV_ZERO ) ! = 0 ,
2012-11-10 19:16:29 +01:00
( flags & G_SPAWN_CLOEXEC_PIPES ) ! = 0 ,
2000-10-09 18:24:57 +02:00
child_setup ,
user_data ,
child_pid ,
standard_input ,
standard_output ,
standard_error ,
error ) ;
}
/**
* g_spawn_command_line_sync :
* @ command_line : a command line
2011-06-10 18:58:49 +02:00
* @ standard_output : ( out ) ( array zero - terminated = 1 ) ( element - type guint8 ) ( allow - none ) : return location for child output
* @ standard_error : ( out ) ( array zero - terminated = 1 ) ( element - type guint8 ) ( allow - none ) : return location for child errors
2011-04-03 18:53:04 +02:00
* @ exit_status : ( out ) ( allow - none ) : return location for child exit status , as returned by waitpid ( )
2000-10-09 18:24:57 +02:00
* @ error : return location for errors
*
* A simple version of g_spawn_sync ( ) with little - used parameters
* removed , taking a command line instead of an argument vector . See
* g_spawn_sync ( ) for full details . @ command_line will be parsed by
* g_shell_parse_argv ( ) . Unlike g_spawn_sync ( ) , the % G_SPAWN_SEARCH_PATH flag
* is enabled . Note that % G_SPAWN_SEARCH_PATH can have security
* implications , so consider using g_spawn_sync ( ) directly if
* appropriate . Possible errors are those from g_spawn_sync ( ) and those
* from g_shell_parse_argv ( ) .
2005-05-20 21:30:02 +02:00
*
2012-07-10 17:27:22 +02:00
* If @ exit_status is non - % NULL , the platform - specific exit status of
* the child is stored there ; see the documentation of
* g_spawn_check_exit_status ( ) for how to use and interpret this .
2000-10-09 18:24:57 +02:00
*
2002-04-19 22:26:04 +02:00
* On Windows , please note the implications of g_shell_parse_argv ( )
2005-08-26 01:28:24 +02:00
* parsing @ command_line . Parsing is done according to Unix shell rules , not
* Windows command interpreter rules .
* Space is a separator , and backslashes are
2003-02-05 00:37:04 +01:00
* special . Thus you cannot simply pass a @ command_line containing
* canonical Windows paths , like " c: \\ program files \\ app \\ app.exe " , as
* the backslashes will be eaten , and the space will act as a
* separator . You need to enclose such paths with single quotes , like
* " 'c: \\ program files \\ app \\ app.exe' 'e: \\ folder \\ argument.txt' " .
2002-04-19 22:26:04 +02:00
*
2001-12-16 20:31:36 +01:00
* Return value : % TRUE on success , % FALSE if an error was set
2000-10-09 18:24:57 +02:00
* */
gboolean
g_spawn_command_line_sync ( const gchar * command_line ,
gchar * * standard_output ,
gchar * * standard_error ,
gint * exit_status ,
GError * * error )
{
gboolean retval ;
2004-10-24 03:37:42 +02:00
gchar * * argv = NULL ;
2000-10-09 18:24:57 +02:00
g_return_val_if_fail ( command_line ! = NULL , FALSE ) ;
if ( ! g_shell_parse_argv ( command_line ,
NULL , & argv ,
error ) )
return FALSE ;
retval = g_spawn_sync ( NULL ,
argv ,
NULL ,
G_SPAWN_SEARCH_PATH ,
NULL ,
NULL ,
standard_output ,
standard_error ,
exit_status ,
error ) ;
g_strfreev ( argv ) ;
return retval ;
}
/**
* g_spawn_command_line_async :
* @ command_line : a command line
* @ error : return location for errors
*
* A simple version of g_spawn_async ( ) that parses a command line with
* g_shell_parse_argv ( ) and passes it to g_spawn_async ( ) . Runs a
* command line in the background . Unlike g_spawn_async ( ) , the
* % G_SPAWN_SEARCH_PATH flag is enabled , other flags are not . Note
* that % G_SPAWN_SEARCH_PATH can have security implications , so
* consider using g_spawn_async ( ) directly if appropriate . Possible
* errors are those from g_shell_parse_argv ( ) and g_spawn_async ( ) .
*
2002-04-19 22:26:04 +02:00
* The same concerns on Windows apply as for g_spawn_command_line_sync ( ) .
*
2014-01-31 20:56:10 +01:00
* Return value : % TRUE on success , % FALSE if error is set
2000-10-09 18:24:57 +02:00
* */
gboolean
g_spawn_command_line_async ( const gchar * command_line ,
GError * * error )
{
gboolean retval ;
2004-10-24 03:37:42 +02:00
gchar * * argv = NULL ;
2000-10-09 18:24:57 +02:00
g_return_val_if_fail ( command_line ! = NULL , FALSE ) ;
if ( ! g_shell_parse_argv ( command_line ,
NULL , & argv ,
error ) )
return FALSE ;
retval = g_spawn_async ( NULL ,
argv ,
NULL ,
G_SPAWN_SEARCH_PATH ,
NULL ,
NULL ,
NULL ,
error ) ;
g_strfreev ( argv ) ;
return retval ;
}
2012-07-10 17:27:22 +02:00
/**
* g_spawn_check_exit_status :
* @ exit_status : An exit code as returned from g_spawn_sync ( )
* @ error : a # GError
*
* Set @ error if @ exit_status indicates the child exited abnormally
* ( e . g . with a nonzero exit code , or via a fatal signal ) .
*
* The g_spawn_sync ( ) and g_child_watch_add ( ) family of APIs return an
* exit status for subprocesses encoded in a platform - specific way .
2014-01-31 20:56:10 +01:00
* On Unix , this is guaranteed to be in the same format waitpid ( ) returns ,
* and on Windows it is guaranteed to be the result of GetExitCodeProcess ( ) .
*
* Prior to the introduction of this function in GLib 2.34 , interpreting
* @ exit_status required use of platform - specific APIs , which is problematic
* for software using GLib as a cross - platform layer .
2012-07-10 17:27:22 +02:00
*
* Additionally , many programs simply want to determine whether or not
* the child exited successfully , and either propagate a # GError or
2014-01-31 20:56:10 +01:00
* print a message to standard error . In that common case , this function
* can be used . Note that the error message in @ error will contain
* human - readable information about the exit status .
2012-07-10 17:27:22 +02:00
*
2014-01-31 20:56:10 +01:00
* The @ domain and @ code of @ error have special semantics in the case
* where the process has an " exit code " , as opposed to being killed by
* a signal . On Unix , this happens if WIFEXITED ( ) would be true of
* @ exit_status . On Windows , it is always the case .
2012-07-10 17:27:22 +02:00
*
* The special semantics are that the actual exit code will be the
* code set in @ error , and the domain will be % G_SPAWN_EXIT_ERROR .
* This allows you to differentiate between different exit codes .
*
* If the process was terminated by some means other than an exit
* status , the domain will be % G_SPAWN_ERROR , and the code will be
* % G_SPAWN_ERROR_FAILED .
*
* This function just offers convenience ; you can of course also check
* the available platform via a macro such as % G_OS_UNIX , and use
2014-01-31 20:56:10 +01:00
* WIFEXITED ( ) and WEXITSTATUS ( ) on @ exit_status directly . Do not attempt
* to scan or parse the error message string ; it may be translated and / or
* change in future versions of GLib .
*
* Returns : % TRUE if child exited successfully , % FALSE otherwise ( and
* @ error will be set )
2012-07-10 17:27:22 +02:00
*
* Since : 2.34
*/
gboolean
g_spawn_check_exit_status ( gint exit_status ,
GError * * error )
{
gboolean ret = FALSE ;
if ( WIFEXITED ( exit_status ) )
{
if ( WEXITSTATUS ( exit_status ) ! = 0 )
{
g_set_error ( error , G_SPAWN_EXIT_ERROR , WEXITSTATUS ( exit_status ) ,
_ ( " Child process exited with code %ld " ) ,
( long ) WEXITSTATUS ( exit_status ) ) ;
goto out ;
}
}
else if ( WIFSIGNALED ( exit_status ) )
{
g_set_error ( error , G_SPAWN_ERROR , G_SPAWN_ERROR_FAILED ,
_ ( " Child process killed by signal %ld " ) ,
( long ) WTERMSIG ( exit_status ) ) ;
goto out ;
}
else if ( WIFSTOPPED ( exit_status ) )
{
g_set_error ( error , G_SPAWN_ERROR , G_SPAWN_ERROR_FAILED ,
_ ( " Child process stopped by signal %ld " ) ,
( long ) WSTOPSIG ( exit_status ) ) ;
goto out ;
}
else
{
g_set_error ( error , G_SPAWN_ERROR , G_SPAWN_ERROR_FAILED ,
_ ( " Child process exited abnormally " ) ) ;
goto out ;
}
ret = TRUE ;
out :
return ret ;
}
2000-10-09 18:24:57 +02:00
static gint
exec_err_to_g_error ( gint en )
{
switch ( en )
{
# ifdef EACCES
case EACCES :
return G_SPAWN_ERROR_ACCES ;
break ;
# endif
# ifdef EPERM
case EPERM :
return G_SPAWN_ERROR_PERM ;
break ;
# endif
# ifdef E2BIG
case E2BIG :
2012-03-02 16:22:11 +01:00
return G_SPAWN_ERROR_TOO_BIG ;
2000-10-09 18:24:57 +02:00
break ;
# endif
# ifdef ENOEXEC
case ENOEXEC :
return G_SPAWN_ERROR_NOEXEC ;
break ;
# endif
# ifdef ENAMETOOLONG
case ENAMETOOLONG :
return G_SPAWN_ERROR_NAMETOOLONG ;
break ;
# endif
# ifdef ENOENT
case ENOENT :
return G_SPAWN_ERROR_NOENT ;
break ;
# endif
# ifdef ENOMEM
case ENOMEM :
return G_SPAWN_ERROR_NOMEM ;
break ;
# endif
# ifdef ENOTDIR
case ENOTDIR :
return G_SPAWN_ERROR_NOTDIR ;
break ;
# endif
# ifdef ELOOP
case ELOOP :
return G_SPAWN_ERROR_LOOP ;
break ;
# endif
# ifdef ETXTBUSY
case ETXTBUSY :
return G_SPAWN_ERROR_TXTBUSY ;
break ;
# endif
# ifdef EIO
case EIO :
return G_SPAWN_ERROR_IO ;
break ;
# endif
# ifdef ENFILE
case ENFILE :
return G_SPAWN_ERROR_NFILE ;
break ;
# endif
# ifdef EMFILE
case EMFILE :
return G_SPAWN_ERROR_MFILE ;
break ;
# endif
# ifdef EINVAL
case EINVAL :
return G_SPAWN_ERROR_INVAL ;
break ;
# endif
# ifdef EISDIR
case EISDIR :
return G_SPAWN_ERROR_ISDIR ;
break ;
# endif
# ifdef ELIBBAD
case ELIBBAD :
return G_SPAWN_ERROR_LIBBAD ;
break ;
# endif
default :
return G_SPAWN_ERROR_FAILED ;
break ;
}
}
2003-06-02 20:20:25 +02:00
static gssize
write_all ( gint fd , gconstpointer vbuf , gsize to_write )
{
gchar * buf = ( gchar * ) vbuf ;
while ( to_write > 0 )
{
gssize count = write ( fd , buf , to_write ) ;
if ( count < 0 )
{
if ( errno ! = EINTR )
return FALSE ;
}
else
{
to_write - = count ;
buf + = count ;
}
}
return TRUE ;
}
2008-12-31 06:51:47 +01:00
G_GNUC_NORETURN
2000-10-09 18:24:57 +02:00
static void
write_err_and_exit ( gint fd , gint msg )
{
gint en = errno ;
2003-06-02 20:20:25 +02:00
write_all ( fd , & msg , sizeof ( msg ) ) ;
write_all ( fd , & en , sizeof ( en ) ) ;
2000-10-09 18:24:57 +02:00
_exit ( 1 ) ;
}
2006-12-17 18:45:03 +01:00
static int
2006-12-15 06:33:32 +01:00
set_cloexec ( void * data , gint fd )
2000-10-09 18:24:57 +02:00
{
2006-12-17 18:45:03 +01:00
if ( fd > = GPOINTER_TO_INT ( data ) )
2006-12-15 06:33:32 +01:00
fcntl ( fd , F_SETFD , FD_CLOEXEC ) ;
2006-12-17 18:45:03 +01:00
return 0 ;
2000-10-09 18:24:57 +02:00
}
2006-12-15 06:33:32 +01:00
# ifndef HAVE_FDWALK
static int
fdwalk ( int ( * cb ) ( void * data , int fd ) , void * data )
{
gint open_max ;
gint fd ;
2007-10-16 07:28:10 +02:00
gint res = 0 ;
# ifdef HAVE_SYS_RESOURCE_H
struct rlimit rl ;
# endif
# ifdef __linux__
DIR * d ;
if ( ( d = opendir ( " /proc/self/fd " ) ) ) {
struct dirent * de ;
while ( ( de = readdir ( d ) ) ) {
glong l ;
gchar * e = NULL ;
if ( de - > d_name [ 0 ] = = ' . ' )
continue ;
errno = 0 ;
l = strtol ( de - > d_name , & e , 10 ) ;
if ( errno ! = 0 | | ! e | | * e )
continue ;
fd = ( gint ) l ;
if ( ( glong ) fd ! = l )
continue ;
if ( fd = = dirfd ( d ) )
continue ;
if ( ( res = cb ( data , fd ) ) ! = 0 )
break ;
}
closedir ( d ) ;
return res ;
}
2006-12-15 06:33:32 +01:00
2007-10-16 07:28:10 +02:00
/* If /proc is not mounted or not accessible we fall back to the old
* rlimit trick */
# endif
# ifdef HAVE_SYS_RESOURCE_H
2008-01-07 00:12:24 +01:00
if ( getrlimit ( RLIMIT_NOFILE , & rl ) = = 0 & & rl . rlim_max ! = RLIM_INFINITY )
2007-10-16 07:28:10 +02:00
open_max = rl . rlim_max ;
else
# endif
open_max = sysconf ( _SC_OPEN_MAX ) ;
for ( fd = 0 ; fd < open_max ; fd + + )
if ( ( res = cb ( data , fd ) ) ! = 0 )
break ;
2006-12-15 06:33:32 +01:00
return res ;
}
# endif
2000-10-09 18:24:57 +02:00
static gint
sane_dup2 ( gint fd1 , gint fd2 )
{
gint ret ;
retry :
ret = dup2 ( fd1 , fd2 ) ;
if ( ret < 0 & & errno = = EINTR )
goto retry ;
return ret ;
}
2011-06-10 16:14:25 +02:00
static gint
sane_open ( const char * path , gint mode )
{
gint ret ;
retry :
ret = open ( path , mode ) ;
if ( ret < 0 & & errno = = EINTR )
goto retry ;
return ret ;
}
2000-10-09 18:24:57 +02:00
enum
{
CHILD_CHDIR_FAILED ,
CHILD_EXEC_FAILED ,
CHILD_DUP2_FAILED ,
CHILD_FORK_FAILED
} ;
static void
do_exec ( gint child_err_report_fd ,
gint stdin_fd ,
gint stdout_fd ,
gint stderr_fd ,
const gchar * working_directory ,
gchar * * argv ,
gchar * * envp ,
gboolean close_descriptors ,
gboolean search_path ,
2012-05-20 00:01:35 +02:00
gboolean search_path_from_envp ,
2000-10-09 18:24:57 +02:00
gboolean stdout_to_null ,
gboolean stderr_to_null ,
gboolean child_inherits_stdin ,
2001-06-08 21:41:51 +02:00
gboolean file_and_argv_zero ,
2000-10-09 18:24:57 +02:00
GSpawnChildSetupFunc child_setup ,
gpointer user_data )
{
if ( working_directory & & chdir ( working_directory ) < 0 )
write_err_and_exit ( child_err_report_fd ,
CHILD_CHDIR_FAILED ) ;
/* Close all file descriptors but stdin stdout and stderr as
* soon as we exec . Note that this includes
* child_err_report_fd , which keeps the parent from blocking
* forever on the other end of that pipe .
*/
if ( close_descriptors )
{
2006-12-17 18:45:03 +01:00
fdwalk ( set_cloexec , GINT_TO_POINTER ( 3 ) ) ;
2000-10-09 18:24:57 +02:00
}
else
{
/* We need to do child_err_report_fd anyway */
2006-12-17 18:45:03 +01:00
set_cloexec ( GINT_TO_POINTER ( 0 ) , child_err_report_fd ) ;
2000-10-09 18:24:57 +02:00
}
/* Redirect pipes as required */
if ( stdin_fd > = 0 )
{
/* dup2 can't actually fail here I don't think */
if ( sane_dup2 ( stdin_fd , 0 ) < 0 )
write_err_and_exit ( child_err_report_fd ,
CHILD_DUP2_FAILED ) ;
/* ignore this if it doesn't work */
close_and_invalidate ( & stdin_fd ) ;
}
else if ( ! child_inherits_stdin )
{
/* Keep process from blocking on a read of stdin */
gint read_null = open ( " /dev/null " , O_RDONLY ) ;
2012-06-21 21:37:39 +02:00
g_assert ( read_null ! = - 1 ) ;
2000-10-09 18:24:57 +02:00
sane_dup2 ( read_null , 0 ) ;
close_and_invalidate ( & read_null ) ;
}
if ( stdout_fd > = 0 )
{
/* dup2 can't actually fail here I don't think */
if ( sane_dup2 ( stdout_fd , 1 ) < 0 )
write_err_and_exit ( child_err_report_fd ,
CHILD_DUP2_FAILED ) ;
/* ignore this if it doesn't work */
close_and_invalidate ( & stdout_fd ) ;
}
else if ( stdout_to_null )
{
2011-06-10 16:14:25 +02:00
gint write_null = sane_open ( " /dev/null " , O_WRONLY ) ;
2012-06-21 21:37:39 +02:00
g_assert ( write_null ! = - 1 ) ;
2000-10-09 18:24:57 +02:00
sane_dup2 ( write_null , 1 ) ;
close_and_invalidate ( & write_null ) ;
}
if ( stderr_fd > = 0 )
{
/* dup2 can't actually fail here I don't think */
if ( sane_dup2 ( stderr_fd , 2 ) < 0 )
write_err_and_exit ( child_err_report_fd ,
CHILD_DUP2_FAILED ) ;
/* ignore this if it doesn't work */
close_and_invalidate ( & stderr_fd ) ;
}
else if ( stderr_to_null )
{
2011-06-10 16:14:25 +02:00
gint write_null = sane_open ( " /dev/null " , O_WRONLY ) ;
2000-10-09 18:24:57 +02:00
sane_dup2 ( write_null , 2 ) ;
close_and_invalidate ( & write_null ) ;
}
/* Call user function just before we exec */
if ( child_setup )
{
( * child_setup ) ( user_data ) ;
}
2001-06-08 21:41:51 +02:00
g_execute ( argv [ 0 ] ,
file_and_argv_zero ? argv + 1 : argv ,
2012-05-20 00:01:35 +02:00
envp , search_path , search_path_from_envp ) ;
2000-10-09 18:24:57 +02:00
/* Exec failed */
write_err_and_exit ( child_err_report_fd ,
CHILD_EXEC_FAILED ) ;
}
static gboolean
read_ints ( int fd ,
gint * buf ,
Changes for 64-bit cleanliness, loosely based on patch from Mark Murnane.
Wed Jun 20 12:00:54 2001 Owen Taylor <otaylor@redhat.com>
Changes for 64-bit cleanliness, loosely based on patch
from Mark Murnane.
* gconvert.c (g_convert/g_convert_with_fallback): Remove
workarounds for since-fixed GNU libc bugs. Minor
doc fix.
* gconvert.[ch]: Change gint to gsize/gssize as
appropriate.
* gconvert.c (g_locale/filename_to/from_utf8): Fix incorrect
computation of bytes_read / bytes_written.
* gfileutils.[ch] (g_file_get_contents): Make length
out parameter 'gsize *len'.
* ghook.c (g_hook_compare_ids): Don't compare a
and b as 'a - b'.
* gmacros.h (GSIZE_TO_POINTER): Add GPOINTER_TO_SIZE,
GSIZE_TO_POINTER.
* gmain.c (g_timeout_prepare): Rewrite to avoid
overflows. (Fixes bug when system clock skews
backwards more than 24 days.)
* gmarkup.[ch]: Make lengths passed to callbacks
gsize, length for g_markup_parse-context_parse(),
g_markup_escape_text() gssize.
* gmessages.[ch] (g_printf_string_upper_bound): Change
return value to gsize.
* gmessages.c (printf_string_upper_bound): Remove
a ridiculous use of 'inline' on a 300 line function.
* gstring.[ch]: Represent size of string as a gsize,
not gint. Make parameters to functions take gsize,
or gssize where -1 is allowed.
* gstring.c (g_string_erase): Make
g_string_erase (string, pos, -1) a synonym for
g_string_truncate for consistency with other G*
APIs.
* gstrfuncs.[ch]: Make all functions taking a string
length, take a gsize, or gssize if -1 is allowed.
(g_strstr_len, g_strrstr_len). Also fix some boundary
conditions in g_str[r]str[_len].
* gutf8.c tests/unicode-encoding.c: Make parameters that
are byte lengths gsize, gssize as appropriate. Make
character offsets, other counts, glong.
* gasyncqueue.c gcompletion.c
timeloop.c timeloop-basic.c gutils.c gspawn.c.
Small 64 bit cleanliness fixups.
* glist.c (g_list_sort2, g_list_sort_real): Fix functions
that should have been static.
* gdate.c (g_date_fill_parse_tokens): Fix extra
declaration that was shadowing another.
* tests/module-test.c: Include string.h
Mon Jun 18 15:43:29 2001 Owen Taylor <otaylor@redhat.com>
* gutf8.c (g_get_charset): Make argument
G_CONST_RETURN char **.
2001-06-23 15:55:09 +02:00
gint n_ints_in_buf ,
gint * n_ints_read ,
2000-10-09 18:24:57 +02:00
GError * * error )
{
Changes for 64-bit cleanliness, loosely based on patch from Mark Murnane.
Wed Jun 20 12:00:54 2001 Owen Taylor <otaylor@redhat.com>
Changes for 64-bit cleanliness, loosely based on patch
from Mark Murnane.
* gconvert.c (g_convert/g_convert_with_fallback): Remove
workarounds for since-fixed GNU libc bugs. Minor
doc fix.
* gconvert.[ch]: Change gint to gsize/gssize as
appropriate.
* gconvert.c (g_locale/filename_to/from_utf8): Fix incorrect
computation of bytes_read / bytes_written.
* gfileutils.[ch] (g_file_get_contents): Make length
out parameter 'gsize *len'.
* ghook.c (g_hook_compare_ids): Don't compare a
and b as 'a - b'.
* gmacros.h (GSIZE_TO_POINTER): Add GPOINTER_TO_SIZE,
GSIZE_TO_POINTER.
* gmain.c (g_timeout_prepare): Rewrite to avoid
overflows. (Fixes bug when system clock skews
backwards more than 24 days.)
* gmarkup.[ch]: Make lengths passed to callbacks
gsize, length for g_markup_parse-context_parse(),
g_markup_escape_text() gssize.
* gmessages.[ch] (g_printf_string_upper_bound): Change
return value to gsize.
* gmessages.c (printf_string_upper_bound): Remove
a ridiculous use of 'inline' on a 300 line function.
* gstring.[ch]: Represent size of string as a gsize,
not gint. Make parameters to functions take gsize,
or gssize where -1 is allowed.
* gstring.c (g_string_erase): Make
g_string_erase (string, pos, -1) a synonym for
g_string_truncate for consistency with other G*
APIs.
* gstrfuncs.[ch]: Make all functions taking a string
length, take a gsize, or gssize if -1 is allowed.
(g_strstr_len, g_strrstr_len). Also fix some boundary
conditions in g_str[r]str[_len].
* gutf8.c tests/unicode-encoding.c: Make parameters that
are byte lengths gsize, gssize as appropriate. Make
character offsets, other counts, glong.
* gasyncqueue.c gcompletion.c
timeloop.c timeloop-basic.c gutils.c gspawn.c.
Small 64 bit cleanliness fixups.
* glist.c (g_list_sort2, g_list_sort_real): Fix functions
that should have been static.
* gdate.c (g_date_fill_parse_tokens): Fix extra
declaration that was shadowing another.
* tests/module-test.c: Include string.h
Mon Jun 18 15:43:29 2001 Owen Taylor <otaylor@redhat.com>
* gutf8.c (g_get_charset): Make argument
G_CONST_RETURN char **.
2001-06-23 15:55:09 +02:00
gsize bytes = 0 ;
2000-10-09 18:24:57 +02:00
while ( TRUE )
{
Changes for 64-bit cleanliness, loosely based on patch from Mark Murnane.
Wed Jun 20 12:00:54 2001 Owen Taylor <otaylor@redhat.com>
Changes for 64-bit cleanliness, loosely based on patch
from Mark Murnane.
* gconvert.c (g_convert/g_convert_with_fallback): Remove
workarounds for since-fixed GNU libc bugs. Minor
doc fix.
* gconvert.[ch]: Change gint to gsize/gssize as
appropriate.
* gconvert.c (g_locale/filename_to/from_utf8): Fix incorrect
computation of bytes_read / bytes_written.
* gfileutils.[ch] (g_file_get_contents): Make length
out parameter 'gsize *len'.
* ghook.c (g_hook_compare_ids): Don't compare a
and b as 'a - b'.
* gmacros.h (GSIZE_TO_POINTER): Add GPOINTER_TO_SIZE,
GSIZE_TO_POINTER.
* gmain.c (g_timeout_prepare): Rewrite to avoid
overflows. (Fixes bug when system clock skews
backwards more than 24 days.)
* gmarkup.[ch]: Make lengths passed to callbacks
gsize, length for g_markup_parse-context_parse(),
g_markup_escape_text() gssize.
* gmessages.[ch] (g_printf_string_upper_bound): Change
return value to gsize.
* gmessages.c (printf_string_upper_bound): Remove
a ridiculous use of 'inline' on a 300 line function.
* gstring.[ch]: Represent size of string as a gsize,
not gint. Make parameters to functions take gsize,
or gssize where -1 is allowed.
* gstring.c (g_string_erase): Make
g_string_erase (string, pos, -1) a synonym for
g_string_truncate for consistency with other G*
APIs.
* gstrfuncs.[ch]: Make all functions taking a string
length, take a gsize, or gssize if -1 is allowed.
(g_strstr_len, g_strrstr_len). Also fix some boundary
conditions in g_str[r]str[_len].
* gutf8.c tests/unicode-encoding.c: Make parameters that
are byte lengths gsize, gssize as appropriate. Make
character offsets, other counts, glong.
* gasyncqueue.c gcompletion.c
timeloop.c timeloop-basic.c gutils.c gspawn.c.
Small 64 bit cleanliness fixups.
* glist.c (g_list_sort2, g_list_sort_real): Fix functions
that should have been static.
* gdate.c (g_date_fill_parse_tokens): Fix extra
declaration that was shadowing another.
* tests/module-test.c: Include string.h
Mon Jun 18 15:43:29 2001 Owen Taylor <otaylor@redhat.com>
* gutf8.c (g_get_charset): Make argument
G_CONST_RETURN char **.
2001-06-23 15:55:09 +02:00
gssize chunk ;
2000-10-09 18:24:57 +02:00
if ( bytes > = sizeof ( gint ) * 2 )
break ; /* give up, who knows what happened, should not be
* possible .
*/
again :
chunk = read ( fd ,
( ( gchar * ) buf ) + bytes ,
Changes for 64-bit cleanliness, loosely based on patch from Mark Murnane.
Wed Jun 20 12:00:54 2001 Owen Taylor <otaylor@redhat.com>
Changes for 64-bit cleanliness, loosely based on patch
from Mark Murnane.
* gconvert.c (g_convert/g_convert_with_fallback): Remove
workarounds for since-fixed GNU libc bugs. Minor
doc fix.
* gconvert.[ch]: Change gint to gsize/gssize as
appropriate.
* gconvert.c (g_locale/filename_to/from_utf8): Fix incorrect
computation of bytes_read / bytes_written.
* gfileutils.[ch] (g_file_get_contents): Make length
out parameter 'gsize *len'.
* ghook.c (g_hook_compare_ids): Don't compare a
and b as 'a - b'.
* gmacros.h (GSIZE_TO_POINTER): Add GPOINTER_TO_SIZE,
GSIZE_TO_POINTER.
* gmain.c (g_timeout_prepare): Rewrite to avoid
overflows. (Fixes bug when system clock skews
backwards more than 24 days.)
* gmarkup.[ch]: Make lengths passed to callbacks
gsize, length for g_markup_parse-context_parse(),
g_markup_escape_text() gssize.
* gmessages.[ch] (g_printf_string_upper_bound): Change
return value to gsize.
* gmessages.c (printf_string_upper_bound): Remove
a ridiculous use of 'inline' on a 300 line function.
* gstring.[ch]: Represent size of string as a gsize,
not gint. Make parameters to functions take gsize,
or gssize where -1 is allowed.
* gstring.c (g_string_erase): Make
g_string_erase (string, pos, -1) a synonym for
g_string_truncate for consistency with other G*
APIs.
* gstrfuncs.[ch]: Make all functions taking a string
length, take a gsize, or gssize if -1 is allowed.
(g_strstr_len, g_strrstr_len). Also fix some boundary
conditions in g_str[r]str[_len].
* gutf8.c tests/unicode-encoding.c: Make parameters that
are byte lengths gsize, gssize as appropriate. Make
character offsets, other counts, glong.
* gasyncqueue.c gcompletion.c
timeloop.c timeloop-basic.c gutils.c gspawn.c.
Small 64 bit cleanliness fixups.
* glist.c (g_list_sort2, g_list_sort_real): Fix functions
that should have been static.
* gdate.c (g_date_fill_parse_tokens): Fix extra
declaration that was shadowing another.
* tests/module-test.c: Include string.h
Mon Jun 18 15:43:29 2001 Owen Taylor <otaylor@redhat.com>
* gutf8.c (g_get_charset): Make argument
G_CONST_RETURN char **.
2001-06-23 15:55:09 +02:00
sizeof ( gint ) * n_ints_in_buf - bytes ) ;
2000-10-09 18:24:57 +02:00
if ( chunk < 0 & & errno = = EINTR )
goto again ;
if ( chunk < 0 )
{
2009-08-20 15:13:43 +02:00
int errsv = errno ;
2000-10-09 18:24:57 +02:00
/* Some weird shit happened, bail out */
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FAILED ,
_ ( " Failed to read from child pipe (%s) " ) ,
2009-08-20 15:13:43 +02:00
g_strerror ( errsv ) ) ;
2000-10-09 18:24:57 +02:00
return FALSE ;
}
else if ( chunk = = 0 )
break ; /* EOF */
Changes for 64-bit cleanliness, loosely based on patch from Mark Murnane.
Wed Jun 20 12:00:54 2001 Owen Taylor <otaylor@redhat.com>
Changes for 64-bit cleanliness, loosely based on patch
from Mark Murnane.
* gconvert.c (g_convert/g_convert_with_fallback): Remove
workarounds for since-fixed GNU libc bugs. Minor
doc fix.
* gconvert.[ch]: Change gint to gsize/gssize as
appropriate.
* gconvert.c (g_locale/filename_to/from_utf8): Fix incorrect
computation of bytes_read / bytes_written.
* gfileutils.[ch] (g_file_get_contents): Make length
out parameter 'gsize *len'.
* ghook.c (g_hook_compare_ids): Don't compare a
and b as 'a - b'.
* gmacros.h (GSIZE_TO_POINTER): Add GPOINTER_TO_SIZE,
GSIZE_TO_POINTER.
* gmain.c (g_timeout_prepare): Rewrite to avoid
overflows. (Fixes bug when system clock skews
backwards more than 24 days.)
* gmarkup.[ch]: Make lengths passed to callbacks
gsize, length for g_markup_parse-context_parse(),
g_markup_escape_text() gssize.
* gmessages.[ch] (g_printf_string_upper_bound): Change
return value to gsize.
* gmessages.c (printf_string_upper_bound): Remove
a ridiculous use of 'inline' on a 300 line function.
* gstring.[ch]: Represent size of string as a gsize,
not gint. Make parameters to functions take gsize,
or gssize where -1 is allowed.
* gstring.c (g_string_erase): Make
g_string_erase (string, pos, -1) a synonym for
g_string_truncate for consistency with other G*
APIs.
* gstrfuncs.[ch]: Make all functions taking a string
length, take a gsize, or gssize if -1 is allowed.
(g_strstr_len, g_strrstr_len). Also fix some boundary
conditions in g_str[r]str[_len].
* gutf8.c tests/unicode-encoding.c: Make parameters that
are byte lengths gsize, gssize as appropriate. Make
character offsets, other counts, glong.
* gasyncqueue.c gcompletion.c
timeloop.c timeloop-basic.c gutils.c gspawn.c.
Small 64 bit cleanliness fixups.
* glist.c (g_list_sort2, g_list_sort_real): Fix functions
that should have been static.
* gdate.c (g_date_fill_parse_tokens): Fix extra
declaration that was shadowing another.
* tests/module-test.c: Include string.h
Mon Jun 18 15:43:29 2001 Owen Taylor <otaylor@redhat.com>
* gutf8.c (g_get_charset): Make argument
G_CONST_RETURN char **.
2001-06-23 15:55:09 +02:00
else /* chunk > 0 */
bytes + = chunk ;
2000-10-09 18:24:57 +02:00
}
Changes for 64-bit cleanliness, loosely based on patch from Mark Murnane.
Wed Jun 20 12:00:54 2001 Owen Taylor <otaylor@redhat.com>
Changes for 64-bit cleanliness, loosely based on patch
from Mark Murnane.
* gconvert.c (g_convert/g_convert_with_fallback): Remove
workarounds for since-fixed GNU libc bugs. Minor
doc fix.
* gconvert.[ch]: Change gint to gsize/gssize as
appropriate.
* gconvert.c (g_locale/filename_to/from_utf8): Fix incorrect
computation of bytes_read / bytes_written.
* gfileutils.[ch] (g_file_get_contents): Make length
out parameter 'gsize *len'.
* ghook.c (g_hook_compare_ids): Don't compare a
and b as 'a - b'.
* gmacros.h (GSIZE_TO_POINTER): Add GPOINTER_TO_SIZE,
GSIZE_TO_POINTER.
* gmain.c (g_timeout_prepare): Rewrite to avoid
overflows. (Fixes bug when system clock skews
backwards more than 24 days.)
* gmarkup.[ch]: Make lengths passed to callbacks
gsize, length for g_markup_parse-context_parse(),
g_markup_escape_text() gssize.
* gmessages.[ch] (g_printf_string_upper_bound): Change
return value to gsize.
* gmessages.c (printf_string_upper_bound): Remove
a ridiculous use of 'inline' on a 300 line function.
* gstring.[ch]: Represent size of string as a gsize,
not gint. Make parameters to functions take gsize,
or gssize where -1 is allowed.
* gstring.c (g_string_erase): Make
g_string_erase (string, pos, -1) a synonym for
g_string_truncate for consistency with other G*
APIs.
* gstrfuncs.[ch]: Make all functions taking a string
length, take a gsize, or gssize if -1 is allowed.
(g_strstr_len, g_strrstr_len). Also fix some boundary
conditions in g_str[r]str[_len].
* gutf8.c tests/unicode-encoding.c: Make parameters that
are byte lengths gsize, gssize as appropriate. Make
character offsets, other counts, glong.
* gasyncqueue.c gcompletion.c
timeloop.c timeloop-basic.c gutils.c gspawn.c.
Small 64 bit cleanliness fixups.
* glist.c (g_list_sort2, g_list_sort_real): Fix functions
that should have been static.
* gdate.c (g_date_fill_parse_tokens): Fix extra
declaration that was shadowing another.
* tests/module-test.c: Include string.h
Mon Jun 18 15:43:29 2001 Owen Taylor <otaylor@redhat.com>
* gutf8.c (g_get_charset): Make argument
G_CONST_RETURN char **.
2001-06-23 15:55:09 +02:00
* n_ints_read = ( gint ) ( bytes / sizeof ( gint ) ) ;
2000-10-09 18:24:57 +02:00
return TRUE ;
}
static gboolean
fork_exec_with_pipes ( gboolean intermediate_child ,
const gchar * working_directory ,
gchar * * argv ,
gchar * * envp ,
gboolean close_descriptors ,
gboolean search_path ,
2012-05-20 00:01:35 +02:00
gboolean search_path_from_envp ,
2000-10-09 18:24:57 +02:00
gboolean stdout_to_null ,
gboolean stderr_to_null ,
gboolean child_inherits_stdin ,
2001-06-08 21:41:51 +02:00
gboolean file_and_argv_zero ,
2012-11-10 19:16:29 +01:00
gboolean cloexec_pipes ,
2000-10-09 18:24:57 +02:00
GSpawnChildSetupFunc child_setup ,
gpointer user_data ,
2004-03-01 21:47:49 +01:00
GPid * child_pid ,
2000-10-09 18:24:57 +02:00
gint * standard_input ,
gint * standard_output ,
gint * standard_error ,
GError * * error )
{
2004-03-01 21:47:49 +01:00
GPid pid = - 1 ;
2000-10-09 18:24:57 +02:00
gint stdin_pipe [ 2 ] = { - 1 , - 1 } ;
gint stdout_pipe [ 2 ] = { - 1 , - 1 } ;
gint stderr_pipe [ 2 ] = { - 1 , - 1 } ;
gint child_err_report_pipe [ 2 ] = { - 1 , - 1 } ;
gint child_pid_report_pipe [ 2 ] = { - 1 , - 1 } ;
2012-11-10 19:16:29 +01:00
guint pipe_flags = cloexec_pipes ? FD_CLOEXEC : 0 ;
2000-10-09 18:24:57 +02:00
gint status ;
2012-11-10 19:16:29 +01:00
if ( ! g_unix_open_pipe ( child_err_report_pipe , pipe_flags , error ) )
2000-10-09 18:24:57 +02:00
return FALSE ;
2012-11-10 19:16:29 +01:00
if ( intermediate_child & & ! g_unix_open_pipe ( child_pid_report_pipe , pipe_flags , error ) )
2000-10-09 18:24:57 +02:00
goto cleanup_and_fail ;
2012-11-10 19:16:29 +01:00
if ( standard_input & & ! g_unix_open_pipe ( stdin_pipe , pipe_flags , error ) )
2000-10-09 18:24:57 +02:00
goto cleanup_and_fail ;
2012-11-10 19:16:29 +01:00
if ( standard_output & & ! g_unix_open_pipe ( stdout_pipe , pipe_flags , error ) )
2000-10-09 18:24:57 +02:00
goto cleanup_and_fail ;
2012-11-10 19:16:29 +01:00
if ( standard_error & & ! g_unix_open_pipe ( stderr_pipe , FD_CLOEXEC , error ) )
2000-10-09 18:24:57 +02:00
goto cleanup_and_fail ;
2005-12-02 22:37:25 +01:00
pid = fork ( ) ;
2000-10-09 18:24:57 +02:00
if ( pid < 0 )
2009-08-20 15:13:43 +02:00
{
int errsv = errno ;
2000-10-09 18:24:57 +02:00
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FORK ,
_ ( " Failed to fork (%s) " ) ,
2009-08-20 15:13:43 +02:00
g_strerror ( errsv ) ) ;
2000-10-09 18:24:57 +02:00
goto cleanup_and_fail ;
}
else if ( pid = = 0 )
{
/* Immediate child. This may or may not be the child that
* actually execs the new process .
*/
2011-06-10 16:48:07 +02:00
/* Reset some signal handlers that we may use */
signal ( SIGCHLD , SIG_DFL ) ;
signal ( SIGINT , SIG_DFL ) ;
signal ( SIGTERM , SIG_DFL ) ;
signal ( SIGHUP , SIG_DFL ) ;
2000-10-09 18:24:57 +02:00
/* Be sure we crash if the parent exits
* and we write to the err_report_pipe
*/
signal ( SIGPIPE , SIG_DFL ) ;
/* Close the parent's end of the pipes;
* not needed in the close_descriptors case ,
* though
*/
close_and_invalidate ( & child_err_report_pipe [ 0 ] ) ;
close_and_invalidate ( & child_pid_report_pipe [ 0 ] ) ;
close_and_invalidate ( & stdin_pipe [ 1 ] ) ;
close_and_invalidate ( & stdout_pipe [ 0 ] ) ;
close_and_invalidate ( & stderr_pipe [ 0 ] ) ;
if ( intermediate_child )
{
/* We need to fork an intermediate child that launches the
* final child . The purpose of the intermediate child
* is to exit , so we can waitpid ( ) it immediately .
* Then the grandchild will not become a zombie .
*/
2004-03-01 21:47:49 +01:00
GPid grandchild_pid ;
2000-10-09 18:24:57 +02:00
2005-12-02 22:37:25 +01:00
grandchild_pid = fork ( ) ;
2000-10-09 18:24:57 +02:00
if ( grandchild_pid < 0 )
{
/* report -1 as child PID */
2003-06-02 20:20:25 +02:00
write_all ( child_pid_report_pipe [ 1 ] , & grandchild_pid ,
sizeof ( grandchild_pid ) ) ;
2000-10-09 18:24:57 +02:00
write_err_and_exit ( child_err_report_pipe [ 1 ] ,
CHILD_FORK_FAILED ) ;
}
else if ( grandchild_pid = = 0 )
{
2013-07-01 22:10:28 +02:00
close_and_invalidate ( & child_pid_report_pipe [ 1 ] ) ;
2000-10-09 18:24:57 +02:00
do_exec ( child_err_report_pipe [ 1 ] ,
stdin_pipe [ 0 ] ,
stdout_pipe [ 1 ] ,
stderr_pipe [ 1 ] ,
working_directory ,
argv ,
envp ,
close_descriptors ,
search_path ,
2012-05-20 00:01:35 +02:00
search_path_from_envp ,
2000-10-09 18:24:57 +02:00
stdout_to_null ,
stderr_to_null ,
child_inherits_stdin ,
2001-06-08 21:41:51 +02:00
file_and_argv_zero ,
2000-10-09 18:24:57 +02:00
child_setup ,
user_data ) ;
}
else
{
2003-06-02 20:20:25 +02:00
write_all ( child_pid_report_pipe [ 1 ] , & grandchild_pid , sizeof ( grandchild_pid ) ) ;
2000-10-09 18:24:57 +02:00
close_and_invalidate ( & child_pid_report_pipe [ 1 ] ) ;
_exit ( 0 ) ;
}
}
else
{
/* Just run the child.
*/
do_exec ( child_err_report_pipe [ 1 ] ,
stdin_pipe [ 0 ] ,
stdout_pipe [ 1 ] ,
stderr_pipe [ 1 ] ,
working_directory ,
argv ,
envp ,
close_descriptors ,
search_path ,
2012-05-20 00:01:35 +02:00
search_path_from_envp ,
2000-10-09 18:24:57 +02:00
stdout_to_null ,
stderr_to_null ,
child_inherits_stdin ,
2001-06-08 21:41:51 +02:00
file_and_argv_zero ,
2000-10-09 18:24:57 +02:00
child_setup ,
user_data ) ;
}
}
else
{
/* Parent */
gint buf [ 2 ] ;
Changes for 64-bit cleanliness, loosely based on patch from Mark Murnane.
Wed Jun 20 12:00:54 2001 Owen Taylor <otaylor@redhat.com>
Changes for 64-bit cleanliness, loosely based on patch
from Mark Murnane.
* gconvert.c (g_convert/g_convert_with_fallback): Remove
workarounds for since-fixed GNU libc bugs. Minor
doc fix.
* gconvert.[ch]: Change gint to gsize/gssize as
appropriate.
* gconvert.c (g_locale/filename_to/from_utf8): Fix incorrect
computation of bytes_read / bytes_written.
* gfileutils.[ch] (g_file_get_contents): Make length
out parameter 'gsize *len'.
* ghook.c (g_hook_compare_ids): Don't compare a
and b as 'a - b'.
* gmacros.h (GSIZE_TO_POINTER): Add GPOINTER_TO_SIZE,
GSIZE_TO_POINTER.
* gmain.c (g_timeout_prepare): Rewrite to avoid
overflows. (Fixes bug when system clock skews
backwards more than 24 days.)
* gmarkup.[ch]: Make lengths passed to callbacks
gsize, length for g_markup_parse-context_parse(),
g_markup_escape_text() gssize.
* gmessages.[ch] (g_printf_string_upper_bound): Change
return value to gsize.
* gmessages.c (printf_string_upper_bound): Remove
a ridiculous use of 'inline' on a 300 line function.
* gstring.[ch]: Represent size of string as a gsize,
not gint. Make parameters to functions take gsize,
or gssize where -1 is allowed.
* gstring.c (g_string_erase): Make
g_string_erase (string, pos, -1) a synonym for
g_string_truncate for consistency with other G*
APIs.
* gstrfuncs.[ch]: Make all functions taking a string
length, take a gsize, or gssize if -1 is allowed.
(g_strstr_len, g_strrstr_len). Also fix some boundary
conditions in g_str[r]str[_len].
* gutf8.c tests/unicode-encoding.c: Make parameters that
are byte lengths gsize, gssize as appropriate. Make
character offsets, other counts, glong.
* gasyncqueue.c gcompletion.c
timeloop.c timeloop-basic.c gutils.c gspawn.c.
Small 64 bit cleanliness fixups.
* glist.c (g_list_sort2, g_list_sort_real): Fix functions
that should have been static.
* gdate.c (g_date_fill_parse_tokens): Fix extra
declaration that was shadowing another.
* tests/module-test.c: Include string.h
Mon Jun 18 15:43:29 2001 Owen Taylor <otaylor@redhat.com>
* gutf8.c (g_get_charset): Make argument
G_CONST_RETURN char **.
2001-06-23 15:55:09 +02:00
gint n_ints = 0 ;
2000-10-09 18:24:57 +02:00
/* Close the uncared-about ends of the pipes */
close_and_invalidate ( & child_err_report_pipe [ 1 ] ) ;
close_and_invalidate ( & child_pid_report_pipe [ 1 ] ) ;
close_and_invalidate ( & stdin_pipe [ 0 ] ) ;
close_and_invalidate ( & stdout_pipe [ 1 ] ) ;
close_and_invalidate ( & stderr_pipe [ 1 ] ) ;
/* If we had an intermediate child, reap it */
if ( intermediate_child )
{
wait_again :
if ( waitpid ( pid , & status , 0 ) < 0 )
{
if ( errno = = EINTR )
goto wait_again ;
else if ( errno = = ECHILD )
; /* do nothing, child already reaped */
else
2000-11-02 13:31:10 +01:00
g_warning ( " waitpid() should not fail in "
" 'fork_exec_with_pipes' " ) ;
2000-10-09 18:24:57 +02:00
}
}
if ( ! read_ints ( child_err_report_pipe [ 0 ] ,
buf , 2 , & n_ints ,
error ) )
goto cleanup_and_fail ;
if ( n_ints > = 2 )
{
/* Error from the child. */
switch ( buf [ 0 ] )
{
case CHILD_CHDIR_FAILED :
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_CHDIR ,
_ ( " Failed to change to directory '%s' (%s) " ) ,
working_directory ,
g_strerror ( buf [ 1 ] ) ) ;
break ;
case CHILD_EXEC_FAILED :
g_set_error ( error ,
G_SPAWN_ERROR ,
exec_err_to_g_error ( buf [ 1 ] ) ,
2001-12-14 17:26:24 +01:00
_ ( " Failed to execute child process \" %s \" (%s) " ) ,
argv [ 0 ] ,
2000-10-09 18:24:57 +02:00
g_strerror ( buf [ 1 ] ) ) ;
break ;
case CHILD_DUP2_FAILED :
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FAILED ,
_ ( " Failed to redirect output or input of child process (%s) " ) ,
g_strerror ( buf [ 1 ] ) ) ;
break ;
case CHILD_FORK_FAILED :
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FORK ,
_ ( " Failed to fork child process (%s) " ) ,
g_strerror ( buf [ 1 ] ) ) ;
break ;
default :
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FAILED ,
2001-12-14 17:26:24 +01:00
_ ( " Unknown error executing child process \" %s \" " ) ,
argv [ 0 ] ) ;
2000-10-09 18:24:57 +02:00
break ;
}
goto cleanup_and_fail ;
}
/* Get child pid from intermediate child pipe. */
if ( intermediate_child )
{
n_ints = 0 ;
if ( ! read_ints ( child_pid_report_pipe [ 0 ] ,
buf , 1 , & n_ints , error ) )
goto cleanup_and_fail ;
if ( n_ints < 1 )
{
2009-08-20 15:13:43 +02:00
int errsv = errno ;
2000-10-09 18:24:57 +02:00
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FAILED ,
_ ( " Failed to read enough data from child pid pipe (%s) " ) ,
2009-08-20 15:13:43 +02:00
g_strerror ( errsv ) ) ;
2000-10-09 18:24:57 +02:00
goto cleanup_and_fail ;
}
else
{
/* we have the child pid */
pid = buf [ 0 ] ;
}
}
/* Success against all odds! return the information */
2002-05-23 17:36:53 +02:00
close_and_invalidate ( & child_err_report_pipe [ 0 ] ) ;
close_and_invalidate ( & child_pid_report_pipe [ 0 ] ) ;
2000-10-09 18:24:57 +02:00
if ( child_pid )
* child_pid = pid ;
if ( standard_input )
* standard_input = stdin_pipe [ 1 ] ;
if ( standard_output )
* standard_output = stdout_pipe [ 0 ] ;
if ( standard_error )
* standard_error = stderr_pipe [ 0 ] ;
return TRUE ;
}
cleanup_and_fail :
2002-09-23 08:45:10 +02:00
/* There was an error from the Child, reap the child to avoid it being
a zombie .
*/
if ( pid > 0 )
{
wait_failed :
if ( waitpid ( pid , NULL , 0 ) < 0 )
{
if ( errno = = EINTR )
goto wait_failed ;
else if ( errno = = ECHILD )
; /* do nothing, child already reaped */
else
g_warning ( " waitpid() should not fail in "
" 'fork_exec_with_pipes' " ) ;
}
}
2000-10-09 18:24:57 +02:00
close_and_invalidate ( & child_err_report_pipe [ 0 ] ) ;
close_and_invalidate ( & child_err_report_pipe [ 1 ] ) ;
close_and_invalidate ( & child_pid_report_pipe [ 0 ] ) ;
close_and_invalidate ( & child_pid_report_pipe [ 1 ] ) ;
close_and_invalidate ( & stdin_pipe [ 0 ] ) ;
close_and_invalidate ( & stdin_pipe [ 1 ] ) ;
close_and_invalidate ( & stdout_pipe [ 0 ] ) ;
close_and_invalidate ( & stdout_pipe [ 1 ] ) ;
close_and_invalidate ( & stderr_pipe [ 0 ] ) ;
close_and_invalidate ( & stderr_pipe [ 1 ] ) ;
return FALSE ;
}
/* Based on execvp from GNU C Library */
static void
script_execute ( const gchar * file ,
gchar * * argv ,
2012-05-20 00:01:35 +02:00
gchar * * envp )
2000-10-09 18:24:57 +02:00
{
/* Count the arguments. */
int argc = 0 ;
while ( argv [ argc ] )
+ + argc ;
/* Construct an argument list for the shell. */
{
gchar * * new_argv ;
2001-12-29 21:11:07 +01:00
new_argv = g_new0 ( gchar * , argc + 2 ) ; /* /bin/sh and NULL */
2000-10-09 18:24:57 +02:00
new_argv [ 0 ] = ( char * ) " /bin/sh " ;
new_argv [ 1 ] = ( char * ) file ;
2001-12-29 21:11:07 +01:00
while ( argc > 0 )
2000-10-09 18:24:57 +02:00
{
2001-12-29 21:11:07 +01:00
new_argv [ argc + 1 ] = argv [ argc ] ;
2000-10-09 18:24:57 +02:00
- - argc ;
}
/* Execute the shell. */
if ( envp )
execve ( new_argv [ 0 ] , new_argv , envp ) ;
else
execv ( new_argv [ 0 ] , new_argv ) ;
g_free ( new_argv ) ;
}
}
static gchar *
my_strchrnul ( const gchar * str , gchar c )
{
gchar * p = ( gchar * ) str ;
while ( * p & & ( * p ! = c ) )
+ + p ;
return p ;
}
static gint
g_execute ( const gchar * file ,
gchar * * argv ,
gchar * * envp ,
2012-05-20 00:01:35 +02:00
gboolean search_path ,
gboolean search_path_from_envp )
2000-10-09 18:24:57 +02:00
{
if ( * file = = ' \0 ' )
{
/* We check the simple case first. */
errno = ENOENT ;
return - 1 ;
}
2012-05-20 00:01:35 +02:00
if ( ! ( search_path | | search_path_from_envp ) | | strchr ( file , ' / ' ) ! = NULL )
2000-10-09 18:24:57 +02:00
{
/* Don't search when it contains a slash. */
if ( envp )
execve ( file , argv , envp ) ;
else
execv ( file , argv ) ;
if ( errno = = ENOEXEC )
2012-05-20 00:01:35 +02:00
script_execute ( file , argv , envp ) ;
2000-10-09 18:24:57 +02:00
}
else
{
gboolean got_eacces = 0 ;
2001-02-18 00:30:48 +01:00
const gchar * path , * p ;
gchar * name , * freeme ;
2006-12-28 05:48:06 +01:00
gsize len ;
gsize pathlen ;
2000-10-09 18:24:57 +02:00
2012-05-20 00:01:35 +02:00
path = NULL ;
if ( search_path_from_envp )
path = g_environ_getenv ( envp , " PATH " ) ;
if ( search_path & & path = = NULL )
path = g_getenv ( " PATH " ) ;
2000-10-09 18:24:57 +02:00
if ( path = = NULL )
{
2013-05-20 22:54:48 +02:00
/* There is no 'PATH' in the environment. The default
2000-10-09 18:24:57 +02:00
* search path in libc is the current directory followed by
2013-05-20 22:54:48 +02:00
* the path ' confstr ' returns for ' _CS_PATH ' .
2000-10-09 18:24:57 +02:00
*/
/* In GLib we put . last, for security, and don't use the
* unportable confstr ( ) ; UNIX98 does not actually specify
* what to search if PATH is unset . POSIX may , dunno .
*/
path = " /bin:/usr/bin:. " ;
}
len = strlen ( file ) + 1 ;
pathlen = strlen ( path ) ;
freeme = name = g_malloc ( pathlen + len + 1 ) ;
/* Copy the file name at the top, including '\0' */
memcpy ( name + pathlen + 1 , file , len ) ;
name = name + pathlen ;
/* And add the slash before the filename */
* name = ' / ' ;
p = path ;
do
{
char * startp ;
path = p ;
p = my_strchrnul ( path , ' : ' ) ;
if ( p = = path )
/* Two adjacent colons, or a colon at the beginning or the end
2013-05-20 22:54:48 +02:00
* of ' PATH ' means to search the current directory .
2000-10-09 18:24:57 +02:00
*/
startp = name + 1 ;
else
startp = memcpy ( name - ( p - path ) , path , p - path ) ;
/* Try to execute this name. If it works, execv will not return. */
if ( envp )
execve ( startp , argv , envp ) ;
else
execv ( startp , argv ) ;
if ( errno = = ENOEXEC )
2012-05-20 00:01:35 +02:00
script_execute ( startp , argv , envp ) ;
2000-10-09 18:24:57 +02:00
switch ( errno )
{
case EACCES :
2013-05-20 22:54:48 +02:00
/* Record the we got a 'Permission denied' error. If we end
2000-10-09 18:24:57 +02:00
* up finding no executable we can use , we want to diagnose
* that we did find one but were denied access .
*/
got_eacces = TRUE ;
/* FALL THRU */
case ENOENT :
# ifdef ESTALE
case ESTALE :
# endif
# ifdef ENOTDIR
case ENOTDIR :
# endif
/* Those errors indicate the file is missing or not executable
* by us , in which case we want to just try the next path
* directory .
*/
break ;
2012-03-16 00:16:02 +01:00
case ENODEV :
case ETIMEDOUT :
/* Some strange filesystems like AFS return even
* stranger error numbers . They cannot reasonably mean anything
* else so ignore those , too .
*/
break ;
2000-10-09 18:24:57 +02:00
default :
/* Some other error means we found an executable file, but
* something went wrong executing it ; return the error to our
* caller .
*/
g_free ( freeme ) ;
return - 1 ;
}
}
while ( * p + + ! = ' \0 ' ) ;
/* We tried every element and none of them worked. */
if ( got_eacces )
/* At least one failure was due to permissions, so report that
* error .
*/
errno = EACCES ;
g_free ( freeme ) ;
}
/* Return the error from the last attempt (probably ENOENT). */
return - 1 ;
}
2004-03-01 21:47:49 +01:00
/**
* g_spawn_close_pid :
2008-06-11 08:57:22 +02:00
* @ pid : The process reference to close
2004-03-01 21:47:49 +01:00
*
2008-06-11 08:57:22 +02:00
* On some platforms , notably Windows , the # GPid type represents a resource
2004-03-01 21:47:49 +01:00
* which must be closed to prevent resource leaking . g_spawn_close_pid ( )
* is provided for this purpose . It should be used on all platforms , even
* though it doesn ' t do anything under UNIX .
* */
void
g_spawn_close_pid ( GPid pid )
{
}