Import from release candidate 2.13.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
Sami Kerola 2011-01-21 18:15:50 +01:00
commit 74aef1c34e
38 changed files with 15998 additions and 0 deletions

8
src/Makefile.am Normal file
View file

@ -0,0 +1,8 @@
## Makefile.am -- Process this file with automake to produce Makefile.in
bin_PROGRAMS = dhcpd-pools
AC_PROG_RANLIB = resolv
dhcpd_pools_SOURCES = dhcpd-pools.h defaults.h dhcpd-pools.c analyze.c getdata.c getopt1.c getopt.c other.c sort.c output.c getopt.h
INCLUDES = -I. -I..

460
src/Makefile.in Normal file
View file

@ -0,0 +1,460 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
bin_PROGRAMS = dhcpd-pools$(EXEEXT)
subdir = src
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
am_dhcpd_pools_OBJECTS = dhcpd-pools.$(OBJEXT) analyze.$(OBJEXT) \
getdata.$(OBJEXT) getopt1.$(OBJEXT) getopt.$(OBJEXT) \
other.$(OBJEXT) sort.$(OBJEXT) output.$(OBJEXT)
dhcpd_pools_OBJECTS = $(am_dhcpd_pools_OBJECTS)
dhcpd_pools_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(dhcpd_pools_SOURCES)
DIST_SOURCES = $(dhcpd_pools_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build_alias = @build_alias@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AC_PROG_RANLIB = resolv
dhcpd_pools_SOURCES = dhcpd-pools.h defaults.h dhcpd-pools.c analyze.c getdata.c getopt1.c getopt.c other.c sort.c output.c getopt.h
INCLUDES = -I. -I..
all: all-am
.SUFFIXES:
.SUFFIXES: .c .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p; \
then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
} \
; done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' `; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(bindir)" && rm -f $$files
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
dhcpd-pools$(EXEEXT): $(dhcpd_pools_OBJECTS) $(dhcpd_pools_DEPENDENCIES)
@rm -f dhcpd-pools$(EXEEXT)
$(LINK) $(dhcpd_pools_OBJECTS) $(dhcpd_pools_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/analyze.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-pools.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdata.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/other.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sort.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-binPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
clean-generic ctags distclean distclean-compile \
distclean-generic distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-binPROGRAMS \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
uninstall-am uninstall-binPROGRAMS
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

161
src/analyze.c Normal file
View file

@ -0,0 +1,161 @@
/*
** Copyright (C) 2006- Sami Kerola <kerolasa@iki.fi>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include "dhcpd-pools.h"
/* Clean up data */
int prepare_data(void)
{
unsigned long int i, j, k;
/* Sort leases */
qsort(leases, (size_t) num_leases, sizeof(long int), &intcomp);
/* Get rid of lease dublicates */
for (k = j = i = 0; i < num_leases; i++) {
if (j != leases[i]) {
leases[k] = leases[i];
j = leases[i];
k++;
}
}
num_leases = k;
/* Delete touched IPs that are in use. */
j = 0;
for (i = 0; i < num_touches; i++) {
if (bsearch
(&touches[i], leases, (size_t) num_leases,
sizeof(long int), &intcomp) == NULL) {
touches[j] = touches[i];
j++;
}
}
num_touches = j;
qsort(touches, (size_t) num_touches, sizeof(long int), &intcomp);
/* Sort ranges */
qsort(ranges, (size_t) num_ranges, sizeof(struct range_t),
&rangecomp);
/* Sort backups */
if (num_backups > 0) {
qsort(backups, (size_t) num_backups, sizeof(long int),
&intcomp);
}
return 0;
}
/* Join leases and ranges into couter structs */
int do_counting(void)
{
struct range_t *range_p;
unsigned int i, j, k, m, block_size;
i = j = m = 0;
range_p = ranges;
/* Walk through ranges */
for (k = 0; k < num_ranges; k++) {
/* Count IPs in use */
for (; range_p->last_ip > leases[i]
&& (unsigned long) i < num_leases; i++) {
if (range_p->first_ip > leases[i]) {
continue;
}
/* IP with in range */
range_p->count++;
if (range_p->shared_net) {
range_p->shared_net->used++;
}
}
/* Count touched IPs */
for (; range_p->last_ip > touches[j]
&& (unsigned long) j < num_touches; j++) {
if (range_p->first_ip > touches[j]) {
continue;
}
/* IP with in range */
range_p->touched++;
if (range_p->shared_net) {
range_p->shared_net->touched++;
}
}
/* Count backup IPs */
if (num_backups > 0) {
for (; range_p->last_ip > backups[m]
&& (unsigned long) m < num_touches; m++) {
if (range_p->first_ip > touches[m]) {
continue;
}
/* IP with in range */
range_p->backups++;
if (range_p->shared_net) {
range_p->shared_net->backups++;
}
}
}
/* Size of range, shared net & all networks */
block_size =
(unsigned int) (range_p->last_ip - range_p->first_ip -
1);
if (range_p->shared_net) {
range_p->shared_net->available += block_size;
}
/* Reverse so that not even a one IP will be missed. */
if (i) {
i--;
}
if (j) {
j--;
}
range_p++;
}
/* During count of other shared networks default network and
* all networks got mixed to gether semantically. This fixes
* the problem, but is not elegant. TODO: fix semantics of all
* and default share_network. */
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 +=
range_p->last_ip - range_p->first_ip - 1;
shared_networks->used += range_p->count;
shared_networks->touched += range_p->touched;
shared_networks->backups += range_p->backups;
range_p++;
}
return 0;
}

37
src/defaults.h Normal file
View file

@ -0,0 +1,37 @@
/*
** Copyright (C) 2006 Sami Kerola <kerolasa@iki.fi>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef DEFAULTS_H
# define DEFAULTS_H 1
/* Maximum line length in dhcpd.conf and dhcpd.leases */
static const int MAXLEN = 1024;
/* Total number of characters in all shared network names */
static const int SHARED_NETWORKS_NAMES = 24576;
/* Maximum number of shared networks */
static const int SHARED_NETWORKS = 1024;
/* Maximum number of ranges */
static const unsigned int RANGES = 65536;
/* Merge sort split size */
static const int MIN_MERGE_SIZE = 8;
#endif /* DEFAULTS_H */

288
src/dhcpd-pools.c Normal file
View file

