Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/lib/util/event.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2013-2018 Todd C. Miller <[email protected]>
5
*
6
* Permission to use, copy, modify, and distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*/
18
19
#include <config.h>
20
21
#include <sys/types.h>
22
#include <sys/time.h>
23
#include <stdio.h>
24
#include <stdlib.h>
25
#ifdef HAVE_STDBOOL_H
26
# include <stdbool.h>
27
#else
28
# include <compat/stdbool.h>
29
#endif /* HAVE_STDBOOL_H */
30
#include <string.h>
31
#include <errno.h>
32
#include <fcntl.h>
33
#include <time.h>
34
#include <unistd.h>
35
36
#include <sudo_compat.h>
37
#include <sudo_fatal.h>
38
#include <sudo_debug.h>
39
#include <sudo_event.h>
40
#include <sudo_util.h>
41
42
static void sudo_ev_init(struct sudo_event *ev, int fd, int events,
43
sudo_ev_callback_t callback, void *closure);
44
45
/* Default event base when none is specified. */
46
static struct sudo_event_base *default_base;
47
48
/* We need the event base to be available from the signal handler. */
49
static struct sudo_event_base *signal_base;
50
51
/*
52
* Add an event to the base's active queue and mark it active.
53
* This is extern so sudo_ev_scan_impl() can call it.
54
*/
55
void
56
sudo_ev_activate(struct sudo_event_base *base, struct sudo_event *ev)
57
{
58
TAILQ_INSERT_TAIL(&base->active, ev, active_entries);
59
SET(ev->flags, SUDO_EVQ_ACTIVE);
60
}
61
62
/*
63
* Remove an event from the base's active queue and mark it inactive.
64
*/
65
static inline void
66
sudo_ev_deactivate(struct sudo_event_base *base, struct sudo_event *ev)
67
{
68
CLR(ev->flags, SUDO_EVQ_ACTIVE);
69
TAILQ_REMOVE(&base->active, ev, active_entries);
70
}
71
72
/*
73
* Clear out the base's active queue and mark all events as inactive.
74
*/
75
static void
76
sudo_ev_deactivate_all(struct sudo_event_base *base)
77
{
78
struct sudo_event *ev;
79
debug_decl(sudo_ev_deactivate_all, SUDO_DEBUG_EVENT);
80
81
while ((ev = TAILQ_FIRST(&base->active)) != NULL)
82
sudo_ev_deactivate(base, ev);
83
84
debug_return;
85
}
86
87
/*
88
* Activate all signal events for which the corresponding signal_pending[]
89
* flag is set.
90
*/
91
static void
92
sudo_ev_activate_sigevents(struct sudo_event_base *base)
93
{
94
struct sudo_event *ev;
95
sigset_t set, oset;
96
unsigned int i;
97
debug_decl(sudo_ev_activate_sigevents, SUDO_DEBUG_EVENT);
98
99
/*
100
* We treat this as a critical section since the signal handler
101
* could modify the siginfo[] entry.
102
*/
103
sigfillset(&set);
104
sigprocmask(SIG_BLOCK, &set, &oset);
105
base->signal_caught = 0;
106
for (i = 0; i < NSIG; i++) {
107
if (!base->signal_pending[i])
108
continue;
109
base->signal_pending[i] = 0;
110
TAILQ_FOREACH(ev, &base->signals[i], entries) {
111
if (ISSET(ev->events, SUDO_EV_SIGINFO)) {
112
struct sudo_ev_siginfo_container *sc = ev->closure;
113
if (base->siginfo[i]->si_signo == 0) {
114
/* No siginfo available. */
115
sc->siginfo = NULL;
116
} else {
117
sc->siginfo = (siginfo_t *)sc->si_buf;
118
memcpy(sc->siginfo, base->siginfo[i], sizeof(siginfo_t));
119
}
120
}
121
/* Make event active. */
122
ev->revents = ev->events & (SUDO_EV_SIGNAL|SUDO_EV_SIGINFO);
123
TAILQ_INSERT_TAIL(&base->active, ev, active_entries);
124
SET(ev->flags, SUDO_EVQ_ACTIVE);
125
}
126
}
127
sigprocmask(SIG_SETMASK, &oset, NULL);
128
129
debug_return;
130
}
131
132
/*
133
* Internal callback for SUDO_EV_SIGNAL and SUDO_EV_SIGINFO.
134
*/
135
static void
136
signal_pipe_cb(int fd, int what, void *v)
137
{
138
struct sudo_event_base *base = v;
139
unsigned char ch;
140
ssize_t nread;
141
debug_decl(signal_pipe_cb, SUDO_DEBUG_EVENT);
142
143
/*
144
* Drain signal_pipe, the signal handler updated base->signals_pending.
145
* Actual processing of signal events is done when poll/select is
146
* interrupted by a signal.
147
*/
148
while ((nread = read(fd, &ch, 1)) > 0) {
149
sudo_debug_printf(SUDO_DEBUG_INFO,
150
"%s: received signal %d", __func__, (int)ch);
151
}
152
if (nread < 0 && errno != EAGAIN) {
153
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
154
"%s: error reading from signal pipe fd %d", __func__, fd);
155
}
156
157
/* Activate signal events. */
158
sudo_ev_activate_sigevents(base);
159
160
debug_return;
161
}
162
163
static int
164
sudo_ev_base_init(struct sudo_event_base *base)
165
{
166
unsigned int i;
167
debug_decl(sudo_ev_base_init, SUDO_DEBUG_EVENT);
168
169
TAILQ_INIT(&base->events);
170
TAILQ_INIT(&base->timeouts);
171
for (i = 0; i < NSIG; i++)
172
TAILQ_INIT(&base->signals[i]);
173
if (sudo_ev_base_alloc_impl(base) != 0) {
174
sudo_debug_printf(SUDO_DEBUG_ERROR,
175
"%s: unable to allocate impl base", __func__);
176
goto bad;
177
}
178
if (pipe2(base->signal_pipe, O_NONBLOCK|O_CLOEXEC) != 0) {
179
sudo_debug_printf(SUDO_DEBUG_ERROR,
180
"%s: unable to create signal pipe", __func__);
181
goto bad;
182
}
183
sudo_ev_init(&base->signal_event, base->signal_pipe[0],
184
SUDO_EV_READ|SUDO_EV_PERSIST, signal_pipe_cb, base);
185
186
debug_return_int(0);
187
bad:
188
/* Note: signal_pipe[] not filled in. */
189
sudo_ev_base_free_impl(base);
190
debug_return_int(-1);
191
}
192
193
struct sudo_event_base *
194
sudo_ev_base_alloc_v1(void)
195
{
196
struct sudo_event_base *base;
197
debug_decl(sudo_ev_base_alloc, SUDO_DEBUG_EVENT);
198
199
base = calloc(1, sizeof(*base));
200
if (base == NULL) {
201
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
202
"%s: unable to allocate base", __func__);
203
debug_return_ptr(NULL);
204
}
205
if (sudo_ev_base_init(base) != 0) {
206
free(base);
207
debug_return_ptr(NULL);
208
}
209
debug_return_ptr(base);
210
}
211
212
void
213
sudo_ev_base_free_v1(struct sudo_event_base *base)
214
{
215
struct sudo_event *ev, *next;
216
unsigned int i;
217
debug_decl(sudo_ev_base_free, SUDO_DEBUG_EVENT);
218
219
if (base == NULL)
220
debug_return;
221
222
/* Reset the default base if necessary. */
223
if (default_base == base)
224
default_base = NULL;
225
226
/* Remove any existing events before freeing the base. */
227
TAILQ_FOREACH_SAFE(ev, &base->events, entries, next) {
228
sudo_ev_del(base, ev);
229
ev->base = NULL;
230
}
231
for (i = 0; i < NSIG; i++) {
232
TAILQ_FOREACH_SAFE(ev, &base->signals[i], entries, next) {
233
sudo_ev_del(base, ev);
234
ev->base = NULL;
235
}
236
free(base->siginfo[i]);
237
free(base->orig_handlers[i]);
238
}
239
sudo_ev_base_free_impl(base);
240
close(base->signal_pipe[0]);
241
close(base->signal_pipe[1]);
242
free(base);
243
244
debug_return;
245
}
246
247
void
248
sudo_ev_base_setdef_v1(struct sudo_event_base *base)
249
{
250
debug_decl(sudo_ev_base_setdef, SUDO_DEBUG_EVENT);
251
252
default_base = base;
253
254
debug_return;
255
}
256
257
/*
258
* Clear and fill in a struct sudo_event.
259
*/
260
static void
261
sudo_ev_init(struct sudo_event *ev, int fd, int events,
262
sudo_ev_callback_t callback, void *closure)
263
{
264
debug_decl(sudo_ev_init, SUDO_DEBUG_EVENT);
265
266
memset(ev, 0, sizeof(*ev));
267
ev->fd = fd;
268
ev->events = events & SUDO_EV_MASK;
269
ev->pfd_idx = -1;
270
ev->callback = callback;
271
ev->closure = closure;
272
273
debug_return;
274
}
275
276
/*
277
* Set a pre-allocated struct sudo_event.
278
* Allocates space for siginfo_t for SUDO_EV_SIGINFO as needed.
279
*/
280
int
281
sudo_ev_set_v2(struct sudo_event *ev, int fd, int events,
282
sudo_ev_callback_t callback, void *closure)
283
{
284
debug_decl(sudo_ev_set, SUDO_DEBUG_EVENT);
285
286
/* For SUDO_EV_SIGINFO we use a container to store closure + siginfo_t */
287
if (ISSET(events, SUDO_EV_SIGINFO)) {
288
struct sudo_ev_siginfo_container *container =
289
malloc(sizeof(*container) + sizeof(siginfo_t));
290
if (container == NULL) {
291
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
292
"%s: unable to allocate siginfo container", __func__);
293
debug_return_int(-1);
294
}
295
container->closure = closure;
296
closure = container;
297
}
298
sudo_ev_init(ev, fd, events, callback, closure);
299
300
debug_return_int(0);
301
}
302
303
int
304
sudo_ev_set_v1(struct sudo_event *ev, int fd, short events,
305
sudo_ev_callback_t callback, void *closure)
306
{
307
return sudo_ev_set_v2(ev, fd, events, callback, closure);
308
}
309
310
struct sudo_event *
311
sudo_ev_alloc_v2(int fd, int events, sudo_ev_callback_t callback, void *closure)
312
{
313
struct sudo_event *ev;
314
debug_decl(sudo_ev_alloc, SUDO_DEBUG_EVENT);
315
316
ev = malloc(sizeof(*ev));
317
if (ev == NULL) {
318
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
319
"%s: unable to allocate event", __func__);
320
debug_return_ptr(NULL);
321
}
322
if (sudo_ev_set(ev, fd, events, callback, closure) == -1) {
323
free(ev);
324
debug_return_ptr(NULL);
325
}
326
debug_return_ptr(ev);
327
}
328
329
struct sudo_event *
330
sudo_ev_alloc_v1(int fd, short events, sudo_ev_callback_t callback, void *closure)
331
{
332
return sudo_ev_alloc_v2(fd, events, callback, closure);
333
}
334
335
void
336
sudo_ev_free_v1(struct sudo_event *ev)
337
{
338
debug_decl(sudo_ev_free, SUDO_DEBUG_EVENT);
339
340
if (ev == NULL)
341
debug_return;
342
343
/* Make sure ev is not in use before freeing it. */
344
if (ISSET(ev->flags, SUDO_EVQ_INSERTED))
345
(void)sudo_ev_del(NULL, ev);
346
if (ISSET(ev->events, SUDO_EV_SIGINFO))
347
free(ev->closure);
348
free(ev);
349
350
debug_return;
351
}
352
353
static void
354
sudo_ev_handler(int signo, siginfo_t *info, void *context)
355
{
356
unsigned char ch = (unsigned char)signo;
357
358
if (signal_base != NULL) {
359
/*
360
* Update signals_pending[] and siginfo[].
361
* All signals must be blocked any time siginfo[] is accessed.
362
* If no siginfo available, zero out the struct in base.
363
*/
364
if (info == NULL)
365
memset(signal_base->siginfo[signo], 0, sizeof(*info));
366
else
367
memcpy(signal_base->siginfo[signo], info, sizeof(*info));
368
signal_base->signal_pending[signo] = 1;
369
signal_base->signal_caught = 1;
370
371
/* Wake up the other end of the pipe. */
372
ignore_result(write(signal_base->signal_pipe[1], &ch, 1));
373
}
374
}
375
376
static int
377
sudo_ev_add_signal(struct sudo_event_base *base, struct sudo_event *ev,
378
bool tohead)
379
{
380
const int signo = ev->fd;
381
debug_decl(sudo_ev_add_signal, SUDO_DEBUG_EVENT);
382
383
sudo_debug_printf(SUDO_DEBUG_INFO,
384
"%s: adding event %p to base %p, signal %d, events %d",
385
__func__, ev, base, signo, ev->events);
386
if (signo >= NSIG) {
387
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
388
"%s: signo %d larger than max %d", __func__, signo, NSIG - 1);
389
debug_return_int(-1);
390
}
391
if ((ev->events & ~(SUDO_EV_SIGNAL|SUDO_EV_SIGINFO|SUDO_EV_PERSIST)) != 0) {
392
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
393
"%s: invalid event set 0x%x", __func__, ev->events);
394
debug_return_int(-1);
395
}
396
397
/*
398
* Allocate base->siginfo[signo] and base->orig_handlers[signo] as needed.
399
*/
400
if (base->siginfo[signo] == NULL) {
401
base->siginfo[signo] = malloc(sizeof(*base->siginfo[signo]));
402
if (base->siginfo[signo] == NULL) {
403
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
404
"%s: unable to allocate siginfo for signo %d",
405
__func__, signo);
406
debug_return_int(-1);
407
}
408
}
409
if (base->orig_handlers[signo] == NULL) {
410
base->orig_handlers[signo] =
411
malloc(sizeof(*base->orig_handlers[signo]));
412
if (base->orig_handlers[signo] == NULL) {
413
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
414
"%s: unable to allocate orig_handlers for signo %d",
415
__func__, signo);
416
debug_return_int(-1);
417
}
418
}
419
420
/* Install signal handler as needed, saving the original value. */
421
if (TAILQ_EMPTY(&base->signals[signo])) {
422
struct sigaction sa;
423
memset(&sa, 0, sizeof(sa));
424
sigfillset(&sa.sa_mask);
425
sa.sa_flags = SA_RESTART|SA_SIGINFO;
426
sa.sa_sigaction = sudo_ev_handler;
427
if (sigaction(signo, &sa, base->orig_handlers[signo]) != 0) {
428
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
429
"%s: unable to install handler for signo %d", __func__, signo);
430
debug_return_int(-1);
431
}
432
base->num_handlers++;
433
}
434
435
/*
436
* Insert signal event into the proper tail queue.
437
* Signal events are always persistent.
438
*/
439
ev->base = base;
440
if (tohead) {
441
TAILQ_INSERT_HEAD(&base->signals[signo], ev, entries);
442
} else {
443
TAILQ_INSERT_TAIL(&base->signals[signo], ev, entries);
444
}
445
SET(ev->events, SUDO_EV_PERSIST);
446
SET(ev->flags, SUDO_EVQ_INSERTED);
447
448
/* Add the internal signal_pipe event on demand. */
449
if (!ISSET(base->signal_event.flags, SUDO_EVQ_INSERTED))
450
sudo_ev_add(base, &base->signal_event, NULL, true);
451
452
/* Update global signal base so handler to update signals_pending[] */
453
signal_base = base;
454
455
debug_return_int(0);
456
}
457
458
int
459
sudo_ev_add_v1(struct sudo_event_base *base, struct sudo_event *ev,
460
const struct timeval *timo, bool tohead)
461
{
462
struct timespec tsbuf, *ts = NULL;
463
464
if (timo != NULL) {
465
TIMEVAL_TO_TIMESPEC(timo, &tsbuf);
466
ts = &tsbuf;
467
}
468
469
return sudo_ev_add_v2(base, ev, ts, tohead);
470
}
471
472
int
473
sudo_ev_add_v2(struct sudo_event_base *base, struct sudo_event *ev,
474
const struct timespec *timo, bool tohead)
475
{
476
debug_decl(sudo_ev_add, SUDO_DEBUG_EVENT);
477
478
/* If no base specified, use existing or default base. */
479
if (base == NULL) {
480
if (ev->base != NULL) {
481
base = ev->base;
482
} else if (default_base != NULL) {
483
base = default_base;
484
} else {
485
sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: no base specified",
486
__func__);
487
debug_return_int(-1);
488
}
489
}
490
491
/* Only add new events to the events list. */
492
if (ISSET(ev->flags, SUDO_EVQ_INSERTED)) {
493
/* If event no longer has a timeout, remove from timeouts queue. */
494
if (timo == NULL && ISSET(ev->flags, SUDO_EVQ_TIMEOUTS)) {
495
sudo_debug_printf(SUDO_DEBUG_INFO,
496
"%s: removing event %p from timeouts queue", __func__, ev);
497
CLR(ev->flags, SUDO_EVQ_TIMEOUTS);
498
TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
499
}
500
} else {
501
/* Special handling for signal events. */
502
if (ev->events & (SUDO_EV_SIGNAL|SUDO_EV_SIGINFO))
503
debug_return_int(sudo_ev_add_signal(base, ev, tohead));
504
505
/* Add event to the base. */
506
sudo_debug_printf(SUDO_DEBUG_INFO,
507
"%s: adding event %p to base %p, fd %d, events %d",
508
__func__, ev, base, ev->fd, ev->events);
509
if (ev->events & (SUDO_EV_READ|SUDO_EV_WRITE)) {
510
if (sudo_ev_add_impl(base, ev) != 0)
511
debug_return_int(-1);
512
}
513
ev->base = base;
514
if (tohead) {
515
TAILQ_INSERT_HEAD(&base->events, ev, entries);
516
} else {
517
TAILQ_INSERT_TAIL(&base->events, ev, entries);
518
}
519
SET(ev->flags, SUDO_EVQ_INSERTED);
520
}
521
/* Timeouts can be changed for existing events. */
522
if (timo != NULL) {
523
struct sudo_event *evtmp;
524
if (ISSET(ev->flags, SUDO_EVQ_TIMEOUTS)) {
525
/* Remove from timeouts list, then add back. */
526
TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
527
}
528
/* Convert to absolute time and insert in sorted order; O(n). */
529
sudo_gettime_mono(&ev->timeout);
530
sudo_timespecadd(&ev->timeout, timo, &ev->timeout);
531
TAILQ_FOREACH(evtmp, &base->timeouts, timeouts_entries) {
532
if (sudo_timespeccmp(&ev->timeout, &evtmp->timeout, <))
533
break;
534
}
535
if (evtmp != NULL) {
536
TAILQ_INSERT_BEFORE(evtmp, ev, timeouts_entries);
537
} else {
538
TAILQ_INSERT_TAIL(&base->timeouts, ev, timeouts_entries);
539
}
540
SET(ev->flags, SUDO_EVQ_TIMEOUTS);
541
}
542
debug_return_int(0);
543
}
544
545
/*
546
* Remove an event from the base, if specified, or the base embedded
547
* in the event if not. Note that there are multiple tail queues.
548
*/
549
int
550
sudo_ev_del_v1(struct sudo_event_base *base, struct sudo_event *ev)
551
{
552
debug_decl(sudo_ev_del, SUDO_DEBUG_EVENT);
553
554
/* Make sure event is really in the queue. */
555
if (!ISSET(ev->flags, SUDO_EVQ_INSERTED)) {
556
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: event %p not in queue",
557
__func__, ev);
558
debug_return_int(0);
559
}
560
561
/* Check for event base mismatch, if one is specified. */
562
if (base == NULL) {
563
if (ev->base == NULL) {
564
sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: no base specified",
565
__func__);
566
debug_return_int(-1);
567
}
568
base = ev->base;
569
} else if (base != ev->base) {
570
sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: mismatch base %p, ev->base %p",
571
__func__, base, ev->base);
572
debug_return_int(-1);
573
}
574
575
if (ev->events & (SUDO_EV_SIGNAL|SUDO_EV_SIGINFO)) {
576
const int signo = ev->fd;
577
578
sudo_debug_printf(SUDO_DEBUG_INFO,
579
"%s: removing event %p from base %p, signo %d, events %d",
580
__func__, ev, base, signo, ev->events);
581
582
/* Unlink from signal event list. */
583
TAILQ_REMOVE(&base->signals[signo], ev, entries);
584
if (TAILQ_EMPTY(&base->signals[signo])) {
585
if (sigaction(signo, base->orig_handlers[signo], NULL) != 0) {
586
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
587
"%s: unable to restore handler for signo %d",
588
__func__, signo);
589
debug_return_int(-1);
590
}
591
base->num_handlers--;
592
}
593
if (base->num_handlers == 0) {
594
/* No registered signal events, remove internal event. */
595
sudo_ev_del(base, &base->signal_event);
596
}
597
} else {
598
sudo_debug_printf(SUDO_DEBUG_INFO,
599
"%s: removing event %p from base %p, fd %d, events %d",
600
__func__, ev, base, ev->fd, ev->events);
601
602
/* Call backend. */
603
if (ev->events & (SUDO_EV_READ|SUDO_EV_WRITE)) {
604
if (sudo_ev_del_impl(base, ev) != 0)
605
debug_return_int(-1);
606
}
607
608
/* Unlink from event list. */
609
TAILQ_REMOVE(&base->events, ev, entries);
610
611
/* Unlink from timeouts list. */
612
if (ISSET(ev->flags, SUDO_EVQ_TIMEOUTS))
613
TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
614
}
615
616
/* Unlink from active list. */
617
if (ISSET(ev->flags, SUDO_EVQ_ACTIVE))
618
TAILQ_REMOVE(&base->active, ev, active_entries);
619
620
/* Mark event unused. */
621
ev->flags = 0;
622
ev->pfd_idx = -1;
623
624
debug_return_int(0);
625
}
626
627
int
628
sudo_ev_dispatch_v1(struct sudo_event_base *base)
629
{
630
return sudo_ev_loop_v1(base, 0);
631
}
632
633
/*
634
* Run main event loop.
635
* Returns 0 on success, 1 if no events registered and -1 on error
636
*/
637
int
638
sudo_ev_loop_v1(struct sudo_event_base *base, unsigned int flags)
639
{
640
struct timespec now;
641
struct sudo_event *ev;
642
int nready, rc = 0;
643
debug_decl(sudo_ev_loop, SUDO_DEBUG_EVENT);
644
645
/*
646
* If sudo_ev_loopexit() was called when events were not running
647
* the next invocation of sudo_ev_loop() only runs once.
648
* All other base flags are ignored unless we are running events.
649
* Note that SUDO_EVLOOP_ONCE and SUDO_EVBASE_LOOPONCE are equivalent.
650
*/
651
base->flags |= (flags & SUDO_EVLOOP_ONCE);
652
base->flags &= (SUDO_EVBASE_LOOPEXIT|SUDO_EVBASE_LOOPONCE);
653
654
for (;;) {
655
rescan:
656
/* Make sure we have some events. */
657
if (TAILQ_EMPTY(&base->events)) {
658
rc = 1;
659
break;
660
}
661
662
/* Call backend to scan for I/O events. */
663
TAILQ_INIT(&base->active);
664
nready = sudo_ev_scan_impl(base, flags);
665
switch (nready) {
666
case -1:
667
if (errno == ENOMEM || errno == EAGAIN)
668
continue;
669
if (errno == EINTR) {
670
/* Interrupted by signal, check for sigevents. */
671
if (base->signal_caught) {
672
signal_pipe_cb(base->signal_pipe[0], SUDO_EV_READ, base);
673
break;
674
}
675
continue;
676
}
677
rc = -1;
678
goto done;
679
case 0:
680
/* Timed out, activate timeout events. */
681
sudo_gettime_mono(&now);
682
while ((ev = TAILQ_FIRST(&base->timeouts)) != NULL) {
683
if (sudo_timespeccmp(&ev->timeout, &now, >))
684
break;
685
/* Remove from timeouts list. */
686
CLR(ev->flags, SUDO_EVQ_TIMEOUTS);
687
TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
688
/* Make event active. */
689
ev->revents = SUDO_EV_TIMEOUT;
690
TAILQ_INSERT_TAIL(&base->active, ev, active_entries);
691
SET(ev->flags, SUDO_EVQ_ACTIVE);
692
}
693
if (ISSET(flags, SUDO_EVLOOP_NONBLOCK)) {
694
/* If nonblocking, return immediately if no active events. */
695
if (TAILQ_EMPTY(&base->active))
696
goto done;
697
}
698
break;
699
default:
700
/* I/O events active, sudo_ev_scan_impl() already added them. */
701
break;
702
}
703
704
/*
705
* Service each event in the active queue.
706
* We store the current event pointer in the base so that
707
* it can be cleared by sudo_ev_del(). This prevents a use
708
* after free if the callback frees its own event.
709
*/
710
while ((ev = TAILQ_FIRST(&base->active)) != NULL) {
711
/* Pop first event off the active queue. */
712
sudo_ev_deactivate(base, ev);
713
/* Remove from base unless persistent. */
714
if (!ISSET(ev->events, SUDO_EV_PERSIST))
715
sudo_ev_del(base, ev);
716
ev->callback(ev->fd, ev->revents,
717
ev->closure == sudo_ev_self_cbarg() ? ev : ev->closure);
718
if (ISSET(base->flags, SUDO_EVBASE_LOOPBREAK)) {
719
/* Stop processing events immediately. */
720
SET(base->flags, SUDO_EVBASE_GOT_BREAK);
721
sudo_ev_deactivate_all(base);
722
goto done;
723
}
724
if (ISSET(base->flags, SUDO_EVBASE_LOOPCONT)) {
725
/* Rescan events and start polling again. */
726
CLR(base->flags, SUDO_EVBASE_LOOPCONT);
727
sudo_ev_deactivate_all(base);
728
goto rescan;
729
}
730
}
731
if (ISSET(base->flags, SUDO_EVBASE_LOOPONCE)) {
732
/* SUDO_EVBASE_LOOPEXIT is always set w/ SUDO_EVBASE_LOOPONCE */
733
if (ISSET(base->flags, SUDO_EVBASE_LOOPEXIT))
734
SET(base->flags, SUDO_EVBASE_GOT_EXIT);
735
sudo_ev_deactivate_all(base);
736
break;
737
}
738
}
739
done:
740
base->flags &= SUDO_EVBASE_GOT_MASK;
741
debug_return_int(rc);
742
}
743
744
void
745
sudo_ev_loopexit_v1(struct sudo_event_base *base)
746
{
747
debug_decl(sudo_ev_loopexit, SUDO_DEBUG_EVENT);
748
749
if (base == NULL) {
750
if ((base = default_base) == NULL)
751
debug_return;
752
}
753
754
/* SUDO_EVBASE_LOOPBREAK trumps SUDO_EVBASE_LOOPEXIT */
755
if (!ISSET(base->flags, SUDO_EVBASE_LOOPBREAK)) {
756
/* SUDO_EVBASE_LOOPEXIT trumps SUDO_EVBASE_LOOPCONT */
757
CLR(base->flags, SUDO_EVBASE_LOOPCONT);
758
SET(base->flags, (SUDO_EVBASE_LOOPEXIT|SUDO_EVBASE_LOOPONCE));
759
}
760
debug_return;
761
}
762
763
void
764
sudo_ev_loopbreak_v1(struct sudo_event_base *base)
765
{
766
debug_decl(sudo_ev_loopbreak, SUDO_DEBUG_EVENT);
767
768
if (base == NULL) {
769
if ((base = default_base) == NULL)
770
debug_return;
771
}
772
773
/* SUDO_EVBASE_LOOPBREAK trumps SUDO_EVBASE_LOOP{CONT,EXIT,ONCE}. */
774
CLR(base->flags, (SUDO_EVBASE_LOOPCONT|SUDO_EVBASE_LOOPEXIT|SUDO_EVBASE_LOOPONCE));
775
SET(base->flags, SUDO_EVBASE_LOOPBREAK);
776
debug_return;
777
}
778
779
void
780
sudo_ev_loopcontinue_v1(struct sudo_event_base *base)
781
{
782
debug_decl(sudo_ev_loopcontinue, SUDO_DEBUG_EVENT);
783
784
if (base == NULL) {
785
if ((base = default_base) == NULL)
786
debug_return;
787
}
788
789
/* SUDO_EVBASE_LOOP{BREAK,EXIT} trumps SUDO_EVBASE_LOOPCONT */
790
if (!ISSET(base->flags, SUDO_EVBASE_LOOPONCE|SUDO_EVBASE_LOOPBREAK)) {
791
SET(base->flags, SUDO_EVBASE_LOOPCONT);
792
}
793
debug_return;
794
}
795
796
bool
797
sudo_ev_got_exit_v1(struct sudo_event_base *base)
798
{
799
debug_decl(sudo_ev_got_exit, SUDO_DEBUG_EVENT);
800
801
if (base == NULL) {
802
if ((base = default_base) == NULL)
803
debug_return_bool(false);
804
}
805
debug_return_bool(ISSET(base->flags, SUDO_EVBASE_GOT_EXIT));
806
}
807
808
bool
809
sudo_ev_got_break_v1(struct sudo_event_base *base)
810
{
811
debug_decl(sudo_ev_got_break, SUDO_DEBUG_EVENT);
812
813
if (base == NULL) {
814
if ((base = default_base) == NULL)
815
debug_return_bool(false);
816
}
817
debug_return_bool(ISSET(base->flags, SUDO_EVBASE_GOT_BREAK));
818
}
819
820
int
821
sudo_ev_get_timeleft_v1(struct sudo_event *ev, struct timeval *tv)
822
{
823
struct timespec ts;
824
int ret;
825
826
ret = sudo_ev_get_timeleft_v2(ev, &ts);
827
TIMESPEC_TO_TIMEVAL(tv, &ts);
828
829
return ret;
830
}
831
832
int
833
sudo_ev_get_timeleft_v2(struct sudo_event *ev, struct timespec *ts)
834
{
835
debug_decl(sudo_ev_get_timeleft, SUDO_DEBUG_EVENT);
836
837
sudo_timespecclear(ts);
838
if (sudo_ev_pending_v1(ev, SUDO_EV_TIMEOUT, ts) != SUDO_EV_TIMEOUT)
839
debug_return_int(-1);
840
debug_return_int(0);
841
}
842
843
int
844
sudo_ev_pending_v2(struct sudo_event *ev, int events, struct timespec *ts)
845
{
846
int ret;
847
debug_decl(sudo_ev_pending, SUDO_DEBUG_EVENT);
848
849
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: event %p, flags 0x%x, events 0x%x",
850
__func__, ev, ev->flags, ev->events);
851
852
if (!ISSET(ev->flags, SUDO_EVQ_INSERTED))
853
debug_return_int(0);
854
855
ret = ev->events & events;
856
CLR(ret, SUDO_EV_TIMEOUT);
857
if (ISSET(ev->flags, SUDO_EVQ_TIMEOUTS) && ISSET(events, SUDO_EV_TIMEOUT)) {
858
ret |= SUDO_EV_TIMEOUT;
859
if (ts != NULL) {
860
struct timespec now;
861
862
sudo_gettime_mono(&now);
863
sudo_timespecsub(&ev->timeout, &now, ts);
864
if (ts->tv_sec < 0)
865
sudo_timespecclear(ts);
866
}
867
}
868
869
debug_return_int(ret);
870
}
871
872
int
873
sudo_ev_pending_v1(struct sudo_event *ev, short events, struct timespec *ts)
874
{
875
return sudo_ev_pending_v2(ev, events, ts);
876
}
877
878