Home | History | Annotate | Download | only in dhcpcd-6.8.2
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2015 Roy Marples <roy (at) marples.name>
      4  * All rights reserved
      5 
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/time.h>
     29 
     30 #include <errno.h>
     31 #include <limits.h>
     32 #include <signal.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <unistd.h>
     36 
     37 #include "config.h"
     38 #include "common.h"
     39 #include "dhcpcd.h"
     40 #include "eloop.h"
     41 
     42 #if defined(HAVE_KQUEUE)
     43 #include <sys/event.h>
     44 #include <fcntl.h>
     45 #ifdef __NetBSD__
     46 /* udata is void * except on NetBSD
     47  * lengths are int except on NetBSD */
     48 #define UPTR(x)	((intptr_t)(x))
     49 #define LENC(x)	(x)
     50 #else
     51 #define UPTR(x)	(x)
     52 #define LENC(x)	((int)(x))
     53 #endif
     54 #define eloop_event_setup_fds(ctx)
     55 #elif defined(HAVE_EPOLL)
     56 #include <sys/epoll.h>
     57 #define eloop_event_setup_fds(ctx)
     58 #else
     59 #include <poll.h>
     60 static void
     61 eloop_event_setup_fds(struct eloop_ctx *ctx)
     62 {
     63 	struct eloop_event *e;
     64 	size_t i;
     65 
     66 	i = 0;
     67 	TAILQ_FOREACH(e, &ctx->events, next) {
     68 		ctx->fds[i].fd = e->fd;
     69 		ctx->fds[i].events = 0;
     70 		if (e->read_cb)
     71 			ctx->fds[i].events |= POLLIN;
     72 		if (e->write_cb)
     73 			ctx->fds[i].events |= POLLOUT;
     74 		ctx->fds[i].revents = 0;
     75 		e->pollfd = &ctx->fds[i];
     76 		i++;
     77 	}
     78 }
     79 #endif
     80 
     81 int
     82 eloop_event_add(struct eloop_ctx *ctx, int fd,
     83     void (*read_cb)(void *), void *read_cb_arg,
     84     void (*write_cb)(void *), void *write_cb_arg)
     85 {
     86 	struct eloop_event *e;
     87 #if defined(HAVE_KQUEUE)
     88 	struct kevent ke[2];
     89 #elif defined(HAVE_EPOLL)
     90 	struct epoll_event epe;
     91 #else
     92 	struct pollfd *nfds;
     93 #endif
     94 
     95 #ifdef HAVE_EPOLL
     96 	memset(&epe, 0, sizeof(epe));
     97 	epe.data.fd = fd;
     98 	epe.events = EPOLLIN;
     99 	if (write_cb)
    100 		epe.events |= EPOLLOUT;
    101 #endif
    102 
    103 	/* We should only have one callback monitoring the fd */
    104 	TAILQ_FOREACH(e, &ctx->events, next) {
    105 		if (e->fd == fd) {
    106 			int error;
    107 
    108 #if defined(HAVE_KQUEUE)
    109 			EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD,
    110 			    0, 0, UPTR(e));
    111 			if (write_cb)
    112 				EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
    113 				    EV_ADD, 0, 0, UPTR(e));
    114 			else if (e->write_cb)
    115 				EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
    116 				    EV_DELETE, 0, 0, UPTR(e));
    117 			error = kevent(ctx->poll_fd, ke,
    118 			    e->write_cb || write_cb ? 2 : 1, NULL, 0, NULL);
    119 #elif defined(HAVE_EPOLL)
    120 			epe.data.ptr = e;
    121 			error = epoll_ctl(ctx->poll_fd, EPOLL_CTL_MOD,
    122 			    fd, &epe);
    123 #else
    124 			error = 0;
    125 #endif
    126 			if (read_cb) {
    127 				e->read_cb = read_cb;
    128 				e->read_cb_arg = read_cb_arg;
    129 			}
    130 			if (write_cb) {
    131 				e->write_cb = write_cb;
    132 				e->write_cb_arg = write_cb_arg;
    133 			}
    134 			eloop_event_setup_fds(ctx);
    135 			return error;
    136 		}
    137 	}
    138 
    139 	/* Allocate a new event if no free ones already allocated */
    140 	if ((e = TAILQ_FIRST(&ctx->free_events))) {
    141 		TAILQ_REMOVE(&ctx->free_events, e, next);
    142 	} else {
    143 		e = malloc(sizeof(*e));
    144 		if (e == NULL)
    145 			goto err;
    146 	}
    147 
    148 	/* Ensure we can actually listen to it */
    149 	ctx->events_len++;
    150 #if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL)
    151 	if (ctx->events_len > ctx->fds_len) {
    152 		nfds = realloc(ctx->fds, sizeof(*ctx->fds) * (ctx->fds_len+5));
    153 		if (nfds == NULL)
    154 			goto err;
    155 		ctx->fds_len += 5;
    156 		ctx->fds = nfds;
    157 	}
    158 #endif
    159 
    160 	/* Now populate the structure and add it to the list */
    161 	e->fd = fd;
    162 	e->read_cb = read_cb;
    163 	e->read_cb_arg = read_cb_arg;
    164 	e->write_cb = write_cb;
    165 	e->write_cb_arg = write_cb_arg;
    166 
    167 #if defined(HAVE_KQUEUE)
    168 	EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD, 0, 0, UPTR(e));
    169 	if (write_cb)
    170 		EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
    171 		    EV_ADD, 0, 0, UPTR(e));
    172 	if (kevent(ctx->poll_fd, ke, write_cb ? 2 : 1, NULL, 0, NULL) == -1)
    173 		goto err;
    174 #elif defined(HAVE_EPOLL)
    175 	epe.data.ptr = e;
    176 	if (epoll_ctl(ctx->poll_fd, EPOLL_CTL_ADD, fd, &epe) == -1)
    177 		goto err;
    178 #endif
    179 
    180 	/* The order of events should not matter.
    181 	 * However, some PPP servers love to close the link right after
    182 	 * sending their final message. So to ensure dhcpcd processes this
    183 	 * message (which is likely to be that the DHCP addresses are wrong)
    184 	 * we insert new events at the queue head as the link fd will be
    185 	 * the first event added. */
    186 	TAILQ_INSERT_HEAD(&ctx->events, e, next);
    187 	eloop_event_setup_fds(ctx);
    188 	return 0;
    189 
    190 err:
    191 	logger(ctx->ctx, LOG_ERR, "%s: %m", __func__);
    192 	if (e) {
    193 		ctx->events_len--;
    194 		TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
    195 	}
    196 	return -1;
    197 }
    198 
    199 void
    200 eloop_event_delete(struct eloop_ctx *ctx, int fd, int write_only)
    201 {
    202 	struct eloop_event *e;
    203 #if defined(HAVE_KQUEUE)
    204 	struct kevent ke[2];
    205 #elif defined(HAVE_EPOLL)
    206 	struct epoll_event epe;
    207 #endif
    208 
    209 	TAILQ_FOREACH(e, &ctx->events, next) {
    210 		if (e->fd == fd) {
    211 			if (write_only) {
    212 				if (e->write_cb) {
    213 					e->write_cb = NULL;
    214 					e->write_cb_arg = NULL;
    215 #if defined(HAVE_KQUEUE)
    216 					EV_SET(&ke[0], (uintptr_t)fd,
    217 					    EVFILT_WRITE, EV_DELETE,
    218 					    0, 0, UPTR(NULL));
    219 					kevent(ctx->poll_fd, ke, 1, NULL, 0,
    220 					    NULL);
    221 #elif defined(HAVE_EPOLL)
    222 					memset(&epe, 0, sizeof(epe));
    223 					epe.data.fd = e->fd;
    224 					epe.data.ptr = e;
    225 					epe.events = EPOLLIN;
    226 					epoll_ctl(ctx->poll_fd, EPOLL_CTL_MOD,
    227 					    fd, &epe);
    228 #endif
    229 				}
    230 
    231 			} else {
    232 				TAILQ_REMOVE(&ctx->events, e, next);
    233 #if defined(HAVE_KQUEUE)
    234 				EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ,
    235 				    EV_DELETE, 0, 0, UPTR(NULL));
    236 				if (e->write_cb)
    237 					EV_SET(&ke[1], (uintptr_t)fd,
    238 					    EVFILT_WRITE, EV_DELETE,
    239 					    0, 0, UPTR(NULL));
    240 				kevent(ctx->poll_fd, ke, e->write_cb ? 2 : 1,
    241 				    NULL, 0, NULL);
    242 #elif defined(HAVE_EPOLL)
    243 				/* NULL event is safe because we
    244 				 * rely on epoll_pwait which as added
    245 				 * after the delete without event was fixed. */
    246 				epoll_ctl(ctx->poll_fd, EPOLL_CTL_DEL,
    247 				    fd, NULL);
    248 #endif
    249 				TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
    250 				ctx->events_len--;
    251 			}
    252 			eloop_event_setup_fds(ctx);
    253 			break;
    254 		}
    255 	}
    256 }
    257 
    258 int
    259 eloop_q_timeout_add_tv(struct eloop_ctx *ctx, int queue,
    260     const struct timespec *when, void (*callback)(void *), void *arg)
    261 {
    262 	struct timespec now, w;
    263 	struct eloop_timeout *t, *tt = NULL;
    264 
    265 	get_monotonic(&now);
    266 	timespecadd(&now, when, &w);
    267 	/* Check for time_t overflow. */
    268 	if (timespeccmp(&w, &now, <)) {
    269 		errno = ERANGE;
    270 		return -1;
    271 	}
    272 
    273 	/* Remove existing timeout if present */
    274 	TAILQ_FOREACH(t, &ctx->timeouts, next) {
    275 		if (t->callback == callback && t->arg == arg) {
    276 			TAILQ_REMOVE(&ctx->timeouts, t, next);
    277 			break;
    278 		}
    279 	}
    280 
    281 	if (t == NULL) {
    282 		/* No existing, so allocate or grab one from the free pool */
    283 		if ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
    284 			TAILQ_REMOVE(&ctx->free_timeouts, t, next);
    285 		} else {
    286 			t = malloc(sizeof(*t));
    287 			if (t == NULL) {
    288 				logger(ctx->ctx, LOG_ERR, "%s: %m", __func__);
    289 				return -1;
    290 			}
    291 		}
    292 	}
    293 
    294 	t->when = w;
    295 	t->callback = callback;
    296 	t->arg = arg;
    297 	t->queue = queue;
    298 
    299 	/* The timeout list should be in chronological order,
    300 	 * soonest first. */
    301 	TAILQ_FOREACH(tt, &ctx->timeouts, next) {
    302 		if (timespeccmp(&t->when, &tt->when, <)) {
    303 			TAILQ_INSERT_BEFORE(tt, t, next);
    304 			return 0;
    305 		}
    306 	}
    307 	TAILQ_INSERT_TAIL(&ctx->timeouts, t, next);
    308 	return 0;
    309 }
    310 
    311 int
    312 eloop_q_timeout_add_sec(struct eloop_ctx *ctx, int queue, time_t when,
    313     void (*callback)(void *), void *arg)
    314 {
    315 	struct timespec tv;
    316 
    317 	tv.tv_sec = when;
    318 	tv.tv_nsec = 0;
    319 	return eloop_q_timeout_add_tv(ctx, queue, &tv, callback, arg);
    320 }
    321 
    322 #if !defined(HAVE_KQUEUE)
    323 int
    324 eloop_timeout_add_now(struct eloop_ctx *ctx,
    325     void (*callback)(void *), void *arg)
    326 {
    327 
    328 	if (ctx->timeout0 != NULL) {
    329 		logger(ctx->ctx, LOG_WARNING,
    330 		    "%s: timeout0 already set", __func__);
    331 		return eloop_q_timeout_add_sec(ctx, 0, 0, callback, arg);
    332 	}
    333 
    334 	ctx->timeout0 = callback;
    335 	ctx->timeout0_arg = arg;
    336 	return 0;
    337 }
    338 #endif
    339 
    340 void
    341 eloop_q_timeout_delete(struct eloop_ctx *ctx, int queue,
    342     void (*callback)(void *), void *arg)
    343 {
    344 	struct eloop_timeout *t, *tt;
    345 
    346 	TAILQ_FOREACH_SAFE(t, &ctx->timeouts, next, tt) {
    347 		if ((queue == 0 || t->queue == queue) &&
    348 		    t->arg == arg &&
    349 		    (!callback || t->callback == callback))
    350 		{
    351 			TAILQ_REMOVE(&ctx->timeouts, t, next);
    352 			TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
    353 		}
    354 	}
    355 }
    356 
    357 void
    358 eloop_exit(struct eloop_ctx *ctx, int code)
    359 {
    360 
    361 	ctx->exitcode = code;
    362 	ctx->exitnow = 1;
    363 }
    364 
    365 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
    366 static int
    367 eloop_open(struct eloop_ctx *ctx)
    368 {
    369 #if defined(HAVE_KQUEUE1)
    370 	return (ctx->poll_fd = kqueue1(O_CLOEXEC));
    371 #elif defined(HAVE_KQUEUE)
    372 	int i;
    373 
    374 	if ((ctx->poll_fd = kqueue()) == -1)
    375 		return -1;
    376 	if ((i = fcntl(ctx->poll_fd, F_GETFD, 0)) == -1 ||
    377 	    fcntl(ctx->poll_fd, F_SETFD, i | FD_CLOEXEC) == -1)
    378 	{
    379 		close(ctx->poll_fd);
    380 		ctx->poll_fd = -1;
    381 		return -1;
    382 	}
    383 
    384 	return ctx->poll_fd;
    385 #elif defined (HAVE_EPOLL)
    386 	return (ctx->poll_fd = epoll_create1(EPOLL_CLOEXEC));
    387 #endif
    388 }
    389 
    390 int
    391 eloop_requeue(struct eloop_ctx *ctx)
    392 {
    393 	struct eloop_event *e;
    394 	int error;
    395 #if defined(HAVE_KQUEUE)
    396 	size_t i;
    397 	struct kevent *ke;
    398 #elif defined(HAVE_EPOLL)
    399 	struct epoll_event epe;
    400 #endif
    401 
    402 	if (ctx->poll_fd != -1)
    403 		close(ctx->poll_fd);
    404 	if (eloop_open(ctx) == -1)
    405 		return -1;
    406 #if defined (HAVE_KQUEUE)
    407 	i = 0;
    408 	while (dhcpcd_handlesigs[i])
    409 		i++;
    410 	TAILQ_FOREACH(e, &ctx->events, next) {
    411 		i++;
    412 		if (e->write_cb)
    413 			i++;
    414 	}
    415 
    416 	if ((ke = malloc(sizeof(*ke) * i)) == NULL)
    417 		return -1;
    418 
    419 	for (i = 0; dhcpcd_handlesigs[i]; i++)
    420 		EV_SET(&ke[i], (uintptr_t)dhcpcd_handlesigs[i],
    421 		    EVFILT_SIGNAL, EV_ADD, 0, 0, UPTR(NULL));
    422 
    423 	TAILQ_FOREACH(e, &ctx->events, next) {
    424 		EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_READ,
    425 		    EV_ADD, 0, 0, UPTR(e));
    426 		i++;
    427 		if (e->write_cb) {
    428 			EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_WRITE,
    429 			    EV_ADD, 0, 0, UPTR(e));
    430 			i++;
    431 		}
    432 	}
    433 
    434 	error =  kevent(ctx->poll_fd, ke, LENC(i), NULL, 0, NULL);
    435 	free(ke);
    436 
    437 #elif defined(HAVE_EPOLL)
    438 
    439 	error = 0;
    440 	TAILQ_FOREACH(e, &ctx->events, next) {
    441 		memset(&epe, 0, sizeof(epe));
    442 		epe.data.fd = e->fd;
    443 		epe.events = EPOLLIN;
    444 		if (e->write_cb)
    445 			epe.events |= EPOLLOUT;
    446 		epe.data.ptr = e;
    447 		if (epoll_ctl(ctx->poll_fd, EPOLL_CTL_ADD, e->fd, &epe) == -1)
    448 			error = -1;
    449 	}
    450 #endif
    451 
    452 	return error;
    453 }
    454 #endif
    455 
    456 struct eloop_ctx *
    457 eloop_init(struct dhcpcd_ctx *dctx)
    458 {
    459 	struct eloop_ctx *ctx;
    460 	struct timespec now;
    461 
    462 	/* Check we have a working monotonic clock. */
    463 	if (get_monotonic(&now) == -1)
    464 		return NULL;
    465 
    466 	ctx = calloc(1, sizeof(*ctx));
    467 	if (ctx) {
    468 		ctx->ctx = dctx;
    469 		TAILQ_INIT(&ctx->events);
    470 		TAILQ_INIT(&ctx->free_events);
    471 		TAILQ_INIT(&ctx->timeouts);
    472 		TAILQ_INIT(&ctx->free_timeouts);
    473 		ctx->exitcode = EXIT_FAILURE;
    474 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
    475 		ctx->poll_fd = -1;
    476 #endif
    477 		if (eloop_requeue(ctx) == -1) {
    478 			free(ctx);
    479 			return NULL;
    480 		}
    481 	}
    482 
    483 	return ctx;
    484 }
    485 
    486 void eloop_free(struct eloop_ctx *ctx)
    487 {
    488 	struct eloop_event *e;
    489 	struct eloop_timeout *t;
    490 
    491 	if (ctx == NULL)
    492 		return;
    493 
    494 	while ((e = TAILQ_FIRST(&ctx->events))) {
    495 		TAILQ_REMOVE(&ctx->events, e, next);
    496 		free(e);
    497 	}
    498 	while ((e = TAILQ_FIRST(&ctx->free_events))) {
    499 		TAILQ_REMOVE(&ctx->free_events, e, next);
    500 		free(e);
    501 	}
    502 	while ((t = TAILQ_FIRST(&ctx->timeouts))) {
    503 		TAILQ_REMOVE(&ctx->timeouts, t, next);
    504 		free(t);
    505 	}
    506 	while ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
    507 		TAILQ_REMOVE(&ctx->free_timeouts, t, next);
    508 		free(t);
    509 	}
    510 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
    511 	close(ctx->poll_fd);
    512 #else
    513 	free(ctx->fds);
    514 #endif
    515 	free(ctx);
    516 }
    517 
    518 int
    519 eloop_start(struct eloop_ctx *ctx)
    520 {
    521 	int n;
    522 	struct eloop_event *e;
    523 	struct eloop_timeout *t;
    524 	struct timespec now, ts, *tsp;
    525 	void (*t0)(void *);
    526 #if defined(HAVE_EPOLL) || !defined(USE_SIGNALS)
    527 	int timeout;
    528 #endif
    529 #if defined(HAVE_KQUEUE)
    530 	struct kevent ke;
    531 #elif defined(HAVE_EPOLL)
    532 	struct epoll_event epe;
    533 #endif
    534 
    535 	for (;;) {
    536 		if (ctx->exitnow)
    537 			break;
    538 
    539 		/* Run all timeouts first */
    540 		if (ctx->timeout0) {
    541 			t0 = ctx->timeout0;
    542 			ctx->timeout0 = NULL;
    543 			t0(ctx->timeout0_arg);
    544 			continue;
    545 		}
    546 		if ((t = TAILQ_FIRST(&ctx->timeouts))) {
    547 			get_monotonic(&now);
    548 			if (timespeccmp(&now, &t->when, >)) {
    549 				TAILQ_REMOVE(&ctx->timeouts, t, next);
    550 				t->callback(t->arg);
    551 				TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
    552 				continue;
    553 			}
    554 			timespecsub(&t->when, &now, &ts);
    555 			tsp = &ts;
    556 		} else
    557 			/* No timeouts, so wait forever */
    558 			tsp = NULL;
    559 
    560 		if (tsp == NULL && ctx->events_len == 0) {
    561 			logger(ctx->ctx, LOG_ERR, "nothing to do");
    562 			break;
    563 		}
    564 
    565 #if defined(HAVE_EPOLL) || !defined(USE_SIGNALS)
    566 		if (tsp == NULL)
    567 			timeout = -1;
    568 		else if (tsp->tv_sec > INT_MAX / 1000 ||
    569 		    (tsp->tv_sec == INT_MAX / 1000 &&
    570 		    (tsp->tv_nsec + 999999) / 1000000 > INT_MAX % 1000000))
    571 			timeout = INT_MAX;
    572 		else
    573 			timeout = (int)(tsp->tv_sec * 1000 +
    574 			    (tsp->tv_nsec + 999999) / 1000000);
    575 #endif
    576 
    577 #if defined(HAVE_KQUEUE)
    578 		n = kevent(ctx->poll_fd, NULL, 0, &ke, 1, tsp);
    579 #elif defined(HAVE_EPOLL)
    580 #ifdef USE_SIGNALS
    581 		n = epoll_pwait(ctx->poll_fd, &epe, 1, timeout,
    582 		    &ctx->ctx->sigset);
    583 #else
    584 		n = epoll_wait(ctx->poll_fd, &epe, 1, timeout);
    585 #endif
    586 #else
    587 #ifdef USE_SIGNALS
    588 		n = pollts(ctx->fds, (nfds_t)ctx->events_len, tsp,
    589 		    &ctx->ctx->sigset);
    590 #else
    591 		n = poll(ctx->fds, (nfds_t)ctx->events_len, timeout);
    592 #endif
    593 #endif
    594 		if (n == -1) {
    595 			if (errno == EINTR)
    596 				continue;
    597 			logger(ctx->ctx, LOG_ERR, "poll: %m");
    598 			break;
    599 		}
    600 
    601 		/* Process any triggered events.
    602 		 * We go back to the start after calling each callback incase
    603 		 * the current event or next event is removed. */
    604 #if defined(HAVE_KQUEUE)
    605 		if (n) {
    606 			if (ke.filter == EVFILT_SIGNAL) {
    607 				struct dhcpcd_siginfo si;
    608 
    609 				si.signo = (int)ke.ident;
    610 				dhcpcd_handle_signal(&si);
    611 				continue;
    612 			}
    613 			e = (struct eloop_event *)ke.udata;
    614 			if (ke.filter == EVFILT_WRITE) {
    615 				e->write_cb(e->write_cb_arg);
    616 				continue;
    617 			} else if (ke.filter == EVFILT_READ) {
    618 				e->read_cb(e->read_cb_arg);
    619 				continue;
    620 			}
    621 		}
    622 #elif defined(HAVE_EPOLL)
    623 		if (n) {
    624 			e = (struct eloop_event *)epe.data.ptr;
    625 			if (epe.events & EPOLLOUT && e->write_cb) {
    626 				e->write_cb(e->write_cb_arg);
    627 				continue;
    628 			}
    629 			if (epe.events &
    630 			    (EPOLLIN | EPOLLERR | EPOLLHUP))
    631 			{
    632 				e->read_cb(e->read_cb_arg);
    633 				continue;
    634 			}
    635 		}
    636 #else
    637 		if (n > 0) {
    638 			TAILQ_FOREACH(e, &ctx->events, next) {
    639 				if (e->pollfd->revents & POLLOUT &&
    640 				    e->write_cb)
    641 				{
    642 					e->write_cb(e->write_cb_arg);
    643 					break;
    644 				}
    645 				if (e->pollfd->revents) {
    646 					e->read_cb(e->read_cb_arg);
    647 					break;
    648 				}
    649 			}
    650 		}
    651 #endif
    652 	}
    653 
    654 	return ctx->exitcode;
    655 }
    656