dhcpd-pools/src/mustach-dhcpd-pools.c
Sami Kerola 50fc4ebe9d
output: avoid mixing ntop_ipaddr() output buffers
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 08:19:56 +00:00

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;
}