2 * SPDX-License-Identifier: ISC
4 * Copyright (c) 2013-2015, 2017 Todd C. Miller <Todd.Miller@sudo.ws>
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.
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.
22 #include <signal.h> /* for sigatomic_t and NSIG */
23 #include "sudo_queue.h"
26 #define SUDO_EV_TIMEOUT 0x01 /* fire after timeout */
27 #define SUDO_EV_READ 0x02 /* fire when readable */
28 #define SUDO_EV_WRITE 0x04 /* fire when writable */
29 #define SUDO_EV_PERSIST 0x08 /* persist until deleted */
30 #define SUDO_EV_SIGNAL 0x10 /* fire on signal receipt */
31 #define SUDO_EV_SIGINFO 0x20 /* fire on signal receipt (siginfo) */
33 /* Event flags (internal) */
34 #define SUDO_EVQ_INSERTED 0x01 /* event is on the event queue */
35 #define SUDO_EVQ_ACTIVE 0x02 /* event is on the active queue */
36 #define SUDO_EVQ_TIMEOUTS 0x04 /* event is on the timeouts queue */
38 /* Event loop flags */
39 #define SUDO_EVLOOP_ONCE 0x01 /* Only run once through the loop */
40 #define SUDO_EVLOOP_NONBLOCK 0x02 /* Do not block in event loop */
42 /* Event base flags (internal) */
43 #define SUDO_EVBASE_LOOPONCE SUDO_EVLOOP_ONCE
44 #define SUDO_EVBASE_LOOPEXIT 0x02
45 #define SUDO_EVBASE_LOOPBREAK 0x04
46 #define SUDO_EVBASE_LOOPCONT 0x08
47 #define SUDO_EVBASE_GOT_EXIT 0x10
48 #define SUDO_EVBASE_GOT_BREAK 0x20
49 #define SUDO_EVBASE_GOT_MASK 0xf0
51 typedef void (*sudo_ev_callback_t)(int fd, int what, void *closure);
54 * Container for SUDO_EV_SIGINFO events that gets passed as the closure
55 * pointer. This allows us to pass a siginfo_t without changing everything.
57 struct sudo_ev_siginfo_container {
63 /* Member of struct sudo_event_base. */
65 TAILQ_ENTRY(sudo_event) entries;
66 TAILQ_ENTRY(sudo_event) active_entries;
67 TAILQ_ENTRY(sudo_event) timeouts_entries;
68 struct sudo_event_base *base; /* base this event belongs to */
69 int fd; /* fd/signal we are interested in */
70 short events; /* SUDO_EV_* flags (in) */
71 short revents; /* SUDO_EV_* flags (out) */
72 short flags; /* internal event flags */
73 short pfd_idx; /* index into pfds array (XXX) */
74 sudo_ev_callback_t callback;/* user-provided callback */
75 struct timespec timeout; /* for SUDO_EV_TIMEOUT */
76 void *closure; /* user-provided data pointer */
78 TAILQ_HEAD(sudo_event_list, sudo_event);
80 struct sudo_event_base {
81 struct sudo_event_list events; /* tail queue of all events */
82 struct sudo_event_list active; /* tail queue of active events */
83 struct sudo_event_list timeouts; /* tail queue of timeout events */
84 struct sudo_event signal_event; /* storage for signal pipe event */
85 struct sudo_event_list signals[NSIG]; /* array of signal event tail queues */
86 struct sigaction *orig_handlers[NSIG]; /* original signal handlers */
87 siginfo_t *siginfo[NSIG]; /* detailed signal info */
88 sig_atomic_t signal_pending[NSIG]; /* pending signals */
89 sig_atomic_t signal_caught; /* at least one signal caught */
90 int num_handlers; /* number of installed handlers */
91 int signal_pipe[2]; /* so we can wake up on singal */
92 #if defined(HAVE_POLL) || defined(HAVE_PPOLL)
93 struct pollfd *pfds; /* array of struct pollfd */
94 int pfd_max; /* size of the pfds array */
95 int pfd_high; /* highest slot used */
96 int pfd_free; /* idx of next free entry or pfd_max if full */
98 fd_set *readfds_in; /* read I/O descriptor set (in) */
99 fd_set *writefds_in; /* write I/O descriptor set (in) */
100 fd_set *readfds_out; /* read I/O descriptor set (out) */
101 fd_set *writefds_out; /* write I/O descriptor set (out) */
102 int maxfd; /* max fd we can store in readfds/writefds */
103 int highfd; /* highest fd to pass as 1st arg to select */
104 #endif /* HAVE_POLL */
105 unsigned int flags; /* SUDO_EVBASE_* */
108 /* Allocate a new event base. */
109 __dso_public struct sudo_event_base *sudo_ev_base_alloc_v1(void);
110 #define sudo_ev_base_alloc() sudo_ev_base_alloc_v1()
112 /* Free an event base. */
113 __dso_public void sudo_ev_base_free_v1(struct sudo_event_base *base);
114 #define sudo_ev_base_free(_a) sudo_ev_base_free_v1((_a))
116 /* Set the default event base. */
117 __dso_public void sudo_ev_base_setdef_v1(struct sudo_event_base *base);
118 #define sudo_ev_base_setdef(_a) sudo_ev_base_setdef_v1((_a))
120 /* Allocate a new event. */
121 __dso_public struct sudo_event *sudo_ev_alloc_v1(int fd, short events, sudo_ev_callback_t callback, void *closure);
122 #define sudo_ev_alloc(_a, _b, _c, _d) sudo_ev_alloc_v1((_a), (_b), (_c), (_d))
125 __dso_public void sudo_ev_free_v1(struct sudo_event *ev);
126 #define sudo_ev_free(_a) sudo_ev_free_v1((_a))
128 /* Add an event, returns 0 on success, -1 on error */
129 __dso_public int sudo_ev_add_v1(struct sudo_event_base *head, struct sudo_event *ev, struct timeval *timo, bool tohead);
130 __dso_public int sudo_ev_add_v2(struct sudo_event_base *head, struct sudo_event *ev, struct timespec *timo, bool tohead);
131 #define sudo_ev_add(_a, _b, _c, _d) sudo_ev_add_v2((_a), (_b), (_c), (_d))
133 /* Delete an event, returns 0 on success, -1 on error */
134 __dso_public int sudo_ev_del_v1(struct sudo_event_base *head, struct sudo_event *ev);
135 #define sudo_ev_del(_a, _b) sudo_ev_del_v1((_a), (_b))
137 /* Dispatch events, returns SUDO_CB_SUCCESS, SUDO_CB_BREAK or SUDO_CB_ERROR */
138 __dso_public int sudo_ev_dispatch_v1(struct sudo_event_base *head);
139 #define sudo_ev_dispatch(_a) sudo_ev_dispatch_v1((_a))
141 /* Main event loop, returns SUDO_CB_SUCCESS, SUDO_CB_BREAK or SUDO_CB_ERROR */
142 __dso_public int sudo_ev_loop_v1(struct sudo_event_base *head, int flags);
143 #define sudo_ev_loop(_a, _b) sudo_ev_loop_v1((_a), (_b))
145 /* Return the remaining timeout associated with an event. */
146 __dso_public int sudo_ev_get_timeleft_v1(struct sudo_event *ev, struct timeval *tv);
147 __dso_public int sudo_ev_get_timeleft_v2(struct sudo_event *ev, struct timespec *tv);
148 #define sudo_ev_get_timeleft(_a, _b) sudo_ev_get_timeleft_v2((_a), (_b))
150 /* Cause the event loop to exit after one run through. */
151 __dso_public void sudo_ev_loopexit_v1(struct sudo_event_base *base);
152 #define sudo_ev_loopexit(_a) sudo_ev_loopexit_v1((_a))
154 /* Break out of the event loop right now. */
155 __dso_public void sudo_ev_loopbreak_v1(struct sudo_event_base *base);
156 #define sudo_ev_loopbreak(_a) sudo_ev_loopbreak_v1((_a))
158 /* Rescan for events and restart the event loop. */
159 __dso_public void sudo_ev_loopcontinue_v1(struct sudo_event_base *base);
160 #define sudo_ev_loopcontinue(_a) sudo_ev_loopcontinue_v1((_a))
162 /* Returns true if event loop stopped due to sudo_ev_loopexit(). */
163 __dso_public bool sudo_ev_got_exit_v1(struct sudo_event_base *base);
164 #define sudo_ev_got_exit(_a) sudo_ev_got_exit_v1((_a))
166 /* Returns true if event loop stopped due to sudo_ev_loopbreak(). */
167 __dso_public bool sudo_ev_got_break_v1(struct sudo_event_base *base);
168 #define sudo_ev_got_break(_a) sudo_ev_got_break_v1((_a))
170 /* Return the fd associated with an event. */
171 #define sudo_ev_get_fd(_ev) ((_ev) ? (_ev)->fd : -1)
173 /* Return the (absolute) timeout associated with an event or NULL. */
174 #define sudo_ev_get_timeout(_ev) \
175 (ISSET((_ev)->flags, SUDO_EVQ_TIMEOUTS) ? &(_ev)->timeout : NULL)
177 /* Return the base an event is associated with or NULL. */
178 #define sudo_ev_get_base(_ev) ((_ev) ? (_ev)->base : NULL)
180 /* Magic pointer value to use self pointer as callback arg. */
181 #define sudo_ev_self_cbarg() ((void *)-1)
183 /* Add an event to the base's active queue and mark it active (internal). */
184 void sudo_ev_activate(struct sudo_event_base *base, struct sudo_event *ev);
187 * Backend implementation.
189 int sudo_ev_base_alloc_impl(struct sudo_event_base *base);
190 void sudo_ev_base_free_impl(struct sudo_event_base *base);
191 int sudo_ev_add_impl(struct sudo_event_base *base, struct sudo_event *ev);
192 int sudo_ev_del_impl(struct sudo_event_base *base, struct sudo_event *ev);
193 int sudo_ev_scan_impl(struct sudo_event_base *base, int flags);
195 #endif /* SUDO_EVENT_H */