diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f94220fe..e4e1f191e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Notable improvements and fixes - `fish --no-execute` will no longer complain about unknown commands or non-matching wildcards, as these could be defined differently at runtime (especially for functions). #977 - `jobs --quiet PID` will no longer print 'no suitable job' if the job for PID does not exist (e.g. because it has finished). #6809 +- A variable `fish_kill_signal` will be set to the signal that terminated the last command, or `0` if the command exited normally. ### Syntax changes and new commands diff --git a/doc_src/index.rst b/doc_src/index.rst index 4a41db5cc..14150e904 100644 --- a/doc_src/index.rst +++ b/doc_src/index.rst @@ -1059,6 +1059,8 @@ The user can change the settings of ``fish`` by changing the values of certain v - ``pipestatus``, a list of exit statuses of all processes that made up the last executed pipe. +- ``fish_kill_signal``, the signal that terminated the previous command, or `0` if the command exited normally. + - ``USER``, the current username. This variable can be changed by the user. - ``CMD_DURATION``, the runtime of the last command in milliseconds. diff --git a/src/env.cpp b/src/env.cpp index 7ed5426b2..cdefd3161 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -93,6 +93,7 @@ static const electric_var_t electric_variables[] = { {L"_", electric_var_t::freadonly}, {L"fish_private_mode", electric_var_t::freadonly}, {L"umask", electric_var_t::fcomputed}, + {L"fish_kill_signal", electric_var_t::freadonly | electric_var_t::fcomputed}, }; const electric_var_t *electric_var_t::for_name(const wcstring &name) { @@ -685,6 +686,9 @@ maybe_t env_scoped_impl_t::try_get_computed(const wcstring &key) cons } else if (key == L"status") { const auto &js = perproc_data().statuses; return env_var_t(L"status", to_string(js.status)); + } else if (key == L"fish_kill_signal") { + const auto &js = perproc_data().statuses; + return env_var_t(L"fish_kill_signal", to_string(js.kill_signal)); } else if (key == L"umask") { // note umask() is an absurd API: you call it to set the value and it returns the old // value. Thus we have to call it twice, to reset the value. The env_lock protects diff --git a/src/env.h b/src/env.h index 4b0b6421f..273ce9c5c 100644 --- a/src/env.h +++ b/src/env.h @@ -63,6 +63,10 @@ struct statuses_t { /// Status of the last job to exit. int status{0}; + /// Signal from the most recent process in the last job that was terminated by a signal. + /// 0 if all processes exited normally. + int kill_signal{0}; + /// Pipestatus value. std::vector pipestatus{}; diff --git a/src/proc.cpp b/src/proc.cpp index 18785ba03..1bd91739c 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -187,7 +187,11 @@ statuses_t job_t::get_statuses() const { statuses_t st{}; st.pipestatus.reserve(processes.size()); for (const auto &p : processes) { - st.pipestatus.push_back(p->status.status_value()); + auto status = p->status; + if (status.signal_exited()) { + st.kill_signal = status.signal_code(); + } + st.pipestatus.push_back(status.status_value()); } int laststatus = st.pipestatus.back(); st.status = flags().negate ? !laststatus : laststatus; diff --git a/tests/signals.expect b/tests/signals.expect index 1cfc44f06..c7c632c12 100644 --- a/tests/signals.expect +++ b/tests/signals.expect @@ -12,6 +12,22 @@ send_line read expect -re "\\r\\n?read> $" exec -- kill -INT $pid expect "fish_postexec spotted" +expect_prompt + +# Verify that the fish_kill_signal is set. +send_line "functions -e postexec; function postexec --on-event fish_postexec; echo fish_kill_signal \$fish_kill_signal; end" +expect_prompt +send_line "sleep 5" +sleep 0.100 +exec -- pkill -INT sleep -P $pid +expect "fish_kill_signal 2" +expect_prompt + +send_line "sleep 5" +sleep 0.100 +exec -- pkill -TERM sleep -P $pid +expect "fish_kill_signal 15" +expect_prompt # Verify that sending SIGHUP to the shell, such as will happen when the tty is # closed by the terminal, terminates the shell and the foreground command and