@ -0,0 +1,288 @@
/*
** Copyright (C) 2006- Sami Kerola <kerolasa@iki.fi>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else /* Not STDC_HEADERS */
extern void exit();
extern char *malloc();
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <getopt.h>
#include "dhcpd-pools.h"
#include "defaults.h"
int main(int argc, char **argv)
{
int c, sorts = 0;
int option_index = 0;
char *tmp;
struct range_t *tmp_ranges;
/* Options for getopt_long */
static struct option const long_options[] = {
{"config", required_argument, 0, (int) 'c'},
{"leases", required_argument, 0, (int) 'l'},
{"format", required_argument, 0, (int) 'f'},
{"sort", required_argument, 0, (int) 's'},
{"reverse", no_argument, 0, (int) 'r'},
{"output", required_argument, 0, (int) 'o'},
{"limit", required_argument, 0, (int) 'L'},
{"version", no_argument, 0, (int) 'v'},
{"help", no_argument, 0, (int) 'h'},
{0, 0, 0, 0}
};
program_name = argv[0];
atexit(clean_up);
/* TODO: make either dynamic or find out max path lenght that auto config
* provides */
config.dhcpdconf_file = safe_malloc(sizeof(char) * MAXLEN);
config.dhcpdlease_file = safe_malloc(sizeof(char) * MAXLEN);
config.output_file = safe_malloc(sizeof(char) * MAXLEN);
/* Make sure string has zero lenght if there is no command line
* option */
config.output_file[0] = '\0';
/* File location defaults */
strncpy(config.dhcpdconf_file, DHCPDCONF_FILE,
(size_t) MAXLEN - 1);
strncpy(config.dhcpdlease_file, DHCPDLEASE_FILE,
(size_t) MAXLEN - 1);
tmp = OUTPUT_LIMIT;
config.output_limit[0] = (int) (*tmp - '0');
tmp++;
config.output_limit[1] = (int) (*tmp - '0');
fullhtml = false;
/* Make sure some output format is selected by default */
strncpy(config.output_format, OUTPUT_FORMAT, (size_t) 1);
/* Default sort order is by IPs small to big */
config.reverse_order = false;
/* Parse command line options */
while (1) {
c = getopt_long(argc, argv, "c:l:f:o:s:rL:vh",
long_options, &option_index);
if (c == EOF)
break;
switch (c) {
case 0:
break;
case 'c':
/* config file */
if (optarg != NULL) {
strncpy(config.dhcpdconf_file, optarg,
(size_t) MAXLEN - 1);
} else {
eprintf
("main: for argument configuration file parameter not set");
usage(EXIT_FAILURE);
}
break;
case 'l':
/* lease file */
if (optarg != NULL) {
strncpy(config.dhcpdlease_file, optarg,
(size_t) MAXLEN - 1);
} else {
eprintf
("main: for argument lease file parameter not set");
usage(EXIT_FAILURE);
}
break;
case 'f':
/* Output format */
if (optarg != NULL) {
strncpy(config.output_format, optarg,
(size_t) 1);
} else {
eprintf
("main: for argument output format parameter not set");
usage(EXIT_FAILURE);
}
break;
case 's':
/* Output sorting option */
if (optarg != NULL) {
sorts = strlen(optarg);
if (sorts > 5) {
eprintf
("main: only 5 first sort orders will be used");
strncpy(config.sort, optarg,
(size_t) 5);
sorts = 5;
} else {
strncpy(config.sort, optarg,
(size_t) sorts);
}
} else {
eprintf
("main: for argument sort order parameter not set");
usage(EXIT_FAILURE);
}
break;
case 'r':
/* What ever sort in reverse order */
config.reverse_order = true;
break;
case 'o':
/* Output file */
if (optarg != NULL) {
strncpy(config.output_file, optarg,
(size_t) MAXLEN - 1);
} else {
eprintf
("main: for argument output file parameter not set");
usage(EXIT_FAILURE);
}
break;
case 'L':
/* Specification what will be printed */
if (optarg != NULL) {
if (optarg[0] >= '0' && optarg[0] < '8') {
config.output_limit[0] =
(int) optarg[0] - '0';
} else {
eprintf
("main: output mask %s illegal",
argv[optind]);
usage(EXIT_FAILURE);
}
if (optarg[1] >= '0' && optarg[1] < '8') {
config.output_limit[1] =
(int) optarg[1] - '0';
} else {
eprintf
("main: output mask %s illegal",
optarg);
usage(EXIT_FAILURE);
}
} else {
eprintf
("main: for argument output mask parameter not set");
usage(EXIT_FAILURE);
}
break;
case 'v':
/* Print version */
print_version();
exit(EXIT_SUCCESS);
case 'h':
/* Print help */
usage(EXIT_SUCCESS);
default:
usage(EXIT_FAILURE);
}
}
/* Output function selection */
switch (config.output_format[0]) {
case 't':
output_analysis = output_txt;
break;
case 'h':
output_analysis = output_html;
break;
case 'H':
output_analysis = output_html;
fullhtml = true;
break;
case 'x':
output_analysis = output_xml;
break;
case 'X':
output_analysis = output_xml;
break;
case 'c':
output_analysis = output_csv;
break;
case 's':
/* output_analysis = output_snmp; */
output_analysis = output_txt;
break;
default:
eprintf("main: unknown ouput format");
usage(EXIT_FAILURE);
}
/* Do the job */
prepare_memory();
parse_config(true, config.dhcpdconf_file, shared_net_names,
shared_net_names + strlen(shared_net_names) + 1,
shared_networks);
if ((config.output_format[0] == 'x')
|| (config.output_format[0] == 'X')) {
printf("<dhcpstatus>\n");
};
parse_leases();
prepare_data();
do_counting();
tmp_ranges = safe_malloc(sizeof(struct range_t) * num_ranges);
if (sorts != 0) {
mergesort_ranges(ranges, num_ranges, tmp_ranges);
}
if (config.reverse_order == true) {
flip_ranges(ranges, tmp_ranges);
}
free(tmp_ranges);
output_analysis();
if ((config.output_format[0] == 'x')
|| (config.output_format[0] == 'X')) {
printf("</dhcpstatus>\n");
};
exit(EXIT_SUCCESS);
}
/* Global allocations, counter resets etc */
int prepare_memory()
{
num_ranges = num_shared_networks = 0;
shared_networks =
safe_malloc(sizeof(struct shared_network_t) * SHARED_NETWORKS);
shared_net_names =
safe_malloc(sizeof(char) * SHARED_NETWORKS_NAMES);
ranges = safe_malloc(sizeof(struct range_t) * RANGES);
/* First shared network entry is all networks */
strcpy(shared_net_names, "All networks");
return 0;
}

130
src/dhcpd-pools.h Normal file
View file

@ -0,0 +1,130 @@
/*
** Copyright (C) 2006- Sami Kerola <kerolasa@iki.fi>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef DHCPD_POOLS_H
# define DHCPD_POOLS_H 1
#include <config.h>
/* Feature test switches */
#define _POSIX_SOURCE 1
#define POSIXLY_CORRECT 1
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else /* Not STDC_HEADERS */
extern void exit ();
extern char *malloc ();
#endif /* STDC_HEADERS */
/* Structures and unions */
struct configuration_t
{
char *dhcpdconf_file;
char *dhcpdlease_file;
char output_format[2];
char sort[6];
int reverse_order;
char *output_file;
int output_limit[2];
};
struct shared_network_t
{
char *name;
unsigned long int available;
unsigned long int used;
unsigned long int touched;
unsigned long int backups;
};
struct range_t
{
struct shared_network_t *shared_net;
unsigned long int first_ip;
unsigned long int last_ip;
unsigned long int count;
unsigned long int touched;
unsigned long int backups;
};
/* Global variables */
static int true = 1;
static int false = 0;
char *program_name;
struct configuration_t config;
static int output_limit_bit_1 = 1;
static int output_limit_bit_2 = 2;
static int output_limit_bit_3 = 4;
unsigned int fullhtml;
struct shared_network_t *shared_networks;
char *shared_net_names;
unsigned int num_shared_networks;
struct range_t *ranges;
unsigned int num_ranges;
unsigned long int *leases;
unsigned long int num_leases;
unsigned long int *touches;
unsigned long int num_touches;
unsigned long int *backups;
unsigned long int num_backups;
/* Function prototypes */
int prepare_memory (void);
int parse_leases (void);
char * parse_config (int, char *, char *, char *, struct shared_network_t *);
int nth_field (int n, char *dest, const char *src);
int prepare_data (void);
int do_counting (void);
void flip_ranges(struct range_t *ranges, struct range_t *tmp_ranges);
/* General support functions */
void *safe_malloc (size_t size);
void eprintf (char *, ...);
void print_version (void);
void usage (int status);
/* qsort required functions... */
/* ...for ranges and... */
int intcomp (const void *x, const void *y);
int rangecomp (const void *r1, const void *r2);
/* sort function pointer and functions */
int sort_name (void);
unsigned long int (*returner) (struct range_t r);
unsigned long int ret_ip(struct range_t r);
unsigned long int ret_cur(struct range_t r);
unsigned long int ret_max(struct range_t r);
unsigned long int ret_percent(struct range_t r);
unsigned long int ret_touched(struct range_t r);
unsigned long int ret_tc(struct range_t r);
unsigned long int ret_tcperc(struct range_t r);
void field_selector(char c);
int get_order(struct range_t *left, struct range_t *right);
void mergesort_ranges (struct range_t *orig, int size, struct range_t *temp);
/* output function pointer and functions */
int (*output_analysis) (void);
int output_txt (void);
int output_html (void);
int output_xml (void);
int output_csv (void);
/* Memory release, file closing etc */
void clean_up (void);
#endif /* DHCPD_POOLS_H */

