mirror of
https://github.com/rsmarples/dhcpcd.git
synced 2024-11-23 18:14:09 +08:00
Replace poll(2) with pselect(2) and vfork(2)+execve(2) with
posix_spawn(3). Now we block all our signals at startup and allow pselect to unblock them for the duration of the call. This allows us to manage interrupts in a fashion to guarantee a consistent internal state. I have added a posix_spawn compat shim for systems that lack that call. pselect(2) has been supported on target for some time so there is no need for a compat shim there.
This commit is contained in:
parent
599c9aeb6b
commit
5c08c0c4ca
6
bind.c
6
bind.c
@ -59,16 +59,12 @@ pid_t
|
||||
daemonise(void)
|
||||
{
|
||||
pid_t pid;
|
||||
sigset_t full;
|
||||
sigset_t old;
|
||||
char buf = '\0';
|
||||
int sidpipe[2], fd;
|
||||
|
||||
delete_timeout(handle_exit_timeout, NULL);
|
||||
if (options & DHCPCD_DAEMONISED || !(options & DHCPCD_DAEMONISE))
|
||||
return 0;
|
||||
sigfillset(&full);
|
||||
sigprocmask(SIG_SETMASK, &full, &old);
|
||||
/* Setup a signal pipe so parent knows when to exit. */
|
||||
if (pipe(sidpipe) == -1) {
|
||||
syslog(LOG_ERR, "pipe: %m");
|
||||
@ -96,7 +92,6 @@ daemonise(void)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
signal_reset();
|
||||
/* Wait for child to detach */
|
||||
close(sidpipe[1]);
|
||||
if (read(sidpipe[0], &buf, 1) == -1)
|
||||
@ -114,7 +109,6 @@ daemonise(void)
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
options |= DHCPCD_DAEMONISED;
|
||||
sigprocmask(SIG_SETMASK, &old, NULL);
|
||||
return pid;
|
||||
}
|
||||
#endif
|
||||
|
135
compat/posix_spawn.c
Normal file
135
compat/posix_spawn.c
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* This implementation of posix_spawn is only suitable for the needs of dhcpcd
|
||||
* but it could easily be extended to other applications.
|
||||
* Also, it does rely on the system being able to modify signals safely within
|
||||
* the vfork process which is undefined behaviour, but seems sane in testing. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../common.h"
|
||||
#include "posix_spawn.h"
|
||||
|
||||
extern char **environ;
|
||||
|
||||
static int
|
||||
posix_spawnattr_handle(const posix_spawnattr_t *attrp)
|
||||
{
|
||||
struct sigaction sa;
|
||||
int i;
|
||||
|
||||
if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGMASK)
|
||||
sigprocmask(SIG_SETMASK, &attrp->posix_attr_sigmask, NULL);
|
||||
|
||||
if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGDEF) {
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
for (i = 1; i <= _SIG_MAXSIG; i++) {
|
||||
if (sigismember(&attrp->posix_attr_sigdefault, i)) {
|
||||
if (sigaction(i, &sa, NULL) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn(pid_t *pid, const char * path,
|
||||
_unused void *arg,
|
||||
const posix_spawnattr_t *attrp,
|
||||
char *const argv[], char *const envp[])
|
||||
{
|
||||
pid_t p;
|
||||
volatile int error;
|
||||
|
||||
error = 0;
|
||||
p = vfork();
|
||||
switch (p) {
|
||||
case -1:
|
||||
return errno;
|
||||
case 0:
|
||||
if (attrp) {
|
||||
error = posix_spawnattr_handle(attrp);
|
||||
if (error)
|
||||
_exit(127);
|
||||
}
|
||||
execve(path, argv, envp);
|
||||
error = errno;
|
||||
_exit(127);
|
||||
default:
|
||||
if (error != 0)
|
||||
waitpid(p, NULL, WNOHANG);
|
||||
else if (pid != NULL)
|
||||
*pid = p;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawnattr_init(posix_spawnattr_t *attr)
|
||||
{
|
||||
|
||||
memset(attr, 0, sizeof(*attr));
|
||||
attr->posix_attr_flags = 0;
|
||||
sigprocmask(0, NULL, &attr->posix_attr_sigmask);
|
||||
sigemptyset(&attr->posix_attr_sigdefault);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
|
||||
{
|
||||
|
||||
attr->posix_attr_flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawnattr_setsigmask(posix_spawnattr_t *attr, const sigset_t *sigmask)
|
||||
{
|
||||
|
||||
attr->posix_attr_sigmask = *sigmask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawnattr_setsigdefault(posix_spawnattr_t *attr, const sigset_t *sigmask)
|
||||
{
|
||||
|
||||
attr->posix_attr_sigdefault = *sigmask;
|
||||
return 0;
|
||||
}
|
46
compat/posix_spawn.h
Normal file
46
compat/posix_spawn.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef POSIX_SPAWN_H
|
||||
#define POSIX_SPAWN_H
|
||||
|
||||
typedef struct {
|
||||
short posix_attr_flags;
|
||||
#define POSIX_SPAWN_SETSIGDEF 0x10
|
||||
#define POSIX_SPAWN_SETSIGMASK 0x20
|
||||
sigset_t posix_attr_sigmask;
|
||||
sigset_t posix_attr_sigdefault;
|
||||
} posix_spawnattr_t;
|
||||
|
||||
int posix_spawn(pid_t *, const char *, void *, const posix_spawnattr_t *,
|
||||
char *const [], char *const []);
|
||||
int posix_spawnattr_init(posix_spawnattr_t *);
|
||||
int posix_spawnattr_setflags(posix_spawnattr_t *, short);
|
||||
int posix_spawnattr_setsigmask(posix_spawnattr_t *, const sigset_t *);
|
||||
int posix_spawnattr_setsigdefault(posix_spawnattr_t *, const sigset_t *);
|
||||
|
||||
#endif
|
25
configure
vendored
25
configure
vendored
@ -412,6 +412,31 @@ if [ "$TAILQ_FOREACH_SAFE" = no ]; then
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ -z "$POSIX_SPAWN" ]; then
|
||||
printf "Testing for posix_spawn ... "
|
||||
cat <<EOF >_posix_spawn.c
|
||||
#include <spawn.h>
|
||||
#include <stdlib.h>
|
||||
int main(void) {
|
||||
posix_spawn(NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if $XCC _posix_spawn.c -o _posix_spawn 2>/dev/null; then
|
||||
POSIX_SPAWN=yes
|
||||
else
|
||||
POSIX_SPAWN=no
|
||||
fi
|
||||
echo "$POSIX_SPAWN"
|
||||
rm -f _posix_spawn.c _posix_spawn
|
||||
fi
|
||||
if [ "$POSIX_SPAWN" = no ]; then
|
||||
echo "COMPAT_SRCS+= compat/posix_spawn.c" >>$CONFIG_MK
|
||||
echo "#include \"compat/posix_spawn.h\"" >>$CONFIG_H
|
||||
else
|
||||
echo "#include <spawn.h>" >>$CONFIG_H
|
||||
fi
|
||||
|
||||
if [ -z "$SERVICECMD" ]; then
|
||||
printf "Checking for OpenRC ... "
|
||||
if [ -x /sbin/rc-service ]; then
|
||||
|
47
configure.c
47
configure.c
@ -35,6 +35,8 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
/* We can't include spawn.h here because it may not exist.
|
||||
* config.h will pull it in, or our compat one. */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
@ -81,29 +83,25 @@ static int
|
||||
exec_script(char *const *argv, char *const *env)
|
||||
{
|
||||
pid_t pid;
|
||||
sigset_t full;
|
||||
sigset_t old;
|
||||
posix_spawnattr_t attr;
|
||||
sigset_t defsigs;
|
||||
int i;
|
||||
|
||||
/* OK, we need to block signals */
|
||||
sigfillset(&full);
|
||||
sigprocmask(SIG_SETMASK, &full, &old);
|
||||
signal_reset();
|
||||
|
||||
switch (pid = vfork()) {
|
||||
case -1:
|
||||
syslog(LOG_ERR, "vfork: %m");
|
||||
break;
|
||||
case 0:
|
||||
sigprocmask(SIG_SETMASK, &old, NULL);
|
||||
execve(argv[0], argv, env);
|
||||
syslog(LOG_ERR, "%s: %m", argv[0]);
|
||||
_exit(127);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* Restore our signals */
|
||||
signal_setup();
|
||||
sigprocmask(SIG_SETMASK, &old, NULL);
|
||||
/* posix_spawn is a safe way of executing another image
|
||||
* and changing signals back to how they should be. */
|
||||
if (posix_spawnattr_init(&attr) == -1)
|
||||
return -1;
|
||||
posix_spawnattr_setflags(&attr,
|
||||
POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF);
|
||||
sigemptyset(&defsigs);
|
||||
for (i = 0; i < handle_sigs[i]; i++)
|
||||
sigaddset(&defsigs, handle_sigs[i]);
|
||||
posix_spawnattr_setsigdefault(&attr, &defsigs);
|
||||
posix_spawnattr_setsigmask(&attr, &dhcpcd_sigset);
|
||||
errno = 0;
|
||||
i = posix_spawn(&pid, argv[0], NULL, &attr, argv, env);
|
||||
if (i)
|
||||
return -1;
|
||||
return pid;
|
||||
}
|
||||
|
||||
@ -423,9 +421,10 @@ run_script_reason(const struct interface *iface, const char *reason)
|
||||
env[++elen] = '\0';
|
||||
|
||||
pid = exec_script(argv, env);
|
||||
if (pid == -1)
|
||||
if (pid == -1) {
|
||||
syslog(LOG_ERR, "exec_script: %m");
|
||||
status = -1;
|
||||
else if (pid != 0) {
|
||||
} else if (pid != 0) {
|
||||
/* Wait for the script to finish */
|
||||
while (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno != EINTR) {
|
||||
|
34
dhcpcd.c
34
dhcpcd.c
@ -92,15 +92,17 @@ char **ifav = NULL;
|
||||
int ifdc = 0;
|
||||
char **ifdv = NULL;
|
||||
|
||||
static char **margv;
|
||||
static int margc;
|
||||
static struct if_options *if_options;
|
||||
static char **ifv;
|
||||
static int ifc;
|
||||
sigset_t dhcpcd_sigset;
|
||||
|
||||
static char *cffile;
|
||||
static struct if_options *if_options;
|
||||
static char *pidfile;
|
||||
static int linkfd = -1, ipv6rsfd = -1, ipv6nsfd = -1;
|
||||
static uint8_t *packet;
|
||||
static char **ifv;
|
||||
static int ifc;
|
||||
static char **margv;
|
||||
static int margc;
|
||||
|
||||
struct dhcp_op {
|
||||
uint8_t value;
|
||||
@ -1538,13 +1540,11 @@ reconf_reboot(int action, int argc, char **argv, int oi)
|
||||
sort_interfaces();
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
handle_signal(_unused void *arg)
|
||||
void
|
||||
handle_signal(int sig)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct if_options *ifo;
|
||||
int sig = signal_read();
|
||||
int do_release, i;
|
||||
|
||||
do_release = 0;
|
||||
@ -1809,7 +1809,7 @@ main(int argc, char **argv)
|
||||
{
|
||||
struct interface *iface;
|
||||
uint16_t family = 0;
|
||||
int opt, oi = 0, signal_fd, sig = 0, i, control_fd;
|
||||
int opt, oi = 0, sig = 0, i, control_fd;
|
||||
size_t len;
|
||||
pid_t pid;
|
||||
struct timespec ts;
|
||||
@ -2059,11 +2059,15 @@ main(int argc, char **argv)
|
||||
eloop_init();
|
||||
#endif
|
||||
|
||||
if ((signal_fd = signal_init()) == -1)
|
||||
/* This blocks all signals we're interested in.
|
||||
* eloop uses pselect(2) so that the signals are unblocked
|
||||
* when we're testing fd's.
|
||||
* This allows us to ensure a consistent state is maintained
|
||||
* regardless of when we are interrupted .*/
|
||||
if (signal_setup(handle_signal, &dhcpcd_sigset) == -1) {
|
||||
syslog(LOG_ERR, "signal_setup: %m");
|
||||
exit(EXIT_FAILURE);
|
||||
if (signal_setup() == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
add_event(signal_fd, handle_signal, NULL);
|
||||
}
|
||||
|
||||
if (options & DHCPCD_MASTER) {
|
||||
if (start_control() == -1)
|
||||
@ -2196,6 +2200,6 @@ main(int argc, char **argv)
|
||||
for (iface = ifaces; iface; iface = iface->next)
|
||||
add_timeout_sec(0, start_interface, iface);
|
||||
|
||||
start_eloop();
|
||||
start_eloop(&dhcpcd_sigset);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
2
dhcpcd.h
2
dhcpcd.h
@ -120,6 +120,7 @@ struct interface {
|
||||
};
|
||||
|
||||
extern char vendor[VENDORCLASSID_MAX_LEN];
|
||||
extern sigset_t dhcpcd_sigset;
|
||||
extern int pidfd;
|
||||
extern int ifac;
|
||||
extern char **ifav;
|
||||
@ -135,6 +136,7 @@ void handle_hwaddr(const char *, unsigned char *, size_t);
|
||||
void handle_ifa(int, const char *,
|
||||
struct in_addr *, struct in_addr *, struct in_addr *);
|
||||
void handle_exit_timeout(void *);
|
||||
void handle_signal(int);
|
||||
void start_interface(void *);
|
||||
void start_discover(void *);
|
||||
void start_request(void *);
|
||||
|
89
eloop.c
89
eloop.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -30,11 +30,13 @@
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "dhcpcd.h"
|
||||
#include "eloop.h"
|
||||
|
||||
static struct timeval now;
|
||||
@ -56,9 +58,6 @@ static struct timeout {
|
||||
} *timeouts;
|
||||
static struct timeout *free_timeouts;
|
||||
|
||||
static struct pollfd *fds;
|
||||
static size_t fds_len;
|
||||
|
||||
void
|
||||
add_event(int fd, void (*callback)(void *), void *arg)
|
||||
{
|
||||
@ -274,7 +273,6 @@ cleanup(void)
|
||||
free(free_timeouts);
|
||||
free_timeouts = t;
|
||||
}
|
||||
free(fds);
|
||||
}
|
||||
|
||||
void
|
||||
@ -286,18 +284,20 @@ eloop_init(void)
|
||||
#endif
|
||||
|
||||
_noreturn void
|
||||
start_eloop(void)
|
||||
start_eloop(const sigset_t *cursigs)
|
||||
{
|
||||
int msecs, n;
|
||||
nfds_t nfds, i;
|
||||
int n, max_fd;
|
||||
fd_set read_fds, error_fds;
|
||||
struct event *e;
|
||||
struct timeout *t;
|
||||
struct timeval tv;
|
||||
struct timespec ts;
|
||||
const struct timespec *tsp;
|
||||
|
||||
for (;;) {
|
||||
/* Run all timeouts first.
|
||||
* When we have one that has not yet occured,
|
||||
* calculate milliseconds until it does for use in poll. */
|
||||
get_monotonic(&now);
|
||||
|
||||
/* Run all timeouts first */
|
||||
if (timeouts) {
|
||||
if (timercmp(&now, &timeouts->when, >)) {
|
||||
t = timeouts;
|
||||
@ -308,61 +308,40 @@ start_eloop(void)
|
||||
continue;
|
||||
}
|
||||
timersub(&timeouts->when, &now, &tv);
|
||||
if (tv.tv_sec > INT_MAX / 1000 ||
|
||||
(tv.tv_sec == INT_MAX / 1000 &&
|
||||
(tv.tv_usec + 999) / 1000 > INT_MAX % 1000))
|
||||
msecs = INT_MAX;
|
||||
else
|
||||
msecs = tv.tv_sec * 1000 +
|
||||
(tv.tv_usec + 999) / 1000;
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
tsp = &ts;
|
||||
} else
|
||||
/* No timeouts, so wait forever. */
|
||||
msecs = -1;
|
||||
/* No timeouts, so wait forever */
|
||||
tsp = NULL;
|
||||
|
||||
/* Allocate memory for our pollfds as and when needed.
|
||||
* We don't bother shrinking it. */
|
||||
nfds = 0;
|
||||
for (e = events; e; e = e->next)
|
||||
nfds++;
|
||||
if (msecs == -1 && nfds == 0) {
|
||||
max_fd = -1;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_ZERO(&error_fds);
|
||||
for (e = events; e; e = e->next) {
|
||||
FD_SET(e->fd, &read_fds);
|
||||
if (e->fd > max_fd)
|
||||
max_fd = e->fd;
|
||||
}
|
||||
if (tsp == NULL && max_fd == -1) {
|
||||
syslog(LOG_ERR, "nothing to do");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (nfds > fds_len) {
|
||||
free(fds);
|
||||
/* Allocate 5 more than we need for future use */
|
||||
fds_len = nfds + 5;
|
||||
fds = xmalloc(sizeof(*fds) * fds_len);
|
||||
}
|
||||
nfds = 0;
|
||||
for (e = events; e; e = e->next) {
|
||||
fds[nfds].fd = e->fd;
|
||||
fds[nfds].events = POLLIN;
|
||||
fds[nfds].revents = 0;
|
||||
nfds++;
|
||||
}
|
||||
n = poll(fds, nfds, msecs);
|
||||
|
||||
n = pselect(max_fd + 1, &read_fds, NULL, &error_fds,
|
||||
tsp, cursigs);
|
||||
if (n == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR) {
|
||||
get_monotonic(&now);
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
}
|
||||
syslog(LOG_ERR, "poll: %m");
|
||||
syslog(LOG_ERR, "pselect: %m");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Get the now time and process any triggered events. */
|
||||
get_monotonic(&now);
|
||||
if (n == 0)
|
||||
continue;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
if (!(fds[i].revents & (POLLIN | POLLHUP)))
|
||||
continue;
|
||||
|
||||
/* Process any triggered events. */
|
||||
if (n) {
|
||||
for (e = events; e; e = e->next) {
|
||||
if (e->fd == fds[i].fd) {
|
||||
if (FD_ISSET(e->fd, &read_fds))
|
||||
e->callback(e->arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
5
eloop.h
5
eloop.h
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -28,6 +28,7 @@
|
||||
#ifndef ELOOP_H
|
||||
#define ELOOP_H
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef ELOOP_QUEUE
|
||||
@ -47,6 +48,6 @@ void add_q_timeout_tv(int queue, const struct timeval *, void (*)(void *),
|
||||
void delete_q_timeout(int, void (*)(void *), void *);
|
||||
void delete_q_timeouts(int, void *, void (*)(void *), ...);
|
||||
void eloop_init(void);
|
||||
void start_eloop(void);
|
||||
void start_eloop(const sigset_t *);
|
||||
|
||||
#endif
|
||||
|
75
signals.c
75
signals.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -25,9 +25,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
@ -37,88 +34,48 @@
|
||||
#include "common.h"
|
||||
#include "signals.h"
|
||||
|
||||
static int signal_pipe[2];
|
||||
|
||||
static const int handle_sigs[] = {
|
||||
const int handle_sigs[] = {
|
||||
SIGALRM,
|
||||
SIGHUP,
|
||||
SIGINT,
|
||||
SIGPIPE,
|
||||
SIGTERM,
|
||||
SIGUSR1,
|
||||
0
|
||||
};
|
||||
|
||||
static void
|
||||
signal_handler(int sig)
|
||||
{
|
||||
int serrno = errno;
|
||||
|
||||
if (write(signal_pipe[1], &sig, sizeof(sig)) != sizeof(sig))
|
||||
syslog(LOG_ERR, "failed to write signal %d: %m", sig);
|
||||
/* Restore errno */
|
||||
errno = serrno;
|
||||
}
|
||||
|
||||
/* Read a signal from the signal pipe. Returns 0 if there is
|
||||
* no signal, -1 on error (and sets errno appropriately), and
|
||||
* your signal on success */
|
||||
int
|
||||
signal_read(void)
|
||||
{
|
||||
int sig = -1;
|
||||
char buf[16];
|
||||
ssize_t bytes;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
bytes = read(signal_pipe[0], buf, sizeof(buf));
|
||||
if (bytes >= 0 && (size_t)bytes >= sizeof(sig))
|
||||
memcpy(&sig, buf, sizeof(sig));
|
||||
return sig;
|
||||
}
|
||||
|
||||
/* Call this before doing anything else. Sets up the socket pair
|
||||
* and installs the signal handler */
|
||||
int
|
||||
signal_init(void)
|
||||
{
|
||||
if (pipe(signal_pipe) == -1)
|
||||
return -1;
|
||||
/* Don't block on read */
|
||||
if (set_nonblock(signal_pipe[0]) == -1)
|
||||
return -1;
|
||||
/* Stop any scripts from inheriting us */
|
||||
if (set_cloexec(signal_pipe[0]) == -1)
|
||||
return -1;
|
||||
if (set_cloexec(signal_pipe[1]) == -1)
|
||||
return -1;
|
||||
return signal_pipe[0];
|
||||
}
|
||||
|
||||
static int
|
||||
signal_handle(void (*func)(int))
|
||||
signal_handle(void (*func)(int), sigset_t *oldset)
|
||||
{
|
||||
unsigned int i;
|
||||
struct sigaction sa;
|
||||
sigset_t newset;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = func;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
for (i = 0; i < sizeof(handle_sigs) / sizeof(handle_sigs[0]); i++)
|
||||
for (i = 0; handle_sigs[i]; i++) {
|
||||
if (sigaction(handle_sigs[i], &sa, NULL) == -1)
|
||||
return -1;
|
||||
if (oldset)
|
||||
sigaddset(&newset, handle_sigs[i]);
|
||||
}
|
||||
if (oldset)
|
||||
return sigprocmask(SIG_BLOCK, &newset, oldset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
signal_setup(void)
|
||||
signal_setup(void (*func)(int), sigset_t *oldset)
|
||||
{
|
||||
return signal_handle(signal_handler);
|
||||
|
||||
return signal_handle(func, oldset);
|
||||
}
|
||||
|
||||
int
|
||||
signal_reset(void)
|
||||
{
|
||||
return signal_handle(SIG_DFL);
|
||||
}
|
||||
|
||||
return signal_handle(SIG_DFL, NULL);
|
||||
}
|
||||
|
11
signals.h
11
signals.h
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -25,12 +25,15 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SIGNAL_H
|
||||
#define SIGNAL_H
|
||||
#ifndef SIGNALS_H
|
||||
#define SIGNALS_H
|
||||
|
||||
extern const int handle_sigs[];
|
||||
|
||||
int signal_init(void);
|
||||
int signal_setup(void);
|
||||
int signal_setup(void (*)(int), sigset_t *);
|
||||
int signal_reset(void);
|
||||
int signal_read(void);
|
||||
int signal_block(int);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user