mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-11 05:31:14 -03:00
A few additional input checks, minor code simplifications, and some indentation/documentation fixes
darcs-hash:20061115133046-ac50b-a6145bd9a63b6667357cc3ec603e185696bf1951.gz
This commit is contained in:
209
exec.c
209
exec.c
@@ -22,6 +22,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef HAVE_SIGINFO_H
|
||||
#include <siginfo.h>
|
||||
@@ -60,10 +61,15 @@
|
||||
*/
|
||||
#define FORK_ERROR _( L"Could not create child process - exiting" )
|
||||
|
||||
/**
|
||||
The number of times to try to call fork() before giving up
|
||||
*/
|
||||
#define FORK_LAPS 5
|
||||
|
||||
/**
|
||||
Base open mode to pass to calls to open
|
||||
*/
|
||||
#define BASE_MASK 0666
|
||||
#define OPEN_MASK 0666
|
||||
|
||||
/**
|
||||
List of all pipes used by internal pipes. These must be closed in
|
||||
@@ -77,6 +83,12 @@ static int set_child_group( job_t *j, process_t *p, int print_errors );
|
||||
void exec_close( int fd )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( fd < 0 )
|
||||
{
|
||||
debug( 0, L"Called close on invalid file descriptor " );
|
||||
return;
|
||||
}
|
||||
|
||||
while( close(fd) == -1 )
|
||||
{
|
||||
@@ -104,7 +116,6 @@ void exec_close( int fd )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int exec_pipe( int fd[2])
|
||||
@@ -267,7 +278,7 @@ static int handle_child_io( io_data_t *io, int exit_on_error )
|
||||
case IO_FILE:
|
||||
{
|
||||
if( (tmp=wopen( io->param1.filename,
|
||||
io->param2.flags, BASE_MASK ) )==-1 )
|
||||
io->param2.flags, OPEN_MASK ) )==-1 )
|
||||
{
|
||||
debug( 1,
|
||||
FILE_ERROR,
|
||||
@@ -385,15 +396,19 @@ static int handle_child_io( io_data_t *io, int exit_on_error )
|
||||
|
||||
/**
|
||||
Initialize a new child process. This should be called right away
|
||||
after forking in the child process. If job control is suitable, the
|
||||
process is put in the jobs group, all signal handlers are reset,
|
||||
SIGCHLD is unblocked (the exec call blocks blocks SIGCHLD), and all
|
||||
IO redirections and other file descriptor actions are performed.
|
||||
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.
|
||||
|
||||
\param j the job to set up the IO for
|
||||
\param p the child process to set up
|
||||
|
||||
\return 0 on sucess, -1 on failiure
|
||||
\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.
|
||||
*/
|
||||
static int setup_child_process( job_t *j, process_t *p )
|
||||
{
|
||||
@@ -478,7 +493,8 @@ static void io_untransmogrify( io_data_t * in, io_data_t *out )
|
||||
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
|
||||
repeatedly reopened for every command in the block.
|
||||
repeatedly reopened for every command in the block, which would
|
||||
reset the cursor position.
|
||||
|
||||
\return the transmogrified chain on sucess, or 0 on failiure
|
||||
*/
|
||||
@@ -519,7 +535,7 @@ static io_data_t *io_transmogrify( io_data_t * in )
|
||||
{
|
||||
int fd;
|
||||
|
||||
if( (fd=wopen( in->param1.filename, in->param2.flags, BASE_MASK ) )==-1 )
|
||||
if( (fd=wopen( in->param1.filename, in->param2.flags, OPEN_MASK ) )==-1 )
|
||||
{
|
||||
debug( 1,
|
||||
FILE_ERROR,
|
||||
@@ -645,6 +661,48 @@ static int set_child_group( job_t *j, process_t *p, int print_errors )
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
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;
|
||||
pollint.tv_nsec = 1000000;
|
||||
|
||||
/*
|
||||
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");
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
|
||||
void exec( job_t *j )
|
||||
@@ -661,7 +719,8 @@ void exec( job_t *j )
|
||||
io_data_t *io_buffer =0;
|
||||
|
||||
/*
|
||||
Set to 1 if something goes wrong while exec:ing the job, in which case the cleanup code will kick in.
|
||||
Set to 1 if something goes wrong while exec:ing the job, in
|
||||
which case the cleanup code will kick in.
|
||||
*/
|
||||
int exec_error=0;
|
||||
|
||||
@@ -776,7 +835,7 @@ void exec( job_t *j )
|
||||
|
||||
if( needs_keepalive )
|
||||
{
|
||||
keepalive.pid = fork();
|
||||
keepalive.pid = exec_fork();
|
||||
|
||||
if( keepalive.pid == 0 )
|
||||
{
|
||||
@@ -785,13 +844,6 @@ void exec( job_t *j )
|
||||
pause();
|
||||
exit(0);
|
||||
}
|
||||
else if( keepalive.pid < 0 )
|
||||
{
|
||||
/* The fork failed. */
|
||||
debug( 0, FORK_ERROR );
|
||||
wperror (L"fork");
|
||||
exit (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_child_group( j, &keepalive, 0 );
|
||||
@@ -814,10 +866,13 @@ void exec( job_t *j )
|
||||
pipe_write.fd = p->pipe_fd;
|
||||
|
||||
/*
|
||||
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
|
||||
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.
|
||||
*/
|
||||
if( p->type == EXTERNAL )
|
||||
env_export_arr( 1 );
|
||||
@@ -918,7 +973,12 @@ void exec( job_t *j )
|
||||
int builtin_stdin=0;
|
||||
int fg;
|
||||
int close_stdin=0;
|
||||
|
||||
|
||||
/*
|
||||
If this is the first process, check the io
|
||||
redirections and see where we should be reading
|
||||
from.
|
||||
*/
|
||||
if( p == j->first_process )
|
||||
{
|
||||
io_data_t *in = io_get( j->io, 0 );
|
||||
@@ -942,7 +1002,7 @@ void exec( job_t *j )
|
||||
case IO_FILE:
|
||||
{
|
||||
builtin_stdin=wopen( in->param1.filename,
|
||||
in->param2.flags, BASE_MASK );
|
||||
in->param2.flags, OPEN_MASK );
|
||||
if( builtin_stdin == -1 )
|
||||
{
|
||||
debug( 1,
|
||||
@@ -985,9 +1045,18 @@ void exec( job_t *j )
|
||||
builtin_push_io( builtin_stdin );
|
||||
|
||||
/*
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
|
||||
builtin_out_redirect = has_fd( j->io, 1 );
|
||||
@@ -1009,6 +1078,10 @@ void exec( job_t *j )
|
||||
job_set_flag( j, JOB_FOREGROUND, fg );
|
||||
}
|
||||
|
||||
/*
|
||||
If stdin has been redirected, close the redirection
|
||||
stream.
|
||||
*/
|
||||
if( close_stdin )
|
||||
{
|
||||
exec_close( builtin_stdin );
|
||||
@@ -1054,7 +1127,7 @@ void exec( job_t *j )
|
||||
|
||||
if( io_buffer->param2.out_buffer->used != 0 )
|
||||
{
|
||||
pid = fork();
|
||||
pid = exec_fork();
|
||||
|
||||
if( pid == 0 )
|
||||
{
|
||||
@@ -1068,13 +1141,6 @@ void exec( job_t *j )
|
||||
io_buffer->param2.out_buffer->used );
|
||||
exit( status );
|
||||
}
|
||||
else if( pid < 0 )
|
||||
{
|
||||
/* The fork failed. */
|
||||
debug( 0, FORK_ERROR );
|
||||
wperror (L"fork");
|
||||
exit (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
@@ -1108,7 +1174,7 @@ void exec( job_t *j )
|
||||
case INTERNAL_BUFFER:
|
||||
{
|
||||
|
||||
pid = fork();
|
||||
pid = exec_fork();
|
||||
|
||||
if( pid == 0 )
|
||||
{
|
||||
@@ -1123,13 +1189,6 @@ void exec( job_t *j )
|
||||
input_redirect->param2.out_buffer->used );
|
||||
exit( 0 );
|
||||
}
|
||||
else if( pid < 0 )
|
||||
{
|
||||
/* The fork failed. */
|
||||
debug( 0, FORK_ERROR );
|
||||
wperror (L"fork");
|
||||
exit (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
@@ -1149,7 +1208,17 @@ void exec( job_t *j )
|
||||
int skip_fork=0;
|
||||
|
||||
/*
|
||||
If a builtin didn't produce any output, and it is not inside a pipeline, there is no need to fork
|
||||
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
|
||||
*/
|
||||
skip_fork =
|
||||
( !sb_out->used ) &&
|
||||
@@ -1157,7 +1226,7 @@ void exec( job_t *j )
|
||||
( !p->next );
|
||||
|
||||
/*
|
||||
If the output of a builtin is to be sent to an internal
|
||||
If the output of a builtin is to be sent to aninternal
|
||||
buffer, there is no need to fork. This helps out the
|
||||
performance quite a bit in complex completion code.
|
||||
*/
|
||||
@@ -1188,8 +1257,12 @@ void exec( job_t *j )
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
|
||||
/*
|
||||
Ok, unfortunatly, we have to do a real fork. Bummer.
|
||||
*/
|
||||
|
||||
pid = exec_fork();
|
||||
if( pid == 0 )
|
||||
{
|
||||
|
||||
@@ -1209,13 +1282,6 @@ void exec( job_t *j )
|
||||
exit( p->status );
|
||||
|
||||
}
|
||||
else if( pid < 0 )
|
||||
{
|
||||
/* The fork failed. */
|
||||
debug( 0, FORK_ERROR );
|
||||
wperror (L"fork");
|
||||
exit (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
@@ -1234,7 +1300,7 @@ void exec( job_t *j )
|
||||
|
||||
case EXTERNAL:
|
||||
{
|
||||
pid = fork();
|
||||
pid = exec_fork();
|
||||
if( pid == 0 )
|
||||
{
|
||||
/*
|
||||
@@ -1248,13 +1314,6 @@ void exec( job_t *j )
|
||||
launch_process _never_ returns...
|
||||
*/
|
||||
}
|
||||
else if( pid < 0 )
|
||||
{
|
||||
/* The fork failed. */
|
||||
debug( 0, FORK_ERROR );
|
||||
wperror( L"fork" );
|
||||
exit( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
@@ -1276,12 +1335,14 @@ void exec( job_t *j )
|
||||
builtin_pop_io();
|
||||
|
||||
/*
|
||||
Close the pipe the current process uses to read from the previous process_t
|
||||
Close the pipe the current process uses to read from the
|
||||
previous process_t
|
||||
*/
|
||||
if( pipe_read.param1.pipe_fd[0] >= 0 )
|
||||
exec_close( pipe_read.param1.pipe_fd[0] );
|
||||
/*
|
||||
Set up the pipe the next process uses to read from the current process_t
|
||||
Set up the pipe the next process uses to read from the
|
||||
current process_t
|
||||
*/
|
||||
if( p->next )
|
||||
pipe_read.param1.pipe_fd[0] = mypipe[0];
|
||||
@@ -1332,7 +1393,7 @@ void exec( job_t *j )
|
||||
}
|
||||
|
||||
int exec_subshell( const wchar_t *cmd,
|
||||
array_list_t *l )
|
||||
array_list_t *lst )
|
||||
{
|
||||
char *begin, *end;
|
||||
char z=0;
|
||||
@@ -1340,14 +1401,8 @@ int exec_subshell( const wchar_t *cmd,
|
||||
int status, prev_status;
|
||||
io_data_t *io_buffer;
|
||||
|
||||
if( !cmd )
|
||||
{
|
||||
debug( 1,
|
||||
_( L"Sent null command to subshell. This is a fish bug. If it can be reproduced, please send a bug report to %s." ),
|
||||
PACKAGE_BUGREPORT );
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHECK( cmd, -1 );
|
||||
|
||||
is_subshell=1;
|
||||
io_buffer= io_buffer_create( 0 );
|
||||
|
||||
@@ -1372,7 +1427,7 @@ int exec_subshell( const wchar_t *cmd,
|
||||
|
||||
begin=end=io_buffer->param2.out_buffer->buff;
|
||||
|
||||
if( l )
|
||||
if( lst )
|
||||
{
|
||||
while( 1 )
|
||||
{
|
||||
@@ -1385,7 +1440,7 @@ int exec_subshell( const wchar_t *cmd,
|
||||
wchar_t *el = str2wcs( begin );
|
||||
if( el )
|
||||
{
|
||||
al_push( l, el );
|
||||
al_push( lst, el );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1403,7 +1458,7 @@ int exec_subshell( const wchar_t *cmd,
|
||||
el = str2wcs( begin );
|
||||
if( el )
|
||||
{
|
||||
al_push( l, el );
|
||||
al_push( lst, el );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
31
screen.c
31
screen.c
@@ -82,6 +82,9 @@ static int try_sequence( char *seq, wchar_t *str )
|
||||
|
||||
static int next_tab_stop( int in )
|
||||
{
|
||||
/*
|
||||
Assume tab stops every 8 characters if undefined
|
||||
*/
|
||||
if( init_tabs <= 0 )
|
||||
init_tabs = 8;
|
||||
|
||||
@@ -188,13 +191,11 @@ static int calc_prompt_width( wchar_t *prompt )
|
||||
}
|
||||
|
||||
if( !found )
|
||||
|
||||
{
|
||||
wchar_t *term_name = env_get( L"TERM" );
|
||||
|
||||
if( term_name && wcscmp( term_name, L"screen" ) == 0 )
|
||||
if( prompt[j+1] == L'k' )
|
||||
{
|
||||
if( prompt[j+1] == L'k' )
|
||||
wchar_t *term_name = env_get( L"TERM" );
|
||||
if( term_name && wcscmp( term_name, L"screen" ) == 0 )
|
||||
{
|
||||
wchar_t *end;
|
||||
j+=2;
|
||||
@@ -202,6 +203,14 @@ static int calc_prompt_width( wchar_t *prompt )
|
||||
end = wcsstr( &prompt[j], L"\e\\" );
|
||||
if( end )
|
||||
{
|
||||
/*
|
||||
You'd thing this should be
|
||||
'(end-prompt)+2', in order to move j
|
||||
past the end of the string, but there is
|
||||
a 'j++' at the end of each lap, so j
|
||||
should always point to the last menged
|
||||
character, e.g. +1.
|
||||
*/
|
||||
j = (end-prompt)+1;
|
||||
}
|
||||
else
|
||||
@@ -215,9 +224,6 @@ static int calc_prompt_width( wchar_t *prompt )
|
||||
}
|
||||
else if( prompt[j] == L'\t' )
|
||||
{
|
||||
/*
|
||||
Assume tab stops every 8 characters if undefined
|
||||
*/
|
||||
res = next_tab_stop( res );
|
||||
}
|
||||
else
|
||||
@@ -330,7 +336,6 @@ static void s_check_status( screen_t *s)
|
||||
/**
|
||||
Free all memory used by one line_t struct.
|
||||
*/
|
||||
|
||||
static void free_line( void *l )
|
||||
{
|
||||
line_t *line = (line_t *)l;
|
||||
@@ -503,10 +508,11 @@ static void s_move( screen_t *s, buffer_t *b, int new_x, int new_y )
|
||||
if( y_steps > 0 && (strcmp( cursor_down, "\n")==0))
|
||||
{
|
||||
/*
|
||||
This is very strange - it seems all (most) consoles use a
|
||||
This is very strange - it seems some (all?) consoles use a
|
||||
simple newline as the cursor down escape. This will of
|
||||
course move the cursor to the beginning of the line as
|
||||
well. The cursor_up does not have this behaviour...
|
||||
course move the cursor to the beginning of the line as well
|
||||
as moving it down one step. The cursor_up does not have this
|
||||
behaviour...
|
||||
*/
|
||||
s->actual_cursor[0]=0;
|
||||
}
|
||||
@@ -591,6 +597,7 @@ static void s_write_char( screen_t *s, buffer_t *b, wchar_t c )
|
||||
|
||||
output_set_writer( writer_old );
|
||||
}
|
||||
|
||||
/**
|
||||
Send the specified string through tputs and append the output to
|
||||
the specified buffer.
|
||||
|
||||
Reference in New Issue
Block a user