mirror of
git://git.code.sf.net/p/dhcpd-pools/code
synced 2025-12-17 00:06:59 +00:00
342 lines
8.7 KiB
C
342 lines
8.7 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 mustach-dhcpd-pools.c
|
|
* \brief Mustache templating specific functions.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <error.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include "close-stream.h"
|
|
#include "dhcpd-pools.h"
|
|
#include "error.h"
|
|
#include "mustach.h"
|
|
#include "xalloc.h"
|
|
|
|
struct expl {
|
|
struct range_t *range_p;
|
|
struct shared_network_t *shnet_p;
|
|
int current;
|
|
};
|
|
|
|
static int must_enter(void *closure, const char *name);
|
|
static int must_leave(void *closure);
|
|
|
|
/* Set mustach function pointers. */
|
|
static struct mustach_itf itf = {
|
|
.start = NULL,
|
|
.enter = must_enter,
|
|
.put = NULL,
|
|
.next = NULL,
|
|
.leave = must_leave
|
|
};
|
|
|
|
static int must_put_range(void *closure, const char *name, int escape
|
|
__attribute__ ((unused)), FILE *file)
|
|
{
|
|
struct expl *e = closure;
|
|
struct output_helper_t oh;
|
|
|
|
if (!strcmp(name, "location")) {
|
|
fprintf(file, "%s", e->range_p->shared_net->name);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "range")) {
|
|
fprintf(file, "%s - ", ntop_ipaddr(&e->range_p->first_ip));
|
|
fprintf(file, "%s", ntop_ipaddr(&e->range_p->last_ip));
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "first_ip")) {
|
|
fprintf(file, "%s", ntop_ipaddr(&e->range_p->first_ip));
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "last_ip")) {
|
|
fprintf(file, "%s", ntop_ipaddr(&e->range_p->last_ip));
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "used")) {
|
|
fprintf(file, "%g", e->range_p->count);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "touched")) {
|
|
fprintf(file, "%g", e->range_p->touched);
|
|
return 0;
|
|
}
|
|
range_output_helper(&oh, e->range_p);
|
|
if (!strcmp(name, "defined")) {
|
|
fprintf(file, "%g", oh.range_size);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "free")) {
|
|
fprintf(file, "%g", oh.range_size - e->range_p->count);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "percent")) {
|
|
fprintf(file, "%g", oh.percent);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "touch_count")) {
|
|
fprintf(file, "%g", oh.tc);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "touch_percent")) {
|
|
fprintf(file, "%g", oh.tcp);
|
|
return 0;
|
|
}
|
|
if (config.backups_found == 1) {
|
|
if (!strcmp(name, "backup_count")) {
|
|
fprintf(file, "%g", e->range_p->backups);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "backup_percent")) {
|
|
fprintf(file, "%g", oh.bup);
|
|
return 0;
|
|
}
|
|
}
|
|
if (!strcmp(name, "status")) {
|
|
fprintf(file, "%d", oh.status);
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int must_put_shnet(void *closure, const char *name, int escape
|
|
__attribute__ ((unused)), FILE *file)
|
|
{
|
|
struct expl *e = closure;
|
|
struct output_helper_t oh;
|
|
|
|
if (!strcmp(name, "location")) {
|
|
fprintf(file, "%s", e->shnet_p->name);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "defined")) {
|
|
fprintf(file, "%g", e->shnet_p->available);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "used")) {
|
|
fprintf(file, "%g", e->shnet_p->used);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "touched")) {
|
|
fprintf(file, "%g", e->shnet_p->touched);
|
|
return 0;
|
|
}
|
|
shnet_output_helper(&oh, e->shnet_p);
|
|
if (!strcmp(name, "free")) {
|
|
fprintf(file, "%g", e->shnet_p->available - e->shnet_p->used);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "percent")) {
|
|
fprintf(file, "%g", oh.percent);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "touch_count")) {
|
|
fprintf(file, "%g", oh.tc);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "touch_percent")) {
|
|
fprintf(file, "%g", oh.tcp);
|
|
return 0;
|
|
}
|
|
if (config.backups_found == 1) {
|
|
if (!strcmp(name, "backup_count")) {
|
|
fprintf(file, "%g", e->shnet_p->backups);
|
|
return 0;
|
|
}
|
|
if (!strcmp(name, "backup_percent")) {
|
|
fprintf(file, "%g", oh.bup);
|
|
return 0;
|
|
}
|
|
}
|
|
if (!strcmp(name, "status")) {
|
|
fprintf(file, "%d", oh.status);
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int must_next_range(void *closure)
|
|
{
|
|
struct expl *e = closure;
|
|
struct output_helper_t oh;
|
|
|
|
do {
|
|
e->range_p++;
|
|
e->current--;
|
|
if (e->current <= 0)
|
|
return 0;
|
|
range_output_helper(&oh, e->range_p);
|
|
} while (config.skip_ok && oh.status == STATUS_OK);
|
|
return 1;
|
|
}
|
|
|
|
static int must_next_shnet(void *closure)
|
|
{
|
|
struct expl *e = closure;
|
|
struct output_helper_t oh;
|
|
|
|
do {
|
|
e->shnet_p++;
|
|
e->current--;
|
|
if (e->current <= 0)
|
|
return 0;
|
|
shnet_output_helper(&oh, e->shnet_p);
|
|
} while (config.skip_ok && oh.status == STATUS_OK);
|
|
return 1;
|
|
}
|
|
|
|
static int must_enter(void *closure, const char *name)
|
|
{
|
|
struct expl *e = closure;
|
|
|
|
if (!strcmp(name, "subnets")) {
|
|
itf.put = must_put_range;
|
|
itf.next = must_next_range;
|
|
e->current = num_ranges;
|
|
e->range_p = ranges;
|
|
/* must_next_range() will skip_ok when needed */
|
|
return must_next_range(closure);
|
|
}
|
|
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;
|
|
return must_next_shnet(closure);
|
|
}
|
|
if (!strcmp(name, "summary")) {
|
|
itf.put = must_put_shnet;
|
|
itf.next = must_next_shnet;
|
|
e->shnet_p = shared_networks;
|
|
e->current = 1;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int must_leave(void *closure __attribute__ ((unused)))
|
|
{
|
|
struct expl *e = closure;
|
|
|
|
e->shnet_p = shared_networks;
|
|
e->range_p = ranges;
|
|
return 0;
|
|
}
|
|
|
|
static char *must_read_template(const char *filename)
|
|
{
|
|
int f;
|
|
struct stat s;
|
|
char *result;
|
|
|
|
if ((f = open(filename, O_RDONLY)) < 0) {
|
|
error(EXIT_FAILURE, errno, "must_read_template: open: %s", filename);
|
|
}
|
|
fstat(f, &s);
|
|
result = xmalloc(s.st_size + 1);
|
|
if (read(f, result, s.st_size) != s.st_size) {
|
|
error(EXIT_FAILURE, errno, "must_read_template: read: %s", filename);
|
|
}
|
|
close(f);
|
|
result[s.st_size] = 0;
|
|
return result;
|
|
}
|
|
|
|
|
|
int mustach_dhcpd_pools(void)
|
|
{
|
|
struct expl e;
|
|
char *template;
|
|
FILE *outfile;
|
|
int ret;
|
|
|
|
template = must_read_template(config.mustach_template);
|
|
if (config.output_file[0]) {
|
|
outfile = fopen(config.output_file, "w+");
|
|
if (outfile == NULL) {
|
|
error(EXIT_FAILURE, errno, "mustach_dhcpd_pools: fopen: %s",
|
|
config.output_file);
|
|
}
|
|
} else {
|
|
outfile = stdout;
|
|
}
|
|
ret = fmustach(template, &itf, &e, outfile);
|
|
free(template);
|
|
if (outfile == stdout) {
|
|
if (fflush(stdout))
|
|
error(EXIT_FAILURE, errno, "mustach_dhcpd_pools: fflush");
|
|
} else {
|
|
if (close_stream(outfile))
|
|
error(EXIT_FAILURE, errno, "mustach_dhcpd_pools: fclose");
|
|
}
|
|
switch (ret) {
|
|
case MUSTACH_OK:
|
|
return 0;
|
|
case MUSTACH_ERROR_SYSTEM:
|
|
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: system error");
|
|
break;
|
|
case MUSTACH_ERROR_UNEXPECTED_END:
|
|
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: unexpected end");
|
|
break;
|
|
case MUSTACH_ERROR_EMPTY_TAG:
|
|
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: empty tag");
|
|
break;
|
|
case MUSTACH_ERROR_TAG_TOO_LONG:
|
|
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: too long tag");
|
|
break;
|
|
case MUSTACH_ERROR_BAD_SEPARATORS:
|
|
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: bad separator");
|
|
break;
|
|
case MUSTACH_ERROR_TOO_DEPTH:
|
|
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: too deep");
|
|
break;
|
|
case MUSTACH_ERROR_CLOSING:
|
|
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: closing");
|
|
break;
|
|
case MUSTACH_ERROR_BAD_UNESCAPE_TAG:
|
|
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: bad escape tag");
|
|
break;
|
|
default:
|
|
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: unknown error");
|
|
}
|
|
return 1;
|
|
}
|