From 97c456a986ca3b20fb7173c25cec6c1e37d2af08 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Thu, 30 Jan 2020 15:16:03 -0800 Subject: [PATCH] Improve support for job control in non-interactive scenarios Avoid complaining about ENOTTY results from tcsetpgrp, and ensure we ignore SIGTTOU the first time job control is enabled. --- src/proc.cpp | 21 ++++++++++++++++---- tests/checks/job-control-noninteractive.fish | 14 +++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/checks/job-control-noninteractive.fish diff --git a/src/proc.cpp b/src/proc.cpp index fda626234..151f56971 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -78,7 +78,19 @@ static relaxed_atomic_t job_control_mode{job_control_t::interacti job_control_t get_job_control_mode() { return job_control_mode; } -void set_job_control_mode(job_control_t mode) { job_control_mode = mode; } +void set_job_control_mode(job_control_t mode) { + job_control_mode = mode; + + // HACK: when fish (or any shell) launches a job with job control, it will put the job into its + // own pgroup and call tcsetpgrp() to allow that pgroup to own the terminal (making fish a + // background process). When the job finishes, fish will try to reclaim the terminal via + // tcsetpgrp(), but as fish is now a background process it will receive SIGTTOU and stop! Ensure + // that doesn't happen by ignoring SIGTTOU. + // Note that if we become interactive, we also ignore SIGTTOU. + if (mode == job_control_t::all) { + signal(SIGTTOU, SIG_IGN); + } +} void proc_init() { signal_set_handlers_once(false); } @@ -776,10 +788,11 @@ int terminal_maybe_give_to_job(const job_t *j, bool continuing_from_stopped) { } else { if (errno == ENOTTY) { redirect_tty_output(); + } else { + FLOGF(warning, _(L"Could not send job %d ('%ls') with pgid %d to foreground"), + j->job_id(), j->command_wcstr(), j->pgid); + wperror(L"tcsetpgrp"); } - FLOGF(warning, _(L"Could not send job %d ('%ls') with pgid %d to foreground"), - j->job_id(), j->command_wcstr(), j->pgid); - wperror(L"tcsetpgrp"); return error; } diff --git a/tests/checks/job-control-noninteractive.fish b/tests/checks/job-control-noninteractive.fish new file mode 100644 index 000000000..a19dd5738 --- /dev/null +++ b/tests/checks/job-control-noninteractive.fish @@ -0,0 +1,14 @@ +#RUN: env fth=%fish_test_helper %fish %s + +# Ensure job control works in non-interactive environments. + +status job-control full +/bin/echo hello +#CHECK: hello + +$fth print_pgrp | read first +$fth print_pgrp | read second +test $first -ne $second +and echo "pgroups differed, meaning job control worked" +or echo "pgroups were the same, job control did not work" +#CHECK: pgroups differed, meaning job control worked