454
src/getdata.c Normal file
View file

@ -0,0 +1,454 @@
/*
** Copyright (C) 2006- Sami Kerola < >
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else /* Not STDC_HEADERS */
extern void exit();
extern char *malloc();
#define EXIT_FAILURE 1 /* Failing exit status. */
#define EXIT_SUCCESS 0 /* Successful exit status. */
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#define _XOPEN_SOURCE 600
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include "dhcpd-pools.h"
#include "defaults.h"
/* Parse dhcpd.leases file. All performance boosts for this
* function are wellcome */
int parse_leases(void)
{
FILE *dhcpd_leases;
char *line, *ipstring, *macstring, *macstring2;
struct in_addr inp;
struct stat lease_file_stats;
unsigned long leasesmallocsize;
unsigned long touchesmallocsize;
unsigned long backupsmallocsize;
int sw_active_lease = 0;
num_touches = num_leases = num_backups = 0;
dhcpd_leases = fopen(config.dhcpdlease_file, "r");
if (dhcpd_leases == NULL) {
eprintf("parse_leases: %s:", config.dhcpdlease_file);
exit(EXIT_FAILURE);
}
#ifdef POSIX_FADV_NOREUSE
posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_NOREUSE);
if (errno) {
eprintf("parse_leases: fadvise:");
exit(EXIT_FAILURE);
}
#endif /* POSIX_FADV_NOREUSE */
#ifdef POSIX_FADV_SEQUENTIAL
posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_SEQUENTIAL);
if (errno) {
eprintf("parse_leases: fadvise:");
exit(EXIT_FAILURE);
}
#endif /* POSIX_FADV_SEQUENTIAL */
/* I found out that there's one lease address per 300 bytes in
* dhcpd.leases file. Malloc is little bit pessimistic and uses
* 250. If someone has higher density in lease file I'm
* interested to hear about that. */
if (stat(config.dhcpdlease_file, &lease_file_stats)) {
eprintf("parse_leases: %s:", config.dhcpdlease_file);
exit(EXIT_FAILURE);
}
leasesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
touchesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
backupsmallocsize = (lease_file_stats.st_size / 120) + MAXLEN - 2;
leases = safe_malloc(sizeof(long int) * leasesmallocsize);
touches =
safe_malloc((size_t) sizeof(long int) * touchesmallocsize);
line = safe_malloc(sizeof(long int) * MAXLEN);
ipstring = safe_malloc(sizeof(long int) * MAXLEN);
macstring = safe_malloc(sizeof(long int) * MAXLEN);
macstring2 = safe_malloc(sizeof(long int) * MAXLEN);
while (!feof(dhcpd_leases)) {
fgets(line, MAXLEN, dhcpd_leases);
/* It's a lease, save IP */
if (strstr(line, "lease") == line) {
strncpy(ipstring, line, (size_t) MAXLEN);
nth_field(2, ipstring, ipstring);
inet_aton(ipstring, &inp);
sw_active_lease = 0;
}
/* Copy IP to correct array */
else if (strstr(line, "binding state active")) {
leases[num_leases] = htonl(inp.s_addr);
num_leases++;
sw_active_lease = 1;
} else if (strstr(line, " binding state free")) {
touches[num_touches] = htonl(inp.s_addr);
num_touches++;
} else if (strstr(line, " binding state backup")) {
if (num_backups == 0) {
backups =
safe_malloc((size_t) sizeof(long int) *
backupsmallocsize);
}
backups[num_backups] = htonl(inp.s_addr);
num_backups++;
}
if ((sw_active_lease == 1)
&& (strstr(line, "hardware ethernet"))) {
nth_field(3, macstring, line);
macstring[strlen(macstring) - 1] = '\0';
if (config.output_format[0] == 'X') {
printf
("<active_lease>\n\t<ip>%s</ip>\n\t<macaddress>%s</macaddress>\n</active_lease>\n",
ipstring, macstring);
};
}
if ((num_leases > leasesmallocsize) ||
(num_touches > touchesmallocsize) ||
(num_backups > backupsmallocsize)) {
printf("WARNING: running out of memory\n");
printf("\tlease/touch/backup = %lu/%lu/%lu\n",
leasesmallocsize, touchesmallocsize,
backupsmallocsize);
printf("\tlease/touch/backup = %lu/%lu/%lu\n",
num_leases, num_touches, num_backups);
printf
("Code should realloc() and init new memory, but no time to write that now!\n");
exit(EXIT_FAILURE);
}
}
return 0;
}
/* Like strcpy but for field which is separated by white spaces.
* Number of first field is 1 and not 0 like C programs should
* have. Question of semantics, send mail to author if this
* annoys. All performance boosts for this function are well
* come. */
int nth_field(int n, char *dest, const char *src)
{
int i, j = 0, wordn = 0, len;
len = strlen(src);
for (i = 0; i < len; i++) {
if (isspace(src[i])) {
if (!(wordn < n)) {
dest[j] = '\0';
break;
}
j = 0;
} else {
if (j == 0) {
wordn++;
}
if (wordn == n) {
dest[j] = src[i];
}
j++;
}
}
return 0;
}
/* dhcpd.conf interesting words */
int is_interesting_config_clause(char *s)
{
if (strstr(s, "shared-network")) {
return 1;
} else if (strstr(s, "range")) {
return 3;
} else if (strstr(s, "include")) {
return 4;
} else {
return 0;
}
}
/* TODO: This spagetti monster function need to be rewrote at
* least ones. */
char *parse_config(int is_include, char *config_file,
char *current_shared_name,
char *next_free_shared_name,
struct shared_network_t *shared_p)
{
FILE *dhcpd_config;
int i = 0, newclause = true, argument = false, comment =
false, braces = 0, quote = false;
char *word, c;
int braces_shared = 1000;
struct in_addr inp;
struct range_t *range_p;
char *last_shared_name;
last_shared_name = SHARED_NETWORKS_NAMES + shared_net_names;
word = safe_malloc(sizeof(char) * MAXLEN);
if (is_include) {
/* Default place holder for ranges "All networks". */
shared_p->name = current_shared_name;
}
/* Open configuration file */
dhcpd_config = fopen(config_file, "r");
if (dhcpd_config == NULL) {
eprintf("parse_config: %s:", config_file);
exit(EXIT_FAILURE);
}
#ifdef POSIX_FADV_NOREUSE
posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_NOREUSE);
if (errno) {
eprintf("parse_config: fadvise:");
exit(EXIT_FAILURE);
}
#endif /* POSIX_FADV_NOREUSE */
#ifdef POSIX_FADV_SEQUENTIAL
posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_SEQUENTIAL);
if (errno) {
eprintf("parse_config: fadvise:");
exit(EXIT_FAILURE);
}
#endif /* POSIX_FADV_SEQUENTIAL */
/* Very hairy stuff begins. */
while (!feof(dhcpd_config)) {
c = fgetc(dhcpd_config);
/* Certain characters are magical */
switch (c) {
/* Handle comments if they are not quoted */
case '#':
if (quote == false) {
comment = true;
}
continue;
case '"':
if (comment == false) {
quote++;
/* Either one or zero */
quote = quote % 2;
}
continue;
case '\n':
/* New line resets comment section, but not if quoted */
if (quote == false) {
comment = false;
}
break;
case ';':
/* Quoted colon does not mean new clause */
if (quote == true) {
break;
}
if (comment == false && argument != 2
&& argument != 4) {
newclause = true;
i = 0;
} else if (argument == 2) {
/* Range ends to ; and this hair in code make two
* ranges wrote to gether like...
*
* range 10.20.30.40 10.20.30.41;range 10.20.30.42 10.20.30.43;
*
* ...to be interpreted correctly. */
c = ' ';
}
continue;
case '{':
if (quote == true) {
break;
}
if (comment == false) {
braces++;
}
/* i == 0 detects word that ends to brace like:
*
* shared-network DSL{ ... */
if (i == 0) {
newclause = true;
}
continue;
case '}':
if (quote == true) {
break;
}
if (comment == false) {
braces--;
/* End of shared-network */
if (braces_shared == braces) {
current_shared_name =
shared_net_names;
/* TODO: Using 1000 is lame, but works. */
braces_shared = 1000;
shared_p = shared_networks;
}
/* Not literally true, but works for this program */
newclause = true;
}
continue;
default:
break;
}
/* Either inside comment or Nth word of clause. */
if (comment == true
|| (newclause == false && argument == 0)) {
continue;
}
/* Strip white spaces before new clause word. */
if ((newclause == true || argument != 0) && isspace(c)
&& i == 0) {
continue;
}
/* Save to word which clause this is. */
if ((newclause == true || argument != 0)
&& (!isspace(c) || quote == true)) {
word[i] = c;
i++;
/* Long word which is almost causing overflow. Not any of words
* this program is looking for are this long. */
if (i > MAXLEN) {
newclause = false;
i = 0;
continue;
}
}
/* See if clause is something that parser is looking for. */
else if (newclause == true) {
/* Insert string end & set state */
word[i] = '\0';
newclause = false;
i = 0;
argument = is_interesting_config_clause(word);
}
/* words after range, shared-network or include */
else if (argument != 0) {
word[i] = '\0';
newclause = false;
i = 0;
switch (argument) {
case 0:
/* printf ("nothing interesting: %s\n", word); */
argument = 0;
break;
case 1:
/* printf ("shared-network named: %s\n", word); */
strcpy(next_free_shared_name, word);
shared_p =
shared_networks + num_shared_networks;
num_shared_networks++;
shared_p++;
shared_p->name = next_free_shared_name;
shared_p->available = 0;
shared_p->used = 0;
shared_p->touched = 0;
shared_p->backups = 0;
/* Temporary abuse of argument variable */
argument =
strlen(next_free_shared_name) + 1;
if (last_shared_name >
next_free_shared_name + argument) {
next_free_shared_name += argument;
} else {
/* TODO: make this go away by reallocationg more space. */
eprintf
("parse_config: End of shared-network space, increase SHARED_NETWORKS_NAMES and recompile");
exit(EXIT_FAILURE);
}
argument = 0;
braces_shared = braces;
break;
case 2:
/* printf ("range 2nd ip: %s\n", word); */
range_p = ranges + num_ranges;
inet_aton(word, &inp);
argument = 0;
range_p->last_ip = htonl(inp.s_addr) + 1;
range_p->count = 0;
range_p->touched = 0;
range_p->backups = 0;
range_p->shared_net = shared_p;
num_ranges++;
if (num_ranges > RANGES) {
eprintf
("parse_config: Range space full! Increase RANGES and recompile.");
exit(EXIT_FAILURE);
}
newclause = true;
break;
case 3:
/* printf ("range 1nd ip: %s\n", word); */
range_p = ranges + num_ranges;
inet_aton(word, &inp);
range_p->first_ip = htonl(inp.s_addr) - 1;
if (range_p->first_ip == UINT_MAX) {
/* word was not ip, try again */
break;
}
argument = 2;
break;
case 4:
/* printf ("include file: %s\n", word); */
argument = 0;
next_free_shared_name =
parse_config(false, word, current_shared_name,
next_free_shared_name,
shared_p);
newclause = true;
break;
default:
eprintf
("parse_config: This cannot happen, report a bug!");
exit(EXIT_FAILURE);
}
}
}
free(word);
return next_free_shared_name;
}

1043
src/getopt.c Normal file

File diff suppressed because it is too large Load diff

183
src/getopt.h Normal file
View file

@ -0,0 +1,183 @@
/* Declarations for getopt.
Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef _GETOPT_H
#ifndef __need_getopt
# define _GETOPT_H 1
#endif
/* If __GNU_LIBRARY__ is not already defined, either we are being used
standalone, or this is the first header included in the source file.
If we are being used with glibc, we need to include <features.h>, but
that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
not defined, include <ctype.h>, which will pull in <features.h> for us
if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
doesn't flood the namespace with stuff the way some other headers do.) */
#if !defined __GNU_LIBRARY__
# include <ctype.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
#ifndef __need_getopt
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
# if (defined __STDC__ && __STDC__) || defined __cplusplus
const char *name;
# else
char *name;
# endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
# define no_argument 0
# define required_argument 1
# define optional_argument 2
#endif /* need getopt */
/* Get definitions and prototypes for functions to process the
arguments in ARGV (ARGC of them, minus the program name) for
options given in OPTS.
Return the option character from OPTS just read. Return -1 when
there are no more options. For unrecognized options, or options
missing arguments, `optopt' is set to the option letter, and '?' is
returned.
The OPTS string is a list of characters which are recognized option
letters, optionally followed by colons, specifying that that letter
takes an argument, to be placed in `optarg'.
If a letter in OPTS is followed by two colons, its argument is
optional. This behavior is specific to the GNU `getopt'.
The argument `--' causes premature termination of argument
scanning, explicitly telling `getopt' that there are no more
options.
If OPTS begins with `--', then non-option arguments are treated as
arguments to the option '\0'. This behavior is specific to the GNU
`getopt'. */
#if (defined __STDC__ && __STDC__) || defined __cplusplus
# ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int __argc, char *const *__argv,
const char *__shortopts);
# else /* not __GNU_LIBRARY__ */
extern int getopt ();
# endif /* __GNU_LIBRARY__ */
# ifndef __need_getopt
extern int getopt_long (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind);
extern int getopt_long_only (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts,
int *__longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts,
int *__longind, int __long_only);
# endif
#else /* not __STDC__ */
extern int getopt ();
# ifndef __need_getopt
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
# endif
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
/* Make sure we later can get all the definitions and declarations. */
#undef __need_getopt
#endif /* getopt.h */

187
src/getopt1.c Normal file
View file

@ -0,0 +1,187 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "getopt.h"
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
#include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE
#endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#endif
#ifndef NULL
#define NULL 0
#endif
int getopt_long(argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal(argc, argv, options, long_options,
opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int getopt_long_only(argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal(argc, argv, options, long_options,
opt_index, 1);
}
#endif /* Not ELIDE_CODE. */
#ifdef TEST
#include <stdio.h>
int main(argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1) {
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
printf("option %s",
long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0
&& digit_optind != this_option_optind)
printf
("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf("option %c\n", c);
break;
case 'a':
printf("option a\n");
break;
case 'b':
printf("option b\n");
break;
case 'c':
printf("option c with value `%s'\n", optarg);
break;
case 'd':
printf("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf
("?? getopt returned character code 0%o ??\n",
c);
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
exit(0);
}
#endif /* TEST */

174
src/other.c Normal file
View file

@ -0,0 +1,174 @@
/*
** Copyright (C) 2006- Sami Kerola <kerolasa@iki.fi>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "dhcpd-pools.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else /* Not STDC_HEADERS */
extern void exit();
extern char *malloc();
#endif /* STDC_HEADERS */
#include <errno.h>
#include <stdarg.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
/* Simple memory allocation wrapper */
void *safe_malloc(size_t size)
{
void *ret = malloc(size);
if (ret == NULL) {
eprintf("safe_malloc: malloc: ");
exit(EXIT_FAILURE);
}
return ret;
}
/* Copyright (C) 1999 Lucent Technologies
* Excerpted from 'The Practice of Programming'
* by Brian W. Kernighan and Rob Pike
* slight modifications by Sami Kerola.
* eprintf: print error message and exit */
void eprintf(char *fmt, ...)
{
va_list args;
fflush(stdout);
fprintf(stderr, "%s: ", program_name);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (fmt[0] != '\0' && fmt[strlen(fmt) - 1] == ':')
fprintf(stderr, " %s", strerror(errno));
/* Should be safe, after all dhcpd-pools has only one
* thread. */
errno = 0;
fprintf(stderr, "\n");
fflush(stderr);
}
void flip_ranges(struct range_t *ranges, struct range_t *tmp_ranges)
{
unsigned int i = num_ranges - 1, j;
for (j = 0; j < num_ranges; j++) {
*(tmp_ranges + j) = *(ranges + i);
i--;
}
memcpy(ranges, tmp_ranges, num_ranges * sizeof(struct range_t));
}
/* Free memory, flush buffers etc */
void clean_up(void)
{
int ret;
if (errno) {
eprintf
("clean_up: errno (%d) set but not checked in correct place; if this is repeatable send strace output as a bug report:",
errno);
}
/* Just in case there something in buffers */
ret = fflush(stdout);
if (errno || ret) {
eprintf("clean_up: stdout:");
}
ret = fflush(stderr);
if (errno || ret) {
eprintf("clean_up: stderr:");
}
free(config.dhcpdconf_file);
free(config.dhcpdlease_file);
free(config.output_file);
free(ranges);
free(shared_net_names);
free(shared_networks);
}
void print_version(void)
{
fprintf(stdout, "%s\n", PACKAGE_STRING);
fprintf(stdout,
"Written by Sami Kerola.\nXML support by Dominic Germain, Sogetel inc.\n\n");
fprintf(stdout,
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n");
fprintf(stdout,
"This is free software: you are free to change and redistribute it.\n");
fprintf(stdout,
"There is NO WARRANTY, to the extent permitted by law.\n");
}
void usage(int status)
{
FILE *out;
out = status != 0 ? stderr : stdout;
fprintf(out, "\
Usage: %s [OPTIONS]\n", program_name);
fprintf(out, "\
This is ISC dhcpd pools usage analyzer.\n\
\n");
fprintf(out, "\
-c --config file path to the dhcpd.conf file\n\
-l --leases file path to the dhcpd.leases file\n\
-f --format [thcxX] output format\n");
fprintf(out, "\
t for text\n\
h for html table\n\
H for full html page\n\
x for xml\n\
X for xml with active lease details\n\
c for comma separated values\n");
/* TODO
s for snmp\n");
*/
fprintf(out, "\
-s --sort [nimcptTe] sort ranges by\n\
n name\n\
i IP\n\
m maxium\n\
c current\n\
p percent\n\
t touched\n\
T t+c\n\
e t+c perc\n");
fprintf(out, "\
-r --reverse reverse order sort\n\
-o --output file output into a file\n\
-L --limit nr output limit mask 77 - 00\n\
-v --version version information\n\
-h --help this screen\n\
\n\
Report bugs to <%s>\n\
Homepage: %s\n", PACKAGE_BUGREPORT, PACKAGE_URL);
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
}

777
src/output.c Normal file
View file

@ -0,0 +1,777 @@
/*
** Copyright (C) 2006- Sami Kerola <kerolasa@iki.fi>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "dhcpd-pools.h"
int output_txt(void)
{
unsigned int i;
struct in_addr first, last;
struct range_t *range_p;
struct shared_network_t *shared_p;
int ret;
FILE *outfile;
if (config.output_file[0]) {
outfile = fopen(config.output_file, "w+");
if (outfile == NULL) {
eprintf("output_txt: %s:", config.output_file);
exit(EXIT_FAILURE);
}
} else {
outfile = stdout;
}
range_p = ranges;
shared_p = shared_networks;
if (config.output_limit[0] & output_limit_bit_1) {
fprintf(outfile, "Ranges:\n");
fprintf
(outfile,
"shared net name first ip last ip max cur percent touch t+c t+c perc");
if (num_backups > 0) {
fprintf(outfile, " bu bu perc");
}
fprintf(outfile, "\n");
}
if (config.output_limit[1] & output_limit_bit_1) {
for (i = 0; i < num_ranges; i++) {
first.s_addr = ntohl(range_p->first_ip + 1);
last.s_addr = ntohl(range_p->last_ip - 1);
if (range_p->shared_net) {
fprintf(outfile, "%-20s",
range_p->shared_net->name);
} else {
fprintf(outfile, "not_defined ");
}
fprintf(outfile, "%-16s", inet_ntoa(first));
fprintf(outfile,
" - %-16s %5lu %5lu %10.3f %5lu %5lu %9.3f",
inet_ntoa(last),
range_p->last_ip - range_p->first_ip - 1,
range_p->count,
(float) (100 * range_p->count) /
(range_p->last_ip - range_p->first_ip - 1),
range_p->touched,
range_p->touched + range_p->count,
(float) (100 *
(range_p->touched +
range_p->count)) /
(range_p->last_ip - range_p->first_ip -
1));
if (num_backups > 0) {
fprintf(outfile, "%7lu %8.3f",
range_p->backups,
(float) (100 * range_p->backups) /
(range_p->last_ip -
range_p->first_ip - 1));
}
fprintf(outfile, "\n");
range_p++;
}
}
if (config.output_limit[1] & output_limit_bit_1
&& config.output_limit[0] & output_limit_bit_2) {
fprintf(outfile, "\n");
}
if (config.output_limit[0] & output_limit_bit_2) {
fprintf(outfile, "Shared networks:\n");
fprintf(outfile,
"name max cur percent touch t+c t+c perc");
if (num_backups > 0) {
fprintf(outfile, " bu bu perc");
}
fprintf(outfile, "\n");
}
if (config.output_limit[1] & output_limit_bit_2) {
for (i = 0; i < num_shared_networks; i++) {
shared_p++;
fprintf(outfile,
"%-20s %5lu %5lu %10.3f %7lu %6lu %9.3f",
shared_p->name, shared_p->available,
shared_p->used,
(float) (100 * shared_p->used) /
shared_p->available, shared_p->touched,
shared_p->touched + shared_p->used,
(float) (100 *
(shared_p->touched +
shared_p->used)) /
shared_p->available);
if (num_backups > 0) {
fprintf(outfile, "%7lu %8.3f",
shared_p->backups,
(float) (100 * shared_p->backups) /
shared_p->available);
}
fprintf(outfile, "\n");
}
}
if (config.output_limit[1] & output_limit_bit_2
&& config.output_limit[0] & output_limit_bit_3) {
fprintf(outfile, "\n");
}
if (config.output_limit[0] & output_limit_bit_3) {
fprintf(outfile, "Sum of all ranges:\n");
fprintf(outfile,
"name max cur percent touch t+c t+c perc");
if (num_backups > 0) {
fprintf(outfile, " bu bu perc");
}
fprintf(outfile, "\n");
}
if (config.output_limit[1] & output_limit_bit_3) {
fprintf(outfile, "%-20s %5lu %5lu %10.3f %7lu %6lu %9.3f",
shared_networks->name,
shared_networks->available,
shared_networks->used,
(float) (100 * shared_networks->used) /
shared_networks->available,
shared_networks->touched,
shared_networks->touched + shared_networks->used,
(float) (100 *
(shared_networks->touched +
shared_networks->used)) /
shared_networks->available);
if (num_backups > 0) {
fprintf(outfile, "%7lu %8.3f",
shared_networks->backups,
(float) (100 * shared_networks->backups) /
shared_networks->available);
}
fprintf(outfile, "\n");
}
if (outfile == stdout) {
ret = fflush(stdout);
if (ret) {
eprintf("output_txt: fflush:");
}
} else {
ret = fclose(outfile);
if (ret) {
eprintf("output_txt: fclose:");
}
}
return 0;
}
int output_xml(void)
{
unsigned int i;
struct in_addr first, last;
struct range_t *range_p;
struct shared_network_t *shared_p;
int ret;
FILE *outfile;
if (config.output_file[0]) {
outfile = fopen(config.output_file, "w+");
if (outfile == NULL) {
eprintf("output_xml: %s:", config.output_file);
exit(EXIT_FAILURE);
}
} else {
outfile = stdout;
}
range_p = ranges;
shared_p = shared_networks;
if (config.output_limit[1] & output_limit_bit_1) {
for (i = 0; i < num_ranges; i++) {
first.s_addr = ntohl(range_p->first_ip + 1);
last.s_addr = ntohl(range_p->last_ip - 1);
fprintf(outfile, "<subnet>\n");
if (range_p->shared_net) {
fprintf(outfile,
"\t<location>%s</location>\n",
range_p->shared_net->name);
} else {
fprintf(outfile,
"\t<location></location>\n");
}
fprintf(outfile, "\t<network></network>\n");
fprintf(outfile, "\t<netmask></netmask>\n");
fprintf(outfile, "\t<range>%s ", inet_ntoa(first));
fprintf(outfile, "- %s</range>\n",
inet_ntoa(last));
fprintf(outfile, "\t<gateway></gateway>\n");
fprintf(outfile, "\t<defined>%lu</defined>\n",
range_p->last_ip - range_p->first_ip - 1);
fprintf(outfile, "\t<used>%lu</used>\n",
range_p->count);
fprintf(outfile, "\t<free>%lu</free>\n",
range_p->last_ip - range_p->first_ip - 1 -
range_p->count);
range_p++;
fprintf(outfile, "</subnet>\n");
}
}
if (config.output_limit[1] & output_limit_bit_2) {
for (i = 0; i < num_shared_networks; i++) {
shared_p++;
fprintf(outfile, "<shared-network>\n");
fprintf(outfile, "\t<location>%s</location>\n",
shared_p->name);
fprintf(outfile, "\t<defined>%lu</defined>\n",
shared_p->available);
fprintf(outfile, "\t<used>%lu</used>\n",
shared_p->used);
fprintf(outfile, "\t<free>%lu</free>\n",
shared_p->available - shared_p->used);
fprintf(outfile, "</shared-network>\n");
}
}
if (config.output_limit[0] & output_limit_bit_3) {
fprintf(outfile, "<summary>\n");
fprintf(outfile, "\t<location>%s</location>\n",
shared_networks->name);
fprintf(outfile, "\t<defined>%lu</defined>\n",
shared_networks->available);
fprintf(outfile, "\t<used>%lu</used>\n",
shared_networks->used);
fprintf(outfile, "\t<free>%lu</free>\n",
shared_networks->available -
shared_networks->used);
fprintf(outfile, "</summary>\n");
}
if (outfile == stdout) {
ret = fflush(stdout);
if (ret) {
eprintf("output_xml: fflush:");
}
} else {
ret = fclose(outfile);
if (ret) {
eprintf("output_xml: fclose:");
}
}
return 0;
}
void html_header(FILE * f)
{
fprintf(f,
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \n");
fprintf(f, " \"http://www.w3.org/TR/html4/strict.dtd\">\n");
fprintf(f, "<html>\n");
fprintf(f, "<head>\n");
fprintf(f, "<meta http-equiv=\"Content-Type\" ");
fprintf(f, "content=\"text/html; charset=iso-8859-1\">\n");
fprintf(f, " <title>ISC dhcpd stats</title>\n");
fprintf(f, " <style TYPE=\"text/css\">\n");
fprintf(f, " <!--\n");
fprintf(f, " table.dhcpd-pools {\n");
fprintf(f, " color: black;\n");
fprintf(f, " vertical-align: middle;\n");
fprintf(f, " text-align: center;\n");
fprintf(f, " }\n");
fprintf(f, " table.dhcpd-pools th.section {\n");
fprintf(f, " color: black;\n");
fprintf(f, " font-size: large;\n");
fprintf(f, " vertical-align: middle;\n");
fprintf(f, " text-align: left;\n");
fprintf(f, " }\n");
fprintf(f, " table.dhcpd-pools th.calign {\n");
fprintf(f, " color: black;\n");
fprintf(f, " vertical-align: middle;\n");
fprintf(f, " text-align: center;\n");
fprintf(f, " text-decoration: underline;\n");
fprintf(f, " }\n");
fprintf(f, " table.dhcpd-pools th.ralign {\n");
fprintf(f, " color: black;\n");
fprintf(f, " vertical-align: middle;\n");
fprintf(f, " text-align: right;\n");
fprintf(f, " text-decoration: underline;\n");
fprintf(f, " }\n");
fprintf(f, " table.dhcpd-pools td.calign {\n");
fprintf(f, " color: black;\n");
fprintf(f, " vertical-align: middle;\n");
fprintf(f, " text-align: center;\n");
fprintf(f, " }\n");
fprintf(f, " table.dhcpd-pools td.ralign {\n");
fprintf(f, " color: black;\n");
fprintf(f, " vertical-align: middle;\n");
fprintf(f, " text-align: right;\n");
fprintf(f, " }\n");
fprintf(f, " p.created {\n");
fprintf(f, " font-size: small;\n");
fprintf(f, " color: grey;\n");
fprintf(f, " }\n");
fprintf(f, " p.updated {\n");
fprintf(f, " font-size: small;\n");
fprintf(f, " color: grey;\n");
fprintf(f, " font-style: italic;\n");
fprintf(f, " }\n");
fprintf(f, " -->\n");
fprintf(f, " </style>\n");
fprintf(f, "</head>\n");
fprintf(f, "<body>\n");
}
void html_footer(FILE * f)
{
fprintf(f, "<p><br></p>\n");
fprintf(f, "<hr>\n");
fprintf(f, "<p class=created>\nData generated by ");
fprintf(f, "<a href=\"%s\">", PACKAGE_URL);
fprintf(f, "dhcpd-pools</a>.\n</p>\n");
fprintf(f, "<p class=updated>\n");
fprintf(f, "<script type=\"text/javascript\">\n");
fprintf(f, " document.write(\"Last Updated On \" + ");
fprintf(f, "document.lastModified + \".\")\n");
fprintf(f, "</script>\n<br>\n</p>\n");
fprintf(f, "</body>\n");
fprintf(f, "</html>\n");
}
void newrow(FILE * f)
{
fprintf(f, "<tr>\n");
}
void endrow(FILE * f)
{
fprintf(f, "</tr>\n\n");
}
void output_line(FILE * f, char *type, char *class, char *text)
{
fprintf(f, " <%s class=%s>%s</%s>\n", type, class, text, type);
}
void output_long(FILE * f, char *type, unsigned long unlong)
{
fprintf(f, " <%s class=ralign>%lu</%s>\n", type, unlong, type);
}
void output_float(FILE * f, char *type, float fl)
{
fprintf(f, " <%s class=ralign>%.3f</%s>\n", type, fl, type);
}
void table_start(FILE * f)
{
fprintf(f, "<table width=\"75%%\" ");
fprintf(f, "class=\"dhcpd-pools\" ");
fprintf(f, "summary=\"ISC dhcpd pool usage report\">\n");
}
void table_end(FILE * f)
{
fprintf(f, "</table>\n");
}
void newsection(FILE * f, char *title)
{
newrow(f);
output_line(f, "td", "calign", "&nbsp;");
endrow(f);
newrow(f);
output_line(f, "th", "section", title);
endrow(f);
}
int output_html(void)
{
unsigned int i;
struct in_addr first, last;
struct range_t *range_p;
struct shared_network_t *shared_p;
int ret;
FILE *outfile;
if (config.output_file[0]) {
outfile = fopen(config.output_file, "w+");
if (outfile == NULL) {
eprintf("output_html: %s:", config.output_file);
exit(EXIT_FAILURE);
}
} else {
outfile = stdout;
}
range_p = ranges;
shared_p = shared_networks;
if (fullhtml) {
html_header(outfile);
}
table_start(outfile);
if (config.output_limit[0] & output_limit_bit_1) {
newsection(outfile, "Ranges:");
newrow(outfile);
output_line(outfile, "th", "calign", "shared net name");
output_line(outfile, "th", "calign", "first ip");
output_line(outfile, "th", "calign", "last ip");
output_line(outfile, "th", "ralign", "max");
output_line(outfile, "th", "ralign", "cur");
output_line(outfile, "th", "ralign", "percent");
output_line(outfile, "th", "ralign", "touch");
output_line(outfile, "th", "ralign", "t+c");
output_line(outfile, "th", "ralign", "t+c perc");
if (num_backups > 0) {
output_line(outfile, "th", "ralign", "bu");
output_line(outfile, "th", "ralign", "bu perc");
}
endrow(outfile);
}
if (config.output_limit[1] & output_limit_bit_1) {
for (i = 0; i < num_ranges; i++) {
first.s_addr = ntohl(range_p->first_ip + 1);
last.s_addr = ntohl(range_p->last_ip - 1);
newrow(outfile);
if (range_p->shared_net) {
output_line(outfile, "td", "calign",
range_p->shared_net->name);
} else {
output_line(outfile, "td", "calign",
"not_defined");
}
output_line(outfile, "td", "calign",
inet_ntoa(first));
output_line(outfile, "td", "calign",
inet_ntoa(last));
output_long(outfile, "td",
range_p->last_ip - range_p->first_ip -
1);
output_long(outfile, "td", range_p->count);
output_float(outfile, "td",
(float) (100 * range_p->count) /
(range_p->last_ip -
range_p->first_ip - 1));
output_long(outfile, "td", range_p->touched);
output_long(outfile, "td",
range_p->touched + range_p->count);
output_float(outfile, "td",
(float) (100 *
(range_p->touched +
range_p->count)) /
(range_p->last_ip -
range_p->first_ip - 1));
if (num_backups > 0) {
output_long(outfile, "td",
range_p->backups);
output_float(outfile, "td",
(float) (100 *
range_p->backups) /
(range_p->last_ip -
range_p->first_ip - 1));
}
endrow(outfile);
range_p++;
}
}
table_end(outfile);
table_start(outfile);
if (config.output_limit[0] & output_limit_bit_2) {
newsection(outfile, "Shared networks:");
newrow(outfile);
output_line(outfile, "th", "calign", "name");
output_line(outfile, "th", "ralign", "max");
output_line(outfile, "th", "ralign", "cur");
output_line(outfile, "th", "ralign", "percent");
output_line(outfile, "th", "ralign", "touch");
output_line(outfile, "th", "ralign", "t+c");
output_line(outfile, "th", "ralign", "t+c perc");
if (num_backups > 0) {
output_line(outfile, "th", "ralign", "bu");
output_line(outfile, "th", "ralign", "bu perc");
}
endrow(outfile);
}
if (config.output_limit[1] & output_limit_bit_2) {
for (i = 0; i < num_shared_networks; i++) {
shared_p++;
newrow(outfile);
output_line(outfile, "td", "calign",
shared_p->name);
output_long(outfile, "td", shared_p->available);
output_long(outfile, "td", shared_p->used);
output_float(outfile, "td",
(float) (100 * shared_p->used) /
shared_p->available);
output_long(outfile, "td", shared_p->touched);
output_long(outfile, "td",
shared_p->touched + shared_p->used);
output_float(outfile, "td",
(float) (100 *
(shared_p->touched +
shared_p->used)) /
shared_p->available);
if (num_backups > 0) {
output_long(outfile, "td",
shared_p->backups);
output_float(outfile, "td",
(float) (100 *
shared_p->backups) /
shared_p->available);
}
endrow(outfile);
}
}
if (config.output_limit[0] & output_limit_bit_3) {
newsection(outfile, "Sum of all ranges:");
newrow(outfile);
output_line(outfile, "th", "calign", "name");
output_line(outfile, "th", "ralign", "max");
output_line(outfile, "th", "ralign", "cur");
output_line(outfile, "th", "ralign", "percent");
output_line(outfile, "th", "ralign", "touch");
output_line(outfile, "th", "ralign", "t+c");
output_line(outfile, "th", "ralign", "t+c perc");
if (num_backups > 0) {
output_line(outfile, "th", "ralign", "bu");
output_line(outfile, "th", "ralign", "bu perc");
}
endrow(outfile);
}
if (config.output_limit[1] & output_limit_bit_3) {
newrow(outfile);
output_line(outfile, "td", "calign",
shared_networks->name);
output_long(outfile, "td", shared_networks->available);
output_long(outfile, "td", shared_networks->used);
output_float(outfile, "td",
(float) (100 * shared_networks->used) /
shared_networks->available);
output_long(outfile, "td", shared_networks->touched);
output_long(outfile, "td",
shared_networks->touched +
shared_networks->used);
output_float(outfile, "td",
(float) (100 *
(shared_networks->touched +
shared_networks->used)) /
shared_networks->available);
if (num_backups > 0) {
output_long(outfile, "td",
shared_networks->backups);
output_float(outfile, "td",
(float) (100 *
shared_networks->backups) /
shared_networks->available);
}
endrow(outfile);
}
table_end(outfile);
if (fullhtml) {
html_footer(outfile);
}
if (outfile == stdout) {
ret = fflush(stdout);
if (ret) {
eprintf("output_html: fflush:");
}
} else {
ret = fclose(outfile);
if (ret) {
eprintf("output_html: fclose:");
}
}
return 0;
}
int output_csv(void)
{
unsigned int i;
struct in_addr first, last;
struct range_t *range_p;
struct shared_network_t *shared_p;
FILE *outfile;
int ret;
if (config.output_file[0]) {
outfile = fopen(config.output_file, "w+");
if (outfile == NULL) {
eprintf("output_csv: %s:", config.output_file);
exit(EXIT_FAILURE);
}
} else {
outfile = stdout;
}
range_p = ranges;
shared_p = shared_networks;
if (config.output_limit[0] & output_limit_bit_1) {
fprintf(outfile, "\"Ranges:\"\n");
fprintf
(outfile,
"\"shared net name\",\"first ip\",\"last ip\",\"max\",\"cur\",\"percent\",\"touch\",\"t+c\",\"t+c perc\"");
if (num_backups > 0) {
fprintf(outfile, ",\"bu\",\"bu perc\"");
}
fprintf(outfile, "\n");
}
if (config.output_limit[1] & output_limit_bit_1) {
for (i = 0; i < num_ranges; i++) {
first.s_addr = ntohl(range_p->first_ip + 1);
last.s_addr = ntohl(range_p->last_ip - 1);
if (range_p->shared_net) {
fprintf(outfile, "\"%s\",",
range_p->shared_net->name);
} else {
fprintf(outfile, "\"not_defined\",");
}
fprintf(outfile, "\"%s\",", inet_ntoa(first));
fprintf(outfile,
"\"%s\",\"%lu\",\"%lu\",\"%.3f\",\"%lu\",\"%lu\",\"%.3f\"",
inet_ntoa(last),
range_p->last_ip - range_p->first_ip - 1,
range_p->count,
(float) (100 * range_p->count) /
(range_p->last_ip - range_p->first_ip - 1),
range_p->touched,
range_p->touched + range_p->count,
(float) (100 *
(range_p->touched +
range_p->count)) /
(range_p->last_ip - range_p->first_ip -
1));
if (num_backups > 0) {
fprintf(outfile, ",\"%lu\",\"%.3f\"",
range_p->backups,
(float) (100 * range_p->backups) /
(range_p->last_ip -
range_p->first_ip - 1));
}
fprintf(outfile, "\n");
range_p++;
}
fprintf(outfile, "\n");
}
if (config.output_limit[0] & output_limit_bit_2) {
fprintf(outfile, "\"Shared networks:\"\n");
fprintf(outfile,
"\"name\",\"max\",\"cur\",\"percent\",\"touch\",\"t+c\",\"t+c perc\"");
if (num_backups > 0) {
fprintf(outfile, ",\"bu\",\"bu perc\"");
}
fprintf(outfile, "\n");
}
if (config.output_limit[1] & output_limit_bit_2) {
for (i = 0; i < num_shared_networks; i++) {
shared_p++;
fprintf(outfile,
"\"%s\",\"%lu\",\"%lu\",\"%.3f\",\"%lu\",\"%lu\",\"%.3f\"",
shared_p->name, shared_p->available,
shared_p->used,
(float) (100 * shared_p->used) /
shared_p->available, shared_p->touched,
shared_p->touched + shared_p->used,
(float) (100 *
(shared_p->touched +
shared_p->used)) /
shared_p->available);
if (num_backups > 0) {
fprintf(outfile, ",\"%lu\",\"%.3f\"",
shared_p->backups,
(float) (100 * shared_p->backups) /
shared_p->available);
}
fprintf(outfile, "\n");
}
fprintf(outfile, "\n");
}
if (config.output_limit[0] & output_limit_bit_3) {
fprintf(outfile, "\"Sum of all ranges:\"\n");
fprintf(outfile,
"\"name\",\"max\",\"cur\",\"percent\",\"touch\",\"t+c\",\"t+c perc\"");
if (num_backups > 0) {
fprintf(outfile, ",\"bu\",\"bu perc\"");
}
fprintf(outfile, "\n");
}
if (config.output_limit[1] & output_limit_bit_3) {
fprintf(outfile,
"\"%s\",\"%lu\",\"%lu\",\"%.3f\",\"%lu\",\"%lu\",\"%.3f\"",
shared_networks->name, shared_networks->available,
shared_networks->used,
(float) (100 * shared_networks->used) /
shared_networks->available,
shared_networks->touched,
shared_networks->touched + shared_networks->used,
(float) (100 *
(shared_networks->touched +
shared_networks->used)) /
shared_networks->available);
if (num_backups > 0) {
fprintf(outfile, "%7lu %8.3f",
shared_networks->backups,
(float) (100 * shared_networks->backups) /
shared_networks->available);
}
fprintf(outfile, "\n");
}
if (outfile == stdout) {
ret = fflush(stdout);
if (ret) {
eprintf("output_cvs: fflush:");
}
} else {
ret = fclose(outfile);
if (ret) {
eprintf("output_cvs: fclose:");
}
}
return 0;
}

213
src/sort.c Normal file
View file

@ -0,0 +1,213 @@
/*
** Copyright (C) 2006- Sami Kerola <kerolasa@iki.fi>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dhcpd-pools.h"
#include "defaults.h"
/* Sort functions for range sorting */
int intcomp(const void *x, const void *y)
{
if (*(unsigned long int *) x < *(unsigned long int *) y)
return -1;
else if (*(unsigned long int *) y < *(unsigned long int *) x)
return 1;
else
return 0;
}
int rangecomp(const void *r1, const void *r2)
{
if ((((struct range_t *) r1)->first_ip) <
(((struct range_t *) r2)->first_ip))
return -1;
else if ((((struct range_t *) r2)->first_ip) <
(((struct range_t *) r1)->first_ip))
return 1;
else
return 0;
}
unsigned long int ret_ip(struct range_t r)
{
return (r.first_ip);
}
unsigned long int ret_cur(struct range_t r)
{
return (r.count);
}
unsigned long int ret_max(struct range_t r)
{
return (r.last_ip - r.first_ip);
}
unsigned long int ret_percent(struct range_t r)
{
float f;
f = (float) r.count / (r.last_ip - r.first_ip - 1);
return ((unsigned long int) (f * 100000));
}
unsigned long int ret_touched(struct range_t r)
{
return (r.touched);
}
unsigned long int ret_tc(struct range_t r)
{
return (r.count + r.touched);
}
unsigned long int ret_tcperc(struct range_t r)
{
float f;
f = (float) (r.count + r.touched) / (r.last_ip - r.first_ip - 1);
return ((unsigned long int) (f * 10000));
}
void field_selector(char c)
{
switch (c) {
case 'n':
break;
case 'i':
returner = ret_ip;
break;
case 'm':
returner = ret_max;
break;
case 'c':
returner = ret_cur;
break;
case 'p':
returner = ret_percent;
break;
case 't':
returner = ret_touched;
break;
case 'T':
returner = ret_tc;
break;
case 'e':
returner = ret_tcperc;
break;
default:
eprintf("field_selector: unknown sort order: %c",
config.sort[0]);
usage(EXIT_FAILURE);
}
}
/* Needed to support multiple key sorting. */
int get_order(struct range_t *left, struct range_t *right)
{
int i, len, ret;
unsigned long int lint, rint;
len = strlen(config.sort);
for (i = 0; i < len; i++) {
/* Handling strings is case of it's own */
if (config.sort[i] == 'n') {
ret =
strcmp(left->shared_net->name,
right->shared_net->name);
if (ret > 0) {
return (0);
} else if (ret < 0) {
return (1);
} else {
continue;
}
}
/* Select which function is pointed by returner */
field_selector(config.sort[i]);
lint = returner(*left);
rint = returner(*right);
/* If fields are equal use next sort method */
if (lint == rint) {
continue;
}
if (lint < rint) {
return (1);
}
return (0);
}
/* If all returners where equal */
return (0);
}
void mergesort_ranges(struct range_t *orig, int size, struct range_t *temp)
{
int left, right, i;
struct range_t hold;
if (size < MIN_MERGE_SIZE) {
for (left = 0; left < size; left++) {
hold = *(orig + left);
for (right = left - 1; right >= 0; right--) {
if (get_order((orig + right), &hold)) {
break;
}
*(orig + right + 1) = *(orig + right);
}
*(orig + right + 1) = hold;
}
return;
}
mergesort_ranges(orig, size / 2, temp);
mergesort_ranges(orig + size / 2, size - size / 2, temp);
left = 0;
right = size / 2;
i = 0;
while (left < size / 2 && right < size) {
if (get_order((orig + left), (orig + right))) {
*(temp + i) = *(orig + left);
left++;
} else {
*(temp + i) = *(orig + right);
right++;
}
i++;
}
while (left < size / 2) {
*(temp + i) = *(orig + left);
left++;
i++;
}
while (right < size) {
*(temp + i) = *(orig + right);
right++;
i++;
}
memcpy(orig, temp, size * sizeof(struct range_t));
}