rpcd-mod-luci: handle lease files from all dnsmasq/odhcpd sections
[project/luci.git] / libs / rpcd-mod-luci / src / luci.c
index 1a1524d49ed14bec2ce10e7182ac5117b4db46b3..94ccdf27160d35e7ecbd86817478b3cc5c9e8909 100644 (file)
@@ -315,9 +315,12 @@ duid2ea(const char *duid)
 
 
 static struct {
-       FILE *dnsmasq_file;
-       FILE *odhcpd_file;
        time_t now;
+       size_t num, off;
+       struct {
+               FILE *fh;
+               bool odhcpd;
+       } *files;
 } lease_state = { };
 
 struct lease_entry {
@@ -333,13 +336,41 @@ struct lease_entry {
        } addr[10];
 };
 
-static char *
-find_leasefile(struct uci_context *uci, const char *section)
+static bool
+add_leasefile(const char *path, bool is_odhcpd)
+{
+       void *ptr;
+       FILE *fh;
+
+       fh = fopen(path, "r");
+
+       if (!fh)
+               return false;
+
+       ptr = realloc(lease_state.files, sizeof(*lease_state.files) * (lease_state.num + 1));
+
+       if (!ptr) {
+               fclose(fh);
+
+               return false;
+       }
+
+       lease_state.files = ptr;
+       lease_state.files[lease_state.num].fh = fh;
+       lease_state.files[lease_state.num].odhcpd = is_odhcpd;
+       lease_state.num++;
+
+       return true;
+}
+
+static bool
+find_leasefiles(struct uci_context *uci, bool is_odhcpd)
 {
        struct uci_ptr ptr = { .package = "dhcp" };
        struct uci_package *pkg = NULL;
        struct uci_section *s;
        struct uci_element *e;
+       bool found = false;
 
        pkg = uci_lookup_package(uci, ptr.package);
 
@@ -353,7 +384,7 @@ find_leasefile(struct uci_context *uci, const char *section)
        uci_foreach_element(&pkg->sections, e) {
                s = uci_to_section(e);
 
-               if (strcmp(s->type, section))
+               if (strcmp(s->type, is_odhcpd ? "odhcpd" : "dnsmasq"))
                        continue;
 
                ptr.flags = 0;
@@ -370,31 +401,30 @@ find_leasefile(struct uci_context *uci, const char *section)
                if (ptr.o->type != UCI_TYPE_STRING)
                        continue;
 
-               return ptr.o->v.string;
+               if (add_leasefile(ptr.o->v.string, is_odhcpd))
+                       found = true;
        }
 
-       return NULL;
+       return found;
 }
 
 static void
 lease_close(void)
 {
-       if (lease_state.dnsmasq_file) {
-               fclose(lease_state.dnsmasq_file);
-               lease_state.dnsmasq_file = NULL;
-       }
+       while (lease_state.num > 0)
+               fclose(lease_state.files[--lease_state.num].fh);
 
-       if (lease_state.odhcpd_file) {
-               fclose(lease_state.odhcpd_file);
-               lease_state.odhcpd_file = NULL;
-       }
+       free(lease_state.files);
+
+       lease_state.files = NULL;
+       lease_state.num = 0;
+       lease_state.off = 0;
 }
 
 static void
 lease_open(void)
 {
        struct uci_context *uci;
-       char *p;
 
        lease_close();
 
@@ -405,11 +435,11 @@ lease_open(void)
 
        lease_state.now = time(NULL);
 
-       p = find_leasefile(uci, "dnsmasq");
-       lease_state.dnsmasq_file = fopen(p ? p : "/tmp/dhcp.leases", "r");
+       if (!find_leasefiles(uci, false))
+               add_leasefile("/tmp/dhcp.leases", false);
 
-       p = find_leasefile(uci, "odhcpd");
-       lease_state.odhcpd_file = fopen(p ? p : "/tmp/hosts/odhcpd", "r");
+       if (!find_leasefiles(uci, true))
+               add_leasefile("/tmp/hosts/odhcpd", true);
 
        uci_free_context(uci);
 }
@@ -424,133 +454,126 @@ lease_next(void)
 
        memset(&e, 0, sizeof(e));
 
