diff --git a/src/.indent.pro b/src/.indent.pro index 2d71c4e..64735c3 100644 --- a/src/.indent.pro +++ b/src/.indent.pro @@ -1,5 +1,6 @@ -linux -TFILE +-Tconf_t -Tipaddr_t -Tleases_t -Toff_t diff --git a/src/Makemodule.am b/src/Makemodule.am index d0bbba5..c072af3 100644 --- a/src/Makemodule.am +++ b/src/Makemodule.am @@ -8,7 +8,6 @@ dhcpd_pools_LDADD = $(top_builddir)/lib/libdhcpd_pools.la dhcpd_pools_SOURCES = \ src/analyze.c \ - src/defaults.h \ src/dhcpd-pools.c \ src/dhcpd-pools.h \ src/getdata.c \ diff --git a/src/analyze.c b/src/analyze.c index 1d5c456..2ed13a6 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -47,28 +47,27 @@ /*! \brief Prepare data for analysis. The function will sort leases and * ranges. */ -void prepare_data(void) +void prepare_data(struct conf_t *state) { /* Sort leases */ - HASH_SORT(leases, leasecomp); + HASH_SORT(state->leases, leasecomp); /* Sort ranges */ - qsort(ranges, (size_t)num_ranges, sizeof(struct range_t), &rangecomp); + qsort(state->ranges, state->num_ranges, sizeof(struct range_t), &rangecomp); } /*! \brief Perform counting. Join leases with ranges, and update counters. */ -void do_counting(void) +void do_counting(struct conf_t *state) { - struct range_t *restrict range_p; - const struct leases_t *restrict l = leases; + struct range_t *restrict range_p = state->ranges; + const struct leases_t *restrict l = state->leases; unsigned long i, k, block_size; /* Walk through ranges */ - range_p = ranges; - for (i = 0; i < num_ranges; i++) { + for (i = 0; i < state->num_ranges; i++) { while (l != NULL && ipcomp(&range_p->first_ip, &l->ip) < 0) l = l->hh.prev; /* rewind */ if (l == NULL) - l = leases; + l = state->leases; for (; l != NULL && ipcomp(&l->ip, &range_p->last_ip) <= 0; l = l->hh.next) { if (ipcomp(&l->ip, &range_p->first_ip) < 0) continue; /* cannot happen? */ @@ -107,15 +106,15 @@ void do_counting(void) /* FIXME: During count of other shared networks default network * and all networks got mixed together semantically. The below * fixes the problem, but is not elegant. */ - shared_networks->available = 0; - shared_networks->used = 0; - shared_networks->touched = 0; - range_p = ranges; - for (k = 0; k < num_ranges; k++) { - shared_networks->available += get_range_size(range_p); - shared_networks->used += range_p->count; - shared_networks->touched += range_p->touched; - shared_networks->backups += range_p->backups; + state->shared_networks->available = 0; + state->shared_networks->used = 0; + state->shared_networks->touched = 0; + range_p = state->ranges; + for (k = 0; k < state->num_ranges; k++) { + state->shared_networks->available += get_range_size(range_p); + state->shared_networks->used += range_p->count; + state->shared_networks->touched += range_p->touched; + state->shared_networks->backups += range_p->backups; range_p++; } } diff --git a/src/defaults.h b/src/defaults.h deleted file mode 100644 index 480f229..0000000 --- a/src/defaults.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * The dhcpd-pools has BSD 2-clause license which also known as "Simplified - * BSD License" or "FreeBSD License". - * - * Copyright 2006- Sami Kerola. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of Sami Kerola. - */ - -/*! \file defaults.h - * \brief Default settings which cannot be changed without recompiling - * the software. - */ - -#ifndef DHCPD_POOLS_DEFAULTS_H -# define DHCPD_POOLS_DEFAULTS_H 1 - -# include "dhcpd-pools.h" - -/*! \var MAXLEN - * \brief Maximum expected line length in dhcpd.conf and dhcpd.leases - * files. */ -static const size_t MAXLEN = 1024; - -/*! \var SHARED_NETWORKS - * \brief Maximum number of different shared networks in dhcpd.conf file. */ -static const unsigned int SHARED_NETWORKS = 8192; - -#endif /* DHCPD_POOLS_DEFAULTS_H */ diff --git a/src/dhcpd-pools.c b/src/dhcpd-pools.c index 1f15052..3841158 100644 --- a/src/dhcpd-pools.c +++ b/src/dhcpd-pools.c @@ -54,37 +54,38 @@ #include "xalloc.h" #include "dhcpd-pools.h" -#include "defaults.h" - -/* Global variables */ -struct configuration_t config; -struct shared_network_t *shared_networks; -unsigned int num_shared_networks; -struct range_t *ranges; -unsigned int num_ranges; -struct leases_t *leases; -unsigned int RANGES; /* Function pointers */ -int (*parse_ipaddr) (const char *restrict src, union ipaddr_t *restrict dst); +int (*parse_ipaddr) (struct conf_t *state, const char *restrict src, union ipaddr_t *restrict dst); void (*copy_ipaddr) (union ipaddr_t *restrict dst, const union ipaddr_t *restrict src); const char *(*ntop_ipaddr) (const union ipaddr_t *ip); double (*get_range_size) (const struct range_t *r); -int (*xstrstr) (const char *restrict str); +int (*xstrstr) (struct conf_t *state, const char *restrict str); int (*ipcomp) (const union ipaddr_t *restrict a, const union ipaddr_t *restrict b); int (*leasecomp) (const struct leases_t *restrict a, const struct leases_t *restrict b); -void (*add_lease) (union ipaddr_t *ip, enum ltype type); -struct leases_t *(*find_lease) (union ipaddr_t *ip); +void (*add_lease) (struct conf_t *state, union ipaddr_t *ip, enum ltype type); +struct leases_t *(*find_lease) (struct conf_t *state, union ipaddr_t *ip); static int return_limit(const char c) { if ('0' <= c && c < '8') return c - '0'; - clean_up(); error(EXIT_FAILURE, 0, "return_limit: output mask %s is illegal", quote(optarg)); return 0; } +/*! \brief Run time initialization. Global allocations, counter + * initializations, etc are here. */ +static void prepare_memory(struct conf_t *state) +{ + /* The SHARED_NETWORKS is a static value from defaults.h */ + state->shared_networks = xcalloc(sizeof(struct shared_network_t), SHARED_NETWORKS); + state->ranges = xmalloc(sizeof(struct range_t) * state->ranges_size); + + /* First shared network entry is all networks */ + state->shared_networks->name = xstrdup("All networks"); +} + /*! \brief Start of execution. Parse options, and call other other * functions one after another. At the moment adding threading support * would be difficult, but there does not seem to be valid reason to @@ -97,11 +98,21 @@ static int return_limit(const char c) * alarming. */ int main(int argc, char **argv) { + struct conf_t state = { + .warning = ALARM_WARN, + .critical = ALARM_CRIT, + .warn_count = 0x100000000, /* == 2^32 that is the entire IPv4 space */ + .crit_count = 0x100000000, /* basically turns off the count criteria */ + .header_limit = 8, + .color_mode = color_auto, + .ranges_size = 64, + .ip_version = IPvUNKNOWN, + 0 + }; + int option_index = 0; char output_format = '\0'; int alarming = 0; - char const *tmp; - struct range_t *tmp_ranges; enum { OPT_SNET_ALARMS = CHAR_MAX + 1, OPT_WARN, @@ -143,36 +154,10 @@ int main(int argc, char **argv) atexit(close_stdout); set_program_name(argv[0]); - /* FIXME: These allocations should be fully dynamic, e.g., grow - * if needed. */ - config.dhcpdconf_file = xmalloc(sizeof(char) * MAXLEN); - config.dhcpdlease_file = xmalloc(sizeof(char) * MAXLEN); - config.output_file = xmalloc(sizeof(char) * MAXLEN); - /* Make sure string has zero length if there is no - * command line option */ - config.output_file[0] = '\0'; - /* Alarming defaults. */ - config.snet_alarms = 0; - config.warning = ALARM_WARN; - config.critical = ALARM_CRIT; - config.warn_count = 0x100000000; /* == 2^32 that is the entire IPv4 space */ - config.crit_count = 0x100000000; /* basically turns off the count criteria */ - config.perfdata = 0; - config.color_mode = color_auto; - /* File location defaults */ - strncpy(config.dhcpdconf_file, DHCPDCONF_FILE, MAXLEN - 1); - strncpy(config.dhcpdlease_file, DHCPDLEASE_FILE, MAXLEN - 1); - tmp = OUTPUT_LIMIT; - config.header_limit = (*tmp - '0'); - tmp++; - config.number_limit = (*tmp - '0'); - /* Default sort order is by IPs small to big */ - config.reverse_order = 0; - config.backups_found = 0; - /* Treat single networks as shared with network CIDR as name */ - config.all_as_shared = 0; - prepare_memory(); - set_ipv_functions(IPvUNKNOWN); + + + prepare_memory(&state); + set_ipv_functions(&state, IPvUNKNOWN); /* Parse command line options */ while (1) { int c; @@ -183,11 +168,11 @@ int main(int argc, char **argv) switch (c) { case 'c': /* config file */ - strncpy(config.dhcpdconf_file, optarg, MAXLEN - 1); + state.dhcpdconf_file = optarg; break; case 'l': /* lease file */ - strncpy(config.dhcpdlease_file, optarg, MAXLEN - 1); + state.dhcpdlease_file = optarg; break; case 'f': /* Output format */ @@ -196,15 +181,15 @@ int main(int argc, char **argv) case 's': { /* Output sorting option */ - struct output_sort *p = config.sorts; + struct output_sort *p = state.sorts; size_t len; while (p && p->next) p = p->next; for (len = 0; len < strlen(optarg); len++) { - if (config.sorts == NULL) { - config.sorts = xcalloc(1, sizeof(struct output_sort)); - p = config.sorts; + if (state.sorts == NULL) { + state.sorts = xcalloc(1, sizeof(struct output_sort)); + p = state.sorts; } else { p->next = xcalloc(1, sizeof(struct output_sort)); p = p->next; @@ -215,62 +200,62 @@ int main(int argc, char **argv) break; case 'r': /* What ever sort in reverse order */ - config.reverse_order = 1; + state.reverse_order = 1; break; case 'o': /* Output file */ - strncpy(config.output_file, optarg, MAXLEN - 1); + state.output_file = optarg; break; case 'L': /* Specification what will be printed */ - config.header_limit = return_limit(optarg[0]); - config.number_limit = return_limit(optarg[1]); + state.header_limit = return_limit(optarg[0]); + state.number_limit = return_limit(optarg[1]); break; case OPT_MUSTACH: #ifdef BUILD_MUSTACH - config.mustach_template = optarg; + state.mustach_template = optarg; output_format = 'm'; #else error(EXIT_FAILURE, 0, "compiled without mustach support"); #endif break; case OPT_COLOR: - config.color_mode = parse_color_mode(optarg); - if (config.color_mode == color_unknown) + state.color_mode = parse_color_mode(optarg); + if (state.color_mode == color_unknown) error(EXIT_FAILURE, errno, "unknown color mode: %s", quote(optarg)); break; case OPT_SKIP_OK: - config.skip_ok = 1; + state.skip_ok = 1; break; case OPT_SNET_ALARMS: - config.snet_alarms = 1; + state.snet_alarms = 1; break; case OPT_WARN: alarming = 1; - config.warning = strtod_or_err(optarg, "illegal argument"); + state.warning = strtod_or_err(optarg, "illegal argument"); break; case OPT_CRIT: alarming = 1; - config.critical = strtod_or_err(optarg, "illegal argument"); + state.critical = strtod_or_err(optarg, "illegal argument"); break; case OPT_WARN_COUNT: alarming = 1; - config.warn_count = strtod_or_err(optarg, "illegal argument"); + state.warn_count = strtod_or_err(optarg, "illegal argument"); break; case OPT_CRIT_COUNT: alarming = 1; - config.crit_count = strtod_or_err(optarg, "illegal argument"); + state.crit_count = strtod_or_err(optarg, "illegal argument"); break; case OPT_MINSIZE: - config.minsize = strtod_or_err(optarg, "illegal argument"); + state.minsize = strtod_or_err(optarg, "illegal argument"); break; case OPT_SET_IPV: switch(optarg[0]) { case '4': - set_ipv_functions(IPv4); + set_ipv_functions(&state, IPv4); break; case '6': - set_ipv_functions(IPv6); + set_ipv_functions(&state, IPv6); break; default: error(EXIT_FAILURE, 0, "unknown --ip-version argument: %s", optarg); @@ -278,11 +263,11 @@ int main(int argc, char **argv) break; case 'p': /* Print additional performance data in alarming mode */ - config.perfdata = 1; + state.perfdata = 1; break; case 'A': /* Treat single networks as shared with network CIDR as name */ - config.all_as_shared = 1; + state.all_as_shared = 1; break; case 'v': /* Print version */ @@ -295,48 +280,45 @@ int main(int argc, char **argv) program_name); } } + + /* Use default dhcpd.conf when user did not define anything. */ + if (state.dhcpdconf_file == NULL) + state.dhcpdconf_file = DHCPDCONF_FILE; + /* Use default dhcpd.leases when user did not define anything. */ + if (state.dhcpdlease_file == NULL) + state.dhcpdlease_file = DHCPDLEASE_FILE; + /* Use default limits when user did not define anything. */ + if (state.header_limit == 8) { + char const *default_limit = OUTPUT_LIMIT; + + state.header_limit = return_limit(default_limit[0]); + state.number_limit = return_limit(default_limit[1]); + } /* Output format is not defined, if alarm thresholds are then it's * alarming, else use the default. */ if (output_format == '\0') { if (alarming == 1) output_format = 'a'; else { - const char *const def = OUTPUT_FORMAT; - output_format = def[0]; + const char *const default_format = OUTPUT_FORMAT; + output_format = default_format[0]; } } + /* Do the job */ - parse_config(1, config.dhcpdconf_file, shared_networks); + parse_config(&state, 1, state.dhcpdconf_file, state.shared_networks); if (output_format == 'X' || output_format == 'J') - parse_leases(1); + parse_leases(&state, 1); else - parse_leases(0); - prepare_data(); - do_counting(); - tmp_ranges = xmalloc(sizeof(struct range_t) * num_ranges); - if (config.sorts != NULL) - mergesort_ranges(ranges, num_ranges, tmp_ranges); - if (config.reverse_order == 1) - flip_ranges(ranges, tmp_ranges); - free(tmp_ranges); - ret_val = output_analysis(output_format); - clean_up(); + parse_leases(&state, 0); + prepare_data(&state); + do_counting(&state); + if (state.sorts != NULL) + mergesort_ranges(&state, state.ranges, state.num_ranges, NULL, 1); + if (state.reverse_order == 1) + flip_ranges(&state); + ret_val = output_analysis(&state, output_format); + clean_up(&state); return (ret_val); } -/*! \brief Run time initialization. Global allocations, counter - * initializations, etc are here. */ -void prepare_memory(void) -{ - config.ip_version = IPvUNKNOWN; - RANGES = 64; - num_ranges = num_shared_networks = 0; - shared_networks = xmalloc(sizeof(struct shared_network_t) * SHARED_NETWORKS); - ranges = xmalloc(sizeof(struct range_t) * RANGES); - /* First shared network entry is all networks */ - shared_networks->name = xstrdup("All networks"); - shared_networks->used = 0; - shared_networks->touched = 0; - shared_networks->backups = 0; - config.sorts = NULL; -} diff --git a/src/dhcpd-pools.h b/src/dhcpd-pools.h index 5617477..f519c6f 100644 --- a/src/dhcpd-pools.h +++ b/src/dhcpd-pools.h @@ -35,8 +35,6 @@ /*! \file dhcpd-pools.h * \brief Global definitions of structures, enums, and function prototypes. - * FIXME: The file has too many global variables. Most of them should be - * removed, if not all. */ #ifndef DHCPD_POOLS_H @@ -76,6 +74,17 @@ union ipaddr_t { uint32_t v4; unsigned char v6[16]; }; + +/*! \enum dhcpd_magic_numbers + * \brief MAXLEN is maximum expected line length in dhcpd.conf and + * dhcpd.leases, and SHARED_NETWORKS is maximum number of different shared + * networks in dhcpd.conf file. + */ +enum dhcpd_magic_numbers { + MAXLEN = 1024, + SHARED_NETWORKS = 8192 +}; + /*! \enum dhcp_version * \brief The IP version, IPv4 or IPv6, served by the dhcpd. */ @@ -214,18 +223,24 @@ struct output_sort { comparer_t func; struct output_sort *next; }; -/*! \struct configuration_t - * \brief Runtime configuration. +/*! \struct conf_t + * \brief Runtime configuration state. */ -struct configuration_t { +struct conf_t { + struct shared_network_t *shared_networks; + unsigned int num_shared_networks; + struct range_t *ranges; + unsigned int num_ranges; + size_t ranges_size; + struct leases_t *leases; char dhcpv6; enum dhcp_version ip_version; - char *dhcpdconf_file; - char *dhcpdlease_file; - int output_format; + const char *dhcpdconf_file; + const char *dhcpdlease_file; + const int output_format; struct output_sort *sorts; - char *output_file; - char *mustach_template; + const char *output_file; + const char *mustach_template; double warning; double critical; double warn_count; @@ -237,50 +252,67 @@ struct configuration_t { snet_alarms:1, perfdata:1, all_as_shared:1, - header_limit:3, + header_limit:4, number_limit:3, skip_ok:1, color_mode:2; }; -/* Global variables */ -/* \var config Runtime configuration. */ -extern struct configuration_t config; -/* \var shared_networks Pointer holding shared network count results. */ -extern struct shared_network_t *shared_networks; -/* \var num_shared_networks Number of shared networks found. */ -extern unsigned int num_shared_networks; -/* \var ranges Pointer holding range count results. */ -extern struct range_t *ranges; -/* \var num_ranges Number of ranges found. */ -extern unsigned int num_ranges; -/* \var leases Pointer holding all leases. */ -extern struct leases_t *leases; -/*! \var RANGES Maximum number of ranges. */ -extern unsigned int RANGES; - /* Function prototypes */ -extern void prepare_memory(void); -extern void set_ipv_functions(int version); -extern int parse_leases(const int print_mac_addreses); -extern void parse_config(int, const char *restrict, struct shared_network_t *restrict) - __attribute__ ((nonnull(2, 3))); -extern void prepare_data(void); -extern void do_counting(void); -extern void flip_ranges(struct range_t *restrict flip_me, struct range_t *restrict tmp_ranges) - __attribute__ ((nonnull(1, 2))); -/* support functions */ -extern int (*parse_ipaddr) (const char *restrict src, union ipaddr_t *restrict dst); -extern int parse_ipaddr_init(const char *restrict src, - union ipaddr_t *restrict dst); -extern int parse_ipaddr_v4(const char *restrict src, union ipaddr_t *restrict dst); -extern int parse_ipaddr_v6(const char *restrict src, union ipaddr_t *restrict dst); -extern void parse_cidr(struct range_t *range_p, const char *word); +/* analyze.c */ +extern void prepare_data(struct conf_t *state); +extern void do_counting(struct conf_t *state); + +/* getdata.c */ +extern int parse_leases(struct conf_t *state, const int print_mac_addreses); +extern void parse_config(struct conf_t *state, const int is_include, + const char *restrict config_file, + struct shared_network_t *restrict shared_p); + +/* hash.c */ +extern void (*add_lease) (struct conf_t *state, union ipaddr_t *addr, enum ltype type); +extern void add_lease_init(struct conf_t *state, union ipaddr_t *addr, enum ltype type); +extern void add_lease_v4(struct conf_t *state, union ipaddr_t *addr, enum ltype type); +extern void add_lease_v6(struct conf_t *state, union ipaddr_t *addr, enum ltype type); + +extern struct leases_t *(*find_lease) (struct conf_t *state, union ipaddr_t *addr); +extern struct leases_t *find_lease_init(struct conf_t *state, union ipaddr_t *addr); +extern struct leases_t *find_lease_v4(struct conf_t *state, union ipaddr_t *addr); +extern struct leases_t *find_lease_v6(struct conf_t *state, union ipaddr_t *addr); + +extern void delete_lease(struct conf_t *state, struct leases_t *lease); +extern void delete_all_leases(struct conf_t *state); + +/* mustach-dhcpd-pools.c */ +extern int mustach_dhcpd_pools(struct conf_t *state); + +/* other.c */ +extern void set_ipv_functions(struct conf_t *state, int version); +extern void flip_ranges(struct conf_t *state); +extern void clean_up(struct conf_t *state); +extern void parse_cidr(struct conf_t *state, struct range_t *range_p, const char *word); +extern int parse_color_mode(const char *restrict optarg); +extern double strtod_or_err(const char *restrict str, const char *restrict errmesg); +extern void __attribute__ ((noreturn)) print_version(void); +extern void __attribute__ ((noreturn)) usage(int status); + +extern int (*parse_ipaddr) (struct conf_t *state, const char *restrict src, + union ipaddr_t *restrict dst); +extern int parse_ipaddr_init(struct conf_t *state, const char *restrict src, + union ipaddr_t *restrict dst); +extern int parse_ipaddr_v4(struct conf_t *state, const char *restrict src, + union ipaddr_t *restrict dst); +extern int parse_ipaddr_v6(struct conf_t *state, const char *restrict src, + union ipaddr_t *restrict dst); + +extern int (*xstrstr) (struct conf_t *state, const char *restrict str); +extern int xstrstr_init(struct conf_t *state, const char *restrict str); +extern int xstrstr_v4(struct conf_t *state, const char *restrict str); +extern int xstrstr_v6(struct conf_t *state, const char *restrict str); extern void (*copy_ipaddr) (union ipaddr_t *restrict dst, const union ipaddr_t *restrict src); -extern void copy_ipaddr_init(union ipaddr_t *restrict dst, - const union ipaddr_t *restrict src); +extern void copy_ipaddr_init(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src); extern void copy_ipaddr_v4(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src); extern void copy_ipaddr_v6(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src); @@ -294,26 +326,17 @@ extern double get_range_size_init(const struct range_t *r); extern double get_range_size_v4(const struct range_t *r); extern double get_range_size_v6(const struct range_t *r); -extern int (*xstrstr) (const char *restrict str); -extern int xstrstr_init(const char *restrict str); -extern int xstrstr_v4(const char *restrict str) -_DP_ATTRIBUTE_HOT; -extern int xstrstr_v6(const char *restrict str) -_DP_ATTRIBUTE_HOT; +/* output.c */ +extern void range_output_helper(struct conf_t *state, struct output_helper_t *oh, + struct range_t *range_p); +extern void shnet_output_helper(struct conf_t *state, struct output_helper_t *oh, + struct shared_network_t *shared_p); +extern int output_analysis(struct conf_t *state, const char output_format); -extern int parse_color_mode(const char *restrict optarg); -extern double strtod_or_err(const char *restrict str, const char *restrict errmesg); -extern void __attribute__ ((noreturn)) print_version(void); -extern void __attribute__ ((noreturn)) usage(int status); -/* qsort required functions... */ -/* ...for ranges and... */ -extern int (*ipcomp) (const union ipaddr_t *restrict a, const union ipaddr_t *restrict b); -extern int ipcomp_init(const union ipaddr_t *restrict a, - const union ipaddr_t *restrict b); -extern int ipcomp_v4(const union ipaddr_t *restrict a, - const union ipaddr_t *restrict b); -extern int ipcomp_v6(const union ipaddr_t *restrict a, - const union ipaddr_t *restrict b); +/* sort.c */ +extern void mergesort_ranges(struct conf_t *state, + struct range_t *restrict orig, unsigned int size, + struct range_t *restrict temp, const int root_call); extern int (*leasecomp) (const struct leases_t *restrict a, const struct leases_t *restrict b); extern int leasecomp_init(const struct leases_t *restrict a @@ -322,6 +345,14 @@ extern int leasecomp_init(const struct leases_t *restrict a extern int leasecomp_v4(const struct leases_t *restrict a, const struct leases_t *restrict b); extern int leasecomp_v6(const struct leases_t *restrict a, const struct leases_t *restrict b); +extern int (*ipcomp) (const union ipaddr_t *restrict a, const union ipaddr_t *restrict b); +extern int ipcomp_init(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b); +extern int ipcomp_v4(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b); +extern int ipcomp_v6(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b); + +extern int rangecomp(const void *restrict r1, const void *restrict r2) + __attribute__ ((nonnull(1, 2))); + extern int comp_cur(struct range_t *r1, struct range_t *r2); extern int comp_double(double f1, double f2); extern int comp_ip(struct range_t *r1, struct range_t *r2); @@ -330,35 +361,10 @@ extern int comp_percent(struct range_t *r1, struct range_t *r2); extern int comp_tc(struct range_t *r1, struct range_t *r2); extern int comp_tcperc(struct range_t *r1, struct range_t *r2); extern int comp_touched(struct range_t *r1, struct range_t *r2); -extern int rangecomp(const void *restrict r1, const void *restrict r2) - __attribute__ ((nonnull(1, 2))); -/* sort function pointer and functions */ + extern comparer_t field_selector(char c); extern double ret_percent(struct range_t r); extern double ret_tc(struct range_t r); extern double ret_tcperc(struct range_t r); -extern void mergesort_ranges(struct range_t *restrict orig, int size, - struct range_t *restrict temp) - __attribute__ ((nonnull(1, 3))); -/* output function */ -extern void range_output_helper(struct output_helper_t *oh, struct range_t *range_p); -extern void shnet_output_helper(struct output_helper_t *oh, struct shared_network_t *shared_p); -extern int output_analysis(const char); -extern int mustach_dhcpd_pools(void); -/* Memory release, file closing etc */ -extern void clean_up(void); -/* Hash functions */ -extern void (*add_lease) (union ipaddr_t *addr, enum ltype type); -extern void add_lease_init(union ipaddr_t *addr, enum ltype type); -extern void add_lease_v4(union ipaddr_t *addr, enum ltype type); -extern void add_lease_v6(union ipaddr_t *addr, enum ltype type); -extern struct leases_t *(*find_lease) (union ipaddr_t *addr); -extern struct leases_t *find_lease_init(union ipaddr_t *addr); -extern struct leases_t *find_lease_v4(union ipaddr_t *addr); -extern struct leases_t *find_lease_v6(union ipaddr_t *addr); - -extern void delete_lease(struct leases_t *lease); -extern void delete_all_leases(void); - -#endif /* DHCPD_POOLS_H */ +#endif /* DHCPD_POOLS_H */ diff --git a/src/getdata.c b/src/getdata.c index e77b76c..5e30ba3 100644 --- a/src/getdata.c +++ b/src/getdata.c @@ -54,11 +54,10 @@ #include "xalloc.h" #include "dhcpd-pools.h" -#include "defaults.h" /*! \brief Lease file parser. The parser can only read ISC DHCPD * dhcpd.leases file format. */ -int parse_leases(const int print_mac_addreses) +int parse_leases(struct conf_t *state, const int print_mac_addreses) { FILE *dhcpd_leases; char *line, *ipstring, macstring[20], *stop; @@ -66,68 +65,68 @@ int parse_leases(const int print_mac_addreses) struct stat lease_file_stats; struct leases_t *lease; - dhcpd_leases = fopen(config.dhcpdlease_file, "r"); + dhcpd_leases = fopen(state->dhcpdlease_file, "r"); if (dhcpd_leases == NULL) - error(EXIT_FAILURE, errno, "parse_leases: %s", config.dhcpdlease_file); + error(EXIT_FAILURE, errno, "parse_leases: %s", state->dhcpdlease_file); #ifdef HAVE_POSIX_FADVISE # ifdef POSIX_FADV_SEQUENTIAL if (posix_fadvise(fileno(dhcpd_leases), 0, 0, POSIX_FADV_SEQUENTIAL) != 0) - error(EXIT_FAILURE, errno, "parse_leases: fadvise %s", config.dhcpdlease_file); + error(EXIT_FAILURE, errno, "parse_leases: fadvise %s", state->dhcpdlease_file); # endif /* POSIX_FADV_SEQUENTIAL */ #endif /* HAVE_POSIX_FADVISE */ /* 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. */ - if (stat(config.dhcpdlease_file, &lease_file_stats)) - error(EXIT_FAILURE, errno, "parse_leases: %s", config.dhcpdlease_file); + if (stat(state->dhcpdlease_file, &lease_file_stats)) + error(EXIT_FAILURE, errno, "parse_leases: %s", state->dhcpdlease_file); line = xmalloc(sizeof(char) * MAXLEN); line[0] = '\0'; ipstring = xmalloc(sizeof(char) * MAXLEN); ipstring[0] = '\0'; while (!feof(dhcpd_leases)) { if (!fgets(line, MAXLEN, dhcpd_leases) && ferror(dhcpd_leases)) - error(EXIT_FAILURE, errno, "parse_leases: %s", config.dhcpdlease_file); - switch (xstrstr(line)) { + error(EXIT_FAILURE, errno, "parse_leases: %s", state->dhcpdlease_file); + switch (xstrstr(state, line)) { /* It's a lease, save IP */ case PREFIX_LEASE: stop = memccpy(ipstring, - line + (config.ip_version == + line + (state->ip_version == IPv4 ? 6 : 9), ' ', strlen(line)); if (stop != NULL) { --stop; *stop = '\0'; } - parse_ipaddr(ipstring, &addr); + parse_ipaddr(state, ipstring, &addr); break; case PREFIX_BINDING_STATE_FREE: case PREFIX_BINDING_STATE_ABANDONED: case PREFIX_BINDING_STATE_EXPIRED: case PREFIX_BINDING_STATE_RELEASED: - if ((lease = find_lease(&addr)) != NULL) - delete_lease(lease); - add_lease(&addr, FREE); + if ((lease = find_lease(state, &addr)) != NULL) + delete_lease(state, lease); + add_lease(state, &addr, FREE); break; case PREFIX_BINDING_STATE_ACTIVE: /* remove old entry, if exists */ - if ((lease = find_lease(&addr)) != NULL) - delete_lease(lease); - add_lease(&addr, ACTIVE); + if ((lease = find_lease(state, &addr)) != NULL) + delete_lease(state, lease); + add_lease(state, &addr, ACTIVE); break; case PREFIX_BINDING_STATE_BACKUP: /* remove old entry, if exists */ - if ((lease = find_lease(&addr)) != NULL) - delete_lease(lease); - add_lease(&addr, BACKUP); - config.backups_found = 1; + if ((lease = find_lease(state, &addr)) != NULL) + delete_lease(state, lease); + add_lease(state, &addr, BACKUP); + state->backups_found = 1; break; case PREFIX_HARDWARE_ETHERNET: if (print_mac_addreses == 0) break; memcpy(macstring, line + 20, 17); macstring[17] = '\0'; - if ((lease = find_lease(&addr)) != NULL) + if ((lease = find_lease(state, &addr)) != NULL) lease->ethernet = xstrdup(macstring); break; default: @@ -144,13 +143,13 @@ int parse_leases(const int print_mac_addreses) /*! \brief Keyword search in dhcpd.conf file. * \param s A line from the dhcpd.conf file. * \return Indicator what configuration was found. */ -static int is_interesting_config_clause(char const *restrict s) +static int is_interesting_config_clause(struct conf_t *state, char const *restrict s) { if (strstr(s, "range")) return ITS_A_RANGE_FIRST_IP; if (strstr(s, "shared-network")) return ITS_A_SHAREDNET; - if (config.all_as_shared) { + if (state->all_as_shared) { if (strstr(s, "subnet")) return ITS_A_SUBNET; if (strstr(s, "netmask")) @@ -178,7 +177,7 @@ static void reorder_last_first(struct range_t *range_p) * FIXME: This spaghetti monster function need to be rewrote at least * ones. */ -void parse_config(int is_include, const char *restrict config_file, +void parse_config(struct conf_t *state, const int is_include, const char *restrict config_file, struct shared_network_t *restrict shared_p) { FILE *dhcpd_config; @@ -193,7 +192,7 @@ void parse_config(int is_include, const char *restrict config_file, word = xmalloc(sizeof(char) * MAXLEN); if (is_include) /* Default place holder for ranges "All networks". */ - shared_p->name = shared_networks->name; + shared_p->name = state->shared_networks->name; /* Open configuration file */ dhcpd_config = fopen(config_file, "r"); if (dhcpd_config == NULL) @@ -283,7 +282,7 @@ void parse_config(int is_include, const char *restrict config_file, /* FIXME: Using 1000 is lame, but * works. */ braces_shared = 1000; - shared_p = shared_networks; + shared_p = state->shared_networks; } /* Not literally 1, but works for this * program */ @@ -321,7 +320,7 @@ void parse_config(int is_include, const char *restrict config_file, if (word[i - 1] != '{') newclause = 0; i = 0; - argument = is_interesting_config_clause(word); + argument = is_interesting_config_clause(state, word); if (argument == ITS_A_RANGE_FIRST_IP) one_ip_range = 1; } @@ -334,14 +333,14 @@ void parse_config(int is_include, const char *restrict config_file, switch (argument) { case ITS_A_RANGE_SECOND_IP: /* printf ("range 2nd ip: %s\n", word); */ - range_p = ranges + num_ranges; + range_p = state->ranges + state->num_ranges; argument = ITS_NOTHING_INTERESTING; if (strchr(word, '/')) { - parse_cidr(range_p, word); + parse_cidr(state, range_p, word); one_ip_range = 0; } else { /* not cidr */ - parse_ipaddr(word, &addr); + parse_ipaddr(state, word, &addr); if (one_ip_range == 1) { one_ip_range = 0; copy_ipaddr(&range_p->first_ip, &addr); @@ -354,18 +353,18 @@ void parse_config(int is_include, const char *restrict config_file, range_p->touched = 0; range_p->backups = 0; range_p->shared_net = shared_p; - num_ranges++; - if (RANGES < num_ranges + 1) { - RANGES *= 2; - ranges = xrealloc(ranges, sizeof(struct range_t) * RANGES); - range_p = ranges + num_ranges; + state->num_ranges++; + if (state->ranges_size <= state->num_ranges) { + state->ranges_size *= 2; + state->ranges = xrealloc(state->ranges, sizeof(struct range_t) * state->ranges_size); + range_p = state->ranges + state->num_ranges; } newclause = 1; break; case ITS_A_RANGE_FIRST_IP: /* printf ("range 1nd ip: %s\n", word); */ - range_p = ranges + num_ranges; - if (!(parse_ipaddr(word, &addr))) + range_p = state->ranges + state->num_ranges; + if (!(parse_ipaddr(state, word, &addr))) /* word was not ip, try again */ break; copy_ipaddr(&range_p->first_ip, &addr); @@ -375,23 +374,19 @@ void parse_config(int is_include, const char *restrict config_file, case ITS_A_SHAREDNET: case ITS_A_SUBNET: /* ignore subnets inside a shared-network */ - if (argument == ITS_A_SUBNET && shared_p != shared_networks) { + if (argument == ITS_A_SUBNET && shared_p != state->shared_networks) { argument = ITS_NOTHING_INTERESTING; break; } /* printf ("shared-network named: %s\n", word); */ - num_shared_networks++; - shared_p = shared_networks + num_shared_networks; + state->num_shared_networks++; + shared_p = state->shared_networks + state->num_shared_networks; shared_p->name = xstrdup(word); - shared_p->available = 0; - shared_p->used = 0; - shared_p->touched = 0; - shared_p->backups = 0; shared_p->netmask = (argument == ITS_A_SUBNET ? -1 : 0); /* do not fill in netmask */ - if (SHARED_NETWORKS < num_shared_networks + 2) + if (SHARED_NETWORKS < state->num_shared_networks + 2) /* FIXME: make this to go away by reallocating more space. */ error(EXIT_FAILURE, 0, - "parse_config: increase default.h SHARED_NETWORKS and recompile"); + "parse_config: increase SHARED_NETWORKS in dhcpd-pools.h and recompile"); /* record network's mask too */ if (argument == ITS_A_SUBNET) newclause = 1; @@ -401,7 +396,7 @@ void parse_config(int is_include, const char *restrict config_file, case ITS_A_NETMASK: /* fill in only when requested to do so */ if (shared_p->netmask) { - if (!(parse_ipaddr(word, &addr))) + if (!(parse_ipaddr(state, word, &addr))) break; shared_p->netmask = 32; while ((addr.v4 & 0x01) == 0) { @@ -419,7 +414,7 @@ void parse_config(int is_include, const char *restrict config_file, case ITS_AN_INCLUDE: /* printf ("include file: %s\n", word); */ argument = ITS_NOTHING_INTERESTING; - parse_config(0, word, shared_p); + parse_config(state, 0, word, shared_p); newclause = 1; break; case ITS_NOTHING_INTERESTING: diff --git a/src/hash.c b/src/hash.c index 08b95b4..fdc1861 100644 --- a/src/hash.c +++ b/src/hash.c @@ -50,30 +50,30 @@ /*! \brief Add a lease to hash array. * \param addr Binary IP to be added in leases hash. * \param type Lease state of the IP. */ -void add_lease_init(union ipaddr_t *addr +void add_lease_init(struct conf_t *state __attribute__ ((unused)), union ipaddr_t *addr __attribute__ ((unused)), enum ltype type __attribute__ ((unused))) { } -void add_lease_v4(union ipaddr_t *addr, enum ltype type) +void add_lease_v4(struct conf_t *state, union ipaddr_t *addr, enum ltype type) { struct leases_t *l; l = xmalloc(sizeof(struct leases_t)); copy_ipaddr(&l->ip, addr); l->type = type; - HASH_ADD_INT(leases, ip.v4, l); + HASH_ADD_INT(state->leases, ip.v4, l); l->ethernet = NULL; } -void add_lease_v6(union ipaddr_t *addr, enum ltype type) +void add_lease_v6(struct conf_t *state, union ipaddr_t *addr, enum ltype type) { struct leases_t *l; l = xmalloc(sizeof(struct leases_t)); copy_ipaddr(&l->ip, addr); l->type = type; - HASH_ADD_V6(leases, ip.v6, l); + HASH_ADD_V6(state->leases, ip.v6, l); l->ethernet = NULL; } @@ -81,57 +81,57 @@ void add_lease_v6(union ipaddr_t *addr, enum ltype type) * \param addr Binary IP searched from leases hash. * \return A lease structure about requested IP, or NULL. */ -struct leases_t *find_lease_init(union ipaddr_t *addr __attribute__ ((unused))) +struct leases_t *find_lease_init(struct conf_t *state __attribute__ ((unused)), union ipaddr_t *addr __attribute__ ((unused))) { return NULL; } -struct leases_t *find_lease_v4(union ipaddr_t *addr) +struct leases_t *find_lease_v4(struct conf_t *state, union ipaddr_t *addr) { struct leases_t *l; - HASH_FIND_INT(leases, &addr->v4, l); + HASH_FIND_INT(state->leases, &addr->v4, l); return l; } -struct leases_t *find_lease_v6(union ipaddr_t *addr) +struct leases_t *find_lease_v6(struct conf_t *state, union ipaddr_t *addr) { struct leases_t *l; - HASH_FIND_V6(leases, &addr->v4, l); + HASH_FIND_V6(state->leases, &addr->v4, l); return l; } /*! \brief Delete a lease from hash array. * \param lease Pointer to lease hash. */ -void delete_lease(struct leases_t *lease) +void delete_lease(struct conf_t *state, struct leases_t *lease) { free(lease->ethernet); - HASH_DEL(leases, lease); + HASH_DEL(state->leases, lease); free(lease); } /*! \brief Delete all leases from hash array. */ #ifdef HASH_ITER -void delete_all_leases(void) +void delete_all_leases(struct conf_t *state) { struct leases_t *l, *tmp; - HASH_ITER(hh, leases, l, tmp) { + HASH_ITER(hh, state->leases, l, tmp) { free(l->ethernet); - HASH_DEL(leases, l); + HASH_DEL(state->leases, l); free(l); } } #else -void delete_all_leases(void) +void delete_all_leases(struct conf_t *state) { while (leases) { struct leases_t *l; - l = leases; + l = state->leases; free(l->ethernet); - HASH_DEL(leases, l); /* leases advances to next on delete */ + HASH_DEL(state->leases, l); /* leases advances to next on delete */ free(l); } } diff --git a/src/mustach-dhcpd-pools.c b/src/mustach-dhcpd-pools.c index ff06394..54a2009 100644 --- a/src/mustach-dhcpd-pools.c +++ b/src/mustach-dhcpd-pools.c @@ -53,6 +53,7 @@ #include "xalloc.h" struct expl { + struct conf_t *state; struct range_t *range_p; struct shared_network_t *shnet_p; struct output_helper_t oh; @@ -130,7 +131,7 @@ static int must_put_range(void *closure, const char *name, int escape fprintf(file, "%g", e->oh.tcp); return 0; } - if (config.backups_found == 1) { + if (e->state->backups_found == 1) { if (!strcmp(name, "backup_count")) { fprintf(file, "%g", e->range_p->backups); return 0; @@ -184,7 +185,7 @@ static int must_put_shnet(void *closure, const char *name, int escape fprintf(file, "%g", e->oh.tcp); return 0; } - if (config.backups_found == 1) { + if (e->state->backups_found == 1) { if (!strcmp(name, "backup_count")) { fprintf(file, "%g", e->shnet_p->backups); return 0; @@ -210,8 +211,8 @@ static int must_next_range(void *closure) e->current--; if (e->current <= 0) return 0; - range_output_helper(&e->oh, e->range_p); - } while (config.skip_ok && e->oh.status == STATUS_OK); + range_output_helper(e->state, &e->oh, e->range_p); + } while (e->state->skip_ok && e->oh.status == STATUS_OK); return 1; } @@ -224,8 +225,8 @@ static int must_next_shnet(void *closure) e->current--; if (e->current <= 0) return 0; - shnet_output_helper(&e->oh, e->shnet_p); - } while (config.skip_ok && e->oh.status == STATUS_OK); + shnet_output_helper(e->state, &e->oh, e->shnet_p); + } while (e->state->skip_ok && e->oh.status == STATUS_OK); return 1; } @@ -236,8 +237,8 @@ static int must_enter(void *closure, const char *name) if (!strcmp(name, "subnets")) { itf.put = must_put_range; itf.next = must_next_range; - e->current = num_ranges + 1; - e->range_p = ranges; + e->current = e->state->num_ranges + 1; + e->range_p = e->state->ranges; /* must_next_range() will skip_ok when needed */ e->range_p--; return must_next_range(closure); @@ -245,15 +246,15 @@ static int must_enter(void *closure, const char *name) if (!strcmp(name, "shared-networks")) { itf.put = must_put_shnet; itf.next = must_next_shnet; - e->shnet_p = shared_networks; - e->current = num_shared_networks + 1; + e->shnet_p = e->state->shared_networks; + e->current = e->state->num_shared_networks + 1; return must_next_shnet(closure); } if (!strcmp(name, "summary")) { itf.put = must_put_shnet; itf.next = must_next_shnet; - e->shnet_p = shared_networks; - shnet_output_helper(&e->oh, e->shnet_p); + e->shnet_p = e->state->shared_networks; + shnet_output_helper(e->state, &e->oh, e->shnet_p); e->current = 1; return 1; } @@ -264,8 +265,8 @@ static int must_leave(void *closure __attribute__ ((unused))) { struct expl *e = closure; - e->shnet_p = shared_networks; - e->range_p = ranges; + e->shnet_p = e->state->shared_networks; + e->range_p = e->state->ranges; return 0; } @@ -289,19 +290,19 @@ static char *must_read_template(const char *filename) } -int mustach_dhcpd_pools(void) +int mustach_dhcpd_pools(struct conf_t *state) { - struct expl e; + struct expl e = { .state = state }; char *template; FILE *outfile; int ret; - template = must_read_template(config.mustach_template); - if (config.output_file[0]) { - outfile = fopen(config.output_file, "w+"); + template = must_read_template(state->mustach_template); + if (state->output_file) { + outfile = fopen(state->output_file, "w+"); if (outfile == NULL) { error(EXIT_FAILURE, errno, "mustach_dhcpd_pools: fopen: %s", - config.output_file); + state->output_file); } } else { outfile = stdout; diff --git a/src/other.c b/src/other.c index b8a4634..c20bed5 100644 --- a/src/other.c +++ b/src/other.c @@ -55,7 +55,6 @@ #include "xalloc.h" #include "dhcpd-pools.h" -#include "defaults.h" char *(*cidr_last)(union ipaddr_t *restrict addr, const int mask); static char *cidr_last_v4(union ipaddr_t *restrict addr, const int mask); @@ -64,12 +63,12 @@ static char *cidr_last_v6(union ipaddr_t *restrict addr, const int mask); /*! \brief Set function pointers depending on IP version. * \param ip IP version. */ -void set_ipv_functions(int version) +void set_ipv_functions(struct conf_t *state, int version) { switch (version) { case IPv4: - config.ip_version = version; + state->ip_version = version; add_lease = add_lease_v4; copy_ipaddr = copy_ipaddr_v4; find_lease = find_lease_v4; @@ -83,7 +82,7 @@ void set_ipv_functions(int version) break; case IPv6: - config.ip_version = version; + state->ip_version = version; add_lease = add_lease_v6; copy_ipaddr = copy_ipaddr_v6; find_lease = find_lease_v6; @@ -97,7 +96,7 @@ void set_ipv_functions(int version) break; case IPvUNKNOWN: - config.ip_version = version; + state->ip_version = version; add_lease = add_lease_init; copy_ipaddr = copy_ipaddr_init; find_lease = find_lease_init; @@ -122,21 +121,21 @@ void set_ipv_functions(int version) * \param dst An union which will hold conversion result. * \return Was parsing successful. */ -int parse_ipaddr_init(const char *restrict src, union ipaddr_t *restrict dst) +int parse_ipaddr_init(struct conf_t *state, const char *restrict src, union ipaddr_t *restrict dst) { struct in_addr addr; struct in6_addr addr6; if (inet_aton(src, &addr) == 1) - set_ipv_functions(IPv4); + set_ipv_functions(state, IPv4); else if (inet_pton(AF_INET6, src, &addr6) == 1) - set_ipv_functions(IPv6); + set_ipv_functions(state, IPv6); else return 0; - return parse_ipaddr(src, dst); + return parse_ipaddr(state, src, dst); } -int parse_ipaddr_v4(const char *restrict src, union ipaddr_t *restrict dst) +int parse_ipaddr_v4(struct conf_t *state __attribute__ ((unused)), const char *restrict src, union ipaddr_t *restrict dst) { int rv; struct in_addr addr; @@ -146,7 +145,7 @@ int parse_ipaddr_v4(const char *restrict src, union ipaddr_t *restrict dst) return rv == 1; } -int parse_ipaddr_v6(const char *restrict src, union ipaddr_t *restrict dst) +int parse_ipaddr_v6(struct conf_t *state __attribute__ ((unused)), const char *restrict src, union ipaddr_t *restrict dst) { int rv; struct in6_addr addr; @@ -210,7 +209,7 @@ static char *cidr_last_v6(union ipaddr_t *restrict addr, const int mask) return xstrdup(ip); } -void parse_cidr(struct range_t *range_p, const char *word) +void parse_cidr(struct conf_t *state, struct range_t *range_p, const char *word) { char *divider; int mask; @@ -224,20 +223,20 @@ void parse_cidr(struct range_t *range_p, const char *word) if (mask < 0) error(EXIT_FAILURE, 0, "cidr %s invalid mask %s", word, divider); - if (config.ip_version == IPvUNKNOWN) { + if (state->ip_version == IPvUNKNOWN) { if (!strchr(word, ':')) - set_ipv_functions(IPv4); + set_ipv_functions(state, IPv4); else - set_ipv_functions(IPv6); + set_ipv_functions(state, IPv6); } /* start of the range is easy */ - parse_ipaddr(word, &addr); + parse_ipaddr(state, word, &addr); copy_ipaddr(&range_p->first_ip, &addr); /* end of the range depends cidr size */ last = cidr_last(&addr, mask); - parse_ipaddr(last, &addr); + parse_ipaddr(state, last, &addr); copy_ipaddr(&range_p->last_ip, &addr); free(last); } @@ -332,18 +331,14 @@ double get_range_size_v6(const struct range_t *r) * \param str A line from dhcpd.conf * \return prefix_t enum value */ -int -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) - __attribute__ ((hot)) -#endif - xstrstr_init(const char *restrict str) +int xstrstr_init(struct conf_t *state, const char *restrict str) { if (memcmp("lease ", str, 6)) { - set_ipv_functions(IPv4); + set_ipv_functions(state, IPv4); return PREFIX_LEASE; } if (memcmp(" iaaddr ", str, 9)) { - set_ipv_functions(IPv6); + set_ipv_functions(state, IPv6); return PREFIX_LEASE; } return NUM_OF_PREFIX; @@ -359,7 +354,7 @@ int #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) __attribute__ ((hot)) #endif - xstrstr_v4(const char *restrict str) + xstrstr_v4(struct conf_t *state __attribute__ ((unused)), const char *restrict str) { size_t len; @@ -412,7 +407,7 @@ int #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) __attribute__ ((hot)) #endif - xstrstr_v6(const char *restrict str) + xstrstr_v6(struct conf_t *state __attribute__ ((unused)), const char *restrict str) { size_t len; @@ -495,43 +490,38 @@ double strtod_or_err(const char *restrict str, const char *restrict errmesg) } /*! \brief Reverse range. - * Used before output, if a caller has requested reverse sorting. - * FIXME: The temporary memory area handling should be internal to this - * function, not a parameter. - * - * \param flip_me The range that needs to be inverted. - * \param tmp_ranges Temporary memory area for the flip. */ -void flip_ranges(struct range_t *restrict flip_me, struct range_t *restrict tmp_ranges) + * Used before output, if a caller has requested reverse sorting. */ +void flip_ranges(struct conf_t *state) { - unsigned int i = num_ranges - 1, j; + unsigned int i = state->num_ranges - 1, j; + struct range_t *tmp_ranges; - for (j = 0; j < num_ranges; j++, i--) - *(tmp_ranges + j) = *(flip_me + i); - memcpy(flip_me, tmp_ranges, num_ranges * sizeof(struct range_t)); + tmp_ranges = xmalloc(sizeof(struct range_t) * state->num_ranges); + for (j = 0; j < state->num_ranges; j++, i--) + *(tmp_ranges + j) = *(state->ranges + i); + memcpy(state->ranges, tmp_ranges, state->num_ranges * sizeof(struct range_t)); + free(tmp_ranges); } /*! \brief Free memory, flush buffers etc. */ -void clean_up(void) +void clean_up(struct conf_t *state) { struct output_sort *cur, *next; /* Just in case there something in buffers */ if (fflush(NULL)) error(EXIT_FAILURE, errno, "clean_up: fflush"); - free(config.dhcpdconf_file); - free(config.dhcpdlease_file); - free(config.output_file); - free(ranges); - delete_all_leases(); - if (shared_networks) { + free(state->ranges); + delete_all_leases(state); + if (state->shared_networks) { unsigned int i; - num_shared_networks++; - for (i = 0; i < num_shared_networks; i++) - free((shared_networks + i)->name); - free(shared_networks); + state->num_shared_networks++; + for (i = 0; i < state->num_shared_networks; i++) + free((state->shared_networks + i)->name); + free(state->shared_networks); } - for (cur = config.sorts; cur; cur = next) { + for (cur = state->sorts; cur; cur = next) { next = cur->next; free(cur); } diff --git a/src/output.c b/src/output.c index 225e8cf..cdd37c9 100644 --- a/src/output.c +++ b/src/output.c @@ -60,34 +60,34 @@ #include "dhcpd-pools.h" /*! \brief Calculate range percentages and such. */ -void range_output_helper(struct output_helper_t *oh, struct range_t *range_p) +void range_output_helper(struct conf_t *state, struct output_helper_t *oh, struct range_t *range_p) { /* counts and calculations */ oh->range_size = get_range_size(range_p); oh->percent = (double)(100 * range_p->count) / oh->range_size; oh->tc = range_p->touched + range_p->count; oh->tcp = (double)(100 * oh->tc) / oh->range_size; - if (config.backups_found == 1) { + if (state->backups_found == 1) { oh->bup = (double)(100 * range_p->backups) / oh->range_size; } /* set status */ oh->status = STATUS_OK; - if (config.critical < oh->percent - && (oh->range_size - range_p->count) < config.crit_count) + if (state->critical < oh->percent + && (oh->range_size - range_p->count) < state->crit_count) oh->status = STATUS_CRIT; - else if (config.warning < oh->percent - && (oh->range_size - range_p->count) < config.warn_count) + else if (state->warning < oh->percent + && (oh->range_size - range_p->count) < state->warn_count) oh->status = STATUS_WARN; if (oh->status != STATUS_OK) { - if (oh->range_size <= config.minsize) + if (oh->range_size <= state->minsize) oh->status = STATUS_IGNORED; - else if (config.snet_alarms && range_p->shared_net != shared_networks) + else if (state->snet_alarms && range_p->shared_net != state->shared_networks) oh->status = STATUS_SUPPRESSED; } } /*! \brief Calculate shared network percentages and such. */ -void shnet_output_helper(struct output_helper_t *oh, struct shared_network_t *shared_p) +void shnet_output_helper(struct conf_t *state, struct output_helper_t *oh, struct shared_network_t *shared_p) { /* counts and calculations */ oh->tc = shared_p->touched + shared_p->used; @@ -99,7 +99,7 @@ void shnet_output_helper(struct output_helper_t *oh, struct shared_network_t *sh oh->percent = (double)(100 * shared_p->used) / shared_p->available; oh->tcp = (double)((100 * (shared_p->touched + shared_p->used)) / shared_p->available); - if (config.backups_found == 1) { + if (state->backups_found == 1) { oh->bup = (double)(100 * shared_p->backups) / shared_p->available; } } @@ -108,15 +108,15 @@ void shnet_output_helper(struct output_helper_t *oh, struct shared_network_t *sh oh->status = STATUS_SUPPRESSED; return; } - if (shared_p->available <= config.minsize) { + if (shared_p->available <= state->minsize) { oh->status = STATUS_IGNORED; return; } - if (config.critical < oh->percent && shared_p->used < config.crit_count) { + if (state->critical < oh->percent && shared_p->used < state->crit_count) { oh->status = STATUS_CRIT; return; } - if (config.warning < oh->percent && shared_p->used < config.warn_count) { + if (state->warning < oh->percent && shared_p->used < state->warn_count) { oh->status = STATUS_WARN; return; } @@ -144,14 +144,14 @@ static int start_color(struct output_helper_t *oh, FILE *outfile) return 0; } -static FILE *open_outfile(void) +static FILE *open_outfile(struct conf_t *state) { FILE *outfile; - if (config.output_file[0]) { - outfile = fopen(config.output_file, "w+"); + if (state->output_file) { + outfile = fopen(state->output_file, "w+"); if (outfile == NULL) { - error(EXIT_FAILURE, errno, "open_outfile: %s", config.output_file); + error(EXIT_FAILURE, errno, "open_outfile: %s", state->output_file); } } else { outfile = stdout; @@ -171,24 +171,24 @@ static void close_outfile(FILE *outfile) } /*! \brief Text output format, which is the default. */ -static int output_txt(void) +static int output_txt(struct conf_t *state) { unsigned int i; struct range_t *range_p; struct shared_network_t *shared_p; struct output_helper_t oh; FILE *outfile; - int max_ipaddr_length = config.ip_version == IPv6 ? 39 : 16; + int max_ipaddr_length = state->ip_version == IPv6 ? 39 : 16; - if (config.color_mode == color_auto && isatty(STDIN_FILENO)) { - config.color_mode = color_on; + if (state->color_mode == color_auto && isatty(STDIN_FILENO)) { + state->color_mode = color_on; } - outfile = open_outfile(); - range_p = ranges; - shared_p = shared_networks; + outfile = open_outfile(state); + range_p = state->ranges; + shared_p = state->shared_networks; - if (config.header_limit & R_BIT) { + if (state->header_limit & R_BIT) { fprintf(outfile, "Ranges:\n"); fprintf (outfile, @@ -198,20 +198,20 @@ static int output_txt(void) "first ip", max_ipaddr_length, "last ip", "max", "cur", "percent", "touch", "t+c", "t+c perc"); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, " bu bu perc"); } fprintf(outfile, "\n"); } - if (config.number_limit & R_BIT) { - for (i = 0; i < num_ranges; i++) { + if (state->number_limit & R_BIT) { + for (i = 0; i < state->num_ranges; i++) { int color_set = 0; - range_output_helper(&oh, range_p); - if (config.skip_ok && oh.status == STATUS_OK) { + range_output_helper(state, &oh, range_p); + if (state->skip_ok && oh.status == STATUS_OK) { range_p++; continue; } - if (config.color_mode == color_on) + if (state->color_mode == color_on) color_set = start_color(&oh, outfile); if (range_p->shared_net) { fprintf(outfile, "%-20s", range_p->shared_net->name); @@ -233,7 +233,7 @@ static int output_txt(void) range_p->touched, oh.tc, oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, "%7g %8.3f", range_p->backups, oh.bup); } @@ -243,26 +243,26 @@ static int output_txt(void) range_p++; } } - if (config.number_limit & R_BIT && config.header_limit & S_BIT) { + if (state->number_limit & R_BIT && state->header_limit & S_BIT) { fprintf(outfile, "\n"); } - if (config.header_limit & S_BIT) { + if (state->header_limit & S_BIT) { fprintf(outfile, "Shared networks:\n"); fprintf(outfile, "name max cur percent touch t+c t+c perc"); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, " bu bu perc"); } fprintf(outfile, "\n"); } - if (config.number_limit & S_BIT) { - for (i = 0; i < num_shared_networks; i++) { + if (state->number_limit & S_BIT) { + for (i = 0; i < state->num_shared_networks; i++) { int color_set = 0; shared_p++; - shnet_output_helper(&oh, shared_p); - if (config.skip_ok && oh.status == STATUS_OK) + shnet_output_helper(state, &oh, shared_p); + if (state->skip_ok && oh.status == STATUS_OK) continue; - if (config.color_mode == color_on) + if (state->color_mode == color_on) color_set = start_color(&oh, outfile); fprintf(outfile, "%-20s %5g %5g %10.3f %7g %6g %9.3f", @@ -273,7 +273,7 @@ static int output_txt(void) shared_p->touched, oh.tc, oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, "%7g %8.3f", shared_p->backups, oh.bup); @@ -283,36 +283,36 @@ static int output_txt(void) fprintf(outfile, "\n"); } } - if (config.number_limit & S_BIT && config.header_limit & A_BIT) { + if (state->number_limit & S_BIT && state->header_limit & A_BIT) { fprintf(outfile, "\n"); } - if (config.header_limit & A_BIT) { + if (state->header_limit & A_BIT) { fprintf(outfile, "Sum of all ranges:\n"); fprintf(outfile, "name max cur percent touch t+c t+c perc"); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, " bu bu perc"); } fprintf(outfile, "\n"); } - if (config.number_limit & A_BIT) { + if (state->number_limit & A_BIT) { int color_set = 0; - shnet_output_helper(&oh, shared_networks); - if (config.color_mode == color_on) + shnet_output_helper(state, &oh, state->shared_networks); + if (state->color_mode == color_on) color_set = start_color(&oh, outfile); fprintf(outfile, "%-20s %5g %5g %10.3f %7g %6g %9.3f", - shared_networks->name, - shared_networks->available, - shared_networks->used, + state->shared_networks->name, + state->shared_networks->available, + state->shared_networks->used, oh.percent, - shared_networks->touched, + state->shared_networks->touched, oh.tc, oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, "%7g %8.3f", - shared_networks->backups, + state->shared_networks->backups, oh.bup); } if (color_set) @@ -324,7 +324,7 @@ static int output_txt(void) } /*! \brief The xml output formats. */ -static int output_xml(const int print_mac_addreses) +static int output_xml(struct conf_t *state, const int print_mac_addreses) { unsigned int i; struct range_t *range_p; @@ -332,16 +332,16 @@ static int output_xml(const int print_mac_addreses) struct output_helper_t oh; FILE *outfile; - outfile = open_outfile(); - range_p = ranges; - shared_p = shared_networks; + outfile = open_outfile(state); + range_p = state->ranges; + shared_p = state->shared_networks; fprintf(outfile, "\n"); if (print_mac_addreses == 1) { struct leases_t *l; - for (l = leases; l != NULL; l = l->hh.next) { + for (l = state->leases; l != NULL; l = l->hh.next) { if (l->type == ACTIVE) { fputs("\n\t", outfile); fputs(ntop_ipaddr(&l->ip), outfile); @@ -354,10 +354,10 @@ static int output_xml(const int print_mac_addreses) } } - if (config.number_limit & R_BIT) { - for (i = 0; i < num_ranges; i++) { - range_output_helper(&oh, range_p); - if (config.skip_ok && oh.status == STATUS_OK) { + if (state->number_limit & R_BIT) { + for (i = 0; i < state->num_ranges; i++) { + range_output_helper(state, &oh, range_p); + if (state->skip_ok && oh.status == STATUS_OK) { range_p++; continue; } @@ -379,11 +379,11 @@ static int output_xml(const int print_mac_addreses) } } - if (config.number_limit & S_BIT) { - for (i = 0; i < num_shared_networks; i++) { + if (state->number_limit & S_BIT) { + for (i = 0; i < state->num_shared_networks; i++) { shared_p++; - shnet_output_helper(&oh, shared_p); - if (config.skip_ok && oh.status == STATUS_OK) + shnet_output_helper(state, &oh, shared_p); + if (state->skip_ok && oh.status == STATUS_OK) continue; fprintf(outfile, "\n"); fprintf(outfile, "\t%s\n", shared_p->name); @@ -396,14 +396,14 @@ static int output_xml(const int print_mac_addreses) } } - if (config.header_limit & A_BIT) { + if (state->header_limit & A_BIT) { fprintf(outfile, "\n"); - fprintf(outfile, "\t%s\n", shared_networks->name); - fprintf(outfile, "\t%g\n", shared_networks->available); - fprintf(outfile, "\t%g\n", shared_networks->used); - fprintf(outfile, "\t%g\n", shared_networks->touched); + fprintf(outfile, "\t%s\n", state->shared_networks->name); + fprintf(outfile, "\t%g\n", state->shared_networks->available); + fprintf(outfile, "\t%g\n", state->shared_networks->used); + fprintf(outfile, "\t%g\n", state->shared_networks->touched); fprintf(outfile, "\t%g\n", - shared_networks->available - shared_networks->used); + state->shared_networks->available - state->shared_networks->used); fprintf(outfile, "\n"); } @@ -413,7 +413,7 @@ static int output_xml(const int print_mac_addreses) } /*! \brief The json output formats. */ -static int output_json(const int print_mac_addreses) +static int output_json(struct conf_t *state, const int print_mac_addreses) { unsigned int i = 0; struct range_t *range_p; @@ -422,9 +422,9 @@ static int output_json(const int print_mac_addreses) FILE *outfile; unsigned int sep; - outfile = open_outfile(); - range_p = ranges; - shared_p = shared_networks; + outfile = open_outfile(state); + range_p = state->ranges; + shared_p = state->shared_networks; sep = 0; fprintf(outfile, "{\n"); @@ -433,7 +433,7 @@ static int output_json(const int print_mac_addreses) struct leases_t *l; fprintf(outfile, " \"active_leases\": ["); - for (l = leases; l != NULL; l = l->hh.next) { + for (l = state->leases; l != NULL; l = l->hh.next) { if (l->type == ACTIVE) { if (i == 0) { i = 1; @@ -453,14 +453,14 @@ static int output_json(const int print_mac_addreses) sep++; } - if (config.number_limit & R_BIT) { + if (state->number_limit & R_BIT) { if (sep) { fprintf(outfile, ",\n"); } fprintf(outfile, " \"subnets\": [\n"); - for (i = 0; i < num_ranges; i++) { - range_output_helper(&oh, range_p); - if (config.skip_ok && oh.status == STATUS_OK) { + for (i = 0; i < state->num_ranges; i++) { + range_output_helper(state, &oh, range_p); + if (state->skip_ok && oh.status == STATUS_OK) { range_p++; continue; } @@ -484,14 +484,14 @@ static int output_json(const int print_mac_addreses) fprintf(outfile, "\"percent\":%g, ", oh.percent); fprintf(outfile, "\"touch_count\":%g, ", oh.tc); fprintf(outfile, "\"touch_percent\":%g, ", oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, "\"backup_count\":%g, ", range_p->backups); fprintf(outfile, "\"backup_percent\":%g, ", oh.bup); } fprintf(outfile, "\"status\":%d ", oh.status); range_p++; - if (i + 1 < num_ranges) + if (i + 1 < state->num_ranges) fprintf(outfile, "},\n"); else fprintf(outfile, "}\n"); @@ -500,15 +500,15 @@ static int output_json(const int print_mac_addreses) sep++; } - if (config.number_limit & S_BIT) { + if (state->number_limit & S_BIT) { if (sep) { fprintf(outfile, ",\n"); } fprintf(outfile, " \"shared-networks\": [\n"); - for (i = 0; i < num_shared_networks; i++) { + for (i = 0; i < state->num_shared_networks; i++) { shared_p++; - shnet_output_helper(&oh, shared_p); - if (config.skip_ok && oh.status == STATUS_OK) + shnet_output_helper(state, &oh, shared_p); + if (state->skip_ok && oh.status == STATUS_OK) continue; fprintf(outfile, " "); fprintf(outfile, "{ "); @@ -526,7 +526,7 @@ static int output_json(const int print_mac_addreses) fprintf(outfile, "\"touch_percent\":\"%g\", ", oh.tcp); else fprintf(outfile, "\"touch_percent\":%g, ", oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, "\"backup_count\":%g, ", shared_p->backups); if (shared_p->available == 0) fprintf(outfile, "\"backup_percent\":\"%g\", ", oh.bup); @@ -534,7 +534,7 @@ static int output_json(const int print_mac_addreses) fprintf(outfile, "\"backup_percent\":%g, ", oh.bup); } fprintf(outfile, "\"status\":%d ", oh.status); - if (i + 1 < num_shared_networks) + if (i + 1 < state->num_shared_networks) fprintf(outfile, "},\n"); else fprintf(outfile, "}\n"); @@ -543,23 +543,23 @@ static int output_json(const int print_mac_addreses) sep++; } - if (config.header_limit & A_BIT) { - shnet_output_helper(&oh, shared_networks); + if (state->header_limit & A_BIT) { + shnet_output_helper(state, &oh, state->shared_networks); if (sep) { fprintf(outfile, ",\n"); } fprintf(outfile, " \"summary\": {\n"); - fprintf(outfile, " \"location\":\"%s\",\n", shared_networks->name); - fprintf(outfile, " \"defined\":%g,\n", shared_networks->available); - fprintf(outfile, " \"used\":%g,\n", shared_networks->used); - fprintf(outfile, " \"touched\":%g,\n", shared_networks->touched); + fprintf(outfile, " \"location\":\"%s\",\n", state->shared_networks->name); + fprintf(outfile, " \"defined\":%g,\n", state->shared_networks->available); + fprintf(outfile, " \"used\":%g,\n", state->shared_networks->used); + fprintf(outfile, " \"touched\":%g,\n", state->shared_networks->touched); fprintf(outfile, " \"free\":%g,\n", - shared_networks->available - shared_networks->used); + state->shared_networks->available - state->shared_networks->used); fprintf(outfile, " \"percent\":%g,\n", oh.percent); fprintf(outfile, " \"touch_count\":%g,\n", oh.tc); fprintf(outfile, " \"touch_percent\":%g,\n", oh.tcp); - if (config.backups_found == 1) { - fprintf(outfile, " \"backup_count\":%g,\n", shared_p->backups); + if (state->backups_found == 1) { + fprintf(outfile, " \"backup_count\":%g,\n", state->shared_networks->backups); fprintf(outfile, " \"backup_percent\":%g,\n", oh.bup); } fprintf(outfile, " \"status\":%d\n", oh.status); @@ -574,14 +574,14 @@ static int output_json(const int print_mac_addreses) * * \param f Output file descriptor. */ -static void html_header(FILE *restrict f) +static void html_header(struct conf_t *state, FILE *restrict f) { char outstr[200]; struct tm *tmp, result; struct stat statbuf; - stat(config.dhcpdlease_file, &statbuf); + stat(state->dhcpdlease_file, &statbuf); tmp = localtime_r(&statbuf.st_mtime, &result); if (tmp == NULL) { @@ -608,7 +608,7 @@ static void html_header(FILE *restrict f) fprintf(f, "\n"); fprintf(f, "
\n"); fprintf(f, "

ISC DHCPD status

\n"); - fprintf(f, "File %s was last modified at %s
\n", config.dhcpdlease_file, outstr); + fprintf(f, "File %s was last modified at %s
\n", state->dhcpdlease_file, outstr); } /*! \brief Footer for full html output format. @@ -713,7 +713,7 @@ static void newsection(FILE *restrict f, char const *restrict title) } /*! \brief Output html format. */ -static int output_html(void) +static int output_html(struct conf_t *state) { unsigned int i; struct range_t *range_p; @@ -721,13 +721,13 @@ static int output_html(void) struct output_helper_t oh; FILE *outfile; - outfile = open_outfile(); - range_p = ranges; - shared_p = shared_networks; - html_header(outfile); + outfile = open_outfile(state); + range_p = state->ranges; + shared_p = state->shared_networks; + html_header(state, outfile); newsection(outfile, "Sum of all"); table_start(outfile, "a", "all"); - if (config.header_limit & A_BIT) { + if (state->header_limit & A_BIT) { start_tag(outfile, "thead"); start_tag(outfile, "tr"); output_line(outfile, "th", "name"); @@ -737,26 +737,26 @@ static int output_html(void) output_line(outfile, "th", "touch"); output_line(outfile, "th", "t+c"); output_line(outfile, "th", "t+c perc"); - if (config.backups_found == 1) { + if (state->backups_found == 1) { output_line(outfile, "th", "bu"); output_line(outfile, "th", "bu perc"); } end_tag(outfile, "tr"); end_tag(outfile, "thead"); } - if (config.number_limit & A_BIT) { + if (state->number_limit & A_BIT) { start_tag(outfile, "tbody"); start_tag(outfile, "tr"); - shnet_output_helper(&oh, shared_networks); - output_line(outfile, "td", shared_networks->name); - output_double(outfile, "td", shared_networks->available); - output_double(outfile, "td", shared_networks->used); + shnet_output_helper(state, &oh, state->shared_networks); + output_line(outfile, "td", state->shared_networks->name); + output_double(outfile, "td", state->shared_networks->available); + output_double(outfile, "td", state->shared_networks->used); output_float(outfile, "td", oh.percent); - output_double(outfile, "td", shared_networks->touched); + output_double(outfile, "td", state->shared_networks->touched); output_double(outfile, "td", oh.tc); output_float(outfile, "td", oh.tcp); - if (config.backups_found == 1) { - output_double(outfile, "td", shared_networks->backups); + if (state->backups_found == 1) { + output_double(outfile, "td", state->shared_networks->backups); output_float(outfile, "td", oh.tcp); } end_tag(outfile, "tr"); @@ -765,7 +765,7 @@ static int output_html(void) table_end(outfile); newsection(outfile, "Shared networks"); table_start(outfile, "s", "snet"); - if (config.header_limit & S_BIT) { + if (state->header_limit & S_BIT) { start_tag(outfile, "thead"); start_tag(outfile, "tr"); output_line(outfile, "th", "name"); @@ -775,19 +775,19 @@ static int output_html(void) output_line(outfile, "th", "touch"); output_line(outfile, "th", "t+c"); output_line(outfile, "th", "t+c perc"); - if (config.backups_found == 1) { + if (state->backups_found == 1) { output_line(outfile, "th", "bu"); output_line(outfile, "th", "bu perc"); } end_tag(outfile, "tr"); end_tag(outfile, "thead"); } - if (config.number_limit & S_BIT) { + if (state->number_limit & S_BIT) { start_tag(outfile, "tbody"); - for (i = 0; i < num_shared_networks; i++) { + for (i = 0; i < state->num_shared_networks; i++) { shared_p++; - shnet_output_helper(&oh, shared_networks); - if (config.skip_ok && oh.status == STATUS_OK) + shnet_output_helper(state, &oh, state->shared_networks); + if (state->skip_ok && oh.status == STATUS_OK) continue; start_tag(outfile, "tr"); output_line(outfile, "td", shared_p->name); @@ -797,7 +797,7 @@ static int output_html(void) output_double(outfile, "td", shared_p->touched); output_double(outfile, "td", oh.tc); output_float(outfile, "td", oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { output_double(outfile, "td", shared_p->backups); output_float(outfile, "td", oh.bup); } @@ -808,7 +808,7 @@ static int output_html(void) table_end(outfile); newsection(outfile, "Ranges"); table_start(outfile, "r", "ranges"); - if (config.header_limit & R_BIT) { + if (state->header_limit & R_BIT) { start_tag(outfile, "thead"); start_tag(outfile, "tr"); output_line(outfile, "th", "shared net name"); @@ -820,18 +820,18 @@ static int output_html(void) output_line(outfile, "th", "touch"); output_line(outfile, "th", "t+c"); output_line(outfile, "th", "t+c perc"); - if (config.backups_found == 1) { + if (state->backups_found == 1) { output_line(outfile, "th", "bu"); output_line(outfile, "th", "bu perc"); } end_tag(outfile, "tr"); end_tag(outfile, "thead"); } - if (config.number_limit & R_BIT) { + if (state->number_limit & R_BIT) { start_tag(outfile, "tbody"); - for (i = 0; i < num_ranges; i++) { - range_output_helper(&oh, range_p); - if (config.skip_ok && oh.status == STATUS_OK) { + for (i = 0; i < state->num_ranges; i++) { + range_output_helper(state, &oh, range_p); + if (state->skip_ok && oh.status == STATUS_OK) { range_p++; continue; } @@ -849,7 +849,7 @@ static int output_html(void) output_double(outfile, "td", range_p->touched); output_double(outfile, "td", oh.tc); output_float(outfile, "td", oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { output_double(outfile, "td", range_p->backups); output_float(outfile, "td", oh.bup); } @@ -865,7 +865,7 @@ static int output_html(void) } /*! \brief Output cvs format. */ -static int output_csv(void) +static int output_csv(struct conf_t *state) { unsigned int i; struct range_t *range_p; @@ -873,23 +873,23 @@ static int output_csv(void) struct output_helper_t oh; FILE *outfile; - outfile = open_outfile(); - range_p = ranges; - shared_p = shared_networks; - if (config.header_limit & R_BIT) { + outfile = open_outfile(state); + range_p = state->ranges; + shared_p = state->shared_networks; + if (state->header_limit & R_BIT) { fprintf(outfile, "\"Ranges:\"\n"); fprintf (outfile, "\"shared net name\",\"first ip\",\"last ip\",\"max\",\"cur\",\"percent\",\"touch\",\"t+c\",\"t+c perc\""); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, ",\"bu\",\"bu perc\""); } fprintf(outfile, "\n"); } - if (config.number_limit & R_BIT) { - for (i = 0; i < num_ranges; i++) { - range_output_helper(&oh, range_p); - if (config.skip_ok && oh.status == STATUS_OK) { + if (state->number_limit & R_BIT) { + for (i = 0; i < state->num_ranges; i++) { + range_output_helper(state, &oh, range_p); + if (state->skip_ok && oh.status == STATUS_OK) { range_p++; continue; } @@ -908,7 +908,7 @@ static int output_csv(void) range_p->touched, oh.tc, oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, ",\"%g\",\"%.3f\"", range_p->backups, oh.bup); @@ -919,21 +919,21 @@ static int output_csv(void) } fprintf(outfile, "\n"); } - if (config.header_limit & S_BIT) { + if (state->header_limit & S_BIT) { fprintf(outfile, "\"Shared networks:\"\n"); fprintf(outfile, "\"name\",\"max\",\"cur\",\"percent\",\"touch\",\"t+c\",\"t+c perc\""); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, ",\"bu\",\"bu perc\""); } fprintf(outfile, "\n"); } - if (config.number_limit & S_BIT) { + if (state->number_limit & S_BIT) { - for (i = 0; i < num_shared_networks; i++) { + for (i = 0; i < state->num_shared_networks; i++) { shared_p++; - shnet_output_helper(&oh, shared_p); - if (config.skip_ok && oh.status == STATUS_OK) + shnet_output_helper(state, &oh, shared_p); + if (state->skip_ok && oh.status == STATUS_OK) continue; fprintf(outfile, "\"%s\",\"%g\",\"%g\",\"%.3f\",\"%g\",\"%g\",\"%.3f\"", @@ -944,7 +944,7 @@ static int output_csv(void) shared_p->touched, oh.tc, oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, ",\"%g\",\"%.3f\"", shared_p->backups, oh.bup); @@ -954,29 +954,29 @@ static int output_csv(void) } fprintf(outfile, "\n"); } - if (config.header_limit & A_BIT) { + if (state->header_limit & A_BIT) { fprintf(outfile, "\"Sum of all ranges:\"\n"); fprintf(outfile, "\"name\",\"max\",\"cur\",\"percent\",\"touch\",\"t+c\",\"t+c perc\""); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, ",\"bu\",\"bu perc\""); } fprintf(outfile, "\n"); } - if (config.number_limit & A_BIT) { - shnet_output_helper(&oh, shared_networks); + if (state->number_limit & A_BIT) { + shnet_output_helper(state, &oh, state->shared_networks); fprintf(outfile, "\"%s\",\"%g\",\"%g\",\"%.3f\",\"%g\",\"%g\",\"%.3f\"", - shared_networks->name, - shared_networks->available, - shared_networks->used, + state->shared_networks->name, + state->shared_networks->available, + state->shared_networks->used, oh.percent, - shared_networks->touched, + state->shared_networks->touched, oh.tc, oh.tcp); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, "%7g %8.3f", - shared_networks->backups, + state->shared_networks->backups, oh.bup); } fprintf(outfile, "\n"); @@ -986,7 +986,7 @@ static int output_csv(void) } /*! \brief Output alarm text, and return program exit value. */ -static int output_alarming(void) +static int output_alarming(struct conf_t *state) { FILE *outfile; struct range_t *range_p; @@ -997,14 +997,14 @@ static int output_alarming(void) int rw = 0, rc = 0, ro = 0, ri = 0, sw = 0, sc = 0, so = 0, si = 0; int ret_val; - outfile = open_outfile(); - range_p = ranges; + outfile = open_outfile(state); + range_p = state->ranges; range_size = get_range_size(range_p); - shared_p = shared_networks; + shared_p = state->shared_networks; - if (config.number_limit & R_BIT) { - for (i = 0; i < num_ranges; i++) { - range_output_helper(&oh, range_p); + if (state->number_limit & R_BIT) { + for (i = 0; i < state->num_ranges; i++) { + range_output_helper(state, &oh, range_p); switch (oh.status) { case STATUS_SUPPRESSED: break; @@ -1026,10 +1026,10 @@ static int output_alarming(void) range_p++; } } - if (config.number_limit & S_BIT) { - for (i = 0; i < num_shared_networks; i++) { + if (state->number_limit & S_BIT) { + for (i = 0; i < state->num_shared_networks; i++) { shared_p++; - shnet_output_helper(&oh, shared_p); + shnet_output_helper(state, &oh, shared_p); switch (oh.status) { case STATUS_IGNORED: si++; @@ -1056,14 +1056,14 @@ static int output_alarming(void) else ret_val = STATE_OK; - if ((0 < rc && config.number_limit & R_BIT) - || (0 < sc && config.number_limit & S_BIT)) { + if ((0 < rc && state->number_limit & R_BIT) + || (0 < sc && state->number_limit & S_BIT)) { fprintf(outfile, "CRITICAL: %s:", program_name); - } else if ((0 < rw && config.number_limit & R_BIT) - || (0 < sw && config.number_limit & S_BIT)) { + } else if ((0 < rw && state->number_limit & R_BIT) + || (0 < sw && state->number_limit & S_BIT)) { fprintf(outfile, "WARNING: %s:", program_name); } else { - if (config.number_limit & A_BIT) + if (state->number_limit & A_BIT) fprintf(outfile, "OK:"); else { if (close_stream(outfile)) { @@ -1072,7 +1072,7 @@ static int output_alarming(void) return ret_val; } } - if (config.header_limit & R_BIT) { + if (state->header_limit & R_BIT) { fprintf(outfile, " Ranges - crit: %d warn: %d ok: %d", rc, rw, ro); if (ri != 0) { fprintf(outfile, " ignored: %d", ri); @@ -1081,22 +1081,22 @@ static int output_alarming(void) if (ri != 0) { fprintf(outfile, " range_ignored=%d", ri); } - if (config.perfdata == 1 && config.number_limit & R_BIT) { - for (i = 0; i < num_ranges; i++) { + if (state->perfdata == 1 && state->number_limit & R_BIT) { + for (i = 0; i < state->num_ranges; i++) { range_p--; range_size = get_range_size(range_p); - if (config.minsize < range_size) { + if (state->minsize < range_size) { fprintf(outfile, " %s_r=", ntop_ipaddr(&range_p->first_ip)); fprintf(outfile, "%g;%g;%g;0;%g", range_p->count, - (range_size * config.warning / 100), - (range_size * config.critical / 100), + (range_size * state->warning / 100), + (range_size * state->critical / 100), range_size); fprintf(outfile, " %s_rt=%g", ntop_ipaddr(&range_p->first_ip), range_p->touched); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, " %s_rbu=%g", ntop_ipaddr(&range_p->first_ip), range_p->backups); @@ -1108,7 +1108,7 @@ static int output_alarming(void) } else { fprintf(outfile, " "); } - if (config.header_limit & S_BIT) { + if (state->header_limit & S_BIT) { fprintf(outfile, "Shared nets - crit: %d warn: %d ok: %d", sc, sw, so); if (si != 0) { fprintf(outfile, " ignored: %d", si); @@ -1117,19 +1117,19 @@ static int output_alarming(void) if (si != 0) { fprintf(outfile, " snet_ignored=%d", si); } - if (config.perfdata == 1 && config.header_limit & R_BIT) { - for (i = 0; i < num_shared_networks; i++) { - if (config.minsize < shared_p->available) { + if (state->perfdata == 1 && state->header_limit & R_BIT) { + for (i = 0; i < state->num_shared_networks; i++) { + if (state->minsize < shared_p->available) { fprintf(outfile, " '%s_s'=%g;%g;%g;0;%g", shared_p->name, shared_p->used, - (shared_p->available * config.warning / 100), - (shared_p->available * config.critical / 100), + (shared_p->available * state->warning / 100), + (shared_p->available * state->critical / 100), shared_p->available); fprintf(outfile, " '%s_st'=%g", shared_p->name, shared_p->touched); - if (config.backups_found == 1) { + if (state->backups_found == 1) { fprintf(outfile, " '%s_sbu'=%g", shared_p->name, shared_p->backups); @@ -1146,44 +1146,44 @@ static int output_alarming(void) } /*! \brief Return output_format_names enum based on single char input. */ -int output_analysis(const char c) +int output_analysis(struct conf_t *state, const char output_format) { int ret = 1; - switch (c) { + switch (output_format) { case 't': - ret = output_txt(); + ret = output_txt(state); break; case 'a': - ret = output_alarming(); + ret = output_alarming(state); break; case 'h': error(EXIT_FAILURE, 0, "html table only output format is deprecated"); break; case 'H': - ret = output_html(); + ret = output_html(state); break; case 'x': - ret = output_xml(0); + ret = output_xml(state, 0); break; case 'X': - ret = output_xml(1); + ret = output_xml(state, 1); break; case 'j': - ret = output_json(0); + ret = output_json(state, 0); break; case 'J': - ret = output_json(1); + ret = output_json(state, 1); break; case 'c': - ret = output_csv(); + ret = output_csv(state); break; #ifdef BUILD_MUSTACH case 'm': - ret = mustach_dhcpd_pools(); + ret = mustach_dhcpd_pools(state); break; #endif default: - error(EXIT_FAILURE, 0, "unknown output format: '%c'", c); + error(EXIT_FAILURE, 0, "unknown output format: '%c'", output_format); } return ret; } diff --git a/src/sort.c b/src/sort.c index 0bc9a5b..57d69da 100644 --- a/src/sort.c +++ b/src/sort.c @@ -47,6 +47,7 @@ #include "error.h" #include "progname.h" #include "quote.h" +#include "xalloc.h" #include "dhcpd-pools.h" @@ -239,7 +240,6 @@ comparer_t field_selector(char c) default: { char str[2] = { c, '\0' }; - clean_up(); error(EXIT_FAILURE, 0, "field_selector: unknown sort order: %s", quote(str)); } } @@ -251,12 +251,13 @@ comparer_t field_selector(char c) * \param right The right side of the merge sort. * \return Relevant for merge sort decision. */ -static int merge(struct range_t *restrict left, struct range_t *restrict right) +int merge(struct conf_t *state, struct range_t *restrict left, + struct range_t *restrict right) { struct output_sort *p; int ret; - for (p = config.sorts; p; p = p->next) { + for (p = state->sorts; p; p = p->next) { if (p->func == NULL) { /* String sorting is special. */ ret = strcmp(left->shared_net->name, right->shared_net->name); @@ -274,43 +275,46 @@ static int merge(struct range_t *restrict left, struct range_t *restrict right) } /*! \brief Mergesort for range table. - * \param orig Pointer to range that is requested to be sorted. - * \param size Number of ranges to be sorted. - * \param temp Temporary memory space, needed when a values has to be - * flipped. */ -void mergesort_ranges(struct range_t *restrict orig, int size, struct range_t *restrict temp) +void mergesort_ranges(struct conf_t *state, struct range_t *restrict orig, unsigned int size, + struct range_t *restrict temp, const int root_call) { - int left, right, i; + unsigned int left, i, u_right; + int s_right; struct range_t hold; + if (temp == NULL) + temp = xmalloc(sizeof(struct range_t) * size); + /* Merge sort split size */ - static const int MIN_MERGE_SIZE = 8; + static const unsigned int MIN_MERGE_SIZE = 8; if (size < MIN_MERGE_SIZE) { for (left = 0; left < size; left++) { hold = *(orig + left); - for (right = left - 1; 0 <= right; right--) { - if (merge((orig + right), &hold)) + for (s_right = left - 1; 0 <= s_right; s_right--) { + if (merge(state, (orig + s_right), &hold)) break; - *(orig + right + 1) = *(orig + right); + *(orig + s_right + 1) = *(orig + s_right); } - *(orig + right + 1) = hold; + *(orig + s_right + 1) = hold; } + if (root_call) + free(temp); return; } - mergesort_ranges(orig, size / 2, temp); - mergesort_ranges(orig + size / 2, size - size / 2, temp); + mergesort_ranges(state, orig, size / 2, temp, 0); + mergesort_ranges(state, orig + size / 2, size - size / 2, temp, 0); left = 0; - right = size / 2; + u_right = size / 2; i = 0; - while (left < size / 2 && right < size) { - if (merge((orig + left), (orig + right))) { + while (left < size / 2 && u_right < size) { + if (merge(state, (orig + left), (orig + u_right))) { *(temp + i) = *(orig + left); left++; } else { - *(temp + i) = *(orig + right); - right++; + *(temp + i) = *(orig + u_right); + u_right++; } i++; } @@ -319,10 +323,13 @@ void mergesort_ranges(struct range_t *restrict orig, int size, struct range_t *r left++; i++; } - while (right < size) { - *(temp + i) = *(orig + right); - right++; + while (u_right < size) { + *(temp + i) = *(orig + u_right); + u_right++; i++; } memcpy(orig, temp, size * sizeof(struct range_t)); + + if (root_call) + free(temp); }