1 // Functions for handling event triggers.
2 #include "config.h" // IWYU pragma: keep
3
4 #include "event.h"
5
6 #include <signal.h>
7 #include <stddef.h>
8 #include <unistd.h>
9
10 #include <algorithm>
11 #include <atomic>
12 #include <functional>
13 #include <memory>
14 #include <string>
15 #include <type_traits>
16
17 #include "common.h"
18 #include "fallback.h" // IWYU pragma: keep
19 #include "input_common.h"
20 #include "io.h"
21 #include "parser.h"
22 #include "proc.h"
23 #include "signal.h"
24 #include "termsize.h"
25 #include "wcstringutil.h"
26 #include "wutil.h" // IWYU pragma: keep
27
28 class pending_signals_t {
29 static constexpr size_t SIGNAL_COUNT = NSIG;
30
31 /// A counter that is incremented each time a pending signal is received.
32 std::atomic<uint32_t> counter_{0};
33
34 /// List of pending signals.
35 std::array<std::atomic<bool>, SIGNAL_COUNT> received_{};
36
37 /// The last counter visible in acquire_pending().
38 /// This is not accessed from a signal handler.
39 owning_lock<uint32_t> last_counter_{0};
40
41 public:
42 pending_signals_t() = default;
43
44 /// No copying.
45 pending_signals_t(const pending_signals_t &);
46 void operator=(const pending_signals_t &);
47
48 /// Mark a signal as pending. This may be called from a signal handler.
49 /// We expect only one signal handler to execute at once.
50 /// Also note that these may be coalesced.
mark(int which)51 void mark(int which) {
52 if (which >= 0 && static_cast<size_t>(which) < received_.size()) {
53 // Must mark our received first, then pending.
54 received_[which].store(true, std::memory_order_relaxed);
55 uint32_t count = counter_.load(std::memory_order_relaxed);
56 counter_.store(1 + count, std::memory_order_release);
57 }
58 }
59
60 /// \return the list of signals that were set, clearing them.
acquire_pending()61 std::bitset<SIGNAL_COUNT> acquire_pending() {
62 auto current = last_counter_.acquire();
63
64 // Check the counter first. If it hasn't changed, no signals have been received.
65 uint32_t count = counter_.load(std::memory_order_acquire);
66 if (count == *current) {
67 return {};
68 }
69
70 // The signal count has changed. Store the new counter and fetch all the signals that are
71 // set.
72 *current = count;
73 std::bitset<SIGNAL_COUNT> result{};
74 uint32_t bit = 0;
75 for (auto &signal : received_) {
76 bool val = signal.load(std::memory_order_relaxed);
77 if (val) {
78 result.set(bit);
79 signal.store(false, std::memory_order_relaxed);
80 }
81 bit++;
82 }
83 return result;
84 }
85 };
86
87 static pending_signals_t s_pending_signals;
88
89 /// List of event handlers.
90 static owning_lock<event_handler_list_t> s_event_handlers;
91
92 /// Variables (one per signal) set when a signal is observed. This is inspected by a signal handler.
93 static volatile sig_atomic_t s_observed_signals[NSIG] = {};
94
set_signal_observed(int sig,bool val)95 static void set_signal_observed(int sig, bool val) {
96 if (sig >= 0 &&
97 static_cast<size_t>(sig) < sizeof s_observed_signals / sizeof *s_observed_signals) {
98 s_observed_signals[sig] = val;
99 }
100 }
101
102 /// Tests if one event instance matches the definition of an event class.
103 /// In case of a match, \p only_once indicates that the event cannot match again by nature.
handler_matches(const event_handler_t & classv,const event_t & instance,bool & only_once)104 static bool handler_matches(const event_handler_t &classv, const event_t &instance,
105 bool &only_once) {
106 only_once = false;
107 if (classv.desc.type == event_type_t::any) return true;
108 if (classv.desc.type != instance.desc.type) return false;
109
110 switch (classv.desc.type) {
111 case event_type_t::signal: {
112 return classv.desc.param1.signal == instance.desc.param1.signal;
113 }
114 case event_type_t::variable: {
115 return instance.desc.str_param1 == classv.desc.str_param1;
116 }
117 case event_type_t::process_exit: {
118 if (classv.desc.param1.pid == EVENT_ANY_PID) return true;
119 only_once = true;
120 return classv.desc.param1.pid == instance.desc.param1.pid;
121 }
122 case event_type_t::job_exit: {
123 const auto &jobspec = classv.desc.param1.jobspec;
124 if (jobspec.pid == EVENT_ANY_PID) return true;
125 only_once = true;
126 return jobspec.internal_job_id == instance.desc.param1.jobspec.internal_job_id;
127 }
128 case event_type_t::caller_exit: {
129 only_once = true;
130 return classv.desc.param1.caller_id == instance.desc.param1.caller_id;
131 }
132 case event_type_t::generic: {
133 return classv.desc.str_param1 == instance.desc.str_param1;
134 }
135 case event_type_t::any:
136 default: {
137 DIE("unexpected classv.type");
138 return false;
139 }
140 }
141 }
142
143 /// Test if specified event is blocked.
event_is_blocked(parser_t & parser,const event_t & e)144 static int event_is_blocked(parser_t &parser, const event_t &e) {
145 (void)e;
146 const block_t *block;
147 size_t idx = 0;
148 while ((block = parser.block_at_index(idx++))) {
149 if (event_block_list_blocks_type(block->event_blocks)) return true;
150 }
151 return event_block_list_blocks_type(parser.global_event_blocks);
152 }
153
event_get_desc(const parser_t & parser,const event_t & evt)154 wcstring event_get_desc(const parser_t &parser, const event_t &evt) {
155 const event_description_t &ed = evt.desc;
156 switch (ed.type) {
157 case event_type_t::signal: {
158 return format_string(_(L"signal handler for %ls (%ls)"), sig2wcs(ed.param1.signal),
159 signal_get_desc(ed.param1.signal));
160 }
161
162 case event_type_t::variable: {
163 return format_string(_(L"handler for variable '%ls'"), ed.str_param1.c_str());
164 }
165
166 case event_type_t::process_exit: {
167 return format_string(_(L"exit handler for process %d"), ed.param1.pid);
168 }
169
170 case event_type_t::job_exit: {
171 const auto &jobspec = ed.param1.jobspec;
172 if (const job_t *j = parser.job_get_from_pid(jobspec.pid)) {
173 return format_string(_(L"exit handler for job %d, '%ls'"), j->job_id(),
174 j->command_wcstr());
175 } else {
176 return format_string(_(L"exit handler for job with pid %d"), jobspec.pid);
177 }
178 }
179
180 case event_type_t::caller_exit: {
181 return _(L"exit handler for command substitution caller");
182 }
183
184 case event_type_t::generic: {
185 return format_string(_(L"handler for generic event '%ls'"), ed.str_param1.c_str());
186 }
187 case event_type_t::any: {
188 DIE("Unreachable");
189 }
190 default:
191 DIE("Unknown event type");
192 }
193 }
194
event_add_handler(std::shared_ptr<event_handler_t> eh)195 void event_add_handler(std::shared_ptr<event_handler_t> eh) {
196 if (eh->desc.type == event_type_t::signal) {
197 signal_handle(eh->desc.param1.signal);
198 set_signal_observed(eh->desc.param1.signal, true);
199 }
200
201 s_event_handlers.acquire()->push_back(std::move(eh));
202 }
203
event_remove_function_handlers(const wcstring & name)204 void event_remove_function_handlers(const wcstring &name) {
205 auto handlers = s_event_handlers.acquire();
206 auto begin = handlers->begin(), end = handlers->end();
207 handlers->erase(std::remove_if(begin, end,
208 [&](const shared_ptr<event_handler_t> &eh) {
209 return eh->function_name == name;
210 }),
211 end);
212 }
213
event_get_function_handlers(const wcstring & name)214 event_handler_list_t event_get_function_handlers(const wcstring &name) {
215 auto handlers = s_event_handlers.acquire();
216 event_handler_list_t result;
217 for (const shared_ptr<event_handler_t> &eh : *handlers) {
218 if (eh->function_name == name) {
219 result.push_back(eh);
220 }
221 }
222 return result;
223 }
224
event_is_signal_observed(int sig)225 bool event_is_signal_observed(int sig) {
226 // We are in a signal handler! Don't allocate memory, etc.
227 bool result = false;
228 if (sig >= 0 && static_cast<unsigned long>(sig) <
229 sizeof(s_observed_signals) / sizeof(*s_observed_signals)) {
230 result = s_observed_signals[sig];
231 }
232 return result;
233 }
234
235 /// Perform the specified event. Since almost all event firings will not be matched by even a single
236 /// event handler, we make sure to optimize the 'no matches' path. This means that nothing is
237 /// allocated/initialized unless needed.
event_fire_internal(parser_t & parser,const event_t & event)238 static void event_fire_internal(parser_t &parser, const event_t &event) {
239 auto &ld = parser.libdata();
240 assert(ld.is_event >= 0 && "is_event should not be negative");
241 scoped_push<decltype(ld.is_event)> inc_event{&ld.is_event, ld.is_event + 1};
242
243 // Suppress fish_trace during events.
244 scoped_push<bool> suppress_trace{&ld.suppress_fish_trace, true};
245
246 // Capture the event handlers that match this event.
247 struct firing_handler_t {
248 std::shared_ptr<event_handler_t> handler;
249 bool delete_after_call;
250 };
251 std::vector<firing_handler_t> fire;
252 {
253 for (const auto &handler : *s_event_handlers.acquire()) {
254 // Check if this event is a match.
255 bool only_once = false;
256 if (!handler_matches(*handler, event, only_once)) {
257 continue;
258 }
259
260 // If the nature of the event means it can't be fired more than once, deregister the
261 // event. This also works around a bug where jobs run without job control (no separate
262 // pgrp) cause handlers to run for each subsequent job started without job control
263 // (#7721). We can't erase it here because we check if the event is still extant before
264 // actually calling it below, so we instead push it along with its "delete after
265 // calling" value.
266 fire.push_back(firing_handler_t{handler, only_once});
267 }
268 }
269
270 // Iterate over our list of matching events. Fire the ones that are still present.
271 for (const auto &firing_event : fire) {
272 auto &handler = firing_event.handler;
273 // Only fire if this event is still present.
274 // TODO: this is kind of crazy. We want to support removing (and thereby suppressing) an
275 // event handler from another, but we also don't want to hold the lock across callouts. How
276 // can we make this less silly?
277 {
278 auto event_handlers = s_event_handlers.acquire();
279 if (!contains(*event_handlers, handler)) {
280 continue;
281 }
282
283 // Delete the event before firing it so we don't have to lock and unlock the event
284 // handlers list when handing control off to the handler.
285 if (firing_event.delete_after_call) {
286 FLOGF(event, L"Pruning handler '%ls' before firing", event.desc.str_param1.c_str());
287 for (auto event_handler = event_handlers->begin();
288 event_handler != event_handlers->end(); ++event_handler) {
289 if (event_handler->get() == firing_event.handler.get()) {
290 event_handlers->erase(event_handler);
291 break;
292 }
293 }
294 }
295 }
296
297 // Construct a buffer to evaluate, starting with the function name and then all the
298 // arguments.
299 wcstring buffer = handler->function_name;
300 for (const wcstring &arg : event.arguments) {
301 buffer.push_back(L' ');
302 buffer.append(escape_string(arg, ESCAPE_ALL));
303 }
304
305 // Event handlers are not part of the main flow of code, so they are marked as
306 // non-interactive.
307 scoped_push<bool> interactive{&ld.is_interactive, false};
308 auto prev_statuses = parser.get_last_statuses();
309
310 FLOGF(event, L"Firing event '%ls'", event.desc.str_param1.c_str());
311 block_t *b = parser.push_block(block_t::event_block(event));
312 parser.eval(buffer, io_chain_t());
313 parser.pop_block(b);
314 parser.set_last_statuses(std::move(prev_statuses));
315 }
316 }
317
318 /// Handle all pending signal events.
event_fire_delayed(parser_t & parser)319 void event_fire_delayed(parser_t &parser) {
320 auto &ld = parser.libdata();
321 // Do not invoke new event handlers from within event handlers.
322 if (ld.is_event) return;
323 // Do not invoke new event handlers if we are unwinding (#6649).
324 if (signal_check_cancel()) return;
325
326 std::vector<shared_ptr<const event_t>> to_send;
327 to_send.swap(ld.blocked_events);
328 assert(ld.blocked_events.empty());
329
330 // Append all signal events to to_send.
331 auto signals = s_pending_signals.acquire_pending();
332 if (signals.any()) {
333 for (uint32_t sig = 0; sig < signals.size(); sig++) {
334 if (signals.test(sig)) {
335 // HACK: The only variables we change in response to a *signal*
336 // are $COLUMNS and $LINES.
337 // Do that now.
338 if (sig == SIGWINCH) {
339 (void)termsize_container_t::shared().updating(parser);
340 }
341 auto e = std::make_shared<event_t>(event_type_t::signal);
342 e->desc.param1.signal = sig;
343 e->arguments.push_back(sig2wcs(sig));
344 to_send.push_back(std::move(e));
345 }
346 }
347 }
348
349 // Fire or re-block all events.
350 for (const auto &evt : to_send) {
351 if (event_is_blocked(parser, *evt)) {
352 ld.blocked_events.push_back(evt);
353 } else {
354 event_fire_internal(parser, *evt);
355 }
356 }
357 }
358
event_enqueue_signal(int signal)359 void event_enqueue_signal(int signal) {
360 // Beware, we are in a signal handler
361 s_pending_signals.mark(signal);
362 }
363
event_fire(parser_t & parser,const event_t & event)364 void event_fire(parser_t &parser, const event_t &event) {
365 // Fire events triggered by signals.
366 event_fire_delayed(parser);
367
368 if (event_is_blocked(parser, event)) {
369 parser.libdata().blocked_events.push_back(std::make_shared<event_t>(event));
370 } else {
371 event_fire_internal(parser, event);
372 }
373 }
374
event_name_for_type(event_type_t type)375 static const wchar_t *event_name_for_type(event_type_t type) {
376 switch (type) {
377 case event_type_t::any:
378 return L"any";
379 case event_type_t::signal:
380 return L"signal";
381 case event_type_t::variable:
382 return L"variable";
383 case event_type_t::process_exit:
384 return L"process-exit";
385 case event_type_t::job_exit:
386 return L"job-exit";
387 case event_type_t::caller_exit:
388 return L"caller-exit";
389 case event_type_t::generic:
390 return L"generic";
391 }
392 return L"";
393 }
394
395 const wchar_t *const event_filter_names[] = {L"signal", L"variable", L"exit",
396 L"process-exit", L"job-exit", L"caller-exit",
397 L"generic", nullptr};
398
filter_matches_event(const wcstring & filter,event_type_t type)399 static bool filter_matches_event(const wcstring &filter, event_type_t type) {
400 if (filter.empty()) return true;
401 switch (type) {
402 case event_type_t::any:
403 return false;
404 case event_type_t::signal:
405 return filter == L"signal";
406 case event_type_t::variable:
407 return filter == L"variable";
408 case event_type_t::process_exit:
409 return filter == L"process-exit" || filter == L"exit";
410 case event_type_t::job_exit:
411 return filter == L"job-exit" || filter == L"exit";
412 case event_type_t::caller_exit:
413 return filter == L"process-exit" || filter == L"exit";
414 case event_type_t::generic:
415 return filter == L"generic";
416 }
417 DIE("Unreachable");
418 }
419
event_print(io_streams_t & streams,const wcstring & type_filter)420 void event_print(io_streams_t &streams, const wcstring &type_filter) {
421 event_handler_list_t tmp = *s_event_handlers.acquire();
422 std::sort(tmp.begin(), tmp.end(),
423 [](const shared_ptr<event_handler_t> &e1, const shared_ptr<event_handler_t> &e2) {
424 const event_description_t &d1 = e1->desc;
425 const event_description_t &d2 = e2->desc;
426 if (d1.type != d2.type) {
427 return d1.type < d2.type;
428 }
429 switch (d1.type) {
430 case event_type_t::signal:
431 return d1.param1.signal < d2.param1.signal;
432 case event_type_t::process_exit:
433 return d1.param1.pid < d2.param1.pid;
434 case event_type_t::job_exit:
435 return d1.param1.jobspec.pid < d2.param1.jobspec.pid;
436 case event_type_t::caller_exit:
437 return d1.param1.caller_id < d2.param1.caller_id;
438 case event_type_t::variable:
439 case event_type_t::any:
440 case event_type_t::generic:
441 return d1.str_param1 < d2.str_param1;
442 }
443 DIE("Unreachable");
444 });
445
446 maybe_t<event_type_t> last_type{};
447 for (const shared_ptr<event_handler_t> &evt : tmp) {
448 // If we have a filter, skip events that don't match.
449 if (!filter_matches_event(type_filter, evt->desc.type)) {
450 continue;
451 }
452
453 if (!last_type || *last_type != evt->desc.type) {
454 if (last_type) streams.out.append(L"\n");
455 last_type = evt->desc.type;
456 streams.out.append_format(L"Event %ls\n", event_name_for_type(*last_type));
457 }
458 switch (evt->desc.type) {
459 case event_type_t::signal:
460 streams.out.append_format(L"%ls %ls\n", sig2wcs(evt->desc.param1.signal),
461 evt->function_name.c_str());
462 break;
463 case event_type_t::process_exit:
464 case event_type_t::job_exit:
465 break;
466 case event_type_t::caller_exit:
467 streams.out.append_format(L"caller-exit %ls\n", evt->function_name.c_str());
468 break;
469 case event_type_t::variable:
470 case event_type_t::generic:
471 streams.out.append_format(L"%ls %ls\n", evt->desc.str_param1.c_str(),
472 evt->function_name.c_str());
473 break;
474 case event_type_t::any:
475 DIE("Unreachable");
476 default:
477 streams.out.append_format(L"%ls\n", evt->function_name.c_str());
478 break;
479 }
480 }
481 }
482
event_fire_generic(parser_t & parser,const wchar_t * name,const wcstring_list_t * args)483 void event_fire_generic(parser_t &parser, const wchar_t *name, const wcstring_list_t *args) {
484 assert(name && "Null name");
485
486 event_t ev(event_type_t::generic);
487 ev.desc.str_param1 = name;
488 if (args) ev.arguments = *args;
489 event_fire(parser, ev);
490 }
491
signal(int sig)492 event_description_t event_description_t::signal(int sig) {
493 event_description_t event(event_type_t::signal);
494 event.param1.signal = sig;
495 return event;
496 }
497
variable(wcstring str)498 event_description_t event_description_t::variable(wcstring str) {
499 event_description_t event(event_type_t::variable);
500 event.str_param1 = std::move(str);
501 return event;
502 }
503
generic(wcstring str)504 event_description_t event_description_t::generic(wcstring str) {
505 event_description_t event(event_type_t::generic);
506 event.str_param1 = std::move(str);
507 return event;
508 }
509
510 // static
variable(wcstring name,wcstring_list_t args)511 event_t event_t::variable(wcstring name, wcstring_list_t args) {
512 event_t evt{event_type_t::variable};
513 evt.desc.str_param1 = std::move(name);
514 evt.arguments = std::move(args);
515 return evt;
516 }
517
518 // static
process_exit(pid_t pid,int status)519 event_t event_t::process_exit(pid_t pid, int status) {
520 event_t evt{event_type_t::process_exit};
521 evt.desc.param1.pid = pid;
522 evt.arguments.reserve(3);
523 evt.arguments.push_back(L"PROCESS_EXIT");
524 evt.arguments.push_back(to_string(pid));
525 evt.arguments.push_back(to_string(status));
526 return evt;
527 }
528
529 // static
job_exit(pid_t pid,internal_job_id_t jid)530 event_t event_t::job_exit(pid_t pid, internal_job_id_t jid) {
531 event_t evt{event_type_t::job_exit};
532 evt.desc.param1.jobspec = {pid, jid};
533 evt.arguments.reserve(3);
534 evt.arguments.push_back(L"JOB_EXIT");
535 evt.arguments.push_back(to_string(pid));
536 evt.arguments.push_back(L"0"); // historical
537 return evt;
538 }
539
540 // static
caller_exit(uint64_t caller_id,int job_id)541 event_t event_t::caller_exit(uint64_t caller_id, int job_id) {
542 event_t evt{event_type_t::caller_exit};
543 evt.desc.param1.caller_id = caller_id;
544 evt.arguments.reserve(3);
545 evt.arguments.push_back(L"JOB_EXIT");
546 evt.arguments.push_back(to_string(job_id));
547 evt.arguments.push_back(L"0"); // historical
548 return evt;
549 }
550