-       if (lease_state.dnsmasq_file) {
-               while (fgets(e.buf, sizeof(e.buf), lease_state.dnsmasq_file)) {
-                       p = strtok(e.buf, " \t\n");
+       while (lease_state.off < lease_state.num) {
+               while (fgets(e.buf, sizeof(e.buf), lease_state.files[lease_state.off].fh)) {
+                       if (lease_state.files[lease_state.off].odhcpd) {
+                               strtok(e.buf, " \t\n"); /* # */
+                               strtok(NULL, " \t\n"); /* iface */
 
-                       if (!p)
-                               continue;
+                               e.duid = strtok(NULL, " \t\n"); /* duid */
 
-                       n = strtol(p, NULL, 10);
+                               if (!e.duid)
+                                       continue;
 
-                       if (n > lease_state.now)
-                               e.expire = n - lease_state.now;
-                       else if (n > 0)
-                               e.expire = 0;
-                       else
-                               e.expire = -1;
+                               p = strtok(NULL, " \t\n"); /* iaid */
 
-                       p = strtok(NULL, " \t\n");
+                               if (p)
+                                       e.af = strcmp(p, "ipv4") ? AF_INET6 : AF_INET;
+                               else
+                                       continue;
 
-                       if (!p)
-                               continue;
+                               e.hostname = strtok(NULL, " \t\n"); /* name */
 
-                       ea = ether_aton(p);
+                               if (!e.hostname)
+                                       continue;
 
-                       p = strtok(NULL, " \t\n");
+                               p = strtok(NULL, " \t\n"); /* ts */
 
-                       if (p && inet_pton(AF_INET6, p, &e.addr[0].in6)) {
-                               e.af = AF_INET6;
-                               e.n_addr = 1;
-                       }
-                       else if (p && inet_pton(AF_INET, p, &e.addr[0].in)) {
-                               e.af = AF_INET;
-                               e.n_addr = 1;
-                       }
-                       else {
-                               continue;
-                       }
-
-                       if (!ea && e.af != AF_INET6)
-                               continue;
+                               if (!p)
+                                       continue;
 
-                       e.hostname = strtok(NULL, " \t\n");
-                       e.duid     = strtok(NULL, " \t\n");
+                               n = strtol(p, NULL, 10);
 
-                       if (!e.hostname || !e.duid)
-                               continue;
+                               if (n > lease_state.now)
+                                       e.expire = n - lease_state.now;
+                               else if (n >= 0)
+                                       e.expire = 0;
+                               else
+                                       e.expire = -1;
 
-                       if (!strcmp(e.hostname, "*"))
-                               e.hostname = NULL;
+                               strtok(NULL, " \t\n"); /* id */
+                               strtok(NULL, " \t\n"); /* length */
 
-                       if (!strcmp(e.duid, "*"))
-                               e.duid = NULL;
+                               for (e.n_addr = 0, p = strtok(NULL, "/ \t\n");
+                                    e.n_addr < ARRAY_SIZE(e.addr) && p != NULL;
+                                    p = strtok(NULL, "/ \t\n")) {
+                                       if (inet_pton(e.af, p, &e.addr[e.n_addr].in6))
+                                               e.n_addr++;
+                               }
 
-                       if (!ea && e.duid)
                                ea = duid2ea(e.duid);
 
-                       if (ea)
-                               e.mac = *ea;
+                               if (ea)
+                                       e.mac = *ea;
 
-                       return &e;
-               }
+                               if (!strcmp(e.hostname, "-"))
+                                       e.hostname = NULL;
 
-               fclose(lease_state.dnsmasq_file);
-               lease_state.dnsmasq_file = NULL;
-       }
+                               if (!strcmp(e.duid, "-"))
+                                       e.duid = NULL;
+                       }
+                       else {
+                               p = strtok(e.buf, " \t\n");
 
-       if (lease_state.odhcpd_file) {
-               while (fgets(e.buf, sizeof(e.buf), lease_state.odhcpd_file)) {
-                       strtok(e.buf, " \t\n"); /* # */
-                       strtok(NULL, " \t\n"); /* iface */
+                               if (!p)
+                                       continue;
 
-                       e.duid = strtok(NULL, " \t\n"); /* duid */
+                               n = strtol(p, NULL, 10);
 
-                       if (!e.duid)
-                               continue;
+                               if (n > lease_state.now)
+                                       e.expire = n - lease_state.now;
+                               else if (n > 0)
+                                       e.expire = 0;
+                               else
+                                       e.expire = -1;
 
-                       p = strtok(NULL, " \t\n"); /* iaid */
+                               p = strtok(NULL, " \t\n");
 
-                       if (p)
-                               e.af = strcmp(p, "ipv4") ? AF_INET6 : AF_INET;
-                       else
-                               continue;
-
-                       e.hostname = strtok(NULL, " \t\n"); /* name */
-
-                       if (!e.hostname)
-                               continue;
+                               if (!p)
+                                       continue;
 
-                       p = strtok(NULL, " \t\n"); /* ts */
+                               ea = ether_aton(p);
 
-                       if (!p)
-                               continue;
+                               p = strtok(NULL, " \t\n");
 
-                       n = strtol(p, NULL, 10);
+                               if (p && inet_pton(AF_INET6, p, &e.addr[0].in6)) {
+                                       e.af = AF_INET6;
+                                       e.n_addr = 1;
+                               }
+                               else if (p && inet_pton(AF_INET, p, &e.addr[0].in)) {
+                                       e.af = AF_INET;
+                                       e.n_addr = 1;
+                               }
+                               else {
+                                       continue;
+                               }
 
-                       if (n > lease_state.now)
-                               e.expire = n - lease_state.now;
-                       else if (n >= 0)
-                               e.expire = 0;
-                       else
-                               e.expire = -1;
+                               if (!ea && e.af != AF_INET6)
+                                       continue;
 
-                       strtok(NULL, " \t\n"); /* id */
-                       strtok(NULL, " \t\n"); /* length */
+                               e.hostname = strtok(NULL, " \t\n");
+                               e.duid     = strtok(NULL, " \t\n");
 
-                       for (e.n_addr = 0, p = strtok(NULL, "/ \t\n");
-                            e.n_addr < ARRAY_SIZE(e.addr) && p != NULL;
-                            p = strtok(NULL, "/ \t\n")) {
-                               if (inet_pton(e.af, p, &e.addr[e.n_addr].in6))
-                                       e.n_addr++;
-                       }
+                               if (!e.hostname || !e.duid)
+                                       continue;
 
-                       ea = duid2ea(e.duid);
+                               if (!strcmp(e.hostname, "*"))
+                                       e.hostname = NULL;
 
-                       if (ea)
-                               e.mac = *ea;
+                               if (!strcmp(e.duid, "*"))
+                                       e.duid = NULL;
 
-                       if (!strcmp(e.hostname, "-"))
-                               e.hostname = NULL;
+                               if (!ea && e.duid)
+                                       ea = duid2ea(e.duid);
 
-                       if (!strcmp(e.duid, "-"))
-                               e.duid = NULL;
+                               if (ea)
+                                       e.mac = *ea;
+                       }
 
                        return &e;
                }
 
-               fclose(lease_state.odhcpd_file);
-               lease_state.odhcpd_file = NULL;
+               lease_state.off++;
        }
 
        return NULL;