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-02-18 00:28:43 +01:00
# include <config.h>
2000-10-09 18:24:57 +02:00
# include "glib.h"
# 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>
2000-11-02 12:38:10 +01:00
# ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
# endif /* HAVE_SYS_SELECT_H */
2001-01-16 03:24:24 +01:00
# include "glibintl.h"
2000-10-09 18:24:57 +02:00
static gint g_execute ( const gchar * file ,
gchar * * argv ,
gchar * * envp ,
gboolean search_path ) ;
static gboolean make_pipe ( gint p [ 2 ] ,
GError * * error ) ;
static gboolean fork_exec_with_pipes ( gboolean intermediate_child ,
const gchar * working_directory ,
gchar * * argv ,
gchar * * envp ,
gboolean close_descriptors ,
gboolean search_path ,
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 ,
gint * child_pid ,
gint * standard_input ,
gint * standard_output ,
gint * standard_error ,
GError * * error ) ;
GQuark
g_spawn_error_quark ( void )
{
static GQuark quark = 0 ;
if ( quark = = 0 )
quark = g_quark_from_static_string ( " g-exec-error-quark " ) ;
return quark ;
}
/**
* g_spawn_async :
2001-12-16 20:31:36 +01:00
* @ working_directory : child ' s current working directory , or % NULL to inherit parent ' s
2000-10-09 18:24:57 +02:00
* @ argv : child ' s argument vector
2001-12-16 20:31:36 +01:00
* @ envp : child ' s environment , or % NULL to inherit parent ' s
2000-10-09 18:24:57 +02:00
* @ flags : flags from # GSpawnFlags
2001-12-16 20:31:36 +01:00
* @ child_setup : function to run in the child just before < function > exec ( ) < / function >
2000-10-09 18:24:57 +02:00
* @ user_data : user data for @ child_setup
2001-12-16 20:31:36 +01:00
* @ child_pid : return location for child process ID , 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 .
*
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 ,
gint * child_pid ,
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 )
*/
static gint
close_and_invalidate ( gint * fd )
{
gint ret ;
2002-05-20 21:36:58 +02:00
if ( * fd < 0 )
return - 1 ;
else
{
ret = close ( * fd ) ;
* fd = - 1 ;
}
2000-10-09 18:24:57 +02:00
return ret ;
}
typedef enum
{
READ_FAILED = 0 , /* FALSE */
READ_OK ,
READ_EOF
} ReadResult ;
static ReadResult
read_data ( GString * str ,
gint fd ,
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
gssize bytes ;
gchar buf [ 4096 ] ;
2000-10-09 18:24:57 +02:00
again :
bytes = read ( fd , & buf , 4096 ) ;
if ( bytes = = 0 )
return READ_EOF ;
else if ( bytes > 0 )
{
g_string_append_len ( str , buf , bytes ) ;
return READ_OK ;
}
else if ( bytes < 0 & & errno = = EINTR )
goto again ;
else if ( bytes < 0 )
{
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_READ ,
_ ( " Failed to read data from child process (%s) " ) ,
g_strerror ( errno ) ) ;
return READ_FAILED ;
}
else
return READ_OK ;
}
/**
* g_spawn_sync :
2001-12-16 20:31:36 +01:00
* @ working_directory : child ' s current working directory , or % NULL to inherit parent ' s
2000-10-09 18:24:57 +02:00
* @ argv : child ' s argument vector
2001-12-16 20:31:36 +01:00
* @ envp : child ' s environment , or % NULL to inherit parent ' s
2000-10-09 18:24:57 +02:00
* @ flags : flags from # GSpawnFlags
2001-12-16 20:31:36 +01:00
* @ child_setup : function to run in the child just before < function > exec ( ) < / function >
2000-10-09 18:24:57 +02:00
* @ user_data : user data for @ child_setup
* @ standard_output : return location for child output
* @ standard_error : return location for child error messages
2001-12-16 20:31:36 +01:00
* @ exit_status : child exit status , as returned by < function > waitpid ( ) < / function >
2000-10-09 18:24:57 +02:00
* @ error : return location for error
*
* 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 ,
2001-12-16 20:31:36 +01:00
* if those parameters are non - % NULL . If @ exit_status is non - % NULL , the exit
* status of the child is stored there as it would be returned by
* < function > waitpid ( ) < / function > ; standard UNIX macros such as
* < function > WIFEXITED ( ) < / function > and < function > WEXITSTATUS ( ) < / function >
* must be used to evaluate the exit status . If an error occurs , no data is
* returned in @ standard_output , @ standard_error , or @ exit_status .
2000-10-09 18:24:57 +02:00
*
* This function calls g_spawn_async_with_pipes ( ) internally ; see that function
* for full details on the other parameters .
*
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_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 ;
gint pid ;
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 ,
( 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 ,
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 )
{
outstr = g_string_new ( " " ) ;
}
if ( errpipe > = 0 )
{
errstr = g_string_new ( " " ) ;
}
/* 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 */ ) ;
if ( ret < 0 & & errno ! = EINTR )
{
failed = TRUE ;
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_READ ,
_ ( " Unexpected error in select() reading data from a child process (%s) " ) ,
g_strerror ( errno ) ) ;
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 ) ;
/* Wait for child to exit, even if we have
* an error pending .
*/
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 SIGCHLD action was set to SIG_IGN and ECHILD was received by waitpid(), so exit status can't be returned. This is a bug in the program calling g_spawn_sync(); either don't request the exit status, or don't set the SIGCHLD action. " ) ;
}
else
{
/* We don't need the exit status. */
}
}
else
{
if ( ! failed ) /* avoid error pileups */
{
failed = TRUE ;
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_READ ,
_ ( " Unexpected error in waitpid() (%s) " ) ,
g_strerror ( errno ) ) ;
}
}
}
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 :
2001-12-16 20:31:36 +01:00
* @ working_directory : child ' s current working directory , or % NULL to inherit parent ' s
2000-10-09 18:24:57 +02:00
* @ argv : child ' s argument vector
2001-12-16 20:31:36 +01:00
* @ envp : child ' s environment , or % NULL to inherit parent ' s
2000-10-09 18:24:57 +02:00
* @ flags : flags from # GSpawnFlags
2001-12-16 20:31:36 +01:00
* @ child_setup : function to run in the child just before < function > exec ( ) < / function >
2000-10-09 18:24:57 +02:00
* @ user_data : user data for @ child_setup
2001-12-16 20:31:36 +01:00
* @ child_pid : return location for child process ID , or % NULL
* @ standard_input : return location for file descriptor to write to child ' s stdin , or % NULL
* @ standard_output : return location for file descriptor to read child ' s stdout , or % NULL
* @ standard_error : 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
2001-12-18 00:04:09 +01:00
* the program must be a full path ; the < envar > PATH < / envar > shell variable
2001-12-16 20:31:36 +01:00
* will only be searched if you pass the % G_SPAWN_SEARCH_PATH flag .
2000-10-09 18:24:57 +02:00
*
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
* function ' s behavior . The % G_SPAWN_DO_NOT_REAP_CHILD means that the
2001-12-16 20:31:36 +01:00
* child will not be automatically reaped ; you must call
* < function > waitpid ( ) < / function > or handle % SIGCHLD yourself , or the
* child will become a zombie .
2000-10-09 18:24:57 +02:00
* % G_SPAWN_LEAVE_DESCRIPTORS_OPEN means that the parent ' s open file
* descriptors will be inherited by the child ; otherwise all
* descriptors except stdin / stdout / stderr will be closed before
2001-12-16 20:31:36 +01:00
* calling < function > exec ( ) < / function > in the child . % G_SPAWN_SEARCH_PATH
* means that < literal > argv [ 0 ] < / literal > need not be an absolute path , it
2001-12-18 00:04:09 +01:00
* will be looked for in the user ' s < envar > PATH < / envar > .
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
* 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
*
* @ child_setup and @ user_data are a function and user data to be
* called in the child after GLib has performed all the setup it plans
* to perform ( including creating pipes , closing file descriptors ,
2001-12-16 20:31:36 +01:00
* etc . ) but before calling < function > exec ( ) < / function > . That is ,
* @ child_setup is called just before calling < function > exec ( ) < / function >
* in the child . Obviously actions taken in this function will only affect
* the child , not the parent .
2000-10-09 18:24:57 +02:00
*
2001-12-16 20:31:36 +01:00
* If non - % NULL , @ child_pid will be filled with the child ' s process
2000-10-09 18:24:57 +02:00
* ID . You can use the process ID to send signals to the child , or
2001-12-16 20:31:36 +01:00
* to < function > waitpid ( ) < / function > if you specified the
* % G_SPAWN_DO_NOT_REAP_CHILD flag .
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
2002-10-12 12:36:45 +02:00
* when they are no longer in use . If these parameters are % NULL , the corresponding
* pipe won ' t be created .
*
* If @ standard_input is NULL , the child ' s standard input is attached to / dev / null
* unless % G_SPAWN_CHILD_INHERITS_STDIN is set .
*
* 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 .
*
* 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 .
* If an error is set , the function returns % FALSE . Errors
2000-10-09 18:24:57 +02:00
* are reported even if they occur in the child ( for example if the
* executable in < literal > argv [ 0 ] < / literal > 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 .
*
* If an error occurs , @ child_pid , @ standard_input , @ standard_output ,
* and @ standard_error will not be filled with valid values .
*
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_async_with_pipes ( const gchar * working_directory ,
gchar * * argv ,
gchar * * envp ,
GSpawnFlags flags ,
GSpawnChildSetupFunc child_setup ,
gpointer user_data ,
gint * child_pid ,
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 ,
( 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 ,
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
* @ standard_output : return location for child output
* @ standard_error : return location for child errors
* @ exit_status : return location for child exit status
* @ 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 ( ) .
*
2002-04-19 22:26:04 +02:00
* On Windows , please note the implications of g_shell_parse_argv ( )
* parsing @ command_line . Space is a separator , and backslashes are
* special . Thus you cannot simply pass a @ command_line consisting of
* a canonical Windows path , 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 the path with single quotes , like
* " 'c: \\ program files \\ app \\ app.exe' " .
*
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 ;
gchar * * argv = 0 ;
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 ( ) .
*
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_command_line_async ( const gchar * command_line ,
GError * * error )
{
gboolean retval ;
gchar * * argv = 0 ;
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 ;
}
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 :
return G_SPAWN_ERROR_2BIG ;
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 ;
}
}
static void
write_err_and_exit ( gint fd , gint msg )
{
gint en = errno ;
write ( fd , & msg , sizeof ( msg ) ) ;
write ( fd , & en , sizeof ( en ) ) ;
_exit ( 1 ) ;
}
static void
set_cloexec ( gint fd )
{
fcntl ( fd , F_SETFD , FD_CLOEXEC ) ;
}
static gint
sane_dup2 ( gint fd1 , gint fd2 )
{
gint ret ;
retry :
ret = dup2 ( fd1 , fd2 ) ;
if ( ret < 0 & & errno = = EINTR )
goto retry ;
return ret ;
}
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 ,
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 )
{
gint open_max ;
gint i ;
open_max = sysconf ( _SC_OPEN_MAX ) ;
for ( i = 3 ; i < open_max ; i + + )
set_cloexec ( i ) ;
}
else
{
/* We need to do child_err_report_fd anyway */
set_cloexec ( child_err_report_fd ) ;
}
/* 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 ) ;
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 )
{
gint write_null = open ( " /dev/null " , O_WRONLY ) ;
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 )
{
gint write_null = open ( " /dev/null " , O_WRONLY ) ;
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 ,
envp , search_path ) ;
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 )
{
/* Some weird shit happened, bail out */
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FAILED ,
_ ( " Failed to read from child pipe (%s) " ) ,
g_strerror ( errno ) ) ;
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 ,
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 ,
gint * child_pid ,
gint * standard_input ,
gint * standard_output ,
gint * standard_error ,
GError * * error )
{
2002-09-23 08:45:10 +02:00
gint 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 } ;
gint status ;
if ( ! make_pipe ( child_err_report_pipe , error ) )
return FALSE ;
if ( intermediate_child & & ! make_pipe ( child_pid_report_pipe , error ) )
goto cleanup_and_fail ;
if ( standard_input & & ! make_pipe ( stdin_pipe , error ) )
goto cleanup_and_fail ;
if ( standard_output & & ! make_pipe ( stdout_pipe , error ) )
goto cleanup_and_fail ;
if ( standard_error & & ! make_pipe ( stderr_pipe , error ) )
goto cleanup_and_fail ;
pid = fork ( ) ;
if ( pid < 0 )
{
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FORK ,
_ ( " Failed to fork (%s) " ) ,
g_strerror ( errno ) ) ;
goto cleanup_and_fail ;
}
else if ( pid = = 0 )
{
/* Immediate child. This may or may not be the child that
* actually execs the new process .
*/
/* 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 .
*/
gint grandchild_pid ;
grandchild_pid = fork ( ) ;
if ( grandchild_pid < 0 )
{
/* report -1 as child PID */
write ( child_pid_report_pipe [ 1 ] , & grandchild_pid ,
sizeof ( grandchild_pid ) ) ;
write_err_and_exit ( child_err_report_pipe [ 1 ] ,
CHILD_FORK_FAILED ) ;
}
else if ( grandchild_pid = = 0 )
{
do_exec ( child_err_report_pipe [ 1 ] ,
stdin_pipe [ 0 ] ,
stdout_pipe [ 1 ] ,
stderr_pipe [ 1 ] ,
working_directory ,
argv ,
envp ,
close_descriptors ,
search_path ,
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
{
write ( child_pid_report_pipe [ 1 ] , & grandchild_pid , sizeof ( grandchild_pid ) ) ;
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 ,
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 )
{
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FAILED ,
_ ( " Failed to read enough data from child pid pipe (%s) " ) ,
g_strerror ( errno ) ) ;
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 ;
}
static gboolean
make_pipe ( gint p [ 2 ] ,
GError * * error )
{
if ( pipe ( p ) < 0 )
{
g_set_error ( error ,
G_SPAWN_ERROR ,
G_SPAWN_ERROR_FAILED ,
_ ( " Failed to create pipe for communicating with child process (%s) " ) ,
g_strerror ( errno ) ) ;
return FALSE ;
}
else
return TRUE ;
}
/* Based on execvp from GNU C Library */
static void
script_execute ( const gchar * file ,
gchar * * argv ,
gchar * * envp ,
gboolean search_path )
{
/* 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 ,
gboolean search_path )
{
if ( * file = = ' \0 ' )
{
/* We check the simple case first. */
errno = ENOENT ;
return - 1 ;
}
if ( ! search_path | | strchr ( file , ' / ' ) ! = NULL )
{
/* Don't search when it contains a slash. */
if ( envp )
execve ( file , argv , envp ) ;
else
execv ( file , argv ) ;
if ( errno = = ENOEXEC )
script_execute ( file , argv , envp , FALSE ) ;
}
else
{
gboolean got_eacces = 0 ;
2001-02-18 00:30:48 +01:00
const gchar * path , * p ;
gchar * name , * freeme ;
2000-10-09 18:24:57 +02:00
size_t len ;
size_t pathlen ;
path = g_getenv ( " PATH " ) ;
if ( path = = NULL )
{
/* There is no `PATH' in the environment. The default
* search path in libc is the current directory followed by
* the path ` confstr ' returns for ` _CS_PATH ' .
*/
/* 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
* of ` PATH ' means to search the current directory .
*/
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 )
script_execute ( startp , argv , envp , search_path ) ;
switch ( errno )
{
case EACCES :
/* Record the we got a `Permission denied' error. If we end
* 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 ;
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 ;
}