2005-09-20 13:26:39 +00:00
/** \file exec.c
Functions for executing a program .
Some of the code in this file is based on code from the Glibc
manual , though I the changes performed have been massive .
*/
2006-08-11 01:18:35 +00:00
# include "config.h"
2005-09-20 13:26:39 +00:00
# include <stdlib.h>
# include <stdio.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <termios.h>
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
# include <wchar.h>
# include <string.h>
# include <limits.h>
# include <signal.h>
# include <sys/wait.h>
# include <assert.h>
# include <dirent.h>
2006-11-15 13:30:46 +00:00
# include <time.h>
2005-09-20 13:26:39 +00:00
2006-07-30 20:26:59 +00:00
# ifdef HAVE_SIGINFO_H
# include <siginfo.h>
# endif
2006-02-28 13:17:16 +00:00
# include "fallback.h"
2005-09-20 13:26:39 +00:00
# include "util.h"
2006-02-28 13:17:16 +00:00
2005-09-20 13:26:39 +00:00
# include "common.h"
# include "wutil.h"
# include "proc.h"
# include "exec.h"
# include "parser.h"
# include "builtin.h"
# include "function.h"
# include "env.h"
# include "wildcard.h"
# include "sanity.h"
# include "expand.h"
2005-10-08 11:20:51 +00:00
# include "signal.h"
2006-07-19 22:55:49 +00:00
2006-02-06 15:18:17 +00:00
# include "halloc.h"
2006-02-09 15:50:20 +00:00
# include "halloc_util.h"
2006-02-14 19:56:36 +00:00
# include "parse_util.h"
2005-09-20 13:26:39 +00:00
/**
file descriptor redirection error message
*/
2006-01-04 12:51:02 +00:00
# define FD_ERROR _( L"An error occurred while redirecting file descriptor %d" )
2007-10-26 18:42:32 +00:00
2005-09-20 13:26:39 +00:00
/**
file redirection error message
*/
2006-01-04 12:51:02 +00:00
# define FILE_ERROR _( L"An error occurred while redirecting file '%ls'" )
2007-10-26 18:42:32 +00:00
/**
file redirection clobbering error message
*/
# define NOCLOB_ERROR _( L"The file '%ls' already exists" )
2005-09-20 13:26:39 +00:00
/**
fork error message
*/
2006-01-04 12:51:02 +00:00
# define FORK_ERROR _( L"Could not create child process - exiting" )
2005-09-20 13:26:39 +00:00
2006-11-15 13:30:46 +00:00
/**
The number of times to try to call fork ( ) before giving up
*/
# define FORK_LAPS 5
2007-01-21 15:20:26 +00:00
/**
The number of nanoseconds to sleep between attempts to call fork ( )
*/
# define FORK_SLEEP_TIME 1000000
2006-10-26 15:19:46 +00:00
/**
Base open mode to pass to calls to open
*/
2006-11-15 13:30:46 +00:00
# define OPEN_MASK 0666
2005-10-17 13:24:12 +00:00
2005-10-03 13:09:37 +00:00
/**
List of all pipes used by internal pipes . These must be closed in
many situations in order to make sure that stray fds aren ' t lying
around .
*/
2005-10-17 13:24:12 +00:00
static array_list_t * open_fds = 0 ;
2006-02-04 11:33:20 +00:00
static int set_child_group ( job_t * j , process_t * p , int print_errors ) ;
2006-02-03 21:50:31 +00:00
2005-10-08 11:20:51 +00:00
void exec_close ( int fd )
2005-09-23 13:10:31 +00:00
{
2005-10-03 13:09:37 +00:00
int i ;
2006-11-15 13:30:46 +00:00
if ( fd < 0 )
{
debug ( 0 , L " Called close on invalid file descriptor " ) ;
return ;
}
2005-10-03 13:09:37 +00:00
2005-09-23 13:10:31 +00:00
while ( close ( fd ) = = - 1 )
{
if ( errno ! = EINTR )
{
debug ( 1 , FD_ERROR , fd ) ;
wperror ( L " close " ) ;
2006-06-21 09:54:30 +00:00
break ;
2005-09-23 13:10:31 +00:00
}
}
2006-06-21 09:54:30 +00:00
2005-10-03 13:09:37 +00:00
if ( open_fds )
{
for ( i = 0 ; i < al_get_count ( open_fds ) ; i + + )
{
2006-07-31 16:35:48 +00:00
int n = ( int ) al_get_long ( open_fds , i ) ;
2005-10-03 13:09:37 +00:00
if ( n = = fd )
{
2006-07-31 16:35:48 +00:00
al_set_long ( open_fds ,
2007-10-26 18:42:32 +00:00
i ,
al_get_long ( open_fds , al_get_count ( open_fds ) - 1 ) ) ;
2005-10-03 13:09:37 +00:00
al_truncate ( open_fds ,
2007-10-26 18:42:32 +00:00
al_get_count ( open_fds ) - 1 ) ;
2005-10-03 13:09:37 +00:00
break ;
}
}
}
}
2005-10-08 11:20:51 +00:00
int exec_pipe ( int fd [ 2 ] )
2005-10-03 13:09:37 +00:00
{
2005-10-08 11:20:51 +00:00
int res ;
2005-11-02 15:41:59 +00:00
2005-10-08 11:20:51 +00:00
while ( ( res = pipe ( fd ) ) )
{
if ( errno ! = EINTR )
{
wperror ( L " pipe " ) ;
return res ;
}
2005-11-02 15:41:59 +00:00
}
debug ( 4 , L " Created pipe using fds %d and %d " , fd [ 0 ] , fd [ 1 ] ) ;
2005-10-08 11:20:51 +00:00
2005-10-03 13:09:37 +00:00
if ( open_fds = = 0 )
{
2006-05-18 13:00:39 +00:00
open_fds = al_halloc ( global_context ) ;
2005-10-03 13:09:37 +00:00
}
2006-07-31 16:35:48 +00:00
al_push_long ( open_fds , ( long ) fd [ 0 ] ) ;
al_push_long ( open_fds , ( long ) fd [ 1 ] ) ;
2005-11-02 15:41:59 +00:00
2005-10-03 13:09:37 +00:00
return res ;
}
/**
Check if the specified fd is used as a part of a pipeline in the
specidied set of IO redirections .
\ param fd the fd to search for
\ param io the set of io redirections to search in
*/
static int use_fd_in_pipe ( int fd , io_data_t * io )
{
if ( ! io )
return 0 ;
2005-10-07 14:08:57 +00:00
if ( ( io - > io_mode = = IO_BUFFER ) | |
( io - > io_mode = = IO_PIPE ) )
2005-10-03 13:09:37 +00:00
{
2005-10-11 19:31:16 +00:00
if ( io - > param1 . pipe_fd [ 0 ] = = fd | |
io - > param1 . pipe_fd [ 1 ] = = fd )
2005-10-03 13:09:37 +00:00
return 1 ;
}
2005-10-07 14:08:57 +00:00
2005-10-03 13:09:37 +00:00
return use_fd_in_pipe ( fd , io - > next ) ;
}
/**
Close all fds in open_fds , except for those that are mentioned in
2005-10-21 11:59:45 +00:00
the redirection list io . This should make sure that there are no
stray opened file descriptors in the child .
2006-05-18 13:00:39 +00:00
\ param io the list of io redirections for this job . Pipes mentioned
here should not be closed .
2005-10-03 13:09:37 +00:00
*/
static void close_unused_internal_pipes ( io_data_t * io )
{
int i = 0 ;
if ( open_fds )
{
for ( ; i < al_get_count ( open_fds ) ; i + + )
{
2006-07-31 16:35:48 +00:00
int n = ( long ) al_get_long ( open_fds , i ) ;
2005-10-03 13:09:37 +00:00
if ( ! use_fd_in_pipe ( n , io ) )
{
2005-10-03 13:58:48 +00:00
debug ( 4 , L " Close fd %d, used in other context " , n ) ;
2005-10-08 11:20:51 +00:00
exec_close ( n ) ;
2005-10-03 13:09:37 +00:00
i - - ;
}
}
}
}
2005-09-20 13:26:39 +00:00
/**
Make sure the fd used by this redirection is not used by i . e . a pipe .
*/
void free_fd ( io_data_t * io , int fd )
{
if ( ! io )
return ;
2007-01-07 14:06:46 +00:00
if ( ( io - > io_mode = = IO_PIPE ) | | ( io - > io_mode = = IO_BUFFER ) )
2005-09-20 13:26:39 +00:00
{
int i ;
for ( i = 0 ; i < 2 ; i + + )
{
2005-10-11 19:31:16 +00:00
if ( io - > param1 . pipe_fd [ i ] = = fd )
2005-09-20 13:26:39 +00:00
{
while ( 1 )
{
2005-10-11 19:31:16 +00:00
if ( ( io - > param1 . pipe_fd [ i ] = dup ( fd ) ) = = - 1 )
2005-09-20 13:26:39 +00:00
{
2007-01-07 14:06:46 +00:00
if ( errno ! = EINTR )
2005-09-20 13:26:39 +00:00
{
debug ( 1 ,
FD_ERROR ,
fd ) ;
wperror ( L " dup " ) ;
2007-01-21 15:03:41 +00:00
FATAL_EXIT ( ) ;
2005-09-20 13:26:39 +00:00
}
}
else
2007-01-07 14:06:46 +00:00
{
2005-09-20 13:26:39 +00:00
break ;
2007-01-07 14:06:46 +00:00
}
2005-09-20 13:26:39 +00:00
}
}
}
}
2007-01-07 14:06:46 +00:00
free_fd ( io - > next , fd ) ;
2005-09-20 13:26:39 +00:00
}
2005-10-21 11:59:45 +00:00
/**
Set up a childs io redirections . Should only be called by
setup_child_process ( ) . Does the following : First it closes any open
file descriptors not related to the child by calling
close_unused_internal_pipes ( ) and closing the universal variable
server file descriptor . It then goes on to perform all the
redirections described by \ c io .
\ param io the list of IO redirections for the child
2006-01-15 22:41:48 +00:00
2006-02-03 21:50:31 +00:00
\ return 0 on sucess , - 1 on failiure
2005-10-21 11:59:45 +00:00
*/
2007-01-21 15:19:43 +00:00
static int handle_child_io ( io_data_t * io )
2005-09-20 13:26:39 +00:00
{
2005-10-03 13:09:37 +00:00
close_unused_internal_pipes ( io ) ;
2005-09-20 13:26:39 +00:00
for ( ; io ; io = io - > next )
{
int tmp ;
2005-10-11 19:31:16 +00:00
if ( io - > io_mode = = IO_FD & & io - > fd = = io - > param1 . old_fd )
2005-09-20 13:26:39 +00:00
{
continue ;
}
if ( io - > fd > 2 )
{
/*
2006-02-20 01:40:36 +00:00
Make sure the fd used by this redirection is not used by e . g . a pipe .
2005-09-20 13:26:39 +00:00
*/
free_fd ( io , io - > fd ) ;
}
switch ( io - > io_mode )
{
case IO_CLOSE :
2007-01-21 15:01:14 +00:00
{
2006-06-21 09:54:30 +00:00
if ( close ( io - > fd ) )
{
debug ( 0 , _ ( L " Failed to close file descriptor %d " ) , io - > fd ) ;
wperror ( L " close " ) ;
}
2005-09-20 13:26:39 +00:00
break ;
2007-01-21 15:01:14 +00:00
}
2005-09-20 13:26:39 +00:00
case IO_FILE :
2005-11-29 10:12:06 +00:00
{
2005-10-11 19:31:16 +00:00
if ( ( tmp = wopen ( io - > param1 . filename ,
2007-10-26 18:42:32 +00:00
io - > param2 . flags , OPEN_MASK ) ) = = - 1 )
2005-09-20 13:26:39 +00:00
{
2007-10-26 18:42:32 +00:00
if ( ( io - > param2 . flags & O_EXCL ) & &
( errno = = EEXIST ) )
{
debug ( 1 ,
NOCLOB_ERROR ,
io - > param1 . filename ) ;
}
else
{
debug ( 1 ,
FILE_ERROR ,
io - > param1 . filename ) ;
wperror ( L " open " ) ;
}
2005-09-20 13:26:39 +00:00
2007-01-21 15:19:43 +00:00
return - 1 ;
}
2005-09-20 13:26:39 +00:00
else if ( tmp ! = io - > fd )
{
2006-06-21 09:54:30 +00:00
/*
This call will sometimes fail , but that is ok ,
this is just a precausion .
*/
2005-11-29 10:12:06 +00:00
close ( io - > fd ) ;
2006-06-21 09:54:30 +00:00
2005-09-20 13:26:39 +00:00
if ( dup2 ( tmp , io - > fd ) = = - 1 )
{
debug ( 1 ,
FD_ERROR ,
io - > fd ) ;
wperror ( L " dup2 " ) ;
2007-01-21 15:19:43 +00:00
return - 1 ;
2005-09-20 13:26:39 +00:00
}
2005-10-08 11:20:51 +00:00
exec_close ( tmp ) ;
2005-09-20 13:26:39 +00:00
}
break ;
2005-11-29 10:12:06 +00:00
}
2005-09-20 13:26:39 +00:00
case IO_FD :
2005-11-29 10:12:06 +00:00
{
2006-06-21 09:54:30 +00:00
/*
This call will sometimes fail , but that is ok ,
this is just a precausion .
*/
2005-11-29 10:12:06 +00:00
close ( io - > fd ) ;
2006-01-15 22:41:48 +00:00
2005-10-11 19:31:16 +00:00
if ( dup2 ( io - > param1 . old_fd , io - > fd ) = = - 1 )
2005-09-20 13:26:39 +00:00
{
debug ( 1 ,
FD_ERROR ,
io - > fd ) ;
wperror ( L " dup2 " ) ;
2007-01-21 15:19:43 +00:00
return - 1 ;
2005-09-20 13:26:39 +00:00
}
break ;
2005-11-29 10:12:06 +00:00
}
2005-09-20 13:26:39 +00:00
case IO_BUFFER :
case IO_PIPE :
{
2007-01-07 14:10:52 +00:00
int write_pipe ;
2005-09-20 13:26:39 +00:00
2007-01-07 14:10:52 +00:00
write_pipe = ! io - > is_input ;
/*
debug ( 0 ,
L " %ls %ls on fd %d (%d %d) " ,
write_pipe ? L " write " : L " read " ,
( io - > io_mode = = IO_BUFFER ) ? L " buffer " : L " pipe " ,
io - > fd ,
io - > param1 . pipe_fd [ 0 ] ,
io - > param1 . pipe_fd [ 1 ] ) ;
*/
if ( dup2 ( io - > param1 . pipe_fd [ write_pipe ] , io - > fd ) ! = io - > fd )
2005-09-20 13:26:39 +00:00
{
debug ( 1 , PIPE_ERROR ) ;
wperror ( L " dup2 " ) ;
2007-01-21 15:19:43 +00:00
return - 1 ;
2005-09-20 13:26:39 +00:00
}
2007-01-07 14:10:52 +00:00
if ( write_pipe )
2005-09-20 13:26:39 +00:00
{
2005-10-11 19:31:16 +00:00
exec_close ( io - > param1 . pipe_fd [ 0 ] ) ;
exec_close ( io - > param1 . pipe_fd [ 1 ] ) ;
2005-09-20 13:26:39 +00:00
}
else
2006-01-15 22:41:48 +00:00
{
2005-10-11 19:31:16 +00:00
exec_close ( io - > param1 . pipe_fd [ 0 ] ) ;
2006-01-15 22:41:48 +00:00
}
2005-09-20 13:26:39 +00:00
break ;
}
}
}
2006-01-15 22:41:48 +00:00
2006-02-03 21:50:31 +00:00
return 0 ;
2006-01-15 22:41:48 +00:00
2005-09-20 13:26:39 +00:00
}
2005-10-09 11:48:16 +00:00
/**
Initialize a new child process . This should be called right away
2006-11-15 13:30:46 +00:00
after forking in the child process . If job control is enabled for
this job , the process is put in the process group of the job , all
signal handlers are reset , signals are unblocked ( this function may
only be called inside the exec function , which blocks all signals ) ,
and all IO redirections and other file descriptor actions are
performed .
2006-01-15 22:41:48 +00:00
\ param j the job to set up the IO for
2006-01-23 20:40:14 +00:00
\ param p the child process to set up
2006-01-15 22:41:48 +00:00
2006-11-15 13:30:46 +00:00
\ return 0 on sucess , - 1 on failiure . When this function returns ,
signals are always unblocked . On failiure , signal handlers , io
redirections and process group of the process is undefined .
2005-10-09 11:48:16 +00:00
*/
2006-01-16 00:15:56 +00:00
static int setup_child_process ( job_t * j , process_t * p )
2005-09-20 13:26:39 +00:00
{
2006-02-03 21:50:31 +00:00
int res = 0 ;
2006-02-03 17:27:36 +00:00
2006-02-03 21:50:31 +00:00
if ( p )
{
2006-02-04 11:33:20 +00:00
res = set_child_group ( j , p , 1 ) ;
2006-02-01 12:27:15 +00:00
}
2006-02-03 21:50:31 +00:00
if ( ! res )
2006-02-01 12:27:15 +00:00
{
2007-01-21 15:19:43 +00:00
res = handle_child_io ( j - > io ) ;
if ( p ! = 0 & & res )
{
exit ( 1 ) ;
}
2005-09-20 13:26:39 +00:00
}
2006-01-15 22:41:48 +00:00
/* Set the handling for job control signals back to the default. */
2006-02-03 21:50:31 +00:00
if ( ! res )
2006-01-15 22:41:48 +00:00
{
signal_reset_handlers ( ) ;
}
2005-10-14 11:40:33 +00:00
/* Remove all signal blocks */
signal_unblock ( ) ;
2006-01-15 22:41:48 +00:00
return res ;
2005-09-20 13:26:39 +00:00
}
2008-01-16 01:04:54 +00:00
/**
Returns the interpreter for the specified script . Returns 0 if file
is not a script with a shebang . This function leaks memory on every
call . Only use it in the execve error handler which calls exit
right afterwards , anyway .
*/
static wchar_t * get_interpreter ( wchar_t * file )
{
string_buffer_t sb ;
FILE * fp = wfopen ( file , " r " ) ;
sb_init ( & sb ) ;
wchar_t * res = 0 ;
if ( fp )
{
while ( 1 )
{
wint_t ch = getwc ( fp ) ;
if ( ch = = WEOF )
break ;
if ( ch = = L ' \n ' )
break ;
sb_append_char ( & sb , ( wchar_t ) ch ) ;
}
}
res = ( wchar_t * ) sb . buff ;
if ( ! wcsncmp ( L " #! / " , res , 4 ) )
return res + 3 ;
if ( ! wcsncmp ( L " #!/ " , res , 3 ) )
return res + 2 ;
return 0 ;
}
2005-09-20 13:26:39 +00:00
/**
This function is executed by the child process created by a call to
2005-10-09 11:48:16 +00:00
fork ( ) . It should be called after \ c setup_child_process . It calls
execve to replace the fish process image with the command specified
in \ c p . It never returns .
2005-09-20 13:26:39 +00:00
*/
static void launch_process ( process_t * p )
{
2006-12-11 19:03:08 +00:00
FILE * f ;
2007-01-07 14:09:18 +00:00
int err ;
2006-12-11 19:03:08 +00:00
// debug( 1, L"exec '%ls'", p->argv[0] );
2006-12-08 22:04:28 +00:00
2007-10-15 09:36:15 +00:00
char * * argv = wcsv2strv ( ( const wchar_t * * ) p - > argv ) ;
char * * envv = env_export_arr ( 0 ) ;
2006-12-11 19:03:08 +00:00
execve ( wcs2str ( p - > actual_cmd ) ,
2007-10-15 09:36:15 +00:00
argv ,
envv ) ;
err = errno ;
2007-01-07 14:09:18 +00:00
2006-12-11 19:03:08 +00:00
/*
2007-10-15 09:36:15 +00:00
Something went wrong with execve , check for a " : " , and run
/ bin / sh if encountered . This is a weird predecessor to the shebang
that is still sometimes used since it is supported on Windows .
2006-12-11 19:03:08 +00:00
*/
f = wfopen ( p - > actual_cmd , " r " ) ;
2007-10-15 09:36:15 +00:00
if ( f )
{
char begin [ 1 ] = { 0 } ;
2006-12-11 19:03:08 +00:00
size_t read ;
2007-10-15 09:36:15 +00:00
2006-12-11 19:03:08 +00:00
read = fread ( begin , 1 , 1 , f ) ;
fclose ( f ) ;
2007-10-15 09:36:15 +00:00
if ( ( read = = 1 ) & & ( begin [ 0 ] = = ' : ' ) )
{
int count = 0 ;
int i = 1 ;
2007-01-07 14:09:18 +00:00
wchar_t * * res ;
2008-01-04 01:56:31 +00:00
char * * res_real ;
2007-10-15 09:36:15 +00:00
while ( p - > argv [ count ] ! = 0 )
2006-12-11 19:03:08 +00:00
count + + ;
2007-10-15 09:36:15 +00:00
2006-12-11 19:03:08 +00:00
res = malloc ( sizeof ( wchar_t * ) * ( count + 2 ) ) ;
2007-10-15 09:36:15 +00:00
2006-12-11 19:03:08 +00:00
res [ 0 ] = L " /bin/sh " ;
2007-10-15 09:36:15 +00:00
res [ 1 ] = p - > actual_cmd ;
2006-12-11 19:03:08 +00:00
for ( i = 1 ; p - > argv [ i ] ; i + + ) {
2007-10-15 09:36:15 +00:00
res [ i + 1 ] = p - > argv [ i ] ;
}
res [ i + 1 ] = 0 ;
p - > argv = res ;
p - > actual_cmd = L " /bin/sh " ;
2008-01-04 01:56:31 +00:00
2008-01-16 01:04:54 +00:00
res_real = wcsv2strv ( ( const wchar_t * * ) res ) ;
2006-12-11 19:03:08 +00:00
execve ( wcs2str ( p - > actual_cmd ) ,
2008-01-04 01:56:31 +00:00
res_real ,
2007-10-15 09:36:15 +00:00
envv ) ;
}
}
errno = err ;
2005-09-20 13:26:39 +00:00
debug ( 0 ,
2007-10-15 09:36:15 +00:00
_ ( L " Failed to execute process '%ls'. Reason: " ) ,
p - > actual_cmd ) ;
switch ( errno )
{
case E2BIG :
{
size_t sz = 0 ;
char * * p ;
2007-10-15 09:51:08 +00:00
string_buffer_t sz1 ;
string_buffer_t sz2 ;
2007-10-15 09:36:15 +00:00
2007-10-15 11:39:36 +00:00
long arg_max = - 1 ;
2007-10-15 09:51:08 +00:00
sb_init ( & sz1 ) ;
sb_init ( & sz2 ) ;
2007-10-15 09:36:15 +00:00
for ( p = argv ; * p ; p + + )
{
sz + = strlen ( * p ) + 1 ;
}
for ( p = envv ; * p ; p + + )
{
sz + = strlen ( * p ) + 1 ;
}
2007-10-15 09:51:08 +00:00
sb_format_size ( & sz1 , sz ) ;
2007-10-15 11:39:36 +00:00
arg_max = sysconf ( _SC_ARG_MAX ) ;
2007-10-15 09:51:08 +00:00
2007-10-15 11:39:36 +00:00
if ( arg_max > 0 )
{
2009-02-01 13:23:29 +00:00
sb_format_size ( & sz2 , arg_max ) ;
2007-10-15 11:39:36 +00:00
debug ( 0 ,
2008-01-16 01:04:54 +00:00
L " The total size of the argument and environment lists (%ls) exceeds the operating system limit of %ls. " ,
2007-10-15 11:39:36 +00:00
( wchar_t * ) sz1 . buff ,
( wchar_t * ) sz2 . buff ) ;
}
else
{
debug ( 0 ,
2008-01-16 01:04:54 +00:00
L " The total size of the argument and environment lists (%ls) exceeds the operating system limit. " ,
2007-10-15 11:39:36 +00:00
( wchar_t * ) sz1 . buff ) ;
}
2007-10-15 09:51:08 +00:00
2007-10-15 09:36:15 +00:00
debug ( 0 ,
2008-01-16 01:04:54 +00:00
L " Try running the command again with fewer arguments. " ) ;
2007-10-15 09:51:08 +00:00
sb_destroy ( & sz1 ) ;
sb_destroy ( & sz2 ) ;
2008-01-08 19:31:45 +00:00
exit ( STATUS_EXEC_FAIL ) ;
2007-10-15 09:36:15 +00:00
break ;
}
2007-01-07 14:09:18 +00:00
2008-01-16 01:04:54 +00:00
case ENOEXEC :
{
wperror ( L " exec " ) ;
debug ( 0 , L " The file '%ls' is marked as an executable but could not be run by the operating system. " , p - > actual_cmd ) ;
exit ( STATUS_EXEC_FAIL ) ;
}
case ENOENT :
{
wchar_t * interpreter = get_interpreter ( p - > actual_cmd ) ;
if ( interpreter & & waccess ( interpreter , X_OK ) )
{
debug ( 0 , L " The file '%ls' specified the interpreter '%ls', which is not an executable command. " , p - > actual_cmd , interpreter ) ;
}
else
{
debug ( 0 , L " The file '%ls' or a script or ELF interpreter does not exist, or a shared library needed for file or interpreter cannot be found. " , p - > actual_cmd ) ;
}
exit ( STATUS_EXEC_FAIL ) ;
}
case ENOMEM :
{
debug ( 0 , L " Out of memory " ) ;
exit ( STATUS_EXEC_FAIL ) ;
}
2007-10-15 09:36:15 +00:00
default :
{
2008-01-16 01:04:54 +00:00
wperror ( L " exec " ) ;
// debug(0, L"The file '%ls' is marked as an executable but could not be run by the operating system.", p->actual_cmd);
exit ( STATUS_EXEC_FAIL ) ;
2007-10-15 09:36:15 +00:00
}
}
2007-01-07 14:09:18 +00:00
2005-09-20 13:26:39 +00:00
}
/**
2005-10-03 13:09:37 +00:00
Check if the IO redirection chains contains redirections for the
specified file descriptor
2005-09-20 13:26:39 +00:00
*/
static int has_fd ( io_data_t * d , int fd )
{
return io_get ( d , fd ) ! = 0 ;
}
2006-01-11 14:40:20 +00:00
/**
Free a transmogrified io chain . Only the chain itself and resources
used by a transmogrified IO_FILE redirection are freed , since the
original chain may still be needed .
*/
static void io_untransmogrify ( io_data_t * in , io_data_t * out )
{
if ( ! out )
return ;
io_untransmogrify ( in - > next , out - > next ) ;
switch ( in - > io_mode )
{
case IO_FILE :
exec_close ( out - > param1 . old_fd ) ;
break ;
}
free ( out ) ;
}
2005-09-20 13:26:39 +00:00
/**
2005-10-09 11:48:16 +00:00
Make a copy of the specified io redirection chain , but change file
redirection into fd redirection . This makes the redirection chain
suitable for use as block - level io , since the file won ' t be
2006-11-15 13:30:46 +00:00
repeatedly reopened for every command in the block , which would
reset the cursor position .
2006-01-11 14:40:20 +00:00
\ return the transmogrified chain on sucess , or 0 on failiure
2005-09-20 13:26:39 +00:00
*/
static io_data_t * io_transmogrify ( io_data_t * in )
{
io_data_t * out ;
if ( ! in )
return 0 ;
out = malloc ( sizeof ( io_data_t ) ) ;
if ( ! out )
2006-07-03 10:39:57 +00:00
DIE_MEM ( ) ;
2005-09-20 13:26:39 +00:00
out - > fd = in - > fd ;
out - > io_mode = IO_FD ;
2005-10-11 19:31:16 +00:00
out - > param2 . close_old = 1 ;
2006-01-11 14:40:20 +00:00
out - > next = 0 ;
2005-09-20 13:26:39 +00:00
switch ( in - > io_mode )
{
/*
These redirections don ' t need transmogrification . They can be passed through .
*/
case IO_FD :
case IO_CLOSE :
case IO_BUFFER :
case IO_PIPE :
{
memcpy ( out , in , sizeof ( io_data_t ) ) ;
break ;
}
/*
Transmogrify file redirections
*/
case IO_FILE :
{
int fd ;
2006-11-15 13:30:46 +00:00
if ( ( fd = wopen ( in - > param1 . filename , in - > param2 . flags , OPEN_MASK ) ) = = - 1 )
2005-09-20 13:26:39 +00:00
{
debug ( 1 ,
FILE_ERROR ,
2005-10-11 19:31:16 +00:00
in - > param1 . filename ) ;
2005-09-20 13:26:39 +00:00
wperror ( L " open " ) ;
2006-01-11 14:40:20 +00:00
free ( out ) ;
return 0 ;
2005-09-20 13:26:39 +00:00
}
2005-10-11 19:31:16 +00:00
out - > param1 . old_fd = fd ;
2005-09-20 13:26:39 +00:00
break ;
}
}
2006-01-11 14:40:20 +00:00
if ( in - > next )
{
out - > next = io_transmogrify ( in - > next ) ;
if ( ! out - > next )
{
io_untransmogrify ( in , out ) ;
return 0 ;
}
}
2005-09-20 13:26:39 +00:00
return out ;
}
/**
Morph an io redirection chain into redirections suitable for
passing to eval , call eval , and clean up morphed redirections .
\ param def the code to evaluate
\ param block_type the type of block to push on evaluation
\ param io the io redirections to be performed on this block
*/
2006-01-11 14:40:20 +00:00
static void internal_exec_helper ( const wchar_t * def ,
2005-09-20 13:26:39 +00:00
int block_type ,
io_data_t * io )
{
io_data_t * io_internal = io_transmogrify ( io ) ;
int is_block_old = is_block ;
is_block = 1 ;
2006-05-14 22:29:05 +00:00
2006-01-11 14:40:20 +00:00
/*
Did the transmogrification fail - if so , set error status and return
*/
if ( io & & ! io_internal )
{
2006-10-09 01:21:02 +00:00
proc_set_last_status ( STATUS_EXEC_FAIL ) ;
2006-01-11 14:40:20 +00:00
return ;
}
2005-09-20 13:26:39 +00:00
2006-01-11 14:40:20 +00:00
signal_unblock ( ) ;
2006-05-14 22:29:05 +00:00
2005-09-20 13:26:39 +00:00
eval ( def , io_internal , block_type ) ;
2006-01-11 14:40:20 +00:00
2005-10-14 11:40:33 +00:00
signal_block ( ) ;
2006-01-11 14:40:20 +00:00
2005-09-20 13:26:39 +00:00
io_untransmogrify ( io , io_internal ) ;
2005-10-11 19:23:43 +00:00
job_reap ( 0 ) ;
2005-09-20 13:26:39 +00:00
is_block = is_block_old ;
}
2005-10-09 11:48:16 +00:00
/**
2006-02-04 11:33:20 +00:00
This function should be called by both the parent process and the
child right after fork ( ) has been called . If job control is
enabled , the child is put in the jobs group , and if the child is
also in the foreground , it is also given control of the
terminal . When called in the parent process , this function may
fail , since the child might have already finished and called
exit . The parent process may safely ignore the exit status of this
call .
Returns 0 on sucess , - 1 on failiure .
2005-09-20 13:26:39 +00:00
*/
2006-02-04 11:33:20 +00:00
static int set_child_group ( job_t * j , process_t * p , int print_errors )
2005-09-20 13:26:39 +00:00
{
2006-02-03 21:50:31 +00:00
int res = 0 ;
2005-09-20 13:26:39 +00:00
2006-10-25 20:47:59 +00:00
if ( job_get_flag ( j , JOB_CONTROL ) )
2005-09-20 13:26:39 +00:00
{
if ( ! j - > pgid )
{
j - > pgid = p - > pid ;
}
if ( setpgid ( p - > pid , j - > pgid ) )
2006-08-27 00:52:52 +00:00
{
2006-02-04 11:33:20 +00:00
if ( getpgid ( p - > pid ) ! = j - > pgid & & print_errors )
2005-09-20 13:26:39 +00:00
{
debug ( 1 ,
2007-09-08 22:24:53 +00:00
_ ( L " Could not send process %d, '%ls' in job %d, '%ls' from group %d to group %d " ) ,
p - > pid ,
p - > argv [ 0 ] ,
j - > job_id ,
j - > command ,
getpgid ( p - > pid ) ,
j - > pgid ) ;
2005-09-20 13:26:39 +00:00
wperror ( L " setpgid " ) ;
2006-02-03 21:50:31 +00:00
res = - 1 ;
2005-09-20 13:26:39 +00:00
}
}
}
else
{
j - > pgid = getpid ( ) ;
}
2006-02-04 11:33:20 +00:00
2006-10-25 20:47:59 +00:00
if ( job_get_flag ( j , JOB_TERMINAL ) & & job_get_flag ( j , JOB_FOREGROUND ) )
2006-02-01 12:27:15 +00:00
{
2006-02-04 11:33:20 +00:00
if ( tcsetpgrp ( 0 , j - > pgid ) & & print_errors )
2006-02-01 12:27:15 +00:00
{
debug ( 1 , _ ( L " Could not send job %d ('%ls') to foreground " ) ,
j - > job_id ,
j - > command ) ;
wperror ( L " tcsetpgrp " ) ;
2006-02-03 21:50:31 +00:00
res = - 1 ;
2006-02-01 12:27:15 +00:00
}
}
2006-02-03 21:50:31 +00:00
return res ;
2005-09-20 13:26:39 +00:00
}
2006-11-15 13:30:46 +00:00
/**
This function is a wrapper around fork . If the fork calls fails
with EAGAIN , it is retried FORK_LAPS times , with a very slight
delay between each lap . If fork fails even then , the process will
exit with an error message .
*/
static pid_t exec_fork ( )
{
pid_t pid ;
struct timespec pollint ;
int i ;
for ( i = 0 ; i < FORK_LAPS ; i + + )
{
pid = fork ( ) ;
if ( pid > = 0 )
{
return pid ;
}
if ( errno ! = EAGAIN )
{
break ;
}
pollint . tv_sec = 0 ;
2007-01-21 15:20:26 +00:00
pollint . tv_nsec = FORK_SLEEP_TIME ;
2006-11-15 13:30:46 +00:00
/*
Don ' t sleep on the final lap - sleeping might change the
value of errno , which will break the error reporting below .
*/
if ( i ! = FORK_LAPS - 1 )
{
nanosleep ( & pollint , NULL ) ;
}
}
debug ( 0 , FORK_ERROR ) ;
wperror ( L " fork " ) ;
2007-01-21 15:03:41 +00:00
FATAL_EXIT ( ) ;
2006-11-15 13:30:46 +00:00
}
2005-09-20 13:26:39 +00:00
2008-01-13 16:47:47 +00:00
/**
Perform output from builtins
*/
2007-01-21 14:58:10 +00:00
static void do_builtin_io ( wchar_t * out , wchar_t * err )
{
if ( out )
{
if ( fwprintf ( stdout , L " %ls " , out ) = = - 1 | | fflush ( stdout ) = = EOF )
{
debug ( 0 , L " Error while writing to stdout " ) ;
wperror ( L " fwprintf " ) ;
show_stackframe ( ) ;
}
}
if ( err )
{
if ( fwprintf ( stderr , L " %ls " , err ) = = - 1 | | fflush ( stderr ) = = EOF )
{
/*
Can ' t really show any error message here , since stderr is
2007-01-21 15:22:42 +00:00
dead .
2007-01-21 14:58:10 +00:00
*/
}
}
}
2005-09-20 13:26:39 +00:00
void exec ( job_t * j )
{
process_t * p ;
pid_t pid ;
int mypipe [ 2 ] ;
sigset_t chldset ;
int skip_fork ;
io_data_t pipe_read , pipe_write ;
io_data_t * tmp ;
io_data_t * io_buffer = 0 ;
2005-10-17 13:24:12 +00:00
2005-10-20 23:56:51 +00:00
/*
2006-11-15 13:30:46 +00:00
Set to 1 if something goes wrong while exec : ing the job , in
which case the cleanup code will kick in .
2005-10-20 23:56:51 +00:00
*/
int exec_error = 0 ;
2006-08-27 00:52:52 +00:00
int needs_keepalive = 0 ;
process_t keepalive ;
2006-06-21 00:48:36 +00:00
CHECK ( j , ) ;
2006-10-29 21:09:11 +00:00
CHECK_BLOCK ( ) ;
2006-03-18 01:04:59 +00:00
if ( no_exec )
return ;
sigemptyset ( & chldset ) ;
sigaddset ( & chldset , SIGCHLD ) ;
2005-10-17 13:24:12 +00:00
2006-01-18 12:42:48 +00:00
debug ( 4 , L " Exec job '%ls' with id %d " , j - > command , j - > job_id ) ;
2005-09-20 13:26:39 +00:00
2006-08-13 01:38:03 +00:00
if ( block_io )
{
if ( j - > io )
2007-01-21 15:01:14 +00:00
{
2006-08-13 01:38:03 +00:00
j - > io = io_add ( io_duplicate ( j , block_io ) , j - > io ) ;
2007-01-21 15:01:14 +00:00
}
2006-08-13 01:38:03 +00:00
else
2007-01-21 15:01:14 +00:00
{
2006-08-13 01:38:03 +00:00
j - > io = io_duplicate ( j , block_io ) ;
2007-01-21 15:01:14 +00:00
}
2006-08-13 01:38:03 +00:00
}
2007-01-07 14:10:52 +00:00
io_data_t * input_redirect ;
for ( input_redirect = j - > io ; input_redirect ; input_redirect = input_redirect - > next )
2006-08-13 01:38:03 +00:00
{
2007-01-07 14:10:52 +00:00
if ( ( input_redirect - > io_mode = = IO_BUFFER ) & &
input_redirect - > is_input )
{
/*
Input redirection - create a new gobetween process to take
care of buffering
*/
process_t * fake = halloc ( j , sizeof ( process_t ) ) ;
fake - > type = INTERNAL_BUFFER ;
fake - > pipe_write_fd = 1 ;
j - > first_process - > pipe_read_fd = input_redirect - > fd ;
fake - > next = j - > first_process ;
j - > first_process = fake ;
break ;
}
2006-08-13 01:38:03 +00:00
}
2007-01-07 14:10:52 +00:00
2005-09-20 13:26:39 +00:00
if ( j - > first_process - > type = = INTERNAL_EXEC )
{
/*
Do a regular launch - but without forking first . . .
*/
2005-10-14 11:40:33 +00:00
signal_block ( ) ;
/*
2006-06-03 22:35:33 +00:00
setup_child_process makes sure signals are properly set
2006-02-05 13:12:53 +00:00
up . It will also call signal_unblock
2005-10-14 11:40:33 +00:00
*/
2006-02-03 21:50:31 +00:00
if ( ! setup_child_process ( j , 0 ) )
2006-01-15 22:41:48 +00:00
{
/*
2007-01-21 15:01:14 +00:00
launch_process _never_ returns
2006-01-15 22:41:48 +00:00
*/
launch_process ( j - > first_process ) ;
}
else
{
2006-10-25 20:47:59 +00:00
job_set_flag ( j , JOB_CONSTRUCTED , 1 ) ;
2006-01-15 22:41:48 +00:00
j - > first_process - > completed = 1 ;
return ;
}
2006-08-13 01:38:03 +00:00
2006-01-18 12:42:48 +00:00
}
2005-09-20 13:26:39 +00:00
pipe_read . fd = 0 ;
pipe_write . fd = 1 ;
pipe_read . io_mode = IO_PIPE ;
2005-10-11 19:31:16 +00:00
pipe_read . param1 . pipe_fd [ 0 ] = - 1 ;
pipe_read . param1 . pipe_fd [ 1 ] = - 1 ;
2007-01-07 14:10:52 +00:00
pipe_read . is_input = 1 ;
2005-09-20 13:26:39 +00:00
pipe_write . io_mode = IO_PIPE ;
2007-01-07 14:10:52 +00:00
pipe_write . is_input = 0 ;
2005-09-20 13:26:39 +00:00
pipe_read . next = 0 ;
pipe_write . next = 0 ;
2006-11-17 16:24:38 +00:00
pipe_write . param1 . pipe_fd [ 0 ] = pipe_write . param1 . pipe_fd [ 1 ] = - 1 ;
2005-09-20 13:26:39 +00:00
j - > io = io_add ( j - > io , & pipe_write ) ;
2005-10-14 11:40:33 +00:00
signal_block ( ) ;
2006-08-27 00:52:52 +00:00
/*
2007-09-24 08:18:23 +00:00
See if we need to create a group keepalive process . This is
a process that we create to make sure that the process group
doesn ' t die accidentally , and is often needed when a
builtin / block / function is inside a pipeline , since that
usually means we have to wait for one program to exit before
continuing in the pipeline , causing the group leader to
exit .
2006-08-27 00:52:52 +00:00
*/
2006-10-25 20:47:59 +00:00
if ( job_get_flag ( j , JOB_CONTROL ) )
2006-08-27 00:52:52 +00:00
{
for ( p = j - > first_process ; p ; p = p - > next )
{
2007-09-24 08:21:44 +00:00
if ( p - > type ! = EXTERNAL )
2006-08-27 00:52:52 +00:00
{
if ( p - > next )
{
needs_keepalive = 1 ;
break ;
}
2007-09-24 08:21:44 +00:00
if ( p ! = j - > first_process )
{
needs_keepalive = 1 ;
break ;
}
2006-08-27 00:52:52 +00:00
}
2007-09-24 08:18:23 +00:00
2006-08-27 00:52:52 +00:00
}
}
if ( needs_keepalive )
{
2006-11-15 13:30:46 +00:00
keepalive . pid = exec_fork ( ) ;
2006-08-27 00:52:52 +00:00
if ( keepalive . pid = = 0 )
{
keepalive . pid = getpid ( ) ;
set_child_group ( j , & keepalive , 1 ) ;
pause ( ) ;
exit ( 0 ) ;
}
else
{
set_child_group ( j , & keepalive , 0 ) ;
}
}
2006-08-13 01:38:03 +00:00
2005-10-21 11:59:45 +00:00
/*
This loop loops over every process_t in the job , starting it as
appropriate . This turns out to be rather complex , since a
process_t can be one of many rather different things .
2005-10-20 23:56:51 +00:00
2005-10-21 11:59:45 +00:00
The loop also has to handle pipelining between the jobs .
*/
2006-08-27 00:52:52 +00:00
2005-11-02 15:41:59 +00:00
for ( p = j - > first_process ; p ; p = p - > next )
2005-09-20 13:26:39 +00:00
{
mypipe [ 1 ] = - 1 ;
skip_fork = 0 ;
2006-08-13 01:38:03 +00:00
2007-01-07 14:10:52 +00:00
pipe_write . fd = p - > pipe_write_fd ;
pipe_read . fd = p - > pipe_read_fd ;
// debug( 0, L"Pipe created from fd %d to fd %d", pipe_write.fd, pipe_read.fd );
2005-10-07 14:08:57 +00:00
2005-10-03 13:09:37 +00:00
/*
2006-11-15 13:30:46 +00:00
This call is used so the global environment variable array
is regenerated , if needed , before the fork . That way , we
avoid a lot of duplicate work where EVERY child would need
to generate it , since that result would not get written
back to the parent . This call could be safely removed , but
it would result in slightly lower performance - at least on
uniprocessor systems .
2005-10-03 13:09:37 +00:00
*/
2005-09-22 20:16:52 +00:00
if ( p - > type = = EXTERNAL )
env_export_arr ( 1 ) ;
2005-09-20 13:26:39 +00:00
2005-10-03 13:09:37 +00:00
2005-09-20 13:26:39 +00:00
/*
Set up fd : s that will be used in the pipe
*/
if ( p = = j - > first_process - > next )
{
j - > io = io_add ( j - > io , & pipe_read ) ;
}
2005-11-02 15:41:59 +00:00
if ( p - > next )
2005-09-20 13:26:39 +00:00
{
2005-11-02 15:41:59 +00:00
// debug( 1, L"%ls|%ls" , p->argv[0], p->next->argv[0]);
if ( exec_pipe ( mypipe ) = = - 1 )
2005-09-20 13:26:39 +00:00
{
debug ( 1 , PIPE_ERROR ) ;
wperror ( L " pipe " ) ;
2005-10-20 23:56:51 +00:00
exec_error = 1 ;
break ;
2005-09-20 13:26:39 +00:00
}
2005-10-11 19:31:16 +00:00
memcpy ( pipe_write . param1 . pipe_fd , mypipe , sizeof ( int ) * 2 ) ;
2005-09-20 13:26:39 +00:00
}
else
{
/*
This is the last element of the pipeline .
Remove the io redirection for pipe output .
*/
j - > io = io_remove ( j - > io , & pipe_write ) ;
}
switch ( p - > type )
{
case INTERNAL_FUNCTION :
{
2006-10-29 21:09:11 +00:00
const wchar_t * orig_def ;
wchar_t * def = 0 ;
2007-04-16 20:06:11 +00:00
array_list_t * named_arguments ;
2007-04-22 22:10:33 +00:00
int shadows ;
2007-04-16 20:06:11 +00:00
2006-10-29 21:09:11 +00:00
2006-11-17 16:24:38 +00:00
/*
Calls to function_get_definition might need to
source a file as a part of autoloading , hence there
must be no blocks .
*/
2006-10-29 21:09:11 +00:00
signal_unblock ( ) ;
orig_def = function_get_definition ( p - > argv [ 0 ] ) ;
2007-04-16 20:06:11 +00:00
named_arguments = function_get_named_arguments ( p - > argv [ 0 ] ) ;
2007-04-22 22:10:33 +00:00
shadows = function_get_shadows ( p - > argv [ 0 ] ) ;
2007-04-16 20:06:11 +00:00
2006-10-29 21:09:11 +00:00
signal_block ( ) ;
if ( orig_def )
{
def = halloc_register ( j , wcsdup ( orig_def ) ) ;
}
2005-09-20 13:26:39 +00:00
if ( def = = 0 )
{
2006-01-04 12:51:02 +00:00
debug ( 0 , _ ( L " Unknown function '%ls' " ) , p - > argv [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
break ;
}
2006-09-08 14:12:41 +00:00
2007-04-22 22:10:33 +00:00
parser_push_block ( shadows ? FUNCTION_CALL : FUNCTION_CALL_NO_SHADOW ) ;
2005-09-20 13:26:39 +00:00
2006-02-01 15:49:11 +00:00
current_block - > param2 . function_call_process = p ;
2006-09-08 14:12:41 +00:00
current_block - > param1 . function_call_name = halloc_register ( current_block , wcsdup ( p - > argv [ 0 ] ) ) ;
2006-02-14 19:56:36 +00:00
2007-10-15 13:20:06 +00:00
/*
set_argv might trigger an event
handler , hence we need to unblock
signals .
*/
signal_unblock ( ) ;
2007-04-16 20:06:11 +00:00
parse_util_set_argv ( p - > argv + 1 , named_arguments ) ;
2007-10-15 13:20:06 +00:00
signal_block ( ) ;
2006-02-14 19:56:36 +00:00
2005-09-20 13:26:39 +00:00
parser_forbid_function ( p - > argv [ 0 ] ) ;
if ( p - > next )
{
2006-08-13 01:38:03 +00:00
io_buffer = io_buffer_create ( 0 ) ;
2005-09-20 13:26:39 +00:00
j - > io = io_add ( j - > io , io_buffer ) ;
}
internal_exec_helper ( def , TOP , j - > io ) ;
parser_allow_function ( ) ;
parser_pop_block ( ) ;
break ;
}
case INTERNAL_BLOCK :
{
if ( p - > next )
{
2006-08-13 01:38:03 +00:00
io_buffer = io_buffer_create ( 0 ) ;
2005-09-20 13:26:39 +00:00
j - > io = io_add ( j - > io , io_buffer ) ;
}
2006-05-14 22:29:05 +00:00
2005-09-20 13:26:39 +00:00
internal_exec_helper ( p - > argv [ 0 ] , TOP , j - > io ) ;
break ;
}
2006-08-13 01:38:03 +00:00
2005-09-20 13:26:39 +00:00
case INTERNAL_BUILTIN :
{
int builtin_stdin = 0 ;
int fg ;
int close_stdin = 0 ;
2006-11-15 13:30:46 +00:00
/*
If this is the first process , check the io
redirections and see where we should be reading
from .
*/
2005-09-20 13:26:39 +00:00
if ( p = = j - > first_process )
{
io_data_t * in = io_get ( j - > io , 0 ) ;
2006-05-14 22:29:05 +00:00
2005-09-20 13:26:39 +00:00
if ( in )
{
switch ( in - > io_mode )
{
case IO_FD :
{
2005-10-11 19:31:16 +00:00
builtin_stdin = in - > param1 . old_fd ;
2005-09-20 13:26:39 +00:00
break ;
}
case IO_PIPE :
{
2005-10-11 19:31:16 +00:00
builtin_stdin = in - > param1 . pipe_fd [ 0 ] ;
2005-09-20 13:26:39 +00:00
break ;
}
case IO_FILE :
{
2005-10-20 23:56:51 +00:00
builtin_stdin = wopen ( in - > param1 . filename ,
2006-11-15 13:30:46 +00:00
in - > param2 . flags , OPEN_MASK ) ;
2005-10-20 23:56:51 +00:00
if ( builtin_stdin = = - 1 )
2005-09-20 13:26:39 +00:00
{
2005-10-20 23:56:51 +00:00
debug ( 1 ,
FILE_ERROR ,
in - > param1 . filename ) ;
wperror ( L " open " ) ;
2005-09-20 13:26:39 +00:00
}
else
{
close_stdin = 1 ;
}
break ;
}
2007-10-05 15:01:06 +00:00
case IO_CLOSE :
{
/*
FIXME :
When
requesting
that
stdin
be
closed ,
we
really
don ' t
do
anything . How
should
this
be
handled ?
*/
builtin_stdin = - 1 ;
break ;
}
2005-09-20 13:26:39 +00:00
default :
{
2005-10-20 23:56:51 +00:00
builtin_stdin = - 1 ;
2005-09-20 13:26:39 +00:00
debug ( 1 ,
2006-01-04 12:51:02 +00:00
_ ( L " Unknown input redirection type %d " ) ,
2005-09-20 13:26:39 +00:00
in - > io_mode ) ;
break ;
}
}
}
}
else
{
2005-10-11 19:31:16 +00:00
builtin_stdin = pipe_read . param1 . pipe_fd [ 0 ] ;
2005-09-20 13:26:39 +00:00
}
2005-10-20 23:56:51 +00:00
if ( builtin_stdin = = - 1 )
{
exec_error = 1 ;
break ;
}
2006-06-03 22:35:33 +00:00
else
{
2006-11-17 16:24:38 +00:00
int old_out = builtin_out_redirect ;
int old_err = builtin_err_redirect ;
2006-06-03 22:35:33 +00:00
/*
2006-11-15 13:30:46 +00:00
Since this may be the foreground job , and since
a builtin may execute another foreground job ,
we need to pretend to suspend this job while
running the builtin , in order to avoid a
situation where two jobs are running at once .
The reason this is done here , and not by the
relevant builtins , is that this way , the
builtin does not need to know what job it is
part of . It could probably figure that out by
walking the job list , but it seems more robust
to make exec handle things .
2006-06-03 22:35:33 +00:00
*/
2006-11-17 16:24:38 +00:00
builtin_push_io ( builtin_stdin ) ;
2006-06-03 22:35:33 +00:00
builtin_out_redirect = has_fd ( j - > io , 1 ) ;
builtin_err_redirect = has_fd ( j - > io , 2 ) ;
2006-11-17 16:24:38 +00:00
2006-10-25 20:47:59 +00:00
fg = job_get_flag ( j , JOB_FOREGROUND ) ;
job_set_flag ( j , JOB_FOREGROUND , 0 ) ;
2006-06-03 22:35:33 +00:00
signal_unblock ( ) ;
2007-04-25 18:30:02 +00:00
p - > status = builtin_run ( p - > argv , j - > io ) ;
2006-06-03 22:35:33 +00:00
2006-11-17 16:24:38 +00:00
builtin_out_redirect = old_out ;
builtin_err_redirect = old_err ;
2006-06-03 22:35:33 +00:00
signal_block ( ) ;
/*
Restore the fg flag , which is temporarily set to
false during builtin execution so as not to confuse
some job - handling builtins .
*/
2006-10-25 20:47:59 +00:00
job_set_flag ( j , JOB_FOREGROUND , fg ) ;
2006-06-03 22:35:33 +00:00
}
2005-10-20 23:56:51 +00:00
2006-11-15 13:30:46 +00:00
/*
If stdin has been redirected , close the redirection
stream .
*/
2005-09-20 13:26:39 +00:00
if ( close_stdin )
{
2005-10-08 11:20:51 +00:00
exec_close ( builtin_stdin ) ;
2005-09-20 13:26:39 +00:00
}
break ;
}
}
2005-10-20 23:56:51 +00:00
if ( exec_error )
2007-01-21 15:01:14 +00:00
{
2005-10-20 23:56:51 +00:00
break ;
2007-01-21 15:01:14 +00:00
}
2005-09-20 13:26:39 +00:00
switch ( p - > type )
{
2006-08-13 01:38:03 +00:00
2005-09-20 13:26:39 +00:00
case INTERNAL_BLOCK :
case INTERNAL_FUNCTION :
{
int status = proc_get_last_status ( ) ;
2005-11-29 19:50:30 +00:00
2005-09-20 13:26:39 +00:00
/*
Handle output from a block or function . This usually
means do nothing , but in the case of pipes , we have
2005-11-29 19:50:30 +00:00
to buffer such io , since otherwise the internal pipe
2005-09-20 13:26:39 +00:00
buffer might overflow .
*/
2005-11-02 15:41:59 +00:00
if ( ! io_buffer )
2005-09-20 13:26:39 +00:00
{
2005-11-29 19:50:30 +00:00
/*
2006-01-29 22:04:14 +00:00
No buffer , so we exit directly . This means we
2005-11-29 19:50:30 +00:00
have to manually set the exit status .
*/
if ( p - > next = = 0 )
{
2006-10-25 20:47:59 +00:00
proc_set_last_status ( job_get_flag ( j , JOB_NEGATE ) ? ( ! status ) : status ) ;
2005-11-29 19:50:30 +00:00
}
2005-09-20 13:26:39 +00:00
p - > completed = 1 ;
break ;
}
j - > io = io_remove ( j - > io , io_buffer ) ;
2005-10-08 11:20:51 +00:00
io_buffer_read ( io_buffer ) ;
2005-09-20 13:26:39 +00:00
2005-10-11 19:31:16 +00:00
if ( io_buffer - > param2 . out_buffer - > used ! = 0 )
2005-09-20 13:26:39 +00:00
{
2006-11-15 13:30:46 +00:00
pid = exec_fork ( ) ;
2006-01-18 12:42:48 +00:00
2005-11-02 15:41:59 +00:00
if ( pid = = 0 )
2005-09-20 13:26:39 +00:00
{
/*
This is the child process . Write out the contents of the pipeline .
*/
p - > pid = getpid ( ) ;
2006-01-16 00:15:56 +00:00
setup_child_process ( j , p ) ;
2005-09-20 13:26:39 +00:00
write ( io_buffer - > fd ,
2005-10-11 19:31:16 +00:00
io_buffer - > param2 . out_buffer - > buff ,
io_buffer - > param2 . out_buffer - > used ) ;
2005-09-20 13:26:39 +00:00
exit ( status ) ;
}
else
{
/*
This is the parent process . Store away
2005-10-14 11:40:33 +00:00
information on the child , and possibly give
2005-09-20 13:26:39 +00:00
it control over the terminal .
*/
p - > pid = pid ;
2006-02-04 11:33:20 +00:00
set_child_group ( j , p , 0 ) ;
2005-09-20 13:26:39 +00:00
}
}
2006-01-29 22:04:14 +00:00
else
{
if ( p - > next = = 0 )
{
2006-10-25 20:47:59 +00:00
proc_set_last_status ( job_get_flag ( j , JOB_NEGATE ) ? ( ! status ) : status ) ;
2006-01-29 22:04:14 +00:00
}
p - > completed = 1 ;
}
2005-10-08 11:20:51 +00:00
io_buffer_destroy ( io_buffer ) ;
2005-09-20 13:26:39 +00:00
io_buffer = 0 ;
break ;
}
2006-08-13 01:38:03 +00:00
case INTERNAL_BUFFER :
{
2006-11-15 13:30:46 +00:00
pid = exec_fork ( ) ;
2006-08-13 01:38:03 +00:00
if ( pid = = 0 )
{
/*
2007-01-07 14:10:52 +00:00
This is the child process . Write out the
contents of the pipeline .
2006-08-13 01:38:03 +00:00
*/
p - > pid = getpid ( ) ;
setup_child_process ( j , p ) ;
write ( 1 ,
input_redirect - > param2 . out_buffer - > buff ,
input_redirect - > param2 . out_buffer - > used ) ;
exit ( 0 ) ;
}
else
{
/*
This is the parent process . Store away
information on the child , and possibly give
it control over the terminal .
*/
p - > pid = pid ;
set_child_group ( j , p , 0 ) ;
}
break ;
}
2005-09-20 13:26:39 +00:00
case INTERNAL_BUILTIN :
{
2007-09-22 22:20:41 +00:00
int skip_fork ;
2005-09-20 13:26:39 +00:00
/*
2006-11-15 13:30:46 +00:00
Handle output from builtin commands . In the general
case , this means forking of a worker process , that
will write out the contents of the stdout and stderr
buffers to the correct file descriptor . Since
forking is expensive , fish tries to avoid it wehn
possible .
*/
/*
If a builtin didn ' t produce any output , and it is
not inside a pipeline , there is no need to fork
2005-09-20 13:26:39 +00:00
*/
skip_fork =
( ! sb_out - > used ) & &
( ! sb_err - > used ) & &
( ! p - > next ) ;
2007-03-24 22:34:30 +00:00
2005-09-20 13:26:39 +00:00
/*
2007-01-21 15:01:14 +00:00
If the output of a builtin is to be sent to an internal
2005-09-20 13:26:39 +00:00
buffer , there is no need to fork . This helps out the
performance quite a bit in complex completion code .
*/
2007-09-22 22:20:41 +00:00
io_data_t * io = io_get ( j - > io , 1 ) ;
2005-09-20 13:26:39 +00:00
int buffer_stdout = io & & io - > io_mode = = IO_BUFFER ;
2005-11-02 15:41:59 +00:00
2005-09-20 13:26:39 +00:00
if ( ( ! sb_err - > used ) & &
( ! p - > next ) & &
( sb_out - > used ) & &
( buffer_stdout ) )
{
2007-09-22 22:20:41 +00:00
char * res = wcs2str ( ( wchar_t * ) sb_out - > buff ) ;
2005-10-11 19:31:16 +00:00
b_append ( io - > param2 . out_buffer , res , strlen ( res ) ) ;
2005-09-20 13:26:39 +00:00
skip_fork = 1 ;
2007-09-22 22:20:41 +00:00
free ( res ) ;
2005-09-20 13:26:39 +00:00
}
2007-03-24 22:34:30 +00:00
for ( io = j - > io ; io ; io = io - > next )
{
2007-09-21 21:49:55 +00:00
if ( io - > io_mode = = IO_FILE & & wcscmp ( io - > param1 . filename , L " /dev/null " ) )
2007-03-24 22:34:30 +00:00
{
skip_fork = 0 ;
}
}
2005-09-20 13:26:39 +00:00
if ( skip_fork )
{
p - > completed = 1 ;
if ( p - > next = = 0 )
{
debug ( 3 , L " Set status of %ls to %d using short circut " , j - > command , p - > status ) ;
2006-10-25 20:47:59 +00:00
proc_set_last_status ( job_get_flag ( j , JOB_NEGATE ) ? ( ! p - > status ) : p - > status ) ;
2005-09-20 13:26:39 +00:00
}
break ;
}
2006-11-15 13:30:46 +00:00
/*
Ok , unfortunatly , we have to do a real fork . Bummer .
*/
pid = exec_fork ( ) ;
2005-11-02 15:41:59 +00:00
if ( pid = = 0 )
2005-09-20 13:26:39 +00:00
{
2006-06-03 22:35:33 +00:00
2005-09-20 13:26:39 +00:00
/*
2006-06-03 22:35:33 +00:00
This is the child process . Setup redirections ,
print correct output to stdout and stderr , and
then exit .
2005-09-20 13:26:39 +00:00
*/
p - > pid = getpid ( ) ;
2006-01-16 00:15:56 +00:00
setup_child_process ( j , p ) ;
2007-01-21 14:58:10 +00:00
do_builtin_io ( sb_out - > used ? ( wchar_t * ) sb_out - > buff : 0 , sb_err - > used ? ( wchar_t * ) sb_err - > buff : 0 ) ;
2005-09-20 13:26:39 +00:00
exit ( p - > status ) ;
}
else
{
/*
This is the parent process . Store away
2006-06-03 22:35:33 +00:00
information on the child , and possibly give
2005-09-20 13:26:39 +00:00
it control over the terminal .
*/
p - > pid = pid ;
2006-02-04 11:33:20 +00:00
set_child_group ( j , p , 0 ) ;
2005-09-20 13:26:39 +00:00
}
break ;
}
case EXTERNAL :
{
2006-11-15 13:30:46 +00:00
pid = exec_fork ( ) ;
2005-11-02 15:41:59 +00:00
if ( pid = = 0 )
2005-09-20 13:26:39 +00:00
{
/*
This is the child process .
*/
p - > pid = getpid ( ) ;
2006-01-16 00:15:56 +00:00
setup_child_process ( j , p ) ;
2005-09-20 13:26:39 +00:00
launch_process ( p ) ;
2006-08-27 00:52:52 +00:00
2005-09-20 13:26:39 +00:00
/*
launch_process _never_ returns . . .
*/
}
else
{
/*
This is the parent process . Store away
information on the child , and possibly fice
it control over the terminal .
*/
p - > pid = pid ;
2006-02-04 11:33:20 +00:00
set_child_group ( j , p , 0 ) ;
2005-09-20 13:26:39 +00:00
}
break ;
}
}
2005-11-02 15:41:59 +00:00
if ( p - > type = = INTERNAL_BUILTIN )
2006-02-04 11:33:20 +00:00
builtin_pop_io ( ) ;
2005-11-02 15:41:59 +00:00
2005-09-20 13:26:39 +00:00
/*
2006-11-15 13:30:46 +00:00
Close the pipe the current process uses to read from the
previous process_t
2005-09-20 13:26:39 +00:00
*/
2005-10-11 19:31:16 +00:00
if ( pipe_read . param1 . pipe_fd [ 0 ] > = 0 )
exec_close ( pipe_read . param1 . pipe_fd [ 0 ] ) ;
2005-09-20 13:26:39 +00:00
/*
2006-11-15 13:30:46 +00:00
Set up the pipe the next process uses to read from the
current process_t
2005-09-20 13:26:39 +00:00
*/
if ( p - > next )
2005-10-11 19:31:16 +00:00
pipe_read . param1 . pipe_fd [ 0 ] = mypipe [ 0 ] ;
2005-09-20 13:26:39 +00:00
/*
2006-06-03 22:35:33 +00:00
If there is a next process in the pipeline , close the
output end of the current pipe ( the surrent child
subprocess already has a copy of the pipe - this makes sure
we don ' t leak file descriptors either in the shell or in
the children ) .
2005-09-20 13:26:39 +00:00
*/
if ( p - > next )
{
2005-10-08 11:20:51 +00:00
exec_close ( mypipe [ 1 ] ) ;
2005-09-20 13:26:39 +00:00
}
}
2006-08-27 00:52:52 +00:00
/*
The keepalive process is no longer needed , so we terminate it
with extreme prejudice
*/
if ( needs_keepalive )
{
kill ( keepalive . pid , SIGKILL ) ;
}
2005-10-21 11:59:45 +00:00
signal_unblock ( ) ;
2005-10-20 23:56:51 +00:00
2005-09-23 13:10:31 +00:00
debug ( 3 , L " Job is constructed " ) ;
2005-09-20 13:26:39 +00:00
j - > io = io_remove ( j - > io , & pipe_read ) ;
for ( tmp = block_io ; tmp ; tmp = tmp - > next )
j - > io = io_remove ( j - > io , tmp ) ;
2006-10-25 20:47:59 +00:00
job_set_flag ( j , JOB_CONSTRUCTED , 1 ) ;
2005-09-20 13:26:39 +00:00
2006-10-25 20:47:59 +00:00
if ( ! job_get_flag ( j , JOB_FOREGROUND ) )
2005-09-20 13:26:39 +00:00
{
proc_last_bg_pid = j - > pgid ;
}
2006-04-04 11:27:22 +00:00
2005-10-20 23:56:51 +00:00
if ( ! exec_error )
{
job_continue ( j , 0 ) ;
}
2005-09-20 13:26:39 +00:00
}
int exec_subshell ( const wchar_t * cmd ,
2006-11-15 13:30:46 +00:00
array_list_t * lst )
2005-09-20 13:26:39 +00:00
{
char * begin , * end ;
char z = 0 ;
int prev_subshell = is_subshell ;
int status , prev_status ;
io_data_t * io_buffer ;
2007-04-22 18:49:56 +00:00
const wchar_t * ifs ;
char sep = 0 ;
2006-11-15 13:30:46 +00:00
CHECK ( cmd , - 1 ) ;
2008-01-08 19:31:45 +00:00
2007-04-22 18:49:56 +00:00
ifs = env_get ( L " IFS " ) ;
if ( ifs & & ifs [ 0 ] )
{
if ( ifs [ 0 ] < 128 )
{
sep = ' \n ' ; //ifs[0];
}
else
{
sep = 0 ;
debug ( 0 , L " Warning - invalid command substitution separator '%lc'. Please change the firsta character of IFS " , ifs [ 0 ] ) ;
}
2006-11-15 13:30:46 +00:00
2007-04-22 18:49:56 +00:00
}
2005-09-20 13:26:39 +00:00
is_subshell = 1 ;
2006-08-13 01:38:03 +00:00
io_buffer = io_buffer_create ( 0 ) ;
2005-09-20 13:26:39 +00:00
prev_status = proc_get_last_status ( ) ;
2006-10-19 15:36:03 +00:00
if ( eval ( cmd , io_buffer , SUBST ) )
{
status = - 1 ;
}
else
{
status = proc_get_last_status ( ) ;
}
2005-09-20 13:26:39 +00:00
2005-10-08 11:20:51 +00:00
io_buffer_read ( io_buffer ) ;
2008-01-08 19:31:45 +00:00
2005-09-20 13:26:39 +00:00
proc_set_last_status ( prev_status ) ;
is_subshell = prev_subshell ;
2005-10-11 19:31:16 +00:00
b_append ( io_buffer - > param2 . out_buffer , & z , 1 ) ;
2005-09-20 13:26:39 +00:00
2005-10-11 19:31:16 +00:00
begin = end = io_buffer - > param2 . out_buffer - > buff ;
2005-11-02 15:41:59 +00:00
2006-11-15 13:30:46 +00:00
if ( lst )
2005-09-20 13:26:39 +00:00
{
while ( 1 )
{
2007-04-22 18:49:56 +00:00
if ( * end = = 0 )
2005-09-20 13:26:39 +00:00
{
2007-04-22 18:49:56 +00:00
if ( begin ! = end )
2005-09-20 13:26:39 +00:00
{
2007-04-22 18:49:56 +00:00
wchar_t * el = str2wcs ( begin ) ;
2006-02-22 15:41:52 +00:00
if ( el )
{
2006-11-15 13:30:46 +00:00
al_push ( lst , el ) ;
2006-02-22 15:41:52 +00:00
}
else
{
debug ( 2 , L " Got null string on line %d of file %s " , __LINE__ , __FILE__ ) ;
}
2007-04-22 18:49:56 +00:00
}
io_buffer_destroy ( io_buffer ) ;
return status ;
}
else if ( * end = = sep )
{
wchar_t * el ;
* end = 0 ;
el = str2wcs ( begin ) ;
if ( el )
{
al_push ( lst , el ) ;
}
else
{
debug ( 2 , L " Got null string on line %d of file %s " , __LINE__ , __FILE__ ) ;
2005-09-20 13:26:39 +00:00
}
2007-04-22 18:49:56 +00:00
begin = end + 1 ;
2005-09-20 13:26:39 +00:00
}
end + + ;
}
}
2005-10-08 11:20:51 +00:00
io_buffer_destroy ( io_buffer ) ;
2006-01-18 12:42:48 +00:00
2005-09-20 13:26:39 +00:00
return status ;
}