1 // The library for various signal related issues.
2 #include "config.h"  // IWYU pragma: keep
3 
4 #include <errno.h>
5 #include <signal.h>
6 #include <stdio.h>
7 #ifdef HAVE_SIGINFO_H
8 #include <siginfo.h>
9 #endif
10 #include <pthread.h>
11 
12 #include "common.h"
13 #include "event.h"
14 #include "fallback.h"  // IWYU pragma: keep
15 #include "parser.h"
16 #include "proc.h"
17 #include "reader.h"
18 #include "signal.h"
19 #include "termsize.h"
20 #include "topic_monitor.h"
21 #include "wutil.h"  // IWYU pragma: keep
22 
23 /// Struct describing an entry for the lookup table used to convert between signal names and signal
24 /// ids, etc.
25 struct lookup_entry {
26     /// Signal id.
27     int signal;
28     /// Signal name.
29     const wchar_t *name;
30     /// Signal description.
31     const wchar_t *desc;
32 };
33 
34 /// Lookup table used to convert between signal names and signal ids, etc.
35 static const struct lookup_entry signal_table[] = {
36 #ifdef SIGHUP
37     {SIGHUP, L"SIGHUP", N_(L"Terminal hung up")},
38 #endif
39 #ifdef SIGINT
40     {SIGINT, L"SIGINT", N_(L"Quit request from job control (^C)")},
41 #endif
42 #ifdef SIGQUIT
43     {SIGQUIT, L"SIGQUIT", N_(L"Quit request from job control with core dump (^\\)")},
44 #endif
45 #ifdef SIGILL
46     {SIGILL, L"SIGILL", N_(L"Illegal instruction")},
47 #endif
48 #ifdef SIGTRAP
49     {SIGTRAP, L"SIGTRAP", N_(L"Trace or breakpoint trap")},
50 #endif
51 #ifdef SIGABRT
52     {SIGABRT, L"SIGABRT", N_(L"Abort")},
53 #endif
54 #ifdef SIGBUS
55     {SIGBUS, L"SIGBUS", N_(L"Misaligned address error")},
56 #endif
57 #ifdef SIGFPE
58     {SIGFPE, L"SIGFPE", N_(L"Floating point exception")},
59 #endif
60 #ifdef SIGKILL
61     {SIGKILL, L"SIGKILL", N_(L"Forced quit")},
62 #endif
63 #ifdef SIGUSR1
64     {SIGUSR1, L"SIGUSR1", N_(L"User defined signal 1")},
65 #endif
66 #ifdef SIGUSR2
67     {SIGUSR2, L"SIGUSR2", N_(L"User defined signal 2")},
68 #endif
69 #ifdef SIGSEGV
70     {SIGSEGV, L"SIGSEGV", N_(L"Address boundary error")},
71 #endif
72 #ifdef SIGPIPE
73     {SIGPIPE, L"SIGPIPE", N_(L"Broken pipe")},
74 #endif
75 #ifdef SIGALRM
76     {SIGALRM, L"SIGALRM", N_(L"Timer expired")},
77 #endif
78 #ifdef SIGTERM
79     {SIGTERM, L"SIGTERM", N_(L"Polite quit request")},
80 #endif
81 #ifdef SIGCHLD
82     {SIGCHLD, L"SIGCHLD", N_(L"Child process status changed")},
83 #endif
84 #ifdef SIGCONT
85     {SIGCONT, L"SIGCONT", N_(L"Continue previously stopped process")},
86 #endif
87 #ifdef SIGSTOP
88     {SIGSTOP, L"SIGSTOP", N_(L"Forced stop")},
89 #endif
90 #ifdef SIGTSTP
91     {SIGTSTP, L"SIGTSTP", N_(L"Stop request from job control (^Z)")},
92 #endif
93 #ifdef SIGTTIN
94     {SIGTTIN, L"SIGTTIN", N_(L"Stop from terminal input")},
95 #endif
96 #ifdef SIGTTOU
97     {SIGTTOU, L"SIGTTOU", N_(L"Stop from terminal output")},
98 #endif
99 #ifdef SIGURG
100     {SIGURG, L"SIGURG", N_(L"Urgent socket condition")},
101 #endif
102 #ifdef SIGXCPU
103     {SIGXCPU, L"SIGXCPU", N_(L"CPU time limit exceeded")},
104 #endif
105 #ifdef SIGXFSZ
106     {SIGXFSZ, L"SIGXFSZ", N_(L"File size limit exceeded")},
107 #endif
108 #ifdef SIGVTALRM
109     {SIGVTALRM, L"SIGVTALRM", N_(L"Virtual timer expired")},
110 #endif
111 #ifdef SIGPROF
112     {SIGPROF, L"SIGPROF", N_(L"Profiling timer expired")},
113 #endif
114 #ifdef SIGWINCH
115     {SIGWINCH, L"SIGWINCH", N_(L"Window size change")},
116 #endif
117 #ifdef SIGWIND
118     {SIGWIND, L"SIGWIND", N_(L"Window size change")},
119 #endif
120 #ifdef SIGIO
121     {SIGIO, L"SIGIO", N_(L"I/O on asynchronous file descriptor is possible")},
122 #endif
123 #ifdef SIGPWR
124     {SIGPWR, L"SIGPWR", N_(L"Power failure")},
125 #endif
126 #ifdef SIGSYS
127     {SIGSYS, L"SIGSYS", N_(L"Bad system call")},
128 #endif
129 #ifdef SIGINFO
130     {SIGINFO, L"SIGINFO", N_(L"Information request")},
131 #endif
132 #ifdef SIGSTKFLT
133     {SIGSTKFLT, L"SISTKFLT", N_(L"Stack fault")},
134 #endif
135 #ifdef SIGEMT
136     {SIGEMT, L"SIGEMT", N_(L"Emulator trap")},
137 #endif
138 #ifdef SIGIOT
139     {SIGIOT, L"SIGIOT", N_(L"Abort (Alias for SIGABRT)")},
140 #endif
141 #ifdef SIGUNUSED
142     {SIGUNUSED, L"SIGUNUSED", N_(L"Unused signal")},
143 #endif
144 };
145 
146 /// Test if \c name is a string describing the signal named \c canonical.
match_signal_name(const wchar_t * canonical,const wchar_t * name)147 static int match_signal_name(const wchar_t *canonical, const wchar_t *name) {
148     if (wcsncasecmp(name, L"sig", const_strlen("sig")) == 0) name += 3;
149 
150     return wcscasecmp(canonical + const_strlen("sig"), name) == 0;
151 }
152 
wcs2sig(const wchar_t * str)153 int wcs2sig(const wchar_t *str) {
154     for (const auto &data : signal_table) {
155         if (match_signal_name(data.name, str)) {
156             return data.signal;
157         }
158     }
159 
160     int res = fish_wcstoi(str);
161     if (errno || res < 0) return -1;
162     return res;
163 }
164 
sig2wcs(int sig)165 const wchar_t *sig2wcs(int sig) {
166     for (const auto &data : signal_table) {
167         if (data.signal == sig) {
168             return data.name;
169         }
170     }
171 
172     return _(L"Unknown");
173 }
174 
signal_get_desc(int sig)175 const wchar_t *signal_get_desc(int sig) {
176     for (const auto &data : signal_table) {
177         if (data.signal == sig) {
178             return _(data.desc);
179         }
180     }
181 
182     return _(L"Unknown");
183 }
184 
185 /// Store the "main" pid. This allows us to reliably determine if we are in a forked child.
186 static const pid_t s_main_pid = getpid();
187 
188 /// It's possible that we receive a signal after we have forked, but before we have reset the signal
189 /// handlers (or even run the pthread_atfork calls). In that event we will do something dumb like
190 /// swallow SIGINT. Ensure that doesn't happen. Check if we are the main fish process; if not, reset
191 /// and re-raise the signal. \return whether we re-raised the signal.
reraise_if_forked_child(int sig)192 static bool reraise_if_forked_child(int sig) {
193     // Don't use is_forked_child: it relies on atfork handlers which may have not yet run.
194     if (getpid() == s_main_pid) {
195         return false;
196     }
197     signal(sig, SIG_DFL);
198     raise(sig);
199     return true;
200 }
201 
202 /// The cancellation signal we have received.
203 /// Of course this is modified from a signal handler.
204 static volatile relaxed_atomic_t<sig_atomic_t> s_cancellation_signal{0};
205 
signal_clear_cancel()206 void signal_clear_cancel() { s_cancellation_signal = 0; }
207 
signal_check_cancel()208 int signal_check_cancel() { return s_cancellation_signal; }
209 
210 /// The single signal handler. By centralizing signal handling we ensure that we can never install
211 /// the "wrong" signal handler (see #5969).
fish_signal_handler(int sig,siginfo_t * info,void * context)212 static void fish_signal_handler(int sig, siginfo_t *info, void *context) {
213     UNUSED(info);
214     UNUSED(context);
215 
216     // Ensure we preserve errno.
217     const int saved_errno = errno;
218 
219     // Check if we are a forked child.
220     if (reraise_if_forked_child(sig)) {
221         errno = saved_errno;
222         return;
223     }
224 
225     // Check if fish script cares about this.
226     const bool observed = event_is_signal_observed(sig);
227     if (observed) {
228         event_enqueue_signal(sig);
229     }
230 
231     // Do some signal-specific stuff.
232     switch (sig) {
233 #ifdef SIGWINCH
234         case SIGWINCH:
235             /// Respond to a winch signal by telling the termsize container.
236             termsize_container_t::handle_winch();
237             break;
238 #endif
239 
240         case SIGHUP:
241             /// Respond to a hup signal by exiting, unless it is caught by a shellscript function,
242             /// in which case we do nothing.
243             if (!observed) {
244                 reader_sighup();
245             }
246             topic_monitor_t::principal().post(topic_t::sighupint);
247             break;
248 
249         case SIGTERM:
250             /// Handle sigterm. The only thing we do is restore the front process ID, then die.
251             restore_term_foreground_process_group_for_exit();
252             signal(SIGTERM, SIG_DFL);
253             raise(SIGTERM);
254             break;
255 
256         case SIGINT:
257             /// Interactive mode ^C handler. Respond to int signal by setting interrupted-flag and
258             /// stopping all loops and conditionals.
259             s_cancellation_signal = SIGINT;
260             reader_handle_sigint();
261             topic_monitor_t::principal().post(topic_t::sighupint);
262             break;
263 
264         case SIGCHLD:
265             // A child process stopped or exited.
266             topic_monitor_t::principal().post(topic_t::sigchld);
267             break;
268 
269         case SIGALRM:
270             // We have a sigalarm handler that does nothing. This is used in the signal torture
271             // test, to verify that we behave correctly when receiving lots of irrelevant signals.
272             break;
273     }
274     errno = saved_errno;
275 }
276 
signal_reset_handlers()277 void signal_reset_handlers() {
278     struct sigaction act;
279     sigemptyset(&act.sa_mask);
280     act.sa_flags = 0;
281     act.sa_handler = SIG_DFL;
282 
283     for (const auto &data : signal_table) {
284         if (data.signal == SIGHUP) {
285             struct sigaction oact;
286             sigaction(SIGHUP, nullptr, &oact);
287             if (oact.sa_handler == SIG_IGN) continue;
288         }
289         sigaction(data.signal, &act, nullptr);
290     }
291 }
292 
set_interactive_handlers()293 static void set_interactive_handlers() {
294     struct sigaction act, oact;
295     act.sa_flags = 0;
296     oact.sa_flags = 0;
297     sigemptyset(&act.sa_mask);
298 
299     // Interactive mode. Ignore interactive signals.  We are a shell, we know what is best for
300     // the user.
301     act.sa_handler = SIG_IGN;
302     sigaction(SIGTSTP, &act, nullptr);
303     sigaction(SIGTTOU, &act, nullptr);
304 
305     // We don't ignore SIGTTIN because we might send it to ourself.
306     act.sa_sigaction = &fish_signal_handler;
307     act.sa_flags = SA_SIGINFO;
308     sigaction(SIGTTIN, &act, nullptr);
309 
310     // SIGTERM restores the terminal controlling process before dying.
311     act.sa_sigaction = &fish_signal_handler;
312     act.sa_flags = SA_SIGINFO;
313     sigaction(SIGTERM, &act, nullptr);
314 
315     sigaction(SIGHUP, nullptr, &oact);
316     if (oact.sa_handler == SIG_DFL) {
317         act.sa_sigaction = &fish_signal_handler;
318         act.sa_flags = SA_SIGINFO;
319         sigaction(SIGHUP, &act, nullptr);
320     }
321 
322     // SIGALARM as part of our signal torture test
323     act.sa_sigaction = &fish_signal_handler;
324     act.sa_flags = SA_SIGINFO;
325     sigaction(SIGALRM, &act, nullptr);
326 
327 #ifdef SIGWINCH
328     act.sa_sigaction = &fish_signal_handler;
329     act.sa_flags = SA_SIGINFO;
330     sigaction(SIGWINCH, &act, nullptr);
331 #endif
332 }
333 
334 /// Sets up appropriate signal handlers.
signal_set_handlers(bool interactive)335 void signal_set_handlers(bool interactive) {
336     struct sigaction act;
337     act.sa_flags = 0;
338     sigemptyset(&act.sa_mask);
339 
340     // Ignore SIGPIPE. We'll detect failed writes and deal with them appropriately. We don't want
341     // this signal interrupting other syscalls or terminating us.
342     act.sa_sigaction = nullptr;
343     act.sa_handler = SIG_IGN;
344     sigaction(SIGPIPE, &act, nullptr);
345 
346     // Ignore SIGQUIT.
347     act.sa_handler = SIG_IGN;
348     sigaction(SIGQUIT, &act, nullptr);
349 
350     // Apply our SIGINT handler.
351     act.sa_sigaction = &fish_signal_handler;
352     act.sa_flags = SA_SIGINFO;
353     sigaction(SIGINT, &act, nullptr);
354 
355     // Whether or not we're interactive we want SIGCHLD to not interrupt restartable syscalls.
356     act.sa_sigaction = &fish_signal_handler;
357     act.sa_flags = SA_SIGINFO | SA_RESTART;
358     if (sigaction(SIGCHLD, &act, nullptr)) {
359         wperror(L"sigaction");
360         FATAL_EXIT();
361     }
362 
363     if (interactive) {
364         set_interactive_handlers();
365     }
366 }
367 
signal_set_handlers_once(bool interactive)368 void signal_set_handlers_once(bool interactive) {
369     static std::once_flag s_noninter_once;
370     std::call_once(s_noninter_once, signal_set_handlers, false);
371 
372     static std::once_flag s_inter_once;
373     if (interactive) std::call_once(s_inter_once, set_interactive_handlers);
374 }
375 
signal_handle(int sig)376 void signal_handle(int sig) {
377     struct sigaction act;
378 
379     // These should always be handled.
380     if ((sig == SIGINT) || (sig == SIGQUIT) || (sig == SIGTSTP) || (sig == SIGTTIN) ||
381         (sig == SIGTTOU) || (sig == SIGCHLD))
382         return;
383 
384     act.sa_flags = 0;
385     sigemptyset(&act.sa_mask);
386     act.sa_flags = SA_SIGINFO;
387     act.sa_sigaction = &fish_signal_handler;
388     sigaction(sig, &act, nullptr);
389 }
390 
get_signals_with_handlers(sigset_t * set)391 void get_signals_with_handlers(sigset_t *set) {
392     sigemptyset(set);
393     for (const auto &data : signal_table) {
394         struct sigaction act = {};
395         sigaction(data.signal, nullptr, &act);
396         // If SIGHUP is being ignored (e.g., because were were run via `nohup`) don't reset it.
397         // We don't special case other signals because if they're being ignored that shouldn't
398         // affect processes we spawn. They should get the default behavior for those signals.
399         if (data.signal == SIGHUP && act.sa_handler == SIG_IGN) continue;
400         if (act.sa_handler != SIG_DFL) sigaddset(set, data.signal);
401     }
402 }
403 
404 /// Ensure we did not inherit any blocked signals. See issue #3964.
signal_unblock_all()405 void signal_unblock_all() {
406     sigset_t iset;
407     sigemptyset(&iset);
408     sigprocmask(SIG_SETMASK, &iset, nullptr);
409 }
410 
sigchecker_t(topic_t signal)411 sigchecker_t::sigchecker_t(topic_t signal) : topic_(signal) {
412     // Call check() to update our generation.
413     check();
414 }
415 
check()416 bool sigchecker_t::check() {
417     auto &tm = topic_monitor_t::principal();
418     generation_t gen = tm.generation_for_topic(topic_);
419     bool changed = this->gen_ != gen;
420     this->gen_ = gen;
421     return changed;
422 }
423 
wait() const424 void sigchecker_t::wait() const {
425     auto &tm = topic_monitor_t::principal();
426     generation_list_t gens = generation_list_t::invalids();
427     gens.at(topic_) = this->gen_;
428     tm.check(&gens, true /* wait */);
429 }
430