mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-10 23:24:39 +00:00
Rename the 'terminal' flag to 'job_control', make sure fg and bg only considers jobs under job control and make it configurable which jobs are put under job control using the status builtin. Also add an option to the status builtin to print a stack trace.
darcs-hash:20060130175426-ac50b-46fb79797284cb600c67cb19462b53761446f00a.gz
This commit is contained in:
parent
1c6f685522
commit
f59e9baab9
6 changed files with 119 additions and 53 deletions
68
builtin.c
68
builtin.c
|
@ -1668,6 +1668,7 @@ static int builtin_status( wchar_t **argv )
|
||||||
SUBST,
|
SUBST,
|
||||||
BLOCK,
|
BLOCK,
|
||||||
INTERACTIVE,
|
INTERACTIVE,
|
||||||
|
STACK_TRACE,
|
||||||
LOGIN
|
LOGIN
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -1700,6 +1701,22 @@ static int builtin_status( wchar_t **argv )
|
||||||
L"is-login", no_argument, 0, 'l'
|
L"is-login", no_argument, 0, 'l'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
{
|
||||||
|
L"full-job-control", no_argument, 0, 'f'
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
L"interactive-job-control", no_argument, 0, 'I'
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
L"no-job-control", no_argument, 0, 'n'
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
L"print-stack-trace", no_argument, 0, 't'
|
||||||
|
}
|
||||||
|
,
|
||||||
{
|
{
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
}
|
}
|
||||||
|
@ -1712,7 +1729,7 @@ static int builtin_status( wchar_t **argv )
|
||||||
|
|
||||||
int opt = wgetopt_long( argc,
|
int opt = wgetopt_long( argc,
|
||||||
argv,
|
argv,
|
||||||
L"hcbil",
|
L"hcbilfInt",
|
||||||
long_options,
|
long_options,
|
||||||
&opt_index );
|
&opt_index );
|
||||||
if( opt == -1 )
|
if( opt == -1 )
|
||||||
|
@ -1751,6 +1768,22 @@ static int builtin_status( wchar_t **argv )
|
||||||
mode = LOGIN;
|
mode = LOGIN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
job_control_mode = JOB_CONTROL_ALL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'I':
|
||||||
|
job_control_mode = JOB_CONTROL_INTERACTIVE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
job_control_mode = JOB_CONTROL_NONE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
mode = STACK_TRACE;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
builtin_print_help( argv[0], sb_err );
|
builtin_print_help( argv[0], sb_err );
|
||||||
|
|
||||||
|
@ -1773,7 +1806,13 @@ static int builtin_status( wchar_t **argv )
|
||||||
|
|
||||||
case LOGIN:
|
case LOGIN:
|
||||||
return !is_login;
|
return !is_login;
|
||||||
|
|
||||||
|
case STACK_TRACE:
|
||||||
|
{
|
||||||
|
parser_stack_trace( current_block, sb_out );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2047,7 +2086,7 @@ static int builtin_fg( wchar_t **argv )
|
||||||
*/
|
*/
|
||||||
for( j=first_job; j; j=j->next )
|
for( j=first_job; j; j=j->next )
|
||||||
{
|
{
|
||||||
if( j->constructed && (!job_is_completed(j)) && (job_is_stopped(j) || !j->fg))
|
if( j->constructed && (!job_is_completed(j)) && ( (job_is_stopped(j) || !j->fg) && (j->job_control)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if( !j )
|
if( !j )
|
||||||
|
@ -2098,6 +2137,17 @@ static int builtin_fg( wchar_t **argv )
|
||||||
pid );
|
pid );
|
||||||
builtin_print_help( argv[0], sb_err );
|
builtin_print_help( argv[0], sb_err );
|
||||||
}
|
}
|
||||||
|
if( !j->job_control )
|
||||||
|
{
|
||||||
|
sb_printf( sb_err,
|
||||||
|
_( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
|
||||||
|
argv[0],
|
||||||
|
pid,
|
||||||
|
j->command );
|
||||||
|
builtin_print_help( argv[0], sb_err );
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( j )
|
if( j )
|
||||||
|
@ -2150,6 +2200,16 @@ static int send_to_bg( job_t *j, const wchar_t *name )
|
||||||
builtin_print_help( L"bg", sb_err );
|
builtin_print_help( L"bg", sb_err );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
else if( !j->job_control )
|
||||||
|
{
|
||||||
|
sb_printf( sb_err,
|
||||||
|
_( L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n" ),
|
||||||
|
L"bg",
|
||||||
|
j->job_id,
|
||||||
|
j->command );
|
||||||
|
builtin_print_help( L"bg", sb_err );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb_printf( sb_err,
|
sb_printf( sb_err,
|
||||||
|
@ -2176,7 +2236,7 @@ static int builtin_bg( wchar_t **argv )
|
||||||
job_t *j;
|
job_t *j;
|
||||||
for( j=first_job; j; j=j->next )
|
for( j=first_job; j; j=j->next )
|
||||||
{
|
{
|
||||||
if( job_is_stopped(j) )
|
if( job_is_stopped(j) && j->job_control && (!job_is_completed(j)) )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
exec.c
16
exec.c
|
@ -393,7 +393,7 @@ static int setup_child_process( job_t *j, process_t *p )
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if( j->terminal )
|
if( j->job_control )
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
/*
|
/*
|
||||||
|
@ -602,7 +602,7 @@ static void internal_exec_helper( const wchar_t *def,
|
||||||
static int handle_new_child( job_t *j, process_t *p )
|
static int handle_new_child( job_t *j, process_t *p )
|
||||||
{
|
{
|
||||||
|
|
||||||
if( j->terminal )
|
if( j->job_control )
|
||||||
{
|
{
|
||||||
int new_pgid=0;
|
int new_pgid=0;
|
||||||
|
|
||||||
|
@ -636,18 +636,6 @@ static int handle_new_child( job_t *j, process_t *p )
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( j->fg && new_pgid)
|
|
||||||
{
|
|
||||||
if( tcsetpgrp (0, j->pgid) )
|
|
||||||
{
|
|
||||||
debug( 1, _( L"Could not send job %d ('%ls') to foreground" ),
|
|
||||||
j->job_id,
|
|
||||||
j->command );
|
|
||||||
wperror( L"tcsetpgrp" );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
5
parser.c
5
parser.c
|
@ -1031,7 +1031,7 @@ int eval_args( const wchar_t *line, array_list_t *args )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parser_stack_trace( block_t *b, string_buffer_t *buff)
|
void parser_stack_trace( block_t *b, string_buffer_t *buff)
|
||||||
{
|
{
|
||||||
if( !b )
|
if( !b )
|
||||||
return;
|
return;
|
||||||
|
@ -1363,7 +1363,7 @@ static void parse_job_main_loop( process_t *p,
|
||||||
|
|
||||||
case TOK_BACKGROUND:
|
case TOK_BACKGROUND:
|
||||||
j->fg = 0;
|
j->fg = 0;
|
||||||
j->terminal=0;
|
|
||||||
case TOK_END:
|
case TOK_END:
|
||||||
{
|
{
|
||||||
p->argv = list_to_char_arr( args );
|
p->argv = list_to_char_arr( args );
|
||||||
|
@ -2183,7 +2183,6 @@ static void eval_job( tokenizer *tok )
|
||||||
j->fg=1;
|
j->fg=1;
|
||||||
j->constructed=0;
|
j->constructed=0;
|
||||||
j->skip_notification = is_subshell || is_block || is_event || (!is_interactive);
|
j->skip_notification = is_subshell || is_block || is_event || (!is_interactive);
|
||||||
j->terminal = is_interactive && !is_subshell;
|
|
||||||
|
|
||||||
current_block->job = j;
|
current_block->job = j;
|
||||||
|
|
||||||
|
|
5
parser.h
5
parser.h
|
@ -348,5 +348,10 @@ int parser_is_help( wchar_t *s, int min_match );
|
||||||
*/
|
*/
|
||||||
const wchar_t *parser_current_filename();
|
const wchar_t *parser_current_filename();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Write a stack trace starting at the specified block to the specified string_buffer_t
|
||||||
|
*/
|
||||||
|
void parser_stack_trace( block_t *b, string_buffer_t *buff);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
60
proc.c
60
proc.c
|
@ -83,6 +83,7 @@ int is_login=0;
|
||||||
int is_event=0;
|
int is_event=0;
|
||||||
int proc_had_barrier;
|
int proc_had_barrier;
|
||||||
pid_t proc_last_bg_pid = 0;
|
pid_t proc_last_bg_pid = 0;
|
||||||
|
int job_control_mode = JOB_CONTROL_INTERACTIVE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The event variable used to send all process event
|
The event variable used to send all process event
|
||||||
|
@ -229,6 +230,10 @@ job_t *job_create()
|
||||||
res->next = first_job;
|
res->next = first_job;
|
||||||
res->job_id = free_id;
|
res->job_id = free_id;
|
||||||
first_job = res;
|
first_job = res;
|
||||||
|
|
||||||
|
res->job_control = (job_control_mode==JOB_CONTROL_ALL) ||
|
||||||
|
((job_control_mode == JOB_CONTROL_INTERACTIVE) && (is_interactive));
|
||||||
|
|
||||||
// if( res->job_id > 2 )
|
// if( res->job_id > 2 )
|
||||||
// fwprintf( stderr, L"Create job %d\n", res->job_id );
|
// fwprintf( stderr, L"Create job %d\n", res->job_id );
|
||||||
return res;
|
return res;
|
||||||
|
@ -875,37 +880,34 @@ void job_continue (job_t *j, int cont)
|
||||||
|
|
||||||
if( !job_is_completed( j ) )
|
if( !job_is_completed( j ) )
|
||||||
{
|
{
|
||||||
if( j->terminal )
|
if( j->job_control && j->fg )
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Put the job into the foreground. */
|
/* Put the job into the foreground. */
|
||||||
if( j->fg )
|
signal_block();
|
||||||
|
if( tcsetpgrp (0, j->pgid) )
|
||||||
{
|
{
|
||||||
signal_block();
|
debug( 1,
|
||||||
if( tcsetpgrp (0, j->pgid) )
|
_( L"Could not send job %d ('%ls') to foreground" ),
|
||||||
{
|
j->job_id,
|
||||||
debug( 1,
|
j->command );
|
||||||
_( L"Could not send job %d ('%ls') to foreground" ),
|
wperror( L"tcsetpgrp" );
|
||||||
j->job_id,
|
return;
|
||||||
j->command );
|
|
||||||
wperror( L"tcsetpgrp" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( cont )
|
|
||||||
{
|
|
||||||
if( tcsetattr (0, TCSADRAIN, &j->tmodes))
|
|
||||||
{
|
|
||||||
debug( 1,
|
|
||||||
_( L"Could not send job %d ('%ls') to foreground" ),
|
|
||||||
j->job_id,
|
|
||||||
j->command );
|
|
||||||
wperror( L"tcsetattr" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
signal_unblock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( cont )
|
||||||
|
{
|
||||||
|
if( tcsetattr (0, TCSADRAIN, &j->tmodes))
|
||||||
|
{
|
||||||
|
debug( 1,
|
||||||
|
_( L"Could not send job %d ('%ls') to foreground" ),
|
||||||
|
j->job_id,
|
||||||
|
j->command );
|
||||||
|
wperror( L"tcsetattr" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signal_unblock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1005,7 +1007,7 @@ void job_continue (job_t *j, int cont)
|
||||||
/*
|
/*
|
||||||
Put the shell back in the foreground.
|
Put the shell back in the foreground.
|
||||||
*/
|
*/
|
||||||
if( j->terminal )
|
if( j->job_control && j->fg )
|
||||||
{
|
{
|
||||||
signal_block();
|
signal_block();
|
||||||
if( tcsetpgrp (0, getpid()) )
|
if( tcsetpgrp (0, getpid()) )
|
||||||
|
|
18
proc.h
18
proc.h
|
@ -48,6 +48,13 @@ enum
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
JOB_CONTROL_ALL,
|
||||||
|
JOB_CONTROL_INTERACTIVE,
|
||||||
|
JOB_CONTROL_NONE,
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A structure representing a single fish process. Contains variables
|
A structure representing a single fish process. Contains variables
|
||||||
|
@ -156,9 +163,9 @@ typedef struct job
|
||||||
/** Skip executing this job. This flag is set by the short-circut builtins, i.e. and and or */
|
/** Skip executing this job. This flag is set by the short-circut builtins, i.e. and and or */
|
||||||
int skip;
|
int skip;
|
||||||
|
|
||||||
/** Whether this job wants to have control of the terminal when it is in the foreground */
|
/** Whether the job is under job control */
|
||||||
int terminal;
|
int job_control;
|
||||||
|
|
||||||
/** Pointer to the next job */
|
/** Pointer to the next job */
|
||||||
struct job *next;
|
struct job *next;
|
||||||
}
|
}
|
||||||
|
@ -216,6 +223,11 @@ extern int proc_had_barrier;
|
||||||
*/
|
*/
|
||||||
extern pid_t proc_last_bg_pid;
|
extern pid_t proc_last_bg_pid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Can be one of JOB_CONTROL_ALL, JOB_CONTROL_INTERACTIVE and JOB_CONTROL_NONE
|
||||||
|
*/
|
||||||
|
extern int job_control_mode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the status of the last process to exit
|
Sets the status of the last process to exit
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue