From: Roy Marples Date: Tue, 4 Feb 2014 14:39:26 +0000 (+0000) Subject: Remove DEBUG_MEMORY guard and always free memory and resources. X-Git-Tag: v6.3.0~52 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a9d78def54772d69362d08a9ca83b657e26bd392;p=thirdparty%2Fdhcpcd.git Remove DEBUG_MEMORY guard and always free memory and resources. Remove all atexit(3) and exit(3) calls, instead exiting via the eloop. --- diff --git a/auth.c b/auth.c index ad9075fd..d40410ad 100644 --- a/auth.c +++ b/auth.c @@ -78,7 +78,16 @@ void 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; } @@ -270,7 +279,11 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth, 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; } @@ -317,7 +330,40 @@ gottoken: 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; } diff --git a/auth.h b/auth.h index 9234ca50..7a26fc02 100644 --- a/auth.h +++ b/auth.h @@ -67,7 +67,7 @@ struct auth { struct authstate { uint64_t replay; - const struct token *token; + struct token *token; struct token *reconf; }; diff --git a/common.c b/common.c index 4bf52bad..77d19728 100644 --- a/common.c +++ b/common.c @@ -64,18 +64,6 @@ static char hostname_buffer[HOSTNAME_MAX_LEN + 1]; 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. @@ -88,13 +76,6 @@ get_line(FILE * __restrict fp) 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) @@ -107,6 +88,14 @@ get_line(FILE * __restrict fp) return p; } +void +get_line_free(void) +{ + + free(lbuf); + lbuf_len = 0; +} + int set_cloexec(int fd) { diff --git a/common.h b/common.h index 9e3b48c9..8e14a996 100644 --- a/common.h +++ b/common.h @@ -102,6 +102,7 @@ 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 *); diff --git a/configure b/configure index 98307f8c..ad89b9d7 100755 --- a/configure +++ b/configure @@ -293,21 +293,16 @@ for x in $INCLUDEDIR; do 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 <>$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 diff --git a/control.c b/control.c index fa455517..2e67f398 100644 --- a/control.c +++ b/control.c @@ -48,21 +48,6 @@ static char *argvp[255]; 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) { @@ -201,9 +186,6 @@ control_open(void) if ((len = make_sock()) == -1) return -1; -#ifdef DEBUG_MEMORY - atexit(cleanup); -#endif return connect(fd, (struct sockaddr *)&sun, len); } diff --git a/dev.c b/dev.c index b33a3e00..05a0f8a9 100644 --- a/dev.c +++ b/dev.c @@ -63,11 +63,12 @@ dev_listening(void) } 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; @@ -168,7 +169,7 @@ dev_start(const char *plugin) 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; } } diff --git a/dev.h b/dev.h index b22ad648..f85584fd 100644 --- a/dev.h +++ b/dev.h @@ -48,7 +48,7 @@ int dev_init(struct dev *, const struct dev_dhcpcd *); 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 diff --git a/dhcp.c b/dhcp.c index 99707d6c..0c3cc054 100644 --- a/dhcp.c +++ b/dhcp.c @@ -143,16 +143,6 @@ dhcp_printoptions(void) 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) @@ -1816,7 +1806,8 @@ dhcp_bind(void *arg) 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) { @@ -1842,13 +1833,14 @@ dhcp_bind(void *arg) 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); + } } } @@ -2065,24 +2057,6 @@ dhcp_drop(struct interface *ifp, const char *reason) 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 @@ -2373,7 +2347,8 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp, 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 */ @@ -2618,9 +2593,6 @@ dhcp_open(struct interface *ifp) syslog(LOG_ERR, "%s: %m", __func__); return -1; } -#ifdef DEBUG_MEMORY - atexit(dhcp_cleanup); -#endif } state = D_STATE(ifp); @@ -2705,6 +2677,27 @@ dhcp_free(struct interface *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 diff --git a/dhcp6.c b/dhcp6.c index 841eed2e..bf009193 100644 --- a/dhcp6.c +++ b/dhcp6.c @@ -131,17 +131,6 @@ static const char * const dhcp6_statuses[] = { "Use Multicast" }; -#if DEBUG_MEMORY -static void -dhcp6_cleanup(void) -{ - - free(sndbuf); - free(rcvbuf); - free(status); -} -#endif - void dhcp6_printoptions(void) { @@ -157,10 +146,6 @@ dhcp6_init(void) { int len; -#if DEBUG_MEMORY - atexit(dhcp6_cleanup); -#endif - len = CMSG_SPACE(sizeof(struct in6_pktinfo)); sndbuf = calloc(1, len); if (sndbuf == NULL) @@ -2481,10 +2466,7 @@ recv: (ifp->options->options & DHCPCD_INFORM && !(options & DHCPCD_MASTER))) { -#ifdef DEBUG_MEMORY - dhcp6_free(ifp); -#endif - exit(EXIT_SUCCESS); + eloop_exit(EXIT_SUCCESS); } } @@ -2708,23 +2690,30 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason) 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; } } diff --git a/dhcpcd.c b/dhcpcd.c index 16b8e8af..64040f5a 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -87,7 +87,6 @@ const int handle_sigs[] = { }; static char *cffile; -static char *pidfile; static int linkfd = -1; static char **ifv; static int ifc; @@ -95,7 +94,7 @@ static char **margv; static int margc; static pid_t -read_pid(void) +read_pid(const char *pidfile) { FILE *fp; pid_t pid; @@ -162,46 +161,6 @@ free_globals(void) 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) @@ -217,9 +176,9 @@ 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); @@ -231,6 +190,7 @@ pid_t daemonise(void) { #ifdef THERE_IS_NO_FORK + errno = ENOSYS; return -1; #else pid_t pid; @@ -297,7 +257,8 @@ daemonise(void) close(pidfd); pidfd = -1; options |= DHCPCD_FORKED; - exit(EXIT_SUCCESS); + eloop_exit(EXIT_SUCCESS); + return pid; } options |= DHCPCD_DAEMONISED; return pid; @@ -333,7 +294,7 @@ stop_interface(struct interface *ifp) script_runreason(ifp, "DEPARTED"); free_interface(ifp); if (!(options & (DHCPCD_MASTER | DHCPCD_TEST))) - exit(EXIT_FAILURE); + eloop_exit(EXIT_FAILURE); } static void @@ -904,23 +865,22 @@ handle_signal(int sig, siginfo_t *siginfo, __unused void *context) 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 @@ -1093,15 +1053,17 @@ signal_init(void (*func)(int, siginfo_t *, void *), sigset_t *oldset) 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)); @@ -1110,10 +1072,10 @@ main(int argc, char **argv) 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; } } @@ -1163,7 +1125,7 @@ main(int argc, char **argv) break; case '?': usage(); - exit(EXIT_FAILURE); + goto exit_failure; } } @@ -1174,7 +1136,7 @@ main(int argc, char **argv) if (opt != 1) { if (opt == 0) usage(); - exit(EXIT_FAILURE); + goto exit_failure; } if (i == 3) { printf("Interface options:\n"); @@ -1191,10 +1153,7 @@ main(int argc, char **argv) dhcp6_printoptions(); } #endif -#ifdef DEBUG_MEMORY - cleanup(); -#endif - exit(EXIT_SUCCESS); + goto exit_success; } options = if_options->options; if (i != 0) { @@ -1229,7 +1188,7 @@ main(int argc, char **argv) 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]); @@ -1241,30 +1200,29 @@ main(int argc, char **argv) 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) @@ -1277,7 +1235,7 @@ main(int argc, char **argv) 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); @@ -1286,36 +1244,36 @@ main(int argc, char **argv) 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 */ @@ -1332,10 +1290,10 @@ main(int argc, char **argv) * 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()); } } @@ -1343,14 +1301,10 @@ main(int argc, char **argv) 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) { @@ -1360,7 +1314,7 @@ main(int argc, char **argv) if (open_sockets() == -1) { syslog(LOG_ERR, "open_sockets: %m"); - exit(EXIT_FAILURE); + goto exit_failure; } #if 0 @@ -1407,11 +1361,11 @@ main(int argc, char **argv) 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; } } @@ -1470,6 +1424,51 @@ main(int argc, char **argv) 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; } diff --git a/eloop.c b/eloop.c index 0a7f69a6..3798a82c 100644 --- a/eloop.c +++ b/eloop.c @@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2013 Roy Marples + * Copyright (c) 2006-2014 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -74,6 +74,9 @@ static void *volatile timeout0_arg; static struct pollfd *fds; static size_t fds_len; +static int eloop_exitnow; +static int eloop_exitcode; + static void eloop_event_setup_fds(void) { @@ -94,6 +97,7 @@ int 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) { @@ -119,13 +123,16 @@ eloop_event_add(int fd, void (*callback)(void *), void *arg) 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 */ @@ -292,44 +299,15 @@ eloop_q_timeout_delete(int queue, void (*callback)(void *), void *arg) } } -#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; @@ -339,7 +317,11 @@ eloop_start(const sigset_t *sigmask) struct timespec ts, *tsp; void (*t0)(void *); + eloop_exitcode = EXIT_FAILURE; for (;;) { + if (eloop_exitnow) + break; + /* Run all timeouts first */ if (timeout0) { t0 = timeout0; @@ -364,7 +346,7 @@ eloop_start(const sigset_t *sigmask) if (tsp == NULL && events_len == 0) { syslog(LOG_ERR, "nothing to do"); - exit(EXIT_FAILURE); + break; } n = pollts(fds, events_len, tsp, sigmask); @@ -372,7 +354,7 @@ eloop_start(const sigset_t *sigmask) if (errno == EAGAIN || errno == EINTR) continue; syslog(LOG_ERR, "poll: %m"); - exit(EXIT_FAILURE); + break; } /* Process any triggered events. */ @@ -388,4 +370,26 @@ eloop_start(const sigset_t *sigmask) } } } + + /* 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; } diff --git a/eloop.h b/eloop.h index 01ed843d..afb61727 100644 --- a/eloop.h +++ b/eloop.h @@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2013 Roy Marples + * Copyright (c) 2006-2014 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,10 @@ #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) \ @@ -52,6 +56,7 @@ int eloop_timeout_add_now(void (*)(void *), void *); 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 diff --git a/if-bsd.c b/if-bsd.c index 3d44d43f..1d904612 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -102,14 +102,19 @@ if_conf(__unused struct interface *iface) 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) @@ -128,11 +133,6 @@ open_link_socket(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); diff --git a/if-linux.c b/if-linux.c index b737ac10..efb9722c 100644 --- a/if-linux.c +++ b/if-linux.c @@ -112,6 +112,16 @@ if_conf(struct interface *iface) 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) diff --git a/ipv4.c b/ipv4.c index 066f15e3..8e737b48 100644 --- a/ipv4.c +++ b/ipv4.c @@ -169,15 +169,6 @@ ipv4_freeroutes(struct rt_head *rts) } } -#ifdef DEBUG_MEMORY -static void -ipv4_cleanup() -{ - - ipv4_freeroutes(routes); -} -#endif - int ipv4_init(void) { @@ -187,9 +178,6 @@ ipv4_init(void) if (routes == NULL) return -1; TAILQ_INIT(routes); -#ifdef DEBUG_MEMORY - atexit(ipv4_cleanup); -#endif } return 0; } @@ -776,12 +764,17 @@ ipv4_free(struct interface *ifp) 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; } } diff --git a/ipv6.c b/ipv6.c index 3f3a1033..4d06c59c 100644 --- a/ipv6.c +++ b/ipv6.c @@ -74,20 +74,6 @@ 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) { @@ -97,9 +83,6 @@ ipv6_init(void) if (routes == NULL) return -1; TAILQ_INIT(routes); -#ifdef DEBUG_MEMORY - atexit(ipv6_cleanup); -#endif } return 0; } @@ -659,16 +642,28 @@ ipv6_free(struct interface *ifp) { 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; } } diff --git a/ipv6nd.c b/ipv6nd.c index 2fd20842..1517379f 100644 --- a/ipv6nd.c +++ b/ipv6nd.c @@ -180,16 +180,6 @@ static void ipv6nd_handledata(void *arg); 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) { @@ -230,9 +220,6 @@ 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); @@ -465,11 +452,12 @@ ipv6nd_free(struct interface *ifp) 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) { @@ -477,6 +465,25 @@ ipv6nd_free(struct interface *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; } @@ -1031,8 +1038,10 @@ handle_flag: 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 */ @@ -1292,6 +1301,7 @@ ipv6nd_drop(struct interface *ifp) script_runreason(ifp, "ROUTERADVERT"); } } + static void ipv6nd_unreachable(void *arg) { diff --git a/net.h b/net.h index cc39ae80..94e8844f 100644 --- a/net.h +++ b/net.h @@ -103,6 +103,7 @@ int do_mtu(const char *, short int); 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); diff --git a/platform-bsd.c b/platform-bsd.c index c2364ec2..8e0f813d 100644 --- a/platform-bsd.c +++ b/platform-bsd.c @@ -89,7 +89,7 @@ inet6_sysctl(int code, int val, int action) return val; } -static void +void restore_kernel_ra(void) { @@ -121,7 +121,7 @@ ipv6_ra_flush(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 @@ -141,10 +141,6 @@ check_ipv6(const char *ifname, int own) 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 diff --git a/platform-linux.c b/platform-linux.c index e0fe87e6..083f9787 100644 --- a/platform-linux.c +++ b/platform-linux.c @@ -145,51 +145,36 @@ write_path(const char *path, const char *val) 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); @@ -232,8 +217,6 @@ check_ipv6(const char *ifname, int own) restore[nrestore++] = p; } - if (ex) - atexit(restore_kernel_ra); } return ra; diff --git a/platform.h b/platform.h index 46797c16..7c1c1d29 100644 --- a/platform.h +++ b/platform.h @@ -32,8 +32,10 @@ char *hardware_platform(void); #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