]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Remove DEBUG_MEMORY guard and always free memory and resources.
authorRoy Marples <roy@marples.name>
Tue, 4 Feb 2014 14:39:26 +0000 (14:39 +0000)
committerRoy Marples <roy@marples.name>
Tue, 4 Feb 2014 14:39:26 +0000 (14:39 +0000)
Remove all atexit(3) and exit(3) calls, instead exiting via the eloop.

22 files changed:
auth.c
auth.h
common.c
common.h
configure
control.c
dev.c
dev.h
dhcp.c
dhcp6.c
dhcpcd.c
eloop.c
eloop.h
if-bsd.c
if-linux.c
ipv4.c
ipv6.c
ipv6nd.c
net.h
platform-bsd.c
platform-linux.c
platform.h

diff --git a/auth.c b/auth.c
index ad9075fd4232f1f8edef5c375b220786fc7992d4..d40410ade116b3a94e5a490691dc1e3b3da1d713 100644 (file)
--- 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 9234ca5019d0e29ab024f418d19c6cd016a2703f..7a26fc02b381061e533395a282f1a05c1a0519f4 100644 (file)
--- 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;
 };
 
index 4bf52bad72ccf22ca654af9c25ab77d273d88aec..77d1972802619530db654003f01426930d92b559 100644 (file)
--- 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)
 {
index 9e3b48c9a819c653d4368e3c81b31633a10386fb..8e14a996ab371b170e134b5b292bc8a1a58fd6f4 100644 (file)
--- a/common.h
+++ b/common.h
 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 *);
index 98307f8c0af34011185e204167c57c618ca7537a..ad89b9d75295e1155b3b70c1684ea70680ec4cfa 100755 (executable)
--- 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 <<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
index fa455517e137820c5d21f41188e17cf27c7a6a07..2e67f3988589dad85c3252b54d8bf51b6bec07f2 100644 (file)
--- 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 b33a3e005eb22a17f62b509e55180226f6add506..05a0f8a9bf21e86b0e3ae2acb23664234cf04bcb 100644 (file)
--- 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 b22ad648b2f5b089085bfe6cfca0f9eaa4fd13b3..f85584fd35b349cd9689e041d6cefe2649457946 100644 (file)
--- 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 99707d6cd38b7ac6958f1f617785b5eccf72678d..0c3cc0541851f48e49e035e251409beaf879a9c2 100644 (file)
--- 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 841eed2e3b3c3f9b805229a33aa539f4234b63cf..bf00919336c84f9ada1b1e42c8cf873c10201bad 100644 (file)
--- 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;
        }
 }
 
index 16b8e8afcd40d9b9202febeda3ac81a6a184a2aa..64040f5abd44ed514087a6b5bcd6472f3fe6dd71 100644 (file)
--- 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 0a7f69a63e3e9e92ff71fb25920d7f8a6ac4b2ba..3798a82cf1179be29d345777058cca170991f8e2 100644 (file)
--- a/eloop.c
+++ b/eloop.c
@@ -1,6 +1,6 @@
 /*
  * 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
@@ -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 01ed843deafd5bebcd476bac51ae878ee3ad57bb..afb61727807410852711fd7dd9d3280f44f31381 100644 (file)
--- a/eloop.h
+++ b/eloop.h
@@ -1,6 +1,6 @@
 /*
  * 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) \
@@ -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
index 3d44d43f181faddb2194a33e76b311dbae432785..1d904612e3cbf2bf1b073cc45a04761e4aac7a0c 100644 (file)
--- 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);
index b737ac10b4ba835ffe8ffd6d9e14aafeef25ef1a..efb9722cfa20a13a0406728e81468c4d067c2ad8 100644 (file)
@@ -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 066f15e37758b820e12ab59dea555af88bf25c8b..8e737b48484388cac021a421ad27a2230f9e6ac5 100644 (file)
--- 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 3f3a103381491a5b31f28d14666d528179688e91..4d06c59c5a8b6c5a9d2b7715b712f9f02fcdd8e3 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
 
 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;
        }
 }
 
index 2fd20842e7aab42b9aba86c422e583381f21c0b1..1517379f41faca344decb576e188b7bc8d351e13 100644 (file)
--- 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 cc39ae802eb2d53ab736c81a999d0782ef0f97e3..94e8844fed38575bc3174614a69e36edb4c4eb2e 100644 (file)
--- 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);
index c2364ec2f4d6819dd9567aa53f5bae704431b857..8e0f813d85da62a2a362ee87d5e84942276bcd63 100644 (file)
@@ -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
index e0fe87e63be6e9bf66d86dca2cef061237e21223..083f9787f148b46ca0daa23794df7a8674b4dc18 100644 (file)
@@ -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;
index 46797c16f09a1eef3d6b0a77ef32b3744983bae9..7c1c1d29ec768e1701ae2ab2436009e61a0efb87 100644 (file)
@@ -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