Remove all atexit(3) and exit(3) calls, instead exiting via the eloop.
dhcp_auth_reset(struct authstate *state)
{
+ state->replay = 0;
+ if (state->token) {
+ free(state->token->key);
+ free(state->token->realm);
+ free(state->token);
+ state->token = NULL;
+ }
if (state->reconf) {
+ free(state->reconf->key);
+ free(state->reconf->realm);
free(state->reconf);
state->reconf = NULL;
}
gottoken:
/* First message from the server */
- if (state->token && state->token != t) {
+ if (state->token &&
+ (state->token->secretid != t->secretid ||
+ state->token->realm_len != t->realm_len ||
+ memcmp(state->token->realm, t->realm, t->realm_len)))
+ {
errno = EPERM;
return NULL;
}
finish:
/* If we got here then authentication passed */
state->replay = replay;
- state->token = t;
+ if (state->token == NULL) {
+ /* We cannot just save a pointer because a reconfigure will
+ * recreate the token list. So we duplicate it. */
+ state->token = malloc(sizeof(*state->token));
+ if (state->token) {
+ state->token->secretid = t->secretid;
+ state->token->key = malloc(t->key_len);
+ if (state->token->key) {
+ state->token->key_len = t->key_len;
+ memcpy(state->token->key, t->key, t->key_len);
+ } else {
+ free(state->token);
+ state->token = NULL;
+ }
+ if (t->realm) {
+ state->token->realm = malloc(t->realm_len);
+ if (state->token->realm) {
+ state->token->realm_len = t->realm_len;
+ memcpy(state->token->realm, t->realm,
+ t->realm_len);
+ } else {
+ free(state->token->key);
+ free(state->token);
+ state->token = NULL;
+ }
+ } else {
+ state->token->realm = NULL;
+ state->token->realm_len = 0;
+ }
+ }
+ /* If we cannot save the token, we must invalidate */
+ if (state->token == NULL)
+ return NULL;
+ }
return t;
}
struct authstate {
uint64_t replay;
- const struct token *token;
+ struct token *token;
struct token *reconf;
};
int clock_monotonic;
static char *lbuf;
static size_t lbuf_len;
-#ifdef DEBUG_MEMORY
-static char lbuf_set;
-#endif
-
-#ifdef DEBUG_MEMORY
-static void
-free_lbuf(void)
-{
- free(lbuf);
- lbuf = NULL;
-}
-#endif
/* Handy routine to read very long lines in text files.
* This means we read the whole line and avoid any nasty buffer overflows.
char *p;
ssize_t bytes;
-#ifdef DEBUG_MEMORY
- if (lbuf_set == 0) {
- atexit(free_lbuf);
- lbuf_set = 1;
- }
-#endif
-
do {
bytes = getline(&lbuf, &lbuf_len, fp);
if (bytes == -1)
return p;
}
+void
+get_line_free(void)
+{
+
+ free(lbuf);
+ lbuf_len = 0;
+}
+
int
set_cloexec(int fd)
{
int set_cloexec(int);
int set_nonblock(int);
char *get_line(FILE * __restrict);
+void get_line_free(void);
const char *get_hostname(int);
extern int clock_monotonic;
int get_monotonic(struct timeval *);
echo "CPPFLAGS+= -I$x" >>$CONFIG_MK
done
-if [ -n "$DEBUG" -a "$DEBUG" != no -a "$DEBUG" != false ]; then
- echo "Enabling memory debugging"
- echo "CPPFLAGS+= -DDEBUG_MEMORY" >>$CONFIG_MK
- echo "CFLAGS+= -g" >>$CONFIG_MK
-elif [ -z "$DEBUG" -a -f .fslckout ]; then
+if [ -z "$DEBUG" -a -f .fslckout ]; then
printf "Found fossil checkout ... "
DEBUG=yes
- echo "CFLAGS+= -g" >>$CONFIG_MK
else
DEBUG=no
fi
if [ "$DEBUG" != no -a "$DEBUG" != false ]; then
echo "Adding debugging CFLAGS"
cat <<EOF >>$CONFIG_MK
-CFLAGS+= -Wall -Wextra -Wimplicit -Wshadow -Wformat=2
+CFLAGS+= -g -Wall -Wextra -Wimplicit -Wshadow -Wformat=2
CFLAGS+= -Wmissing-prototypes -Wmissing-declarations
CFLAGS+= -Wmissing-noreturn -Wmissing-format-attribute
CFLAGS+= -Wredundant-decls -Wnested-externs
static struct sockaddr_un sun;
struct fd_list *control_fds = NULL;
-#ifdef DEBUG_MEMORY
-static void
-cleanup(void)
-{
- struct fd_list *f;
-
- f = control_fds;
- while (f) {
- control_fds = f->next;
- free(f);
- f = control_fds;
- }
-}
-#endif
-
static void
control_remove(void *arg)
{
if ((len = make_sock()) == -1)
return -1;
-#ifdef DEBUG_MEMORY
- atexit(cleanup);
-#endif
return connect(fd, (struct sockaddr *)&sun, len);
}
}
void
-dev_stop(void)
+dev_stop(int stop)
{
if (dev) {
- syslog(LOG_DEBUG, "dev: unloaded %s", dev->name);
+ if (stop)
+ syslog(LOG_DEBUG, "dev: unloaded %s", dev->name);
dev->stop();
free(dev);
dev = NULL;
if (fd != -1) {
if (eloop_event_add(fd, dev_handle_data, NULL) == -1) {
syslog(LOG_ERR, "%s: eloop_event_add: %m", __func__);
- dev_stop();
+ dev_stop(1);
return -1;
}
}
int dev_initialized(const char *);
int dev_listening(void);
int dev_start(const char *);
-void dev_stop(void);
+void dev_stop(int);
#else
#define dev_initialized(a) 1
#define dev_listening() 0
printf("%03d %s\n", opt->option, opt->var);
}
-#ifdef DEBUG_MEMORY
-static void
-dhcp_cleanup(void)
-{
-
- free(packet);
- free(opt_buffer);
-}
-#endif
-
#define get_option_raw(dhcp, opt) get_option(dhcp, opt, NULL)
static const uint8_t *
get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len)
if (options & DHCPCD_TEST) {
state->reason = "TEST";
script_runreason(iface, state->reason);
- exit(EXIT_SUCCESS);
+ eloop_exit(EXIT_SUCCESS);
+ return;
}
if (state->reason == NULL) {
if (state->old) {
iface->name, lease->renewaltime, lease->rebindtime);
}
ipv4_applyaddr(iface);
- daemonise();
- if (!ipv4ll)
- arp_close(iface);
- state->state = DHS_BOUND;
- if (ifo->options & DHCPCD_ARP) {
- state->claims = 0;
- arp_announce(iface);
+ if (daemonise() == 0) {
+ if (!ipv4ll)
+ arp_close(iface);
+ state->state = DHS_BOUND;
+ if (ifo->options & DHCPCD_ARP) {
+ state->claims = 0;
+ arp_announce(iface);
+ }
}
}
state->old = NULL;
state->lease.addr.s_addr = 0;
ifp->options->options &= ~ DHCPCD_CSR_WARNED;
- state->auth.token = NULL;
- state->auth.replay = 0;
- free(state->auth.reconf);
- state->auth.reconf = NULL;
-
- /* If we don't have any more DHCP enabled interfaces,
- * close the global socket */
- if (ifaces) {
- TAILQ_FOREACH(ifp, ifaces, next) {
- if (D_STATE(ifp))
- break;
- }
- }
- if (ifp == NULL && udp_fd != -1) {
- close(udp_fd);
- eloop_event_delete(udp_fd);
- udp_fd = -1;
- }
}
static void
state->offer = NULL;
state->reason = "TEST";
script_runreason(iface, state->reason);
- exit(EXIT_SUCCESS);
+ eloop_exit(EXIT_SUCCESS);
+ return;
}
eloop_timeout_delete(send_discover, iface);
/* We don't request BOOTP addresses */
syslog(LOG_ERR, "%s: %m", __func__);
return -1;
}
-#ifdef DEBUG_MEMORY
- atexit(dhcp_cleanup);
-#endif
}
state = D_STATE(ifp);
free(state);
ifp->if_data[IF_DATA_DHCP] = NULL;
}
+
+ /* If we don't have any more DHCP enabled interfaces,
+ * close the global socket and release resources */
+ if (ifaces) {
+ TAILQ_FOREACH(ifp, ifaces, next) {
+ if (D_STATE(ifp))
+ break;
+ }
+ }
+ if (ifp == NULL) {
+ if (udp_fd != -1) {
+ close(udp_fd);
+ eloop_event_delete(udp_fd);
+ udp_fd = -1;
+ }
+
+ free(packet);
+ free(opt_buffer);
+ packet = NULL;
+ opt_buffer = NULL;
+ }
}
static int
"Use Multicast"
};
-#if DEBUG_MEMORY
-static void
-dhcp6_cleanup(void)
-{
-
- free(sndbuf);
- free(rcvbuf);
- free(status);
-}
-#endif
-
void
dhcp6_printoptions(void)
{
{
int len;
-#if DEBUG_MEMORY
- atexit(dhcp6_cleanup);
-#endif
-
len = CMSG_SPACE(sizeof(struct in6_pktinfo));
sndbuf = calloc(1, len);
if (sndbuf == NULL)
(ifp->options->options & DHCPCD_INFORM &&
!(options & DHCPCD_MASTER)))
{
-#ifdef DEBUG_MEMORY
- dhcp6_free(ifp);
-#endif
- exit(EXIT_SUCCESS);
+ eloop_exit(EXIT_SUCCESS);
}
}
free(state->recv);
free(state->new);
free(state->old);
- free(state->auth.reconf);
free(state);
ifp->if_data[IF_DATA_DHCP6] = NULL;
}
/* If we don't have any more DHCP6 enabled interfaces,
- * close the global socket */
+ * close the global socketo and release resources */
if (ifaces) {
TAILQ_FOREACH(ifp, ifaces, next) {
if (D6_STATE(ifp))
break;
}
}
- if (ifp == NULL && sock != -1) {
- close(sock);
- eloop_event_delete(sock);
- sock = -1;
+ if (ifp == NULL) {
+ if (sock != -1) {
+ close(sock);
+ eloop_event_delete(sock);
+ sock = -1;
+ }
+ free(sndbuf);
+ free(rcvbuf);
+ free(status);
+ sndbuf = NULL;
+ rcvbuf = NULL;
+ status = NULL;
}
}
};
static char *cffile;
-static char *pidfile;
static int linkfd = -1;
static char **ifv;
static int ifc;
static int margc;
static pid_t
-read_pid(void)
+read_pid(const char *pidfile)
{
FILE *fp;
pid_t pid;
free(vivso);
}
-static void
-cleanup(void)
-{
-#ifdef DEBUG_MEMORY
- struct interface *ifp;
-
- free(duid);
- free_options(if_options);
-
- if (ifaces) {
- while ((ifp = TAILQ_FIRST(ifaces))) {
- TAILQ_REMOVE(ifaces, ifp, next);
- free_interface(ifp);
- }
- free(ifaces);
- }
-
- free_globals();
-#endif
-
- if (!(options & DHCPCD_FORKED))
- dev_stop();
- if (linkfd != -1)
- close(linkfd);
- if (pidfd > -1) {
- if (options & DHCPCD_MASTER) {
- if (control_stop() == -1)
- syslog(LOG_ERR, "control_stop: %m");
- }
- close(pidfd);
- unlink(pidfile);
- }
-#ifdef DEBUG_MEMORY
- free(pidfile);
-#endif
-
- if (options & DHCPCD_STARTED && !(options & DHCPCD_FORKED))
- syslog(LOG_INFO, "exited");
-}
-
/* ARGSUSED */
static void
handle_exit_timeout(__unused void *arg)
options &=
~(DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6);
daemonise();
- return;
} else
- exit(EXIT_FAILURE);
+ eloop_exit(EXIT_FAILURE);
+ return;
}
options &= ~DHCPCD_TIMEOUT_IPV4LL;
timeout = (PROBE_NUM * PROBE_MAX) + (PROBE_WAIT * 2);
daemonise(void)
{
#ifdef THERE_IS_NO_FORK
+ errno = ENOSYS;
return -1;
#else
pid_t pid;
close(pidfd);
pidfd = -1;
options |= DHCPCD_FORKED;
- exit(EXIT_SUCCESS);
+ eloop_exit(EXIT_SUCCESS);
+ return pid;
}
options |= DHCPCD_DAEMONISED;
return pid;
script_runreason(ifp, "DEPARTED");
free_interface(ifp);
if (!(options & (DHCPCD_MASTER | DHCPCD_TEST)))
- exit(EXIT_FAILURE);
+ eloop_exit(EXIT_FAILURE);
}
static void
return;
}
- if (options & DHCPCD_TEST)
- exit(EXIT_FAILURE);
-
- /* As drop_dhcp could re-arrange the order, we do it like this. */
- for (;;) {
- /* Be sane and drop the last config first */
- ifp = TAILQ_LAST(ifaces, if_head);
- if (ifp == NULL)
- break;
- if (do_release) {
- ifp->options->options |= DHCPCD_RELEASE;
- ifp->options->options &= ~DHCPCD_PERSISTENT;
+ if (!(options & DHCPCD_TEST)) {
+ /* drop_dhcp could change the order, so we do it like this. */
+ for (;;) {
+ /* Be sane and drop the last config first */
+ ifp = TAILQ_LAST(ifaces, if_head);
+ if (ifp == NULL)
+ break;
+ if (do_release) {
+ ifp->options->options |= DHCPCD_RELEASE;
+ ifp->options->options &= ~DHCPCD_PERSISTENT;
+ }
+ ifp->options->options |= DHCPCD_EXITING;
+ stop_interface(ifp);
}
- ifp->options->options |= DHCPCD_EXITING;
- stop_interface(ifp);
}
- exit(EXIT_FAILURE);
+ eloop_exit(EXIT_FAILURE);
}
int
int
main(int argc, char **argv)
{
+ char *pidfile;
struct interface *ifp;
uint16_t family = 0;
- int opt, oi = 0, sig = 0, i, control_fd;
+ int opt, oi = 0, sig = 0, i;
size_t len;
pid_t pid;
struct timespec ts;
struct utsname utn;
const char *platform;
+ pidfile = NULL;
closefrom(3);
openlog(PACKAGE, LOG_PERROR | LOG_PID, LOG_DAEMON);
setlogmask(LOG_UPTO(LOG_INFO));
if (argc > 1) {
if (strcmp(argv[1], "--help") == 0) {
usage();
- exit(EXIT_SUCCESS);
+ return EXIT_SUCCESS;
} else if (strcmp(argv[1], "--version") == 0) {
printf(""PACKAGE" "VERSION"\n%s\n", dhcpcd_copyright);
- exit(EXIT_SUCCESS);
+ return EXIT_SUCCESS;
}
}
break;
case '?':
usage();
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
}
if (opt != 1) {
if (opt == 0)
usage();
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
if (i == 3) {
printf("Interface options:\n");
dhcp6_printoptions();
}
#endif
-#ifdef DEBUG_MEMORY
- cleanup();
-#endif
- exit(EXIT_SUCCESS);
+ goto exit_success;
}
options = if_options->options;
if (i != 0) {
pidfile = malloc(len);
if (pidfile == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
if (optind == argc - 1)
snprintf(pidfile, len, PIDFILE, "-", argv[optind]);
if (chdir("/") == -1)
syslog(LOG_ERR, "chdir `/': %m");
- atexit(cleanup);
if (options & DHCPCD_DUMPLEASE) {
if (optind != argc - 1) {
syslog(LOG_ERR, "dumplease requires an interface");
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
if (dhcp_dump(argv[optind]) == -1)
- exit(EXIT_FAILURE);
- exit(EXIT_SUCCESS);
+ goto exit_failure;
+ goto exit_success;
}
if (!(options & (DHCPCD_MASTER | DHCPCD_TEST))) {
- control_fd = control_open();
- if (control_fd != -1) {
+ if ((i = control_open()) != -1) {
syslog(LOG_INFO,
"sending commands to master dhcpcd process");
- i = control_send(argc, argv);
- if (i > 0) {
+ len = control_send(argc, argv);
+ close(i);
+ if (len > 0) {
syslog(LOG_DEBUG, "send OK");
- exit(EXIT_SUCCESS);
+ goto exit_success;
} else {
syslog(LOG_ERR, "failed to send commands");
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
} else {
if (errno != ENOENT)
PACKAGE " will not work correctly unless run as root");
if (sig != 0) {
- pid = read_pid();
+ pid = read_pid(pidfile);
if (pid != 0)
syslog(LOG_INFO, "sending signal %d to pid %d",
sig, pid);
syslog(LOG_ERR, ""PACKAGE" not running");
if (pid != 0 && errno != ESRCH) {
syslog(LOG_ERR, "kill: %m");
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
unlink(pidfile);
if (sig != SIGALRM)
- exit(EXIT_FAILURE);
+ goto exit_failure;
} else {
if (sig == SIGALRM || sig == SIGUSR1)
- exit(EXIT_SUCCESS);
+ goto exit_success;
/* Spin until it exits */
syslog(LOG_INFO, "waiting for pid %d to exit", pid);
ts.tv_sec = 0;
ts.tv_nsec = 100000000; /* 10th of a second */
for(i = 0; i < 100; i++) {
nanosleep(&ts, NULL);
- if (read_pid() == 0)
- exit(EXIT_SUCCESS);
+ if (read_pid(pidfile) == 0)
+ goto exit_success;
}
syslog(LOG_ERR, "pid %d failed to exit", pid);
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
}
if (!(options & DHCPCD_TEST)) {
- if ((pid = read_pid()) > 0 &&
+ if ((pid = read_pid(pidfile)) > 0 &&
kill(pid, 0) == 0)
{
syslog(LOG_ERR, ""PACKAGE
" already running on pid %d (%s)",
pid, pidfile);
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
/* Ensure we have the needed directories */
* runs on an interface */
if (flock(pidfd, LOCK_EX | LOCK_NB) == -1) {
syslog(LOG_ERR, "flock `%s': %m", pidfile);
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
if (set_cloexec(pidfd) == -1)
- exit(EXIT_FAILURE);
+ goto exit_failure;
writepid(pidfd, getpid());
}
}
syslog(LOG_INFO, "version " VERSION " starting");
options |= DHCPCD_STARTED;
-#ifdef DEBUG_MEMORY
- eloop_init();
-#endif
-
/* Save signal mask, block and redirect signals to our handler */
if (signal_init(handle_signal, &dhcpcd_sigset) == -1) {
syslog(LOG_ERR, "signal_setup: %m");
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
if (options & DHCPCD_MASTER) {
if (open_sockets() == -1) {
syslog(LOG_ERR, "open_sockets: %m");
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
#if 0
if (ifc == 0)
syslog(LOG_ERR, "no valid interfaces found");
else
- exit(EXIT_FAILURE);
+ goto exit_failure;
if (!(options & DHCPCD_LINK)) {
syslog(LOG_ERR,
"aborting as link detection is disabled");
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
}
eloop_timeout_add_sec(0, start_interface, ifp);
}
- eloop_start(&dhcpcd_sigset);
- exit(EXIT_SUCCESS);
+ i = eloop_start(&dhcpcd_sigset);
+ goto exit1;
+
+exit_success:
+ i = EXIT_SUCCESS;
+ goto exit1;
+
+exit_failure:
+ i = EXIT_FAILURE;
+
+exit1:
+
+ if (ifaces) {
+ while ((ifp = TAILQ_FIRST(ifaces))) {
+ TAILQ_REMOVE(ifaces, ifp, next);
+ free_interface(ifp);
+ }
+ free(ifaces);
+ }
+
+ free(duid);
+ free_options(if_options);
+ free_globals();
+ restore_kernel_ra();
+ ipv4_free(NULL);
+ ipv6_free(NULL);
+ if_free();
+ get_line_free();
+ dev_stop(options & DHCPCD_DAEMONISED);
+ if (linkfd != -1) {
+ close(linkfd);
+ linkfd = -1;
+ }
+ if (pidfd > -1) {
+ if (options & DHCPCD_MASTER) {
+ if (control_stop() == -1)
+ syslog(LOG_ERR, "control_stop: %m");
+ }
+ close(pidfd);
+ unlink(pidfile);
+ pidfd = -1;
+ }
+ free(pidfile);
+
+ if (options & DHCPCD_STARTED && !(options & DHCPCD_FORKED))
+ syslog(LOG_INFO, "exited");
+ return i;
}
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
static struct pollfd *fds;
static size_t fds_len;
+static int eloop_exitnow;
+static int eloop_exitcode;
+
static void
eloop_event_setup_fds(void)
{
eloop_event_add(int fd, void (*callback)(void *), void *arg)
{
struct event *e;
+ struct pollfd *nfds;
/* We should only have one callback monitoring the fd */
TAILQ_FOREACH(e, &events, next) {
events_len++;
if (events_len > fds_len) {
fds_len += 5;
- free(fds);
- fds = malloc(sizeof(*fds) * fds_len);
- if (fds == NULL) {
+ nfds = malloc(sizeof(*fds) * (fds_len + 5));
+ if (nfds == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
- free(e);
+ events_len--;
+ TAILQ_INSERT_TAIL(&free_events, e, next);
return -1;
}
+ fds_len += 5;
+ free(fds);
+ fds = nfds;
}
/* Now populate the structure and add it to the list */
}
}
-#ifdef DEBUG_MEMORY
-/* Define this to free all malloced memory.
- * Normally we don't do this as the OS will do it for us at exit,
- * but it's handy for debugging other leaks in valgrind. */
-static void
-eloop_cleanup(void)
-{
- struct event *e;
- struct timeout *t;
-
- while ((e = TAILQ_FIRST(&events))) {
- TAILQ_REMOVE(&events, e, next);
- free(e);
- }
- while ((e = TAILQ_FIRST(&free_events))) {
- TAILQ_REMOVE(&free_events, e, next);
- free(e);
- }
- while ((t = TAILQ_FIRST(&timeouts))) {
- TAILQ_REMOVE(&timeouts, t, next);
- free(t);
- }
- while ((t = TAILQ_FIRST(&free_timeouts))) {
- TAILQ_REMOVE(&free_timeouts, t, next);
- free(t);
- }
- free(fds);
-}
-
void
-eloop_init(void)
+eloop_exit(int code)
{
- atexit(eloop_cleanup);
+ eloop_exitcode = code;
+ eloop_exitnow = 1;
}
-#endif
-__dead void
+int
eloop_start(const sigset_t *sigmask)
{
int n;
struct timespec ts, *tsp;
void (*t0)(void *);
+ eloop_exitcode = EXIT_FAILURE;
for (;;) {
+ if (eloop_exitnow)
+ break;
+
/* Run all timeouts first */
if (timeout0) {
t0 = timeout0;
if (tsp == NULL && events_len == 0) {
syslog(LOG_ERR, "nothing to do");
- exit(EXIT_FAILURE);
+ break;
}
n = pollts(fds, events_len, tsp, sigmask);
if (errno == EAGAIN || errno == EINTR)
continue;
syslog(LOG_ERR, "poll: %m");
- exit(EXIT_FAILURE);
+ break;
}
/* Process any triggered events. */
}
}
}
+
+ /* Release our malloced resources */
+ while ((e = TAILQ_FIRST(&events))) {
+ TAILQ_REMOVE(&events, e, next);
+ free(e);
+ }
+ while ((e = TAILQ_FIRST(&free_events))) {
+ TAILQ_REMOVE(&free_events, e, next);
+ free(e);
+ }
+ while ((t = TAILQ_FIRST(&timeouts))) {
+ TAILQ_REMOVE(&timeouts, t, next);
+ free(t);
+ }
+ while ((t = TAILQ_FIRST(&free_timeouts))) {
+ TAILQ_REMOVE(&free_timeouts, t, next);
+ free(t);
+ }
+ free(fds);
+ fds_len = 0;
+
+ return eloop_exitcode;
}
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
#define ELOOP_QUEUE 1
#endif
+/* EXIT_FAILURE is a non zero value and EXIT_SUCCESS is zero.
+ * To add a CONTINUE definition, simply do the opposite of EXIT_FAILURE. */
+#define ELOOP_CONTINUE -EXIT_FAILURE
+
#define eloop_timeout_add_tv(a, b, c) \
eloop_q_timeout_add_tv(ELOOP_QUEUE, a, b, c)
#define eloop_timeout_add_sec(a, b, c) \
void eloop_q_timeout_delete(int, void (*)(void *), void *);
void eloop_q_timeouts_delete(int, void *, void (*)(void *), ...);
void eloop_init(void);
-void eloop_start(const sigset_t *);
+void eloop_exit(int);
+int eloop_start(const sigset_t *);
#endif
return 0;
}
-#ifdef DEBUG_MEMORY
-static void
-cleanup(void)
+void
+if_free(void)
{
- free(link_buf);
+ if (r_fd != -1) {
+ close(r_fd);
+ r_fd = -1;
+ }
+ if (link_buflen) {
+ free(link_buf);
+ link_buflen = 0;
+ }
}
-#endif
int
open_sockets(void)
{
int fd;
-#ifdef DEBUG_MEMORY
- if (link_buf == NULL)
- atexit(cleanup);
-#endif
-
fd = socket(PF_ROUTE, SOCK_RAW, 0);
if (fd != -1) {
set_cloexec(fd);
return 0;
}
+void
+if_free(void)
+{
+
+ if (sock_fd != -1) {
+ close(sock_fd);
+ sock_fd = -1;
+ }
+}
+
/* XXX work out Virtal Interface Masters */
int
if_vimaster(__unused const char *ifname)
}
}
-#ifdef DEBUG_MEMORY
-static void
-ipv4_cleanup()
-{
-
- ipv4_freeroutes(routes);
-}
-#endif
-
int
ipv4_init(void)
{
if (routes == NULL)
return -1;
TAILQ_INIT(routes);
-#ifdef DEBUG_MEMORY
- atexit(ipv4_cleanup);
-#endif
}
return 0;
}
struct ipv4_state *state;
struct ipv4_addr *addr;
- state = IPV4_STATE(ifp);
- if (state) {
- while ((addr = TAILQ_FIRST(&state->addrs))) {
- TAILQ_REMOVE(&state->addrs, addr, next);
- free(addr);
+ if (ifp) {
+ state = IPV4_STATE(ifp);
+ if (state) {
+ while ((addr = TAILQ_FIRST(&state->addrs))) {
+ TAILQ_REMOVE(&state->addrs, addr, next);
+ free(addr);
+ }
+ free(state);
}
- free(state);
+ } else {
+ ipv4_freeroutes(routes);
+ routes = NULL;
}
}
static struct rt6head *routes;
-#ifdef DEBUG_MEMORY
-static void
-ipv6_cleanup()
-{
- struct rt6 *rt;
-
- while ((rt = TAILQ_FIRST(routes))) {
- TAILQ_REMOVE(routes, rt, next);
- free(rt);
- }
- free(routes);
-}
-#endif
-
int
ipv6_init(void)
{
if (routes == NULL)
return -1;
TAILQ_INIT(routes);
-#ifdef DEBUG_MEMORY
- atexit(ipv6_cleanup);
-#endif
}
return 0;
}
{
struct ipv6_state *state;
struct ipv6_addr_l *ap;
+ struct rt6 *rt;
- ipv6_free_ll_callbacks(ifp);
- state = IPV6_STATE(ifp);
- if (state) {
- while ((ap = TAILQ_FIRST(&state->addrs))) {
- TAILQ_REMOVE(&state->addrs, ap, next);
- free(ap);
+ if (ifp) {
+ ipv6_free_ll_callbacks(ifp);
+ state = IPV6_STATE(ifp);
+ if (state) {
+ while ((ap = TAILQ_FIRST(&state->addrs))) {
+ TAILQ_REMOVE(&state->addrs, ap, next);
+ free(ap);
+ }
+ free(state);
+ ifp->if_data[IF_DATA_IPV6] = NULL;
+ }
+ } else {
+ if (routes) {
+ while ((rt = TAILQ_FIRST(routes))) {
+ TAILQ_REMOVE(routes, rt, next);
+ free(rt);
+ }
+ free(routes);
+ routes = NULL;
}
- free(state);
- ifp->if_data[IF_DATA_IPV6] = NULL;
}
}
memset(filterp, 0xff, sizeof(struct icmp6_filter));
#endif
-#if DEBUG_MEMORY
-static void
-ipv6nd_cleanup(void)
-{
-
- free(sndbuf);
- free(rcvbuf);
-}
-#endif
-
static int
ipv6nd_open(void)
{
goto eexit;
set_cloexec(sock);
-#if DEBUG_MEMORY
- atexit(ipv6nd_cleanup);
-#endif
len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
sndbuf = calloc(1, len);
ssize_t n;
state = RS_STATE(ifp);
- if (state) {
- free(state->rs);
- free(state);
- ifp->if_data[IF_DATA_IPV6ND] = NULL;
- }
+ if (state == NULL)
+ return 0;
+
+ free(state->rs);
+ free(state);
+ ifp->if_data[IF_DATA_IPV6ND] = NULL;
n = 0;
TAILQ_FOREACH_SAFE(rap, &ipv6_routers, next, ran) {
if (rap->iface == ifp) {
n++;
}
}
+
+ /* If we don't have any more IPv6 enabled interfaces,
+ * close the global socket and release resources */
+ TAILQ_FOREACH(ifp, ifaces, next) {
+ if (RS_STATE(ifp))
+ break;
+ }
+ if (ifp == NULL) {
+ if (sock != -1) {
+ close(sock);
+ eloop_event_delete(sock);
+ sock = -1;
+ }
+ free(sndbuf);
+ free(rcvbuf);
+ sndbuf = NULL;
+ rcvbuf = NULL;
+ }
+
return n;
}
if (rap->lifetime && new_data)
syslog(LOG_DEBUG, "%s: No DHCPv6 instruction in RA",
ifp->name);
- if (options & DHCPCD_TEST)
- exit(EXIT_SUCCESS);
+ if (options & DHCPCD_TEST) {
+ eloop_exit(EXIT_SUCCESS);
+ return;
+ }
}
/* Expire should be called last as the rap object could be destroyed */
script_runreason(ifp, "ROUTERADVERT");
}
}
+
static void
ipv6nd_unreachable(void *arg)
{
int up_interface(struct interface *);
int if_conf(struct interface *);
int if_init(struct interface *);
+void if_free(void);
int open_link_socket(void);
int manage_link(int);
return val;
}
-static void
+void
restore_kernel_ra(void)
{
int
check_ipv6(const char *ifname, int own)
{
- static int set_restore = 0, global_ra = 0;
+ static int global_ra = 0;
int ra;
/* BSD doesn't support these values per iface, so just return
syslog(LOG_ERR, "IPV6CTL_ACCEPT_RTADV: %m");
return ra;
}
- if (!set_restore) {
- set_restore = 1;
- atexit(restore_kernel_ra);
- }
ra = 0;
/* Flush the kernel knowledge of advertised routers
static const char *prefix = "/proc/sys/net/ipv6/conf";
-static void
+void
restore_kernel_ra(void)
{
char path[256];
-#ifndef DEBUG_MEMORY
if (options & DHCPCD_FORKED)
return;
-#endif
for (nrestore--; nrestore >= 0; nrestore--) {
-#ifdef DEBUG_MEMORY
if (!(options & DHCPCD_FORKED)) {
-#endif
- syslog(LOG_INFO, "%s: restoring Kernel IPv6 RA support",
- restore[nrestore]);
- snprintf(path, sizeof(path), "%s/%s/accept_ra",
- prefix, restore[nrestore]);
- if (write_path(path, "1") == -1 && errno != ENOENT)
- syslog(LOG_ERR, "write_path: %s: %m", path);
-#ifdef DEBUG_MEMORY
+ syslog(LOG_INFO, "%s: restoring Kernel IPv6 RA support",
+ restore[nrestore]);
+ snprintf(path, sizeof(path), "%s/%s/accept_ra",
+ prefix, restore[nrestore]);
+ if (write_path(path, "1") == -1 && errno != ENOENT)
+ syslog(LOG_ERR, "write_path: %s: %m", path);
}
free(restore[nrestore]);
-#endif
}
-#ifdef DEBUG_MEMORY
free(restore);
-#endif
}
int
check_ipv6(const char *ifname, int own)
{
- static int ipv6_checked = 0;
- int ra, ex, i;
+ int ra, i;
char path[256], *p, **nrest;
- if (ifname == NULL) {
- if (ipv6_checked)
- return 1;
- ipv6_checked = 1;
+ if (ifname == NULL)
ifname = "all";
- ex = 1;
- } else
- ex = 0;
snprintf(path, sizeof(path), "%s/%s/autoconf", prefix, ifname);
i = check_proc_int(path);
restore[nrestore++] = p;
}
- if (ex)
- atexit(restore_kernel_ra);
}
return ra;
#ifdef INET6
int check_ipv6(const char *, int);
int ipv6_dadtransmits(const char *);
+void restore_kernel_ra(void);
#else
#define check_ipv6(a, b) -1
+#define restore_kernel_ra(a)
#endif
#endif