mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-25 12:23:09 +00:00
Increase fish robustness by improving signal handling when forking jobs and minor signal handling improvements
darcs-hash:20051014114033-ac50b-8d0f6274ac590f1b6dbe82c55366f44ed7debf20.gz
This commit is contained in:
parent
f321855c02
commit
0ebf6db4b9
17 changed files with 355 additions and 292 deletions
|
@ -946,7 +946,7 @@ static int builtin_function( wchar_t **argv )
|
|||
{
|
||||
wchar_t *nxt = names_arr[i];
|
||||
int l = wcslen( nxt + 2 );
|
||||
if( chars+l > reader_get_width() )
|
||||
if( chars+l > common_get_width() )
|
||||
{
|
||||
chars = 0;
|
||||
sb_append(sb_err, L"\n" );
|
||||
|
|
57
common.c
57
common.c
|
@ -87,6 +87,11 @@ wchar_t *program_name;
|
|||
|
||||
int debug_level=1;
|
||||
|
||||
/**
|
||||
This struct should be continually updated by signals as the term resizes, and as such always contain the correct current size.
|
||||
*/
|
||||
static struct winsize termsize;
|
||||
|
||||
|
||||
static int block_count=0;
|
||||
|
||||
|
@ -799,7 +804,7 @@ void debug( int level, wchar_t *msg, ... )
|
|||
wchar_t *start, *pos;
|
||||
int line_width = 0;
|
||||
int tok_width = 0;
|
||||
int screen_width = 80;
|
||||
int screen_width = common_get_width();
|
||||
|
||||
if( level > debug_level )
|
||||
return;
|
||||
|
@ -817,35 +822,51 @@ void debug( int level, wchar_t *msg, ... )
|
|||
int overflow = 0;
|
||||
|
||||
tok_width=0;
|
||||
|
||||
|
||||
/*
|
||||
Tokenize on whitespace, and also calculate the width of the token
|
||||
*/
|
||||
while( *pos && ( !wcschr( L" \n\r\t", *pos ) ) )
|
||||
{
|
||||
if((tok_width + wcwidth(*pos)) >= (screen_width-1))
|
||||
|
||||
/*
|
||||
Check is token is wider than one line.
|
||||
If so we mark it as an overflow and break the token.
|
||||
*/
|
||||
if((tok_width + wcwidth(*pos)) > (screen_width-1))
|
||||
{
|
||||
overflow = 1;
|
||||
break;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
tok_width += wcwidth( *pos );
|
||||
pos++;
|
||||
}
|
||||
|
||||
/*
|
||||
If token is zero character long, we don't do anything
|
||||
*/
|
||||
if( pos == start )
|
||||
{
|
||||
start = pos = pos+1;
|
||||
}
|
||||
else if( overflow )
|
||||
{
|
||||
/*
|
||||
In case of overflow, we print a newline, except if we alreade are at position 0
|
||||
*/
|
||||
wchar_t *token = wcsndup( start, pos-start );
|
||||
if( line_width != 0 )
|
||||
putwc( L'\n', stderr );
|
||||
putwc( L'\n', stderr );
|
||||
fwprintf( stderr, L"%ls-\n", token );
|
||||
free( token );
|
||||
line_width=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Print the token
|
||||
*/
|
||||
wchar_t *token = wcsndup( start, pos-start );
|
||||
if( (line_width + (line_width!=0?1:0) + tok_width) > screen_width )
|
||||
{
|
||||
|
@ -856,7 +877,9 @@ void debug( int level, wchar_t *msg, ... )
|
|||
free( token );
|
||||
line_width += (line_width!=0?1:0) + tok_width;
|
||||
}
|
||||
|
||||
/*
|
||||
Break on end of string
|
||||
*/
|
||||
if( !*pos )
|
||||
break;
|
||||
|
||||
|
@ -1383,3 +1406,23 @@ int acquire_lock_file( const char *lockfile, const int timeout, int force )
|
|||
free( linkfile );
|
||||
return ret;
|
||||
}
|
||||
|
||||
void common_handle_winch( int signal )
|
||||
{
|
||||
if (ioctl(1,TIOCGWINSZ,&termsize)!=0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int common_get_width()
|
||||
{
|
||||
return termsize.ws_col;
|
||||
}
|
||||
|
||||
|
||||
int common_get_height()
|
||||
{
|
||||
return termsize.ws_row;
|
||||
}
|
||||
|
||||
|
|
43
common.h
43
common.h
|
@ -231,15 +231,23 @@ void die_mem();
|
|||
void common_destroy();
|
||||
|
||||
/**
|
||||
Issue a debug message
|
||||
Issue a debug message with printf-style string formating and
|
||||
automatic line breaking. The string will begin with the string \c
|
||||
program_name, followed by a colon and a whitespace.
|
||||
|
||||
\param level the priority of the message. Lower number means higher priority. Messages with too high priority number will be discarded.
|
||||
\param the message.
|
||||
\param level the priority of the message. Lower number means higher priority. Messages with a priority_number higher than \c debug_level will be ignored..
|
||||
\param the message format string.
|
||||
|
||||
Example:
|
||||
|
||||
<code>debug( 1, L"Pi = %.3f", M_PI );</code>
|
||||
|
||||
will print the string 'fish: Pi = 3.141', given that debug_level is 1 or higher, and that program_name is 'fish'.
|
||||
*/
|
||||
void debug( int level, wchar_t *msg, ... );
|
||||
|
||||
/**
|
||||
Replace special characters with escape sequences. Newline is
|
||||
Replace special characters with backslash escape sequences. Newline is
|
||||
replaced with \n, etc.
|
||||
|
||||
\param in The string to be escaped
|
||||
|
@ -255,6 +263,31 @@ wchar_t *unescape( const wchar_t * in, int escape_special );
|
|||
void block();
|
||||
void unblock();
|
||||
|
||||
int acquire_lock_file( const char *lockfile, const int timeout, int force );
|
||||
|
||||
/**
|
||||
Returns the width of the terminal window, so that not all
|
||||
functions that use these values continually have to keep track of
|
||||
it.
|
||||
|
||||
Only works if common_handle_winch is registered to handle winch signals.
|
||||
*/
|
||||
int common_get_width();
|
||||
/**
|
||||
Returns the height of the terminal window, so that not all
|
||||
functions that use these values continually have to keep track of
|
||||
it.
|
||||
|
||||
Only works if common_handle_winch is registered to handle winch signals.
|
||||
*/
|
||||
int common_get_height();
|
||||
|
||||
/*
|
||||
Handle a window change event by looking up the new window size and
|
||||
saving it in an internal variable used by common_get_wisth and
|
||||
common_get_height().
|
||||
*/
|
||||
void common_handle_winch( int signal );
|
||||
|
||||
#endif
|
||||
|
||||
int acquire_lock_file( const char *lockfile, const int timeout, int force );
|
||||
|
|
38
env.c
38
env.c
|
@ -251,7 +251,7 @@ void env_init()
|
|||
hash_put( &env_read_only, L"LINES", L"" );
|
||||
hash_put( &env_read_only, L"COLUMNS", L"" );
|
||||
hash_put( &env_read_only, L"PWD", L"" );
|
||||
|
||||
|
||||
/*
|
||||
HOME should be writeable by root, since this is often a
|
||||
convenient way to install software.
|
||||
|
@ -620,6 +620,24 @@ wchar_t *env_get( const wchar_t *key )
|
|||
}
|
||||
return (wchar_t *)dyn_var.buff;
|
||||
}
|
||||
else if( wcscmp( key, L"COLUMNS" )==0 )
|
||||
{
|
||||
sb_clear( &dyn_var );
|
||||
sb_printf( &dyn_var, L"%d", common_get_width() );
|
||||
return (wchar_t *)dyn_var.buff;
|
||||
}
|
||||
else if( wcscmp( key, L"LINES" )==0 )
|
||||
{
|
||||
sb_clear( &dyn_var );
|
||||
sb_printf( &dyn_var, L"%d", common_get_height() );
|
||||
return (wchar_t *)dyn_var.buff;
|
||||
}
|
||||
else if( wcscmp( key, L"status" )==0 )
|
||||
{
|
||||
sb_clear( &dyn_var );
|
||||
sb_printf( &dyn_var, L"%d", proc_get_last_status() );
|
||||
return (wchar_t *)dyn_var.buff;
|
||||
}
|
||||
|
||||
while( env != 0 )
|
||||
{
|
||||
|
@ -658,10 +676,10 @@ int env_exist( const wchar_t *key )
|
|||
env_node_t *env = top;
|
||||
wchar_t *item;
|
||||
|
||||
if( wcscmp( key, L"history" ) == 0 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if( hash_get( &env_read_only, key ) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
while( env != 0 )
|
||||
{
|
||||
|
@ -809,7 +827,17 @@ void env_get_names( array_list_t *l, int flags )
|
|||
add_key_to_hash,
|
||||
&names );
|
||||
if( get_names_show_unexported )
|
||||
{
|
||||
al_push( l, L"history" );
|
||||
al_push( l, L"status" );
|
||||
}
|
||||
|
||||
if( get_names_show_exported )
|
||||
{
|
||||
al_push( l, L"COLUMNS" );
|
||||
al_push( l, L"LINES" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( show_universal )
|
||||
|
|
8
env.h
8
env.h
|
@ -69,9 +69,11 @@ void env_set( const wchar_t *key,
|
|||
|
||||
|
||||
/**
|
||||
Return the value of the variable with the specified name.
|
||||
Returns 0 if the key does not exist.
|
||||
The returned string should not be modified or freed.
|
||||
Return the value of the variable with the specified name. Returns 0
|
||||
if the key does not exist. The returned string should not be
|
||||
modified or freed. The returned string is only guaranteed to be
|
||||
valid until the next call to env_get(), env_set(), env_push() or
|
||||
env_pop() takes place.
|
||||
*/
|
||||
wchar_t *env_get( const wchar_t *key );
|
||||
|
||||
|
|
19
event.c
19
event.c
|
@ -374,10 +374,16 @@ static void event_fire_signal_events()
|
|||
array_list_t a;
|
||||
al_init( &a );
|
||||
|
||||
/*
|
||||
Switch signal lists
|
||||
*/
|
||||
sig_list[1-active_list].count=0;
|
||||
sig_list[1-active_list].overflow=0;
|
||||
active_list=1-active_list;
|
||||
|
||||
|
||||
/*
|
||||
Set up
|
||||
*/
|
||||
e.type=EVENT_SIGNAL;
|
||||
e.function_name=0;
|
||||
|
||||
|
@ -385,16 +391,19 @@ static void event_fire_signal_events()
|
|||
|
||||
if( lst->overflow )
|
||||
{
|
||||
debug( 0, L"Signal overflow. Signals have been ignored" );
|
||||
debug( 0, L"Signal list overflow. Signals have been ignored" );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Send all signals in our private list
|
||||
*/
|
||||
for( i=0; i<lst->count; i++ )
|
||||
{
|
||||
e.param1.signal = lst->signal[i];
|
||||
al_set( &a, 0, sig2wcs( e.param1.signal ) );
|
||||
event_fire_internal( &e, &a );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
al_destroy( &a );
|
||||
|
||||
}
|
||||
|
|
112
exec.c
112
exec.c
|
@ -259,17 +259,7 @@ static void handle_child_io( io_data_t *io )
|
|||
We don't mind if this fails, it is just a speculative close
|
||||
to make sure no unexpected untracked fd causes us to fail
|
||||
*/
|
||||
while( close(io->fd) == -1 )
|
||||
{
|
||||
if( errno != EINTR )
|
||||
break;
|
||||
|
||||
/* debug( 1,
|
||||
FD_ERROR,
|
||||
io->fd );
|
||||
wperror( L"close" );
|
||||
exit(1);*/
|
||||
}
|
||||
close(io->fd);
|
||||
|
||||
switch( io->io_mode )
|
||||
{
|
||||
|
@ -400,13 +390,12 @@ static void setup_child_process( job_t *j )
|
|||
|
||||
/* Set the handling for job control signals back to the default. */
|
||||
signal_reset_handlers();
|
||||
|
||||
sigset_t chldset;
|
||||
sigemptyset( &chldset );
|
||||
sigaddset( &chldset, SIGCHLD );
|
||||
sigprocmask(SIG_UNBLOCK, &chldset, 0);
|
||||
|
||||
|
||||
handle_child_io( j->io );
|
||||
|
||||
/* Remove all signal blocks */
|
||||
signal_unblock();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -539,8 +528,13 @@ static int internal_exec_helper( const wchar_t *def,
|
|||
io_data_t *io_internal = io_transmogrify( io );
|
||||
int is_block_old=is_block;
|
||||
is_block=1;
|
||||
|
||||
signal_unblock();
|
||||
|
||||
eval( def, io_internal, block_type );
|
||||
|
||||
signal_block();
|
||||
|
||||
/*
|
||||
io_data_t *buff = io_get( io, 1 );
|
||||
if( buff && buff->io_mode == IO_BUFFER )
|
||||
|
@ -583,56 +577,37 @@ static int handle_new_child( job_t *j, process_t *p )
|
|||
j->pgid );
|
||||
wperror( L"setpgid" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( j->fg )
|
||||
{
|
||||
while( 1)
|
||||
if( tcsetpgrp (0, j->pgid) )
|
||||
{
|
||||
if( tcsetpgrp (0, j->pgid) )
|
||||
{
|
||||
if( errno != EINTR )
|
||||
{
|
||||
debug( 1, L"Could not send job %d ('%ls')to foreground",
|
||||
j->job_id,
|
||||
j->command );
|
||||
wperror( L"tcsetpgrp" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
debug( 1, L"Could not send job %d ('%ls')to foreground",
|
||||
j->job_id,
|
||||
j->command );
|
||||
wperror( L"tcsetpgrp" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if( j->fg && new_pgid)
|
||||
{
|
||||
while( 1 )
|
||||
if( tcsetpgrp (0, j->pgid) )
|
||||
{
|
||||
if( tcsetpgrp (0, j->pgid) )
|
||||
{
|
||||
if( errno != EINTR )
|
||||
{
|
||||
debug( 1, L"Could not send job %d ('%ls')to foreground",
|
||||
j->job_id,
|
||||
j->command );
|
||||
wperror( L"tcsetpgrp" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
debug( 1, L"Could not send job %d ('%ls')to foreground",
|
||||
j->job_id,
|
||||
j->command );
|
||||
wperror( L"tcsetpgrp" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
j->pgid = getpid();
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -659,6 +634,11 @@ void exec( job_t *j )
|
|||
/*
|
||||
Do a regular launch - but without forking first...
|
||||
*/
|
||||
signal_block();
|
||||
|
||||
/*
|
||||
setup_child_process make sure signals are propelry set up
|
||||
*/
|
||||
setup_child_process( j );
|
||||
launch_process( j->first_process );
|
||||
/*
|
||||
|
@ -689,6 +669,8 @@ void exec( job_t *j )
|
|||
|
||||
j->io = io_add( j->io, &pipe_write );
|
||||
|
||||
signal_block();
|
||||
|
||||
for (p = j->first_process; p; p = p->next)
|
||||
{
|
||||
mypipe[1]=-1;
|
||||
|
@ -890,8 +872,13 @@ void exec( job_t *j )
|
|||
builtin_err_redirect = has_fd( j->io, 2 );
|
||||
fg = j->fg;
|
||||
j->fg = 0;
|
||||
|
||||
signal_unblock();
|
||||
|
||||
p->status = builtin_run( p->argv );
|
||||
|
||||
|
||||
signal_block();
|
||||
|
||||
/*
|
||||
Restore the fg flag, which is temporarily set to
|
||||
false during builtin execution so as not to confuse
|
||||
|
@ -939,8 +926,7 @@ void exec( job_t *j )
|
|||
if( io_buffer->param2.out_buffer->used != 0 )
|
||||
{
|
||||
|
||||
/*Temporary signal block for SIGCHLD */
|
||||
sigprocmask(SIG_BLOCK, &chldset, 0);
|
||||
|
||||
pid = fork ();
|
||||
if (pid == 0)
|
||||
{
|
||||
|
@ -965,12 +951,13 @@ void exec( job_t *j )
|
|||
{
|
||||
/*
|
||||
This is the parent process. Store away
|
||||
information on the child, and possibly fice
|
||||
information on the child, and possibly give
|
||||
it control over the terminal.
|
||||
*/
|
||||
p->pid = pid;
|
||||
if( handle_new_child( j, p ) )
|
||||
return;
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1029,8 +1016,7 @@ void exec( job_t *j )
|
|||
|
||||
}
|
||||
|
||||
/*Temporary signal block for SIGCHLD */
|
||||
sigprocmask(SIG_BLOCK, &chldset, 0);
|
||||
|
||||
pid = fork ();
|
||||
if (pid == 0)
|
||||
{
|
||||
|
@ -1064,7 +1050,8 @@ void exec( job_t *j )
|
|||
p->pid = pid;
|
||||
|
||||
if( handle_new_child( j, p ) )
|
||||
return;
|
||||
exit( 1 );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1072,8 +1059,6 @@ void exec( job_t *j )
|
|||
|
||||
case EXTERNAL:
|
||||
{
|
||||
/*Temporary signal block for SIGCHLD */
|
||||
sigprocmask(SIG_BLOCK, &chldset, 0);
|
||||
|
||||
// fwprintf( stderr,
|
||||
// L"fork on %ls\n", j->command );
|
||||
|
@ -1108,7 +1093,8 @@ void exec( job_t *j )
|
|||
p->pid = pid;
|
||||
|
||||
if( handle_new_child( j, p ) )
|
||||
return;
|
||||
exit( 1 );
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
@ -1120,7 +1106,7 @@ void exec( job_t *j )
|
|||
if(p->type == INTERNAL_BUILTIN)
|
||||
builtin_pop_io();
|
||||
|
||||
sigprocmask(SIG_UNBLOCK, &chldset, 0);
|
||||
|
||||
|
||||
/*
|
||||
Close the pipe the current process uses to read from the previous process_t
|
||||
|
@ -1143,6 +1129,8 @@ void exec( job_t *j )
|
|||
}
|
||||
}
|
||||
|
||||
signal_unblock();
|
||||
|
||||
debug( 3, L"Job is constructed" );
|
||||
|
||||
j->io = io_remove( j->io, &pipe_read );
|
||||
|
@ -1179,7 +1167,7 @@ int exec_subshell( const wchar_t *cmd,
|
|||
PACKAGE_BUGREPORT );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
is_subshell=1;
|
||||
io_buffer= io_buffer_create();
|
||||
|
||||
|
|
|
@ -616,6 +616,7 @@ int main( int argc, char **argv )
|
|||
say( L"Testing low-level functionality");
|
||||
say( L"Lines beginning with '(ignore):' are not errors, they are warning messages\ngenerated by the fish parser library when given broken input, and can be\nignored. All actual errors begin with 'Error:'." );
|
||||
|
||||
proc_init();
|
||||
output_init();
|
||||
event_init();
|
||||
exec_init();
|
||||
|
@ -649,5 +650,6 @@ int main( int argc, char **argv )
|
|||
exec_destroy();
|
||||
event_destroy();
|
||||
output_destroy();
|
||||
proc_destroy();
|
||||
|
||||
}
|
||||
|
|
2
main.c
2
main.c
|
@ -207,6 +207,7 @@ int main( int argc, char **argv )
|
|||
if( force_interactive )
|
||||
is_interactive_session=1;
|
||||
|
||||
proc_init();
|
||||
output_init();
|
||||
event_init();
|
||||
exec_init();
|
||||
|
@ -306,7 +307,6 @@ int main( int argc, char **argv )
|
|||
event_destroy();
|
||||
output_destroy();
|
||||
|
||||
|
||||
intern_free_all();
|
||||
|
||||
return res;
|
||||
|
|
26
parser.c
26
parser.c
|
@ -477,7 +477,7 @@ wchar_t *parser_cdpath_get( wchar_t *dir )
|
|||
{
|
||||
die_mem();
|
||||
}
|
||||
|
||||
|
||||
for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state );
|
||||
nxt_path != 0;
|
||||
nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) )
|
||||
|
@ -1658,7 +1658,7 @@ static void eval_job( tokenizer *tok )
|
|||
job_t *j;
|
||||
|
||||
int start_pos = job_start_pos = tok_get_pos( tok );
|
||||
debug( 2, L"begin eval_job()\n" );
|
||||
debug( 2, L"begin eval_job()" );
|
||||
long long t1=0, t2=0, t3=0;
|
||||
profile_element_t *p=0;
|
||||
int skip = 0;
|
||||
|
@ -1755,7 +1755,6 @@ static void eval_job( tokenizer *tok )
|
|||
|
||||
if( current_block->type == WHILE )
|
||||
{
|
||||
// debug( 2, L"We are at begining of a while block\n" );
|
||||
|
||||
switch( current_block->param1.while_state )
|
||||
{
|
||||
|
@ -1773,8 +1772,6 @@ static void eval_job( tokenizer *tok )
|
|||
if( (!current_block->param1.if_state) &&
|
||||
(!current_block->skip) )
|
||||
{
|
||||
// debug( 2, L"Result of if block is %d\n", proc_get_last_status() );
|
||||
|
||||
current_block->skip = proc_get_last_status()!= 0;
|
||||
current_block->param1.if_state++;
|
||||
}
|
||||
|
@ -1840,7 +1837,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
|
|||
if( !cmd )
|
||||
{
|
||||
debug( 1,
|
||||
L"Tried to evaluate null pointer\n" BUGREPORT_MSG,
|
||||
L"Tried to evaluate null pointer. " BUGREPORT_MSG,
|
||||
PACKAGE_BUGREPORT );
|
||||
return 1;
|
||||
}
|
||||
|
@ -1850,7 +1847,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
|
|||
(block_type != SUBST))
|
||||
{
|
||||
debug( 1,
|
||||
L"Tried to evaluate buffer using invalid block scope of type '%ls'\n" BUGREPORT_MSG,
|
||||
L"Tried to evaluate buffer using invalid block scope of type '%ls'. " BUGREPORT_MSG,
|
||||
parser_get_block_desc( block_type ),
|
||||
PACKAGE_BUGREPORT );
|
||||
return 1;
|
||||
|
@ -1866,11 +1863,16 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
|
|||
tok_init( current_tokenizer, cmd, 0 );
|
||||
error_code = 0;
|
||||
|
||||
event_fire( 0, 0 );
|
||||
|
||||
while( tok_has_next( current_tokenizer ) &&
|
||||
!error_code &&
|
||||
!sanity_check() &&
|
||||
!exit_status() )
|
||||
{
|
||||
eval_job( current_tokenizer );
|
||||
event_fire( 0, 0 );
|
||||
}
|
||||
|
||||
int prev_block_type = current_block->type;
|
||||
parser_pop_block();
|
||||
|
@ -1880,7 +1882,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
|
|||
if( current_block == 0 )
|
||||
{
|
||||
debug( 0,
|
||||
L"End of block mismatch\n"
|
||||
L"End of block mismatch. "
|
||||
L"Program terminating. "
|
||||
BUGREPORT_MSG,
|
||||
PACKAGE_BUGREPORT );
|
||||
|
@ -2300,8 +2302,8 @@ int parser_test( wchar_t * buff,
|
|||
print_errors();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if( babble && count>0 )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
|
@ -2309,9 +2311,9 @@ int parser_test( wchar_t * buff,
|
|||
block_pos[count-1] );
|
||||
print_errors();
|
||||
}
|
||||
|
||||
|
||||
tok_destroy( &tok );
|
||||
|
||||
|
||||
|
||||
current_tokenizer=previous_tokenizer;
|
||||
current_tokenizer_pos = previous_pos;
|
||||
|
|
140
proc.c
140
proc.c
|
@ -75,6 +75,27 @@ int is_event=0;
|
|||
int proc_had_barrier;
|
||||
pid_t proc_last_bg_pid = 0;
|
||||
|
||||
/**
|
||||
List used to store arguments when firing events
|
||||
*/
|
||||
static array_list_t event_arg;
|
||||
/**
|
||||
Stringbuffer used to create arguments when firing events
|
||||
*/
|
||||
static string_buffer_t event_pid;
|
||||
/**
|
||||
Stringbuffer used to create arguments when firing events
|
||||
*/
|
||||
static string_buffer_t event_status;
|
||||
|
||||
|
||||
void proc_init()
|
||||
{
|
||||
al_init( &event_arg );
|
||||
sb_init( &event_pid );
|
||||
sb_init( &event_status );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Recursively free a process and those following it
|
||||
|
@ -164,6 +185,9 @@ void job_free( job_t * j )
|
|||
|
||||
void proc_destroy()
|
||||
{
|
||||
al_destroy( &event_arg );
|
||||
sb_destroy( &event_pid );
|
||||
sb_destroy( &event_status );
|
||||
while( first_job )
|
||||
{
|
||||
debug( 2, L"freeing leaked job %ls", first_job->command );
|
||||
|
@ -174,9 +198,6 @@ void proc_destroy()
|
|||
void proc_set_last_status( int s )
|
||||
{
|
||||
last_status = s;
|
||||
wchar_t stat[16];
|
||||
swprintf( stat, 16, L"%d", s );
|
||||
env_set( L"status", stat, ENV_GLOBAL );
|
||||
// fwprintf( stderr, L"Set last status to %d\n", s );
|
||||
}
|
||||
|
||||
|
@ -464,19 +485,8 @@ static void format_job_info( const job_t *j, const wchar_t *status )
|
|||
static void fire_process_event( const wchar_t *msg, pid_t pid, int status )
|
||||
{
|
||||
static event_t ev;
|
||||
static array_list_t event_arg;
|
||||
static string_buffer_t event_pid, event_status;
|
||||
static int init=0;
|
||||
|
||||
event_t e;
|
||||
|
||||
if( !init )
|
||||
{
|
||||
al_init( &event_arg );
|
||||
sb_init( &event_pid );
|
||||
sb_init( &event_status );
|
||||
init=1;
|
||||
}
|
||||
|
||||
e.function_name=0;
|
||||
|
||||
|
@ -832,49 +842,34 @@ void job_continue (job_t *j, int cont)
|
|||
{
|
||||
if( !is_subshell && is_interactive && !is_block)
|
||||
{
|
||||
|
||||
|
||||
/* Put the job into the foreground. */
|
||||
if( j->fg )
|
||||
{
|
||||
while( 1 )
|
||||
signal_block();
|
||||
if( tcsetpgrp (0, j->pgid) )
|
||||
{
|
||||
if( tcsetpgrp (0, j->pgid) )
|
||||
{
|
||||
if( errno != EINTR )
|
||||
{
|
||||
debug( 1,
|
||||
L"Could not send job %d ('%ls') to foreground",
|
||||
j->job_id,
|
||||
j->command );
|
||||
wperror( L"tcsetpgrp" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
debug( 1,
|
||||
L"Could not send job %d ('%ls') to foreground",
|
||||
j->job_id,
|
||||
j->command );
|
||||
wperror( L"tcsetpgrp" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( cont )
|
||||
{
|
||||
while( 1 )
|
||||
if( tcsetattr (0, TCSADRAIN, &j->tmodes))
|
||||
{
|
||||
if( tcsetattr (0, TCSADRAIN, &j->tmodes))
|
||||
{
|
||||
if( errno != EINTR )
|
||||
{
|
||||
debug( 1,
|
||||
L"Could not send job %d ('%ls') to foreground",
|
||||
j->job_id,
|
||||
j->command );
|
||||
wperror( L"tcsetattr" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
debug( 1,
|
||||
L"Could not send job %d ('%ls') to foreground",
|
||||
j->job_id,
|
||||
j->command );
|
||||
wperror( L"tcsetattr" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
signal_unblock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -976,57 +971,34 @@ void job_continue (job_t *j, int cont)
|
|||
*/
|
||||
if( !is_subshell && is_interactive && !is_block)
|
||||
{
|
||||
|
||||
while( 1 )
|
||||
signal_block();
|
||||
if( tcsetpgrp (0, getpid()) )
|
||||
{
|
||||
|
||||
if( tcsetpgrp (0, getpid()) )
|
||||
{
|
||||
if( errno != EINTR )
|
||||
{
|
||||
debug( 1, L"Could not return shell to foreground" );
|
||||
wperror( L"tcsetpgrp" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else break;
|
||||
debug( 1, L"Could not return shell to foreground" );
|
||||
wperror( L"tcsetpgrp" );
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Save jobs terminal modes.
|
||||
*/
|
||||
while( 1 )
|
||||
if( tcgetattr (0, &j->tmodes) )
|
||||
{
|
||||
if( tcgetattr (0, &j->tmodes) )
|
||||
{
|
||||
if( errno != EINTR )
|
||||
{
|
||||
debug( 1, L"Could not return shell to foreground" );
|
||||
wperror( L"tcgetattr" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
debug( 1, L"Could not return shell to foreground" );
|
||||
wperror( L"tcgetattr" );
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Restore the shell's terminal modes.
|
||||
*/
|
||||
while( 1 )
|
||||
if( tcsetattr (0, TCSADRAIN, &shell_modes))
|
||||
{
|
||||
if( tcsetattr (0, TCSADRAIN, &shell_modes))
|
||||
{
|
||||
if( errno != EINTR )
|
||||
{
|
||||
debug( 1, L"Could not return shell to foreground" );
|
||||
wperror( L"tcsetattr" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
debug( 1, L"Could not return shell to foreground" );
|
||||
wperror( L"tcsetattr" );
|
||||
return;
|
||||
}
|
||||
signal_unblock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
15
proc.h
15
proc.h
|
@ -196,11 +196,6 @@ int job_reap( int interactive );
|
|||
*/
|
||||
void job_handle_signal( int signal, siginfo_t *info, void *con );
|
||||
|
||||
/**
|
||||
Clean up before exiting
|
||||
*/
|
||||
void proc_destroy();
|
||||
|
||||
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
/**
|
||||
|
@ -225,4 +220,14 @@ void proc_update_jiffies();
|
|||
*/
|
||||
void proc_sanity_check();
|
||||
|
||||
/*
|
||||
Initializations
|
||||
*/
|
||||
void proc_init();
|
||||
|
||||
/**
|
||||
Clean up before exiting
|
||||
*/
|
||||
void proc_destroy();
|
||||
|
||||
#endif
|
||||
|
|
59
reader.c
59
reader.c
|
@ -239,11 +239,6 @@ static reader_data_t *data=0;
|
|||
static int end_loop = 0;
|
||||
|
||||
|
||||
/**
|
||||
This struct should be continually updated by signals as the term resizes, and as such always contain the correct current size.
|
||||
*/
|
||||
static struct winsize termsize;
|
||||
|
||||
static int new_size=0;
|
||||
|
||||
/**
|
||||
|
@ -285,8 +280,6 @@ static int interupted=0;
|
|||
static void reader_save_status();
|
||||
static void reader_check_status();
|
||||
static void reader_super_highlight_me_plenty( wchar_t * buff, int *color, int pos, array_list_t *error );
|
||||
static void check_winch();
|
||||
|
||||
|
||||
static struct termios old_modes;
|
||||
|
||||
|
@ -332,8 +325,7 @@ static void term_steal()
|
|||
break;
|
||||
}
|
||||
|
||||
reader_handle_winch(0 );
|
||||
check_winch();
|
||||
common_handle_winch(0 );
|
||||
|
||||
if( tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */
|
||||
{
|
||||
|
@ -372,19 +364,6 @@ void reader_handle_int( int sig )
|
|||
|
||||
}
|
||||
|
||||
|
||||
int reader_get_width()
|
||||
{
|
||||
return termsize.ws_col;
|
||||
}
|
||||
|
||||
|
||||
int reader_get_height()
|
||||
{
|
||||
return termsize.ws_row;
|
||||
}
|
||||
|
||||
|
||||
wchar_t *reader_current_filename()
|
||||
{
|
||||
return (wchar_t *)al_peek( ¤t_filename );
|
||||
|
@ -444,7 +423,7 @@ static int check_size()
|
|||
*/
|
||||
static int force_repaint()
|
||||
{
|
||||
int max_width = reader_get_width() - data->prompt_width;
|
||||
int max_width = common_get_width() - data->prompt_width;
|
||||
int pref_width = my_wcswidth( data->buff ) + (data->buff_pos==data->buff_len);
|
||||
return pref_width >= max_width;
|
||||
}
|
||||
|
@ -457,7 +436,7 @@ static int force_repaint()
|
|||
*/
|
||||
static int calc_output()
|
||||
{
|
||||
int max_width = reader_get_width() - data->prompt_width;
|
||||
int max_width = common_get_width() - data->prompt_width;
|
||||
int pref_width = my_wcswidth( data->buff ) + (data->buff_pos==data->buff_len);
|
||||
if( pref_width <= max_width )
|
||||
{
|
||||
|
@ -1405,7 +1384,7 @@ static int handle_completions( array_list_t *comp )
|
|||
|
||||
|
||||
len = &data->buff[data->buff_pos]-prefix_start;
|
||||
|
||||
|
||||
if( len <= PREFIX_MAX_LEN )
|
||||
{
|
||||
prefix = malloc( sizeof(wchar_t)*(len+1) );
|
||||
|
@ -1457,30 +1436,6 @@ static int handle_completions( array_list_t *comp )
|
|||
}
|
||||
}
|
||||
|
||||
void reader_handle_winch( int signal )
|
||||
{
|
||||
|
||||
if (ioctl(1,TIOCGWINSZ,&termsize)!=0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
new_size=1;
|
||||
}
|
||||
|
||||
static void check_winch()
|
||||
{
|
||||
if( new_size )
|
||||
{
|
||||
wchar_t tmp[64];
|
||||
new_size=0;
|
||||
swprintf(tmp, 64, L"%d", termsize.ws_row );
|
||||
env_set( L"LINES", tmp, ENV_GLOBAL );
|
||||
swprintf(tmp, 64, L"%d", termsize.ws_col );
|
||||
env_set( L"COLUMNS", tmp, ENV_GLOBAL );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Reset the terminal. This function is placed in the list of
|
||||
functions to call when exiting by using the atexit function. It
|
||||
|
@ -1539,8 +1494,7 @@ static void reader_interactive_init()
|
|||
history_init();
|
||||
|
||||
|
||||
reader_handle_winch(0);
|
||||
check_winch();
|
||||
common_handle_winch(0);
|
||||
|
||||
tcgetattr(0,&shell_modes); /* get the current terminal modes */
|
||||
memcpy( &saved_modes,
|
||||
|
@ -2487,7 +2441,6 @@ wchar_t *reader_readline()
|
|||
but it should be ignored. (Example: Trying to add a tilde
|
||||
(~) to digit)
|
||||
*/
|
||||
check_winch();
|
||||
while( 1 )
|
||||
{
|
||||
c=input_readch();
|
||||
|
@ -2529,8 +2482,6 @@ wchar_t *reader_readline()
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
check_winch();
|
||||
reader_check_status();
|
||||
|
||||
if( (last_char == R_COMPLETE) && (c != R_COMPLETE) && (!comp_empty) )
|
||||
|
|
17
reader.h
17
reader.h
|
@ -54,19 +54,6 @@ void reader_push_current_filename( wchar_t *fn );
|
|||
*/
|
||||
wchar_t *reader_pop_current_filename();
|
||||
|
||||
/**
|
||||
Returns the width of the terminal window, so that not all
|
||||
functions that use these values continually have to keep track of
|
||||
it.
|
||||
*/
|
||||
int reader_get_width();
|
||||
/**
|
||||
Returns the height of the terminal window, so that not all
|
||||
functions that use these values continually have to keep track of
|
||||
it.
|
||||
*/
|
||||
int reader_get_height();
|
||||
|
||||
/**
|
||||
Write the title to the titlebar. This function is called just
|
||||
before a new application starts executing and just after it
|
||||
|
@ -191,7 +178,9 @@ void reader_current_token_extent( wchar_t **a, wchar_t **b, wchar_t **pa, wchar_
|
|||
*/
|
||||
void reader_replace_current_token( wchar_t *new_token );
|
||||
|
||||
void reader_handle_winch( int signal );
|
||||
/**
|
||||
The readers interupt signal handler. Cancels all currently running blocks.
|
||||
*/
|
||||
void reader_handle_int( int signal );
|
||||
|
||||
|
||||
|
|
48
signal.c
48
signal.c
|
@ -313,7 +313,7 @@ static void default_handler(int signal, siginfo_t *info, void *context)
|
|||
*/
|
||||
static void handle_winch( int sig, siginfo_t *info, void *context )
|
||||
{
|
||||
reader_handle_winch( sig );
|
||||
common_handle_winch( sig );
|
||||
default_handler( sig, 0, 0 );
|
||||
}
|
||||
|
||||
|
@ -395,7 +395,7 @@ void signal_set_handlers()
|
|||
sigaction( SIGTTIN, &act, 0);
|
||||
sigaction( SIGTTOU, &act, 0);
|
||||
|
||||
act.sa_handler = &handle_int;
|
||||
act.sa_sigaction = &handle_int;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if( sigaction( SIGINT, &act, 0) )
|
||||
{
|
||||
|
@ -412,7 +412,7 @@ void signal_set_handlers()
|
|||
}
|
||||
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_handler= &handle_winch;
|
||||
act.sa_sigaction= &handle_winch;
|
||||
if( sigaction( SIGWINCH, &act, 0 ) )
|
||||
{
|
||||
wperror( L"sigaction" );
|
||||
|
@ -459,8 +459,46 @@ void signal_handle( int sig, int do_handle )
|
|||
return;
|
||||
|
||||
sigemptyset( & act.sa_mask );
|
||||
act.sa_flags=SA_SIGINFO;
|
||||
act.sa_sigaction = (do_handle?&default_handler:SIG_DFL);
|
||||
if( do_handle )
|
||||
{
|
||||
act.sa_flags=SA_SIGINFO;
|
||||
act.sa_sigaction = &default_handler;
|
||||
}
|
||||
else
|
||||
{
|
||||
act.sa_flags=0;
|
||||
act.sa_handler = SIG_DFL;
|
||||
}
|
||||
|
||||
sigaction( sig, &act, 0);
|
||||
}
|
||||
|
||||
void signal_block()
|
||||
{
|
||||
int i;
|
||||
sigset_t chldset;
|
||||
sigemptyset( &chldset );
|
||||
|
||||
for( i=0; lookup[i].desc ; i++ )
|
||||
{
|
||||
sigaddset( &chldset, lookup[i].signal );
|
||||
}
|
||||
|
||||
sigprocmask(SIG_BLOCK, &chldset, 0);
|
||||
}
|
||||
|
||||
void signal_unblock()
|
||||
{
|
||||
int i;
|
||||
sigset_t chldset;
|
||||
sigemptyset( &chldset );
|
||||
|
||||
for( i=0; lookup[i].desc ; i++ )
|
||||
{
|
||||
sigaddset( &chldset, lookup[i].signal );
|
||||
}
|
||||
|
||||
sigprocmask(SIG_UNBLOCK, &chldset, 0);
|
||||
}
|
||||
|
||||
|
||||
|
|
15
signal.h
15
signal.h
|
@ -31,6 +31,19 @@ void signal_reset_handlers();
|
|||
void signal_set_handlers();
|
||||
|
||||
/**
|
||||
Tell fish to catch the specified signal and fire an event, instead of performing the default action
|
||||
Tell fish what to do on the specified signal.
|
||||
|
||||
\param sig The signal to specify the action of
|
||||
\param do_handle If true fish will catch the specified signal and fire an event, otherwise the default action (SIG_DFL) will be set
|
||||
*/
|
||||
void signal_handle( int sig, int do_handle );
|
||||
|
||||
/*
|
||||
Block all signals
|
||||
*/
|
||||
void signal_block();
|
||||
|
||||
/**
|
||||
Unblock all signals
|
||||
*/
|
||||
void signal_unblock();
|
||||
|
|
44
wutil.c
44
wutil.c
|
@ -194,23 +194,26 @@ void wperror(const wchar_t *s)
|
|||
|
||||
|
||||
#if !HAVE_WPRINTF
|
||||
/*
|
||||
Here is my own implementation of *wprintf, included since NetBSD does
|
||||
not provide one of it's own.
|
||||
*/
|
||||
|
||||
/**
|
||||
This function is defined to help vgwprintf when it wants to call
|
||||
itself recursively
|
||||
*/
|
||||
static int gwprintf( void (*writer)(wchar_t),
|
||||
const wchar_t *filter,
|
||||
... );
|
||||
Generic formatting function. All other string formatting functions
|
||||
are secretly a wrapper around this function. vgprintf does not
|
||||
implement all the filters supported by printf, only those that are
|
||||
currently used by fish. vgprintf internally uses snprintf to
|
||||
implement the %f %d and %u filters.
|
||||
|
||||
Currently supported functionality:
|
||||
|
||||
/**
|
||||
Generic formatting function. All other formatting functions are
|
||||
secretly a wrapper around this function.
|
||||
- precision specification, both through .* and .N
|
||||
- width specification through *
|
||||
- long versions of all filters thorugh l and ll prefix
|
||||
- Character outout using %c
|
||||
- String output through %s
|
||||
- Floating point number output through %f
|
||||
- Integer output through %d or %i
|
||||
- Unsigned integer output through %u
|
||||
|
||||
For a full description on the usage of *printf, see use 'man 3 printf'.
|
||||
*/
|
||||
static int vgwprintf( void (*writer)(wchar_t),
|
||||
const wchar_t *filter,
|
||||
|
@ -530,21 +533,6 @@ static int vgwprintf( void (*writer)(wchar_t),
|
|||
return count;
|
||||
}
|
||||
|
||||
static int gwprintf( void (*writer)(wchar_t),
|
||||
const wchar_t *filter,
|
||||
... )
|
||||
{
|
||||
va_list va;
|
||||
int written;
|
||||
|
||||
va_start( va, filter );
|
||||
written=vgwprintf( writer,
|
||||
filter,
|
||||
va );
|
||||
va_end( va );
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
Holds data for swprintf writer
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue