diff --git a/builtin.c b/builtin.c index 67b405105..018507ff7 100644 --- a/builtin.c +++ b/builtin.c @@ -1668,6 +1668,7 @@ static int builtin_status( wchar_t **argv ) SUBST, BLOCK, INTERACTIVE, + STACK_TRACE, LOGIN } ; @@ -1700,6 +1701,22 @@ static int builtin_status( wchar_t **argv ) 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 } @@ -1712,7 +1729,7 @@ static int builtin_status( wchar_t **argv ) int opt = wgetopt_long( argc, argv, - L"hcbil", + L"hcbilfInt", long_options, &opt_index ); if( opt == -1 ) @@ -1751,6 +1768,22 @@ static int builtin_status( wchar_t **argv ) mode = LOGIN; 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 '?': builtin_print_help( argv[0], sb_err ); @@ -1773,7 +1806,13 @@ static int builtin_status( wchar_t **argv ) case LOGIN: return !is_login; - + + case STACK_TRACE: + { + parser_stack_trace( current_block, sb_out ); + break; + } + } return 0; @@ -2047,7 +2086,7 @@ static int builtin_fg( wchar_t **argv ) */ 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; } if( !j ) @@ -2098,6 +2137,17 @@ static int builtin_fg( wchar_t **argv ) pid ); 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 ) @@ -2150,6 +2200,16 @@ static int send_to_bg( job_t *j, const wchar_t *name ) builtin_print_help( L"bg", sb_err ); 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 { sb_printf( sb_err, @@ -2176,7 +2236,7 @@ static int builtin_bg( wchar_t **argv ) job_t *j; 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; } diff --git a/exec.c b/exec.c index 7ebbf2d6d..bb502a1d6 100644 --- a/exec.c +++ b/exec.c @@ -393,7 +393,7 @@ static int setup_child_process( job_t *j, process_t *p ) { int res; - if( j->terminal ) + if( j->job_control ) { 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 ) { - if( j->terminal ) + if( j->job_control ) { int new_pgid=0; @@ -636,18 +636,6 @@ static int handle_new_child( job_t *j, process_t *p ) 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 { diff --git a/parser.c b/parser.c index 372b9e110..673b58668 100644 --- a/parser.c +++ b/parser.c @@ -1031,7 +1031,7 @@ int eval_args( const wchar_t *line, array_list_t *args ) 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 ) return; @@ -1363,7 +1363,7 @@ static void parse_job_main_loop( process_t *p, case TOK_BACKGROUND: j->fg = 0; - j->terminal=0; + case TOK_END: { p->argv = list_to_char_arr( args ); @@ -2183,7 +2183,6 @@ static void eval_job( tokenizer *tok ) j->fg=1; j->constructed=0; j->skip_notification = is_subshell || is_block || is_event || (!is_interactive); - j->terminal = is_interactive && !is_subshell; current_block->job = j; diff --git a/parser.h b/parser.h index 9e8a65372..f8660ba83 100644 --- a/parser.h +++ b/parser.h @@ -348,5 +348,10 @@ int parser_is_help( wchar_t *s, int min_match ); */ 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 diff --git a/proc.c b/proc.c index ed20daf3e..366a3b5cc 100644 --- a/proc.c +++ b/proc.c @@ -83,6 +83,7 @@ int is_login=0; int is_event=0; int proc_had_barrier; pid_t proc_last_bg_pid = 0; +int job_control_mode = JOB_CONTROL_INTERACTIVE; /** The event variable used to send all process event @@ -229,6 +230,10 @@ job_t *job_create() res->next = first_job; res->job_id = free_id; 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 ) // fwprintf( stderr, L"Create job %d\n", res->job_id ); return res; @@ -875,37 +880,34 @@ void job_continue (job_t *j, int cont) if( !job_is_completed( j ) ) { - if( j->terminal ) - { - + if( j->job_control && j->fg ) + { + /* Put the job into the foreground. */ - if( j->fg ) + signal_block(); + if( tcsetpgrp (0, j->pgid) ) { - signal_block(); - 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; - } - - 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(); + debug( 1, + _( L"Could not send job %d ('%ls') to foreground" ), + j->job_id, + 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(); } /* @@ -1005,7 +1007,7 @@ void job_continue (job_t *j, int cont) /* Put the shell back in the foreground. */ - if( j->terminal ) + if( j->job_control && j->fg ) { signal_block(); if( tcsetpgrp (0, getpid()) ) diff --git a/proc.h b/proc.h index 1dc384a44..a0cba675e 100644 --- a/proc.h +++ b/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 @@ -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 */ int skip; - /** Whether this job wants to have control of the terminal when it is in the foreground */ - int terminal; - + /** Whether the job is under job control */ + int job_control; + /** Pointer to the next job */ struct job *next; } @@ -216,6 +223,11 @@ extern int proc_had_barrier; */ 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 */