Fix compile on Linux and fix some memory errors.
[dhcpcd-ui] / src / dhcpcd-curses / dhcpcd-curses.c
index c957a52df855e6fcf476df9826f3e9f0e9d69478..0705a7fe4b43dfdd80d52301445a912c5a095ebf 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <sys/ioctl.h>
 
+#include <assert.h>
 #include <curses.h>
 #include <err.h>
 #include <errno.h>
 #include <unistd.h>
 
 #include "dhcpcd-curses.h"
+#include "event-object.h"
 
 #ifdef HAVE_NC_FREE_AND_EXIT
        void _nc_free_and_exit(void);
 #endif
 
-const int handle_sigs[] = {
-       SIGHUP,
-       SIGINT,
-       SIGPIPE,
-       SIGTERM,
-       SIGWINCH,
-       0
-};
-
-/* Handling signals needs *some* context */
-static struct ctx *_ctx;
-
-static void try_open(void *);
+static void try_open_cb(evutil_socket_t, short, void *);
 
 static void
 set_status(struct ctx *ctx, const char *status)
 {
-       int h, w;
+       int w;
        size_t slen;
 
-       getmaxyx(ctx->win_status, h, w);
-       w -= (slen = strlen(status));
+       w = getmaxx(ctx->win_status);
+       w -= (int)(slen = strlen(status));
        if (ctx->status_len > slen) {
                wmove(ctx->win_status, 0, w - (int)(ctx->status_len - slen));
                wclrtoeol(ctx->win_status);
@@ -138,23 +128,14 @@ notify(struct ctx *ctx, const char *fmt, ...)
 static void
 update_online(struct ctx *ctx, bool show_if)
 {
-       bool online, carrier;
        char *msg, *msgs, *nmsg;
        size_t msgs_len, mlen;
        DHCPCD_IF *ifs, *i;
 
-       online = carrier = false;
        msgs = NULL;
        msgs_len = 0;
        ifs = dhcpcd_interfaces(ctx->con);
        for (i = ifs; i; i = i->next) {
-               if (strcmp(i->type, "link") == 0) {
-                       if (i->up)
-                               carrier = true;
-               } else {
-                       if (i->up)
-                               online = true;
-               }
                msg = dhcpcd_if_message(i, NULL);
                if (msg) {
                        if (show_if) {
@@ -191,15 +172,21 @@ update_online(struct ctx *ctx, bool show_if)
 }
 
 static void
-dispatch(void *arg)
+dispatch_cb(evutil_socket_t fd, __unused short what, void *arg)
 {
        struct ctx *ctx = arg;
 
-       if (dhcpcd_get_fd(ctx->con) == -1) {
-               warning(ctx, _("dhcpcd connection lost"));
-               eloop_event_delete(ctx->eloop, -1, NULL, ctx->con, 0);
-               eloop_timeout_add_msec(ctx->eloop, DHCPCD_RETRYOPEN,
-                   try_open, ctx);
+       if (fd == -1 || dhcpcd_get_fd(ctx->con) == -1) {
+               struct timeval tv = { 0, DHCPCD_RETRYOPEN * MSECS_PER_NSEC };
+               struct event *ev;
+
+               if (fd != -1)
+                       warning(ctx, _("dhcpcd connection lost"));
+               event_object_find_delete(ctx->evobjects, ctx);
+               ev = evtimer_new(ctx->evbase, try_open_cb, ctx);
+               if (ev == NULL ||
+                   event_object_add(ctx->evobjects, ev, &tv, ctx) == NULL)
+                       warning(ctx, "dispatch: event: %s", strerror(errno));
                return;
        }
 
@@ -207,13 +194,18 @@ dispatch(void *arg)
 }
 
 static void
-try_open(void *arg)
+try_open_cb(__unused evutil_socket_t fd, __unused short what, void *arg)
 {
        struct ctx *ctx = arg;
        static int last_error;
+       EVENT_OBJECT *eo;
+       struct event *ev;
 
+       eo = event_object_find(ctx->evobjects, ctx);
        ctx->fd = dhcpcd_open(ctx->con, true);
        if (ctx->fd == -1) {
+               struct timeval tv = { 0, DHCPCD_RETRYOPEN * MSECS_PER_NSEC };
+
                if (errno == EACCES || errno == EPERM) {
                        ctx->fd = dhcpcd_open(ctx->con, false);
                        if (ctx->fd != -1)
@@ -223,51 +215,54 @@ try_open(void *arg)
                        last_error = errno;
                        set_status(ctx, strerror(errno));
                }
-               eloop_timeout_add_msec(ctx->eloop, DHCPCD_RETRYOPEN,
-                   try_open, ctx);
+               event_del(eo->event);
+               event_add(eo->event, &tv);
                return;
        }
 
 unprived:
+       event_object_delete(ctx->evobjects, eo);
+
        /* Start listening to WPA events */
        dhcpcd_wpa_start(ctx->con);
 
-       eloop_event_add(ctx->eloop, ctx->fd, dispatch, ctx, NULL, NULL);
+       ev = event_new(ctx->evbase, ctx->fd, EV_READ | EV_PERSIST,
+           dispatch_cb, ctx);
+       if (ev == NULL ||
+           event_object_add(ctx->evobjects, ev, NULL, ctx) == NULL)
+               warning(ctx, "event_new: %s", strerror(errno));
 }
 
 static void
-status_cb(DHCPCD_CONNECTION *con, const char *status, void *arg)
+status_cb(DHCPCD_CONNECTION *con,
+    unsigned int status, const char *status_msg, void *arg)
 {
        struct ctx *ctx = arg;
 
-       debug(ctx, _("Status changed to %s"), status);
-       set_status(ctx, status);
+       debug(ctx, _("Status changed to %s"), status_msg);
+       set_status(ctx, status_msg);
 
-       if (strcmp(status, "down") == 0) {
-               eloop_event_delete(ctx->eloop, ctx->fd, NULL, NULL, 0);
+       if (status == DHC_DOWN) {
                ctx->fd = -1;
                ctx->online = ctx->carrier = false;
-               eloop_timeout_delete(ctx->eloop, NULL, ctx);
                set_summary(ctx, NULL);
-               eloop_timeout_add_msec(ctx->eloop, DHCPCD_RETRYOPEN,
-                   try_open, ctx);
+               dispatch_cb(-1, 0, ctx);
        } else {
                bool refresh;
 
-               if (ctx->last_status == NULL ||
-                   strcmp(ctx->last_status, "down") == 0)
+               if (ctx->last_status == DHC_UNKNOWN ||
+                   ctx->last_status == DHC_DOWN)
                {
                        debug(ctx, _("Connected to dhcpcd-%s"),
                            dhcpcd_version(con));
                        refresh = true;
                } else
                        refresh =
-                           strcmp(ctx->last_status, "opened") ? false : true;
+                           ctx->last_status == DHC_OPENED ? true : false;
                update_online(ctx, refresh);
        }
 
-       free(ctx->last_status);
-       ctx->last_status = strdup(status);
+       ctx->last_status = status;
 }
 
 static void
@@ -275,9 +270,8 @@ if_cb(DHCPCD_IF *i, void *arg)
 {
        struct ctx *ctx = arg;
 
-       if (strcmp(i->reason, "RENEW") &&
-           strcmp(i->reason, "STOP") &&
-           strcmp(i->reason, "STOPPED"))
+       if (i->state == DHS_RENEW ||
+           i->state == DHS_STOP || i->state == DHS_STOPPED)
        {
                char *msg;
                bool new_msg;
@@ -300,7 +294,7 @@ if_cb(DHCPCD_IF *i, void *arg)
 }
 
 static void
-wpa_dispatch(void *arg)
+wpa_dispatch_cb(__unused evutil_socket_t fd, __unused short what, void *arg)
 {
        DHCPCD_WPA *wpa = arg;
 
@@ -312,6 +306,7 @@ static void
 wpa_scan_cb(DHCPCD_WPA *wpa, void *arg)
 {
        struct ctx *ctx = arg;
+       EVENT_OBJECT *eo;
        DHCPCD_IF *i;
        WI_SCAN *wi;
        DHCPCD_WI_SCAN *scans, *s1, *s2;
@@ -322,8 +317,15 @@ wpa_scan_cb(DHCPCD_WPA *wpa, void *arg)
                debug(ctx, "%s (%p)", _("no fd for WPA"), wpa);
                return;
        }
-       eloop_event_add(ctx->eloop,
-           dhcpcd_wpa_get_fd(wpa), wpa_dispatch, wpa, NULL, NULL);
+       if ((eo = event_object_find(ctx->evobjects, wpa)) == NULL) {
+               struct event *ev;
+
+               ev = event_new(ctx->evbase, fd, EV_READ | EV_PERSIST,
+                   wpa_dispatch_cb, wpa);
+               if (ev == NULL ||
+                   event_object_add(ctx->evobjects, ev, NULL, wpa) == NULL)
+                       warning(ctx, "event_new: %s", strerror(errno));
+       }
 
        i = dhcpcd_wpa_if(wpa);
        if (i == NULL) {
@@ -399,16 +401,17 @@ wpa_scan_cb(DHCPCD_WPA *wpa, void *arg)
 }
 
 static void
-wpa_status_cb(DHCPCD_WPA *wpa, const char *status, void *arg)
+wpa_status_cb(DHCPCD_WPA *wpa,
+    unsigned int status, const char *status_msg, void *arg)
 {
        struct ctx *ctx = arg;
        DHCPCD_IF *i;
        WI_SCAN *w, *wn;
 
        i = dhcpcd_wpa_if(wpa);
-       debug(ctx, _("%s: WPA status %s"), i->ifname, status);
-       if (strcmp(status, "down") == 0) {
-               eloop_event_delete(ctx->eloop, -1, NULL, wpa, 0);
+       debug(ctx, _("%s: WPA status %s"), i->ifname, status_msg);
+       if (status == DHC_DOWN) {
+               event_object_find_delete(ctx->evobjects, wpa);
                TAILQ_FOREACH_SAFE(w, &ctx->wi_scans, next, wn) {
                        if (w->interface == i) {
                                TAILQ_REMOVE(&ctx->wi_scans, w, next);
@@ -419,67 +422,65 @@ wpa_status_cb(DHCPCD_WPA *wpa, const char *status, void *arg)
        }
 }
 
-#ifdef BG_SCAN
 static void
-bg_scan(void *arg)
+bg_scan_cb(__unused evutil_socket_t fd, __unused short what, void *arg)
 {
        struct ctx *ctx = arg;
        WI_SCAN *w;
        DHCPCD_WPA *wpa;
 
        TAILQ_FOREACH(w, &ctx->wi_scans, next) {
-               if (w->interface->wireless && w->interface->up) {
+               if (w->interface->wireless& w->interface->up) {
                        wpa = dhcpcd_wpa_find(ctx->con, w->interface->ifname);
-                       if (wpa)
+                       if (wpa &&
+                           (!w->interface->up ||
+                           dhcpcd_wpa_can_background_scan(wpa)))
                                dhcpcd_wpa_scan(wpa);
                }
        }
+}
+
+static void
+sigint_cb(__unused evutil_socket_t fd, __unused short what, void *arg)
+{
+       struct ctx *ctx = arg;
 
-       eloop_timeout_add_msec(ctx->eloop, DHCPCD_WPA_SCAN_SHORT,
-           bg_scan, ctx);
+       debug(ctx, _("caught SIGINT, exiting"));
+       event_base_loopbreak(ctx->evbase);
 }
-#endif
 
 static void
-signal_handler(int sig)
+sigterm_cb(__unused evutil_socket_t fd, __unused short what, void *arg)
+{
+       struct ctx *ctx = arg;
+
+       debug(ctx, _("caught SIGTERM, exiting"));
+       event_base_loopbreak(ctx->evbase);
+}
+
+static void
+sigwinch_cb(__unused evutil_socket_t fd, __unused short what,
+    __unused void *arg)
 {
        struct winsize ws;
 
-       switch(sig) {
-       case SIGWINCH:
-               if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0)
-                       resizeterm(ws.ws_row, ws.ws_col);
-               break;
-       case SIGINT:
-               debug(_ctx, _("SIGINT caught, exiting"));
-               eloop_exit(_ctx->eloop, EXIT_FAILURE);
-               break;
-       case SIGTERM:
-               debug(_ctx, _("SIGTERM caught, exiting"));
-               eloop_exit(_ctx->eloop, EXIT_FAILURE);
-               break;
-       case SIGHUP:
-               debug(_ctx, _("SIGHUP caught, ignoring"));
-               break;
-       case SIGPIPE:
-               debug(_ctx, _("SIGPIPE caught, ignoring"));
-               break;
-       }
+       if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0)
+               resizeterm(ws.ws_row, ws.ws_col);
 }
 
 static int
-setup_signals()
+setup_signals(struct ctx *ctx)
 {
-       struct sigaction sa;
-       int i;
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_handler = signal_handler;
 
-       for (i = 0; handle_sigs[i]; i++) {
-               if (sigaction(handle_sigs[i], &sa, NULL) == -1)
-                       return -1;
-       }
+       ctx->sigint = evsignal_new(ctx->evbase, SIGINT, sigint_cb, ctx);
+       if (ctx->sigint == NULL || event_add(ctx->sigint, NULL) == -1)
+               return -1;
+       ctx->sigterm = evsignal_new(ctx->evbase, SIGTERM, sigterm_cb, ctx);
+       if (ctx->sigterm == NULL || event_add(ctx->sigterm, NULL) == -1)
+               return -1;
+       ctx->sigwinch = evsignal_new(ctx->evbase, SIGWINCH, sigwinch_cb, ctx);
+       if (ctx->sigwinch == NULL || event_add(ctx->sigwinch, NULL) == -1)
+               return -1;
        return 0;
 }
 
@@ -522,21 +523,25 @@ main(void)
 {
        struct ctx ctx;
        WI_SCAN *wi;
+       struct timeval tv0 = { 0, 0 };
+       struct timeval tv_short = { 0, DHCPCD_WPA_SCAN_SHORT };
+       struct event *ev;
 
        memset(&ctx, 0, sizeof(ctx));
        ctx.fd = -1;
+       if ((ctx.evobjects = event_object_new()) == NULL)
+               err(EXIT_FAILURE, "event_object_new");
        TAILQ_INIT(&ctx.wi_scans);
-       _ctx = &ctx;
 
-       if (setup_signals() == -1)
+       if ((ctx.evbase = event_base_new()) == NULL)
+               err(EXIT_FAILURE, "event_base_new");
+
+       if (setup_signals(&ctx) == -1)
                err(EXIT_FAILURE, "setup_signals");
 
        if ((ctx.con = dhcpcd_new()) == NULL)
                err(EXIT_FAILURE, "dhcpcd_new");
 
-       if ((ctx.eloop = eloop_init()) == NULL)
-               err(EXIT_FAILURE, "malloc");
-
        if ((ctx.stdscr = initscr()) == NULL)
                err(EXIT_FAILURE, "initscr");
 
@@ -554,12 +559,16 @@ main(void)
        dhcpcd_wpa_set_scan_callback(ctx.con, wpa_scan_cb, &ctx);
        dhcpcd_wpa_set_status_callback(ctx.con, wpa_status_cb, &ctx);
 
-       eloop_timeout_add_sec(ctx.eloop, 0, try_open, &ctx);
-#ifdef BG_SCAN
-       eloop_timeout_add_msec(ctx.eloop, DHCPCD_WPA_SCAN_SHORT,
-           bg_scan, &ctx);
-#endif
-       eloop_start(ctx.eloop);
+       if ((ev = event_new(ctx.evbase, 0, 0, try_open_cb, &ctx)) == NULL)
+               err(EXIT_FAILURE, "event_new");
+       if (event_object_add(ctx.evobjects, ev, &tv0, &ctx) == NULL)
+               err(EXIT_FAILURE, "event_object_add");
+       if ((ev = event_new(ctx.evbase, EV_PERSIST, 0,
+           bg_scan_cb, &ctx)) == NULL)
+               err(EXIT_FAILURE, "event_new");
+       if (event_add(ev, &tv_short) == -1)
+               err(EXIT_FAILURE, "event_add");
+       event_base_dispatch(ctx.evbase);
 
        /* Un-resgister the callbacks to avoid spam on close */
        dhcpcd_set_status_callback(ctx.con, NULL, NULL);
@@ -577,9 +586,23 @@ main(void)
        }
 
        /* Free everything else */
-       eloop_free(ctx.eloop);
+       if (ctx.sigint) {
+               event_del(ctx.sigint);
+               event_free(ctx.sigint);
+       }
+       if (ctx.sigterm) {
+               event_del(ctx.sigterm);
+               event_free(ctx.sigterm);
+       }
+       if (ctx.sigwinch) {
+               event_del(ctx.sigwinch);
+               event_free(ctx.sigwinch);
+       }
+       event_del(ev);
+       event_free(ev);
+       event_base_free(ctx.evbase);
+       event_object_free(ctx.evobjects);
        endwin();
-       free(ctx.last_status);
 
 #ifdef HAVE_NC_FREE_AND_EXIT
        /* undefined ncurses function to allow valgrind debugging */