make range allocation dynamic
[debian/dhcpd-pools.git] / src / getdata.c
index 430468c..1334855 100644 (file)
@@ -1,19 +1,18 @@
-/*
-** Copyright (C) 2006- Sami Kerola <kerolasa@iki.fi>
-**  
-** This program is free software; you can redistribute it and/or modify
+/* http://dhcpd-pools.sourceforge.net/
+** Copyright 2006- Sami Kerola <kerolasa@iki.fi>
+**
+** This program is free software: you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
+** the Free Software Foundation, either version 3 of the License, or
 ** (at your option) any later version.
-** 
+**
 ** This program is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
-** 
+**
 ** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software 
-** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+** along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #ifdef HAVE_CONFIG_H
@@ -27,7 +26,6 @@
 #ifdef  HAVE_STDLIB_H
 #include <stdlib.h>
 #else                          /* Not STDC_HEADERS */
-extern void exit();
 extern char *malloc();
 #define EXIT_FAILURE    1      /* Failing exit status.  */
 #define EXIT_SUCCESS    0      /* Successful exit status.  */
@@ -45,22 +43,27 @@ extern char *malloc();
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#ifndef _XOPEN_SOURCE
 #define _XOPEN_SOURCE 600
+#endif
 #include <fcntl.h>
 #include <errno.h>
+#include <err.h>
 #include <ctype.h>
+#include <assert.h>
 
 #include "dhcpd-pools.h"
 #include "defaults.h"
 
-/* Parse dhcpd.leases file. All performance boosts for this
- * function are wellcome */
+/* Parse dhcpd.leases file. All performance boosts for this function are
+ * wellcome */
 int parse_leases(void)
 {
        FILE *dhcpd_leases;
-       char *line, *ipstring, *macstring, *macstring2;
+       char *line, *ipstring, *macstring = NULL;
        struct in_addr inp;
        struct stat lease_file_stats;
+       struct macaddr_t *macaddr_p = NULL;
        unsigned long leasesmallocsize;
        unsigned long touchesmallocsize;
        unsigned long backupsmallocsize;
@@ -70,30 +73,31 @@ int parse_leases(void)
 
        dhcpd_leases = fopen(config.dhcpdlease_file, "r");
        if (dhcpd_leases == NULL) {
-               eprintf("parse_leases: %s:", config.dhcpdlease_file);
-               exit(EXIT_FAILURE);
+               err(EXIT_FAILURE, "parse_leases: %s",
+                   config.dhcpdlease_file);
        }
-#ifdef POSIX_FADV_NOREUSE
-       posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_NOREUSE);
+#ifdef POSIX_FADV_WILLNEED
+       posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_WILLNEED);
        if (errno) {
-               eprintf("parse_leases: fadvise:");
-               exit(EXIT_FAILURE);
+               err(EXIT_FAILURE, "parse_leases: fadvise %s",
+                   config.dhcpdlease_file);
        }
-#endif                         /* POSIX_FADV_NOREUSE */
+#endif                         /* POSIX_FADV_WILLNEED */
 #ifdef POSIX_FADV_SEQUENTIAL
        posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_SEQUENTIAL);
        if (errno) {
-               eprintf("parse_leases: fadvise:");
-               exit(EXIT_FAILURE);
+               err(EXIT_FAILURE, "parse_leases: fadvise %s",
+                   config.dhcpdlease_file);
        }
 #endif                         /* POSIX_FADV_SEQUENTIAL */
+
        /* I found out that there's one lease address per 300 bytes in
-        * dhcpd.leases file. Malloc is little bit pessimistic and uses
-        * 250. If someone has higher density in lease file I'm
-        * interested to hear about that. */
+        * dhcpd.leases file. Malloc is little bit pessimistic and uses 250.
+        * If someone has higher density in lease file I'm interested to
+        * hear about that. */
        if (stat(config.dhcpdlease_file, &lease_file_stats)) {
-               eprintf("parse_leases: %s:", config.dhcpdlease_file);
-               exit(EXIT_FAILURE);
+               err(EXIT_FAILURE, "parse_leases: %s",
+                   config.dhcpdlease_file);
        }
        leasesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
        touchesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
@@ -104,8 +108,12 @@ int parse_leases(void)
 
        line = safe_malloc(sizeof(long int) * MAXLEN);
        ipstring = safe_malloc(sizeof(long int) * MAXLEN);
-       macstring = safe_malloc(sizeof(long int) * MAXLEN);
-       macstring2 = safe_malloc(sizeof(long int) * MAXLEN);
+       if (config.output_format[0] == 'X') {
+               macstring = safe_malloc(sizeof(char) * 18);
+               macaddr = safe_malloc(sizeof(struct macaddr_t));
+               macaddr_p = macaddr;
+               macaddr_p->next = NULL;
+       }
 
        while (!feof(dhcpd_leases)) {
                fgets(line, MAXLEN, dhcpd_leases);
@@ -120,10 +128,12 @@ int parse_leases(void)
                else if (strstr(line, "binding state active")) {
                        leases[num_leases] = htonl(inp.s_addr);
                        num_leases++;
+                       assert(!(leasesmallocsize < num_leases));
                        sw_active_lease = 1;
                } else if (strstr(line, "  binding state free")) {
                        touches[num_touches] = htonl(inp.s_addr);
                        num_touches++;
+                       assert(!(touchesmallocsize < num_touches));
                } else if (strstr(line, "  binding state backup")) {
                        if (num_backups == 0) {
                                backups =
@@ -132,43 +142,35 @@ int parse_leases(void)
                        }
                        backups[num_backups] = htonl(inp.s_addr);
                        num_backups++;
+                       assert(!(backupsmallocsize < num_backups));
                }
 
-               /* FIXME: move to output.c and use FILE *outfile */
-               if ((config.output_format[0] == 'X')
+               if ((macaddr != NULL)
                    && (sw_active_lease == 1)
                    && (strstr(line, "hardware ethernet"))) {
                        nth_field(3, macstring, line);
-                       macstring[strlen(macstring) - 1] = '\0';
-
-                        printf
-                           ("<active_lease>\n\t<ip>%s</ip>\n\t<macaddress>%s</macaddress>\n</active_lease>\n",
-                            ipstring, macstring);
-               }
-
-               if ((leasesmallocsize < num_leases) ||
-                   (touchesmallocsize < num_touches) ||
-                   (backupsmallocsize < num_backups)) {
-                       printf("WARNING: running out of memory\n");
-                       printf("\tlease/touch/backup = %lu/%lu/%lu\n",
-                              leasesmallocsize, touchesmallocsize,
-                              backupsmallocsize);
-                       printf("\tlease/touch/backup = %lu/%lu/%lu\n",
-                              num_leases, num_touches, num_backups);
-                       printf
-                           ("Code should realloc() and init new memory, but no time to write that now!\n");
-                       exit(EXIT_FAILURE);
+                       macstring[17] = '\0';
+                       macaddr_p->ethernet = safe_strdup(macstring);
+                       macaddr_p->ip = safe_strdup(ipstring);
+                       macaddr_p->next =
+                           safe_malloc(sizeof(struct macaddr_t));
+                       macaddr_p = macaddr_p->next;
+                       macaddr_p->next = NULL;
                }
        }
-
+       free(line);
+       free(ipstring);
+       if (macaddr != NULL) {
+               free(macstring);
+       }
+       fclose(dhcpd_leases);
        return 0;
 }
 
-/* Like strcpy but for field which is separated by white spaces.
- * Number of first field is 1 and not 0 like C programs should
- * have. Question of semantics, send mail to author if this
- * annoys. All performance boosts for this function are well
- * come. */
+/* Like strcpy but for field which is separated by white spaces. Number of
+ * first field is 1 and not 0 like C programs should have. Question of
+ * semantics, send mail to author if this annoys. All performance boosts for
+ * this function are well come. */
 int nth_field(int n, char *dest, const char *src)
 {
        int i, j = 0, wordn = 0, len;
@@ -198,10 +200,10 @@ int nth_field(int n, char *dest, const char *src)
 /* dhcpd.conf interesting words */
 int is_interesting_config_clause(char *s)
 {
-       if (strstr(s, "shared-network")) {
-               return 1;
-       } else if (strstr(s, "range")) {
+       if (strstr(s, "range")) {
                return 3;
+       } else if (strstr(s, "shared-network")) {
+               return 1;
        } else if (strstr(s, "include")) {
                return 4;
        } else {
@@ -209,8 +211,7 @@ int is_interesting_config_clause(char *s)
        }
 }
 
-/* TODO: This spagetti monster function need to be rewrote at
- * least ones. */
+/* FIXME: This spagetti monster function need to be rewrote at least ones. */
 char *parse_config(int is_include, char *config_file,
                   char *current_shared_name,
                   char *next_free_shared_name,
@@ -237,23 +238,21 @@ char *parse_config(int is_include, char *config_file,
        /* Open configuration file */
        dhcpd_config = fopen(config_file, "r");
        if (dhcpd_config == NULL) {
-               eprintf("parse_config: %s:", config_file);
-               exit(EXIT_FAILURE);
+               err(EXIT_FAILURE, "parse_config: %s", config_file);
        }
-#ifdef POSIX_FADV_NOREUSE
-       posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_NOREUSE);
+#ifdef POSIX_FADV_WILLNEED
+       posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_WILLNEED);
        if (errno) {
-               eprintf("parse_config: fadvise:");
-               exit(EXIT_FAILURE);
+               err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
        }
-#endif                         /* POSIX_FADV_NOREUSE */
+#endif                         /* POSIX_FADV_WILLNEED */
 #ifdef POSIX_FADV_SEQUENTIAL
        posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_SEQUENTIAL);
        if (errno) {
-               eprintf("parse_config: fadvise:");
-               exit(EXIT_FAILURE);
+               err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
        }
 #endif                         /* POSIX_FADV_SEQUENTIAL */
+
        /* Very hairy stuff begins. */
        while (!feof(dhcpd_config)) {
                c = fgetc(dhcpd_config);
@@ -273,7 +272,8 @@ char *parse_config(int is_include, char *config_file,
                        }
                        continue;
                case '\n':
-                       /* New line resets comment section, but not if quoted */
+                       /* New line resets comment section, but
+                        * not if quoted */
                        if (quote == false) {
                                comment = false;
                        }
@@ -288,11 +288,11 @@ char *parse_config(int is_include, char *config_file,
                                newclause = true;
                                i = 0;
                        } else if (argument == 2) {
-                               /* Range ends to ; and this hair in code make two
-                                * ranges wrote to gether like...
+                               /* Range ends to ; and this hair in code
+                                * make two ranges wrote to gether like...
                                 *
                                 * range 10.20.30.40 10.20.30.41;range 10.20.30.42 10.20.30.43;
-                                * 
+                                *
                                 * ...to be interpreted correctly. */
                                c = ' ';
                        }
@@ -321,11 +321,13 @@ char *parse_config(int is_include, char *config_file,
                                if (braces_shared == braces) {
                                        current_shared_name =
                                            shared_net_names;
-                                       /* TODO: Using 1000 is lame, but works. */
+                                       /* FIXME: Using 1000 is lame, but
+                                        * works. */
                                        braces_shared = 1000;
                                        shared_p = shared_networks;
                                }
-                               /* Not literally true, but works for this program */
+                               /* Not literally true, but works for this
+                                * program */
                                newclause = true;
                        }
                        continue;
@@ -348,8 +350,9 @@ char *parse_config(int is_include, char *config_file,
                    && (!isspace(c) || quote == true)) {
                        word[i] = c;
                        i++;
-                       /* Long word which is almost causing overflow. Not any of words
-                        * this program is looking for are this long. */
+                       /* Long word which is almost causing overflow. None
+                        * of words are this long which the program is
+                        * searching. */
                        if (MAXLEN < i) {
                                newclause = false;
                                i = 0;
@@ -372,37 +375,6 @@ char *parse_config(int is_include, char *config_file,
                        i = 0;
 
                        switch (argument) {
-                       case 0:
-                               /* printf ("nothing interesting: %s\n", word); */
-                               argument = 0;
-                               break;
-                       case 1:
-                               /* printf ("shared-network named: %s\n", word); */
-                               strcpy(next_free_shared_name, word);
-                               shared_p =
-                                   shared_networks + num_shared_networks;
-                               num_shared_networks++;
-                               shared_p++;
-                               shared_p->name = next_free_shared_name;
-                               shared_p->available = 0;
-                               shared_p->used = 0;
-                               shared_p->touched = 0;
-                               shared_p->backups = 0;
-                               /* Temporary abuse of argument variable */
-                               argument =
-                                   strlen(next_free_shared_name) + 1;
-                               if (last_shared_name >
-                                   next_free_shared_name + argument) {
-                                       next_free_shared_name += argument;
-                               } else {
-                                       /* TODO: make this go away by reallocationg more space. */
-                                       eprintf
-                                           ("parse_config: End of shared-network space, increase SHARED_NETWORKS_NAMES and recompile");
-                                       exit(EXIT_FAILURE);
-                               }
-                               argument = 0;
-                               braces_shared = braces;
-                               break;
                        case 2:
                                /* printf ("range 2nd ip: %s\n", word); */
                                range_p = ranges + num_ranges;
@@ -414,10 +386,14 @@ char *parse_config(int is_include, char *config_file,
                                range_p->backups = 0;
                                range_p->shared_net = shared_p;
                                num_ranges++;
-                               if (RANGES < num_ranges) {
-                                       eprintf
-                                           ("parse_config: Range space full! Increase RANGES and recompile.");
-                                       exit(EXIT_FAILURE);
+                               if (RANGES < num_ranges + 1) {
+                                       RANGES *= 2;
+                                       ranges =
+                                           safe_realloc(ranges,
+                                                        sizeof(struct
+                                                               range_t) *
+                                                        RANGES);
+                                       range_p = ranges + num_ranges;
                                }
                                newclause = true;
                                break;
@@ -425,12 +401,50 @@ char *parse_config(int is_include, char *config_file,
                                /* printf ("range 1nd ip: %s\n", word); */
                                range_p = ranges + num_ranges;
                                if (!(inet_aton(word, &inp))) {
-                                       /* word was not ip, try again */
+                                       /* word was not ip, try
+                                        * again */
                                        break;
                                }
                                range_p->first_ip = htonl(inp.s_addr) - 1;
                                argument = 2;
                                break;
+                       case 1:
+                               /* printf ("shared-network named: %s\n", word); */
+                               strcpy(next_free_shared_name, word);
+                               shared_p =
+                                   shared_networks + num_shared_networks;
+                               num_shared_networks++;
+                               shared_p++;
+                               shared_p->name = next_free_shared_name;
+                               shared_p->available = 0;
+                               shared_p->used = 0;
+                               shared_p->touched = 0;
+                               shared_p->backups = 0;
+                               /* Temporary abuse of argument
+                                * variable */
+                               argument =
+                                   strlen(next_free_shared_name) + 1;
+                               if (next_free_shared_name + argument <
+                                   last_shared_name) {
+                                       next_free_shared_name += argument;
+                               } else {
+                                       /* FIXME: make this go
+                                        * away by reallocationg
+                                        * more space. */
+                                       errx(EXIT_FAILURE,
+                                            "parse_config: increase default.h SHARED_NETWORKS_NAMES and recompile");
+                               }
+                               if (SHARED_NETWORKS <
+                                   num_shared_networks + 2) {
+                                       /* FIXME: make this
+                                        * away by reallocationg
+                                        * more space. */
+                                       errx(EXIT_FAILURE,
+                                            "parse_config: increase default.h SHARED_NETWORKS and recompile");
+                               }
+                               argument = 0;
+                               braces_shared = braces;
+                               break;
                        case 4:
                                /* printf ("include file: %s\n", word); */
                                argument = 0;
@@ -441,13 +455,17 @@ char *parse_config(int is_include, char *config_file,
                                                 shared_p);
                                newclause = true;
                                break;
+                       case 0:
+                               /* printf ("nothing interesting: %s\n", word); */
+                               argument = 0;
+                               break;
                        default:
-                               eprintf
-                                   ("parse_config: This cannot happen, report a bug!");
-                               exit(EXIT_FAILURE);
+                               warnx("impossible occurred, report a bug");
+                               assert(0);
                        }
                }
        }
        free(word);
+       fclose(dhcpd_config);
        return next_free_shared_name;
 }