]> granicus.if.org Git - sudo/blob - include/sudo_event.h
Add SPDX-License-Identifier to files.
[sudo] / include / sudo_event.h
1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2013-2015, 2017 Todd C. Miller <Todd.Miller@sudo.ws>
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 #ifndef SUDO_EVENT_H
20 #define SUDO_EVENT_H
21
22 #include <signal.h>     /* for sigatomic_t and NSIG */
23 #include "sudo_queue.h"
24
25 /* Event types */
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) */
32
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 */
37
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 */
41
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
50
51 typedef void (*sudo_ev_callback_t)(int fd, int what, void *closure);
52
53 /*
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.
56  */
57 struct sudo_ev_siginfo_container {
58     void *closure;
59     siginfo_t *siginfo;
60     char si_buf[1];
61 };
62
63 /* Member of struct sudo_event_base. */
64 struct sudo_event {
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 */
77 };
78 TAILQ_HEAD(sudo_event_list, sudo_event);
79
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 */
97 #else
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_* */
106 };
107
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()
111
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))
115
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))
119
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))
123
124 /* Free an event. */
125 __dso_public void sudo_ev_free_v1(struct sudo_event *ev);
126 #define sudo_ev_free(_a) sudo_ev_free_v1((_a))
127
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))
132
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))
136
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))
140
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))
144
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))
149
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))
153
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))
157
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))
161
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))
165
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))
169
170 /* Return the fd associated with an event. */
171 #define sudo_ev_get_fd(_ev) ((_ev) ? (_ev)->fd : -1)
172
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)
176
177 /* Return the base an event is associated with or NULL. */
178 #define sudo_ev_get_base(_ev) ((_ev) ? (_ev)->base : NULL)
179
180 /* Magic pointer value to use self pointer as callback arg. */
181 #define sudo_ev_self_cbarg() ((void *)-1)
182
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);
185
186 /*
187  * Backend implementation.
188  */
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);
194
195 #endif /* SUDO_EVENT_H */