mirror of
git://git.code.sf.net/p/dhcpd-pools/code
synced 2025-12-17 00:06:59 +00:00
Add padding where needed and order structure when it makes alignment fall naturally to better order, with a single padding at the end of structure. Reference: http://www.catb.org/esr/structure-packing/ Signed-off-by: Sami Kerola <kerolasa@iki.fi>
368 lines
11 KiB
C
368 lines
11 KiB
C
/*
|
|
* 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 dhcpd-pools.c
|
|
* \brief The main(), and core initialization.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
|
|
#include "close-stream.h"
|
|
#include "closeout.h"
|
|
#include "error.h"
|
|
#include "progname.h"
|
|
#include "quote.h"
|
|
#include "xalloc.h"
|
|
|
|
#include "dhcpd-pools.h"
|
|
|
|
/* Function pointers */
|
|
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) (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) (struct conf_t *state, union ipaddr_t *ip, enum ltype type);
|
|
struct leases_t *(*find_lease) (struct conf_t *state, union ipaddr_t *ip);
|
|
|
|
/*! \brief An option argument parser to populate state header_limit and
|
|
* number_limit values.
|
|
*/
|
|
static int return_limit(const char c)
|
|
{
|
|
if ('0' <= c && c < '8')
|
|
return c - '0';
|
|
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)
|
|
{
|
|
state->ranges = xmalloc(sizeof(struct range_t) * state->ranges_size);
|
|
/* First shared network entry is all networks */
|
|
state->shared_net_root = xcalloc(sizeof(struct shared_network_t), 1);
|
|
state->shared_net_root->name = xstrdup("All networks");
|
|
state->shared_net_head = state->shared_net_root;
|
|
}
|
|
|
|
/*! \brief The --skip option argument parser. */
|
|
static void skip_arg_parse(struct conf_t *state, char *arg)
|
|
{
|
|
enum {
|
|
OPT_ARG_OK = 0,
|
|
OPT_ARG_WARNING,
|
|
OPT_ARG_CRITICAL,
|
|
OPT_ARG_MINSIZE,
|
|
OPT_ARG_SUPPRESSED
|
|
};
|
|
|
|
char *const tokens[] = {
|
|
[OPT_ARG_OK] = "ok",
|
|
[OPT_ARG_WARNING] = "warning",
|
|
[OPT_ARG_CRITICAL] = "critical",
|
|
[OPT_ARG_MINSIZE] = "minsize",
|
|
[OPT_ARG_SUPPRESSED] = "suppressed",
|
|
NULL
|
|
};
|
|
char *value;
|
|
|
|
while (*arg != '\0') {
|
|
switch (getsubopt(&arg, tokens, &value)) {
|
|
case OPT_ARG_OK:
|
|
state->skip_ok = 1;
|
|
break;
|
|
case OPT_ARG_WARNING:
|
|
state->skip_warning = 1;
|
|
break;
|
|
case OPT_ARG_CRITICAL:
|
|
state->skip_critical = 1;
|
|
break;
|
|
case OPT_ARG_MINSIZE:
|
|
state->skip_minsize = 1;
|
|
break;
|
|
case OPT_ARG_SUPPRESSED:
|
|
state->skip_suppressed = 1;
|
|
break;
|
|
default:
|
|
error(EXIT_FAILURE, 0, "unknown --skip specifier: %s", value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*! \brief Command line options parser. */
|
|
static void parse_command_line_opts(struct conf_t *state, int argc, char **argv)
|
|
{
|
|
enum {
|
|
OPT_SNET_ALARMS = CHAR_MAX + 1,
|
|
OPT_WARN,
|
|
OPT_CRIT,
|
|
OPT_MINSIZE,
|
|
OPT_WARN_COUNT,
|
|
OPT_CRIT_COUNT,
|
|
OPT_COLOR,
|
|
OPT_SKIP,
|
|
OPT_SET_IPV,
|
|
OPT_MUSTACH
|
|
};
|
|
|
|
static struct option const long_options[] = {
|
|
{"config", required_argument, NULL, 'c'},
|
|
{"leases", required_argument, NULL, 'l'},
|
|
{"color", required_argument, NULL, OPT_COLOR},
|
|
{"skip", required_argument, NULL, OPT_SKIP},
|
|
{"format", required_argument, NULL, 'f'},
|
|
{"sort", required_argument, NULL, 's'},
|
|
{"reverse", no_argument, NULL, 'r'},
|
|
{"output", required_argument, NULL, 'o'},
|
|
{"limit", required_argument, NULL, 'L'},
|
|
{"mustach", required_argument, NULL, OPT_MUSTACH},
|
|
{"version", no_argument, NULL, 'v'},
|
|
{"help", no_argument, NULL, 'h'},
|
|
{"snet-alarms", no_argument, NULL, OPT_SNET_ALARMS},
|
|
{"warning", required_argument, NULL, OPT_WARN},
|
|
{"critical", required_argument, NULL, OPT_CRIT},
|
|
{"warn-count", required_argument, NULL, OPT_WARN_COUNT},
|
|
{"crit-count", required_argument, NULL, OPT_CRIT_COUNT},
|
|
{"minsize", required_argument, NULL, OPT_MINSIZE},
|
|
{"perfdata", no_argument, NULL, 'p'},
|
|
{"all-as-shared", no_argument, NULL, 'A'},
|
|
{"ip-version", required_argument, NULL, OPT_SET_IPV},
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
int alarming = 0;
|
|
|
|
while (1) {
|
|
int c;
|
|
|
|
c = getopt_long(argc, argv, "c:l:f:o:s:rL:pAvh", long_options, NULL);
|
|
if (c == EOF)
|
|
break;
|
|
switch (c) {
|
|
case 'c':
|
|
/* config file */
|
|
state->dhcpdconf_file = optarg;
|
|
break;
|
|
case 'l':
|
|
/* lease file */
|
|
state->dhcpdlease_file = optarg;
|
|
break;
|
|
case 'f':
|
|
/* Output format */
|
|
state->output_format = optarg[0];
|
|
break;
|
|
case 's':
|
|
{
|
|
/* Output sorting option */
|
|
struct output_sort *p = state->sorts;
|
|
char *ptr = optarg;
|
|
|
|
while (p && p->next)
|
|
p = p->next;
|
|
while (*ptr) {
|
|
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;
|
|
}
|
|
p->func = field_selector(*ptr++);
|
|
}
|
|
}
|
|
break;
|
|
case 'r':
|
|
/* What ever sort in reverse order */
|
|
state->reverse_order = 1;
|
|
break;
|
|
case 'o':
|
|
/* Output file */
|
|
state->output_file = optarg;
|
|
break;
|
|
case 'L':
|
|
/* Specification what will be printed */
|
|
state->header_limit = return_limit(optarg[0]);
|
|
state->number_limit = return_limit(optarg[1]);
|
|
break;
|
|
case OPT_MUSTACH:
|
|
#ifdef BUILD_MUSTACH
|
|
state->mustach_template = optarg;
|
|
state->output_format = 'm';
|
|
#else
|
|
error(EXIT_FAILURE, 0, "compiled without mustach support");
|
|
#endif
|
|
break;
|
|
case OPT_COLOR:
|
|
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:
|
|
skip_arg_parse(state, optarg);
|
|
break;
|
|
case OPT_SNET_ALARMS:
|
|
state->snet_alarms = 1;
|
|
break;
|
|
case OPT_WARN:
|
|
alarming = 1;
|
|
state->warning = strtod_or_err(optarg, "illegal argument");
|
|
break;
|
|
case OPT_CRIT:
|
|
alarming = 1;
|
|
state->critical = strtod_or_err(optarg, "illegal argument");
|
|
break;
|
|
case OPT_WARN_COUNT:
|
|
alarming = 1;
|
|
state->warn_count = strtod_or_err(optarg, "illegal argument");
|
|
break;
|
|
case OPT_CRIT_COUNT:
|
|
alarming = 1;
|
|
state->crit_count = strtod_or_err(optarg, "illegal argument");
|
|
break;
|
|
case OPT_MINSIZE:
|
|
state->minsize = strtod_or_err(optarg, "illegal argument");
|
|
break;
|
|
case OPT_SET_IPV:
|
|
switch (optarg[0]) {
|
|
case '4':
|
|
set_ipv_functions(state, IPv4);
|
|
break;
|
|
case '6':
|
|
set_ipv_functions(state, IPv6);
|
|
break;
|
|
default:
|
|
error(EXIT_FAILURE, 0, "unknown --ip-version argument: %s", optarg);
|
|
}
|
|
break;
|
|
case 'p':
|
|
/* Print additional performance data in alarming mode */
|
|
state->perfdata = 1;
|
|
break;
|
|
case 'A':
|
|
/* Treat single networks as shared with network CIDR as name */
|
|
state->all_as_shared = 1;
|
|
break;
|
|
case 'v':
|
|
/* Print version */
|
|
print_version();
|
|
case 'h':
|
|
/* Print help */
|
|
usage(EXIT_SUCCESS);
|
|
default:
|
|
error(EXIT_FAILURE, 0, "Try %s --help for more information.", 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 (state->output_format == '\0') {
|
|
if (alarming == 1)
|
|
state->output_format = 'a';
|
|
else {
|
|
const char *const default_format = OUTPUT_FORMAT;
|
|
|
|
state->output_format = default_format[0];
|
|
}
|
|
}
|
|
if (state->output_format == 'X' || state->output_format == 'J') {
|
|
state->print_mac_addreses = 1;
|
|
}
|
|
}
|
|
|
|
/*!\brief Start of execution. This will mostly call other functions one
|
|
* after another.
|
|
*
|
|
* \return Return value indicates success or fail or analysis, unless
|
|
* either --warning or --critical options are in use, which makes the
|
|
* return value in some cases to match with Nagios expectations about
|
|
* 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,
|
|
.ranges_size = 64,
|
|
.ip_version = IPvUNKNOWN,
|
|
.color_mode = color_auto,
|
|
0
|
|
};
|
|
int ret_val;
|
|
|
|
atexit(close_stdout);
|
|
set_program_name(argv[0]);
|
|
prepare_memory(&state);
|
|
set_ipv_functions(&state, IPvUNKNOWN);
|
|
parse_command_line_opts(&state, argc, argv);
|
|
|
|
/* Do the job */
|
|
parse_config(&state, 1, state.dhcpdconf_file, state.shared_net_root);
|
|
parse_leases(&state);
|
|
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);
|
|
clean_up(&state);
|
|
return (ret_val);
|
|
}
|