From: Sebastian Harl Date: Wed, 5 Dec 2012 15:10:48 +0000 (+0100) Subject: Initial commit. X-Git-Tag: sysdb-0.0.0 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=bf3b8e60b2fdc493c4e04b05ce67abf69ca9a4ff Initial commit. This is the initial version of 'syscollector', a system management / inventory collection service. The current version provides a configurable plugin infrastructure to query host / service objects. The system is made up of the following components: - libsyscollector: the library providing the core functionality to manage plugins and the data store * core/object: base "class" for objects being stored in any part of the library; an object contains information about a reference count and the actual data being stored (in derived "classes"); it may be used to ease memory management when using instances in different parts of the software * core/plugin: infrastructure for registering and calling plugin callbacks; each registered plugin has its own context which stores information that should be available to different parts of the software without having the plugin to care much about it; for now, configuration, init, shutdown and collector (backend) callbacks are supported * core/store: implementation of the system object store; currently, host and service entries are supported; each host includes a list of services assigned to it; the store objects are derived from the core object implementation * utils/llist: a linked list implementation, currently supporting sorted insertions, searching and shifting objects and iterators; the list stores core object instances * utils/string: collection of string utilities; currently a wrapper around strerror_r() is available only * utils/time: implementation of a custom time type which is a single integer value storing the time since the epoch in nanoseconds resolution; this is provided for simplified time calculations and comparisons * utils/unixsock: helper functions to connect to and communicate with a UNIX domain socket - backends: plugins implementing collector callbacks * collectd: this backend retrieves host and service information from collectd, the system statistics collection daemon, through its unixsock interface - daemon: 'syscollectord' is a daemon based on libsyscollector which periodically queries all backends - liboconfig: the configuration parsing library used by collectd; this is used by 'syscollectord' for parsing its configuration and it's used by libsyscollector to pass on configuration to the plugins --- bf3b8e60b2fdc493c4e04b05ce67abf69ca9a4ff diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5edd76f --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# build system stuff +m4/argz.m4 +m4/libtool.m4 +m4/ltdl.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +.deps +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +compile +config.* +configure +depcomp +install-sh +missing +stamp-h1 +version +ylwrap + +# ltdl stuff +libltdl +libtool +ltmain.sh + +# build output +src/liboconfig/parser.c +src/liboconfig/parser.h +src/liboconfig/scanner.c +.dirstamp +.libs +*.la +*.lo +*.o +syscollectord +syscollectord.1 +syscollector.h + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..b90bd54 --- /dev/null +++ b/COPYING @@ -0,0 +1,24 @@ +Copyright (c) 2012 Sebastian 'tokkee' Harl +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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..23e5f25 --- /dev/null +++ b/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..cfca249 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,14 @@ +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = src +if BUILD_DOCUMENTATION +SUBDIRS += doc +endif + +EXTRA_DIST = autogen.sh version-gen.sh + +version: FORCE + @# As a side-effect, this updates version. + @echo Building $(PACKAGE_NAME) version $$( cd .. && ./version-gen.sh ) +.PHONY: FORCE + diff --git a/README b/README new file mode 100644 index 0000000..20cbce9 --- /dev/null +++ b/README @@ -0,0 +1,45 @@ + syscollector -- a system management / inventory collection service + ==================================================================== + + “System Collector” (syscollector) is a multi-backend system management and + inventory collection service. It may be used to collect information from + various backends (inventory services, monitoring services, etc.) and + provides a unique interface to access the information independent of the + active backends. This is done by mapping the backend objects to generic + objects and correlating the attributes to create a single hierarchy of your + infrastructure. + + This is free and open source software, licensed under the 2-clause BSD + license. See COPYING for details. + +Prerequisites +------------- + + To compile the syscollector package from source you need: + + * A build environment: autotools, libtool, C compiler, ... + + * A POSIX + Single UNIX Specification compatible C library. + + * asciidoc, xsltproc: + The AsciiDoc text document format is used to write the manpages. + +Configuring / Compiling / Installing +------------------------------------ + + To configure, build and install syscollector with the default settings, run + `./configure && make && make install'. For detailed, generic instructions + see INSTALL. For a complete list of configure options and their description, + run `./configure --help'. + + By default, syscollector will be installed into `/opt/syscollector'. You can + adjust this setting by specifying the `--prefix' configure option - see + INSTALL for details. If you pass DESTDIR= to `make install', + will be prefixed to all installation directories. This might be useful when + creating packages for syscollector. + +Author +------ + + Sebastian "tokkee" Harl + diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..5424ef9 --- /dev/null +++ b/THANKS @@ -0,0 +1,4 @@ +Special thanks goes to Florian 'octo' Forster and +everybody involved in collectd . The project has greatly +influenced the architectural design of syscollector. + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..e4ffee0 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,17 @@ +#! /bin/sh + +libtoolize=libtoolize + +if which glibtoolize > /dev/null 2>&1; then + libtoolize=glibtoolize +fi + +set -ex + +aclocal -I m4 --force --warnings=all +$libtoolize --automake --copy --force +aclocal -I m4 +autoconf --force --warnings=all +autoheader --force --warnings=all +automake --add-missing --copy --foreign --warnings=all + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..fe9331d --- /dev/null +++ b/configure.ac @@ -0,0 +1,247 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl This is the syscollector configure script. +dnl +dnl Copyright (C) 2012 Sebastian 'tokkee' Harl +dnl All rights reserved. +dnl +dnl Redistribution and use in source and binary forms, with or without +dnl modification, are permitted provided that the following conditions +dnl are met: +dnl 1. Redistributions of source code must retain the above copyright +dnl notice, this list of conditions and the following disclaimer. +dnl 2. Redistributions in binary form must reproduce the above copyright +dnl notice, this list of conditions and the following disclaimer in the +dnl documentation and/or other materials provided with the distribution. +dnl +dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +dnl ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +dnl TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +dnl PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR +dnl CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +dnl OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +dnl WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +dnl OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +dnl ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +AC_INIT([system collector],[m4_esyscmd(./version-gen.sh)], + [sh@tokkee.org], + [syscollector], + [http://git.tokkee.org/?p=syscollector.git]) +PACKAGE_MAINTAINER="Sebastian 'tokkee' Harl " +AC_DEFINE_UNQUOTED([PACKAGE_MAINTAINER], ["$PACKAGE_MAINTAINER"], + [Define to the name of the maintainer of this package.]) +AC_CONFIG_SRCDIR([src/syscollector.c]) +AC_CONFIG_HEADERS([src/config.h]) +AC_PREFIX_DEFAULT([/opt/syscollector]) + +AM_INIT_AUTOMAKE([foreign -Wall]) + +AC_LANG(C) + +AC_SYS_LARGEFILE + +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET + +AM_PROG_CC_C_O +AM_PROG_LEX +AC_PROG_YACC + +m4_ifdef([LT_INIT], + [ + LT_CONFIG_LTDL_DIR([libltdl]) + LT_INIT([dlopen]) + LTDL_INIT([convenience]) + ], + # else + # (older libtools) + [ + AC_CONFIG_SUBDIRS(libltdl) + AC_LIBLTDL_CONVENIENCE + AC_SUBST(LTDLINCL) + AC_SUBST(LIBLTDL) + AC_LIBTOOL_DLOPEN + ] +) + +test_cc_flags() { + AC_LANG_CONFTEST([AC_LANG_PROGRAM([[ ]], [[ ]])]) + $CC -c conftest.c $CFLAGS $@ > /dev/null 2> /dev/null + ret=$? + rm -f conftest.o + return $ret +} + +m4_divert_once([HELP_ENABLE], [ +Build options:]) + +dnl Optionally stick to standard C99 and POSIX:2001 as close as possible. +AC_ARG_ENABLE([standards], + AS_HELP_STRING([--enable-standards], + [C99 / POSIX standards compliance mode @<:@default=no@:>@]), + [enable_standards="$enableval"], + [enable_standards="no"]) + +if test "x$enable_standards" = "xyes"; then + AC_DEFINE([_ISOC99_SOURCE], 1, + [Define to enforce ISO/IEC 9899:1999 (C99) compliance.]) + AC_DEFINE([_POSIX_C_SOURCE], 200112L, + [Define to enforce IEEE 1003.1-2001 (POSIX:2001) compliance.]) + AC_DEFINE([_XOPEN_SOURCE], 600, + [Define to enforce X/Open 6 (XSI) compliance.]) + AC_DEFINE([_REENTRANT], 1, + [Define to enable reentrant interfaces.]) + AC_DEFINE([_THREAD_SAFE], 1, + [Define to enable reentrant interfaces.]) + + for flag in -std=c99 -pedantic; do + AC_MSG_CHECKING([whether $CC accepts $flag]) + + if test_cc_flags $flag; then + CFLAGS="$CFLAGS $flag" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + done +fi + +dnl Hardening (see e.g. http://wiki.debian.org/Hardening for a motivation). +AC_DEFINE([_FORTIFY_SOURCE], 2, + [Define to enable protection against static sized buffer overflows.]) +AC_ARG_ENABLE([hardening], + AS_HELP_STRING([--disable-hardening], + [hardening options @<:@default=yes@:>@]), + [enable_hardening="$enableval"], + [enable_hardening="yes"]) + +if test "x$enable_hardening" = "xyes"; then + hardening=0 + hardening_tests=0 + for flag in -Wformat -Wformat-security; do + hardening_tests=$(($hardening_tests + 1)) + AC_MSG_CHECKING([whether $CC accepts $flag]) + + if test_cc_flags $flag; then + CFLAGS="$CFLAGS $flag" + hardening=$(($hardening + 1)) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + done + if test $hardening -ne $hardening_tests; then + AC_MSG_WARN( + [Some hardening options are not supported by your compiler!]) + fi +fi + +dnl Strict checking for potential problems. +AC_ARG_ENABLE([strict-checks], + AS_HELP_STRING([--disable-strict-checks], + [strict compiler checks @<:@default=yes@:>@]), + [enable_strict_checks="$enableval"], + [enable_strict_checks="yes"]) + +STRICT_CFLAGS="" +for flag in -Wall -Werror; do + AC_MSG_CHECKING([whether $CC accepts $flag]) + + if test_cc_flags $flag; then + STRICT_CFLAGS="$STRICT_CFLAGS $flag" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi +done + +if test "x$enable_strict_checks" = "xyes"; then + for flag in -Wextra \ + -Wbad-function-cast \ + -Wcast-align \ + -Wcast-qual \ + -Wconversion \ + -Wdeclaration-after-statement \ + -Wmissing-prototypes \ + -Wpointer-arith \ + -Wshadow \ + -Wstrict-prototypes \ + -Wunreachable-code; do + AC_MSG_CHECKING([whether $CC accepts $flag]) + + if test_cc_flags $flag; then + STRICT_CFLAGS="$STRICT_CFLAGS $flag" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + done +fi +AC_SUBST([STRICT_CFLAGS]) + +AC_CHECK_HEADERS(libgen.h) + +dnl Check for dependencies. +build_documentation="yes" + +have_xsltproc="yes" +AC_PATH_PROG([XSLTPROC], [xsltproc]) +if test "x$XSLTPROC" = "x"; then + have_xsltproc="no" + build_documentation="no (missing xsltproc)" +fi + +have_a2x="yes" +AC_PATH_PROG([A2X], [a2x]) +if test "x$A2X" = "x"; then + have_a2x="no" + build_documentation="no (missing a2x)" +fi +AC_SUBST([A2X]) + +m4_divert_once([HELP_ENABLE], [ +Backends:]) + +AC_SC_PLUGIN_INIT +AC_SC_PLUGIN([collectd], [yes], + [backend accessing the system statistics collection daemon]) + +AM_CONDITIONAL([BUILD_DOCUMENTATION], test "x$build_documentation" = "xyes") + +AC_CONFIG_FILES([Makefile doc/Makefile src/Makefile + src/liboconfig/Makefile]) +AC_OUTPUT + +BUILD_DATE="`date --utc '+%F %T'` (UTC)" + +AC_MSG_RESULT() +AC_MSG_RESULT([$PACKAGE_NAME has been configured successfully.]) +AC_MSG_RESULT() +AC_MSG_RESULT([Run 'make' to compile the software and use 'make install' to]) +AC_MSG_RESULT([install the package into $prefix.]) +AC_MSG_RESULT() +AC_MSG_RESULT([Configuration summary:]) +AC_MSG_RESULT() +AC_MSG_RESULT([ package version: $PACKAGE_VERSION]) +AC_MSG_RESULT([ build date: $BUILD_DATE]) +AC_MSG_RESULT() +AC_MSG_RESULT([ Tools:]) +AC_MSG_RESULT([ AsciiDoc (a2x): . . . . . . $have_a2x]) +AC_MSG_RESULT([ xsltproc: . . . . . . . . . $have_xsltproc]) +AC_MSG_RESULT() +AC_MSG_RESULT([ Features:]) +AC_MSG_RESULT([ documentation: . . . . . . $build_documentation]) +AC_MSG_RESULT() +AC_MSG_RESULT([ Backends:]) +AC_MSG_RESULT([ collectd: . . . . . . . . . $enable_collectd]) +AC_MSG_RESULT() +AC_MSG_RESULT([This package is maintained by $PACKAGE_MAINTAINER.]) +AC_MSG_RESULT([Please report bugs to $PACKAGE_BUGREPORT.]) +AC_MSG_RESULT() + diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..b658384 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,13 @@ +EXTRA_DIST = syscollectord.1.txt +CLEANFILES = syscollectord.1 + +man_MANS = syscollectord.1 + +syscollectord.1: syscollectord.1.txt ../version + +%.1: %.1.txt + @A2X@ -d manpage -f manpage \ + -apackage_version=$(PACKAGE_VERSION) \ + -abuild_date="$$( date --utc '+%F' )" \ + $< + diff --git a/doc/syscollectord.1.txt b/doc/syscollectord.1.txt new file mode 100644 index 0000000..70b1b38 --- /dev/null +++ b/doc/syscollectord.1.txt @@ -0,0 +1,71 @@ +syscollectord(1) +================ +Sebastian "tokkee" Harl +version {package_version}, {build_date} +:doctype: manpage + +NAME +---- +syscollectord - system management collection service + +SYNOPSIS +-------- +*syscollectord* ['options'] + +DESCRIPTION +----------- +*syscollectord* is a multi-backend system management and inventory collection +daemon. It may be used to collect information from various backends (e.g., +inventory services, monitoring services, configuration services) and provides +a uniform combined view of all data. + +The main daemon itself is the central instance managing all collected +information and doing the correlation of objects provided by different +backends. It can be thought of as a database server. All data retrieval, +any further processing, storing and exporting of data is done by plugins. + +OPTIONS +------- +*syscollectord* accepts the following command-line options. + +*-C* '':: + The main configuration file. This file defines the behavior of + *syscollectord* by specifying default settings and the plugins to be + loaded. + +*-d*:: + Daemonize on startup: Start *syscollectord* as a background process + detached from the current terminal and session. + +*-h*:: + Display a usage and help summary and exit. + +*-V*:: + Display the version number and copyright information. + +EXIT CODES +---------- +*0*:: + Success. + +*1*:: + Failure (syntax or usage error). + +BUGS +---- +None known. + +AUTHOR +------ +syscollectord was written by Sebastian "tokkee" Harl . + +COPYRIGHT +--------- +Copyright (C) 2012 Sebastian "tokkee" Harl + +This is free software under the terms of the BSD license, see the source for +copying conditions. There is NO WARRANTY; not even for MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. + +// vim: set tw=78 sw=4 ts=4 noexpandtab spell spelllang=en_us : + diff --git a/m4/sc_plugin.m4 b/m4/sc_plugin.m4 new file mode 100644 index 0000000..bd55725 --- /dev/null +++ b/m4/sc_plugin.m4 @@ -0,0 +1,85 @@ +dnl Autoconf helper functions for the syscollector plugin handling. +dnl +dnl Copyright (C) 2005-2012 Florian 'octo' Forster +dnl Copyright (C) 2009-2012 Sebastian 'tokkee' Harl +dnl +dnl This program is free software; you can redistribute it and/or modify it +dnl under the terms of the GNU General Public License as published by the +dnl Free Software Foundation; only version 2 of the License is applicable. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License along +dnl with this program; if not, write to the Free Software Foundation, Inc., +dnl 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +AC_DEFUN([AC_SC_PLUGIN_INIT], + [ + dependency_error="no" + dependency_warning="no" + AC_ARG_ENABLE([all-plugins], + AS_HELP_STRING([--enable-all-plugins], + [enable all plugins (auto by default)]), + [ + if test "x$enableval" = "xyes"; then + enable_all_plugins="yes" + else if test "x$enableval" = "xauto"; then + enable_all_plugins="auto" + else + enable_all_plugins="no" + fi; fi + ], + [enable_all_plugins="auto"] + ) + ] +) + +dnl AC_SC_PLUGIN(name, default, info) +dnl +dnl Based on AC_PLUGIN of the collectd package. +AC_DEFUN([AC_SC_PLUGIN], + [ + enable_plugin="no" + force="no" + AC_ARG_ENABLE([$1], AS_HELP_STRING([--enable-$1], [$3]), + [ + if test "x$enableval" = "xyes"; then + enable_plugin="yes" + else if test "x$enableval" = "xforce"; then + enable_plugin="yes" + force="yes" + else + enable_plugin="no (disabled on command line)" + fi; fi + ], + [ + if test "x$enable_all_plugins" = "xauto"; then + if test "x$2" = "xyes"; then + enable_plugin="yes" + else + enable_plugin="no" + fi + else + enable_plugin="$enable_all_plugins" + fi + ] + ) + if test "x$enable_plugin" = "xyes"; then + if test "x$2" = "xyes" || test "x$force" = "xyes"; then + AC_DEFINE([HAVE_PLUGIN_]m4_toupper([$1]), 1, [Define to 1 if the $1 plugin is enabled.]) + if test "x$2" != "xyes"; then + dependency_warning="yes" + fi + else # User passed "yes" but dependency checking yielded "no" => Dependency problem. + dependency_error="yes" + enable_plugin="no (dependency error)" + fi + fi + AM_CONDITIONAL([BUILD_PLUGIN_]m4_toupper([$1]), test "x$enable_plugin" = "xyes") + enable_$1="$enable_plugin" + ] +) + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..b2816eb --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,74 @@ +SUBDIRS = liboconfig + +AM_CFLAGS = @STRICT_CFLAGS@ -Iinclude +AM_CPPFLAGS = -DSYSCONFDIR='"${sysconfdir}"' +AM_CPPFLAGS += -DPKGLIBDIR='"${pkglibdir}"' + +BUILT_SOURCES = include/syscollector.h + +pkginclude_HEADERS = include/syscollector.h +pkgcoreincludedir = $(pkgincludedir)/core +pkgcoreinclude_HEADERS = \ + include/core/object.h \ + include/core/plugin.h +pkgutilsincludedir = $(pkgincludedir)/utils +pkgutilsinclude_HEADERS = \ + include/utils/llist.h \ + include/utils/string.h + +lib_LTLIBRARIES = libsyscollector.la + +libsyscollector_la_SOURCES = \ + syscollector.c include/syscollector.h \ + core/object.c include/core/object.h \ + core/plugin.c include/core/plugin.h \ + core/store.c include/core/store.h \ + utils/llist.c include/utils/llist.h \ + utils/string.c include/utils/string.h \ + utils/time.c include/utils/time.h \ + utils/unixsock.c include/utils/unixsock.h +libsyscollector_la_CFLAGS = $(AM_CFLAGS) +libsyscollector_la_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) +libsyscollector_la_LDFLAGS = -version-info 0:0:0 -pthread +libsyscollector_la_LIBADD = $(LIBLTDL) -lrt liboconfig/liboconfig.la +libsyscollector_la_DEPENDENCIES = liboconfig/liboconfig.la + +bin_PROGRAMS = syscollectord + +syscollectord_SOURCES = daemon/syscollectord.c include/syscollector.h \ + daemon/config.c include/daemon/config.h +syscollectord_CFLAGS = $(AM_CFLAGS) -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" +syscollectord_LDADD = libsyscollector.la liboconfig/liboconfig.la +syscollectord_DEPENDENCIES = liboconfig/liboconfig.la + +pkgbackendlibdir = $(pkglibdir)/backend + +pkgbackendlib_LTLIBRARIES = + +if BUILD_PLUGIN_COLLECTD +pkgbackendlib_LTLIBRARIES += backend/collectd.la +backend_collectd_la_SOURCES = backend/collectd.c +backend_collectd_la_LDFLAGS = -module -avoid-version +libsyscollector_la_LIBADD += -dlopen backend/collectd.la +libsyscollector_la_DEPENDENCIES += backend/collectd.la +endif + +include/syscollector.h: include/syscollector.h.in ../version + source ../version; sed \ + -e "s/@SC_VERSION_MAJOR@/$$VERSION_MAJOR/g" \ + -e "s/@SC_VERSION_MINOR@/$$VERSION_MINOR/g" \ + -e "s/@SC_VERSION_PATCH@/$$VERSION_PATCH/g" \ + -e "s/@SC_VERSION_EXTRA@/$$VERSION_EXTRA/g" \ + -e "s/@SC_VERSION_STRING@/$$VERSION_STRING/g" \ + include/syscollector.h.in > include/syscollector.h + +install-exec-hook: + $(mkinstalldirs) $(DESTDIR)$(sysconfdir)/syscollector + if test -e $(DESTDIR)$(sysconfdir)/syscollector/syscollectord.conf; then \ + $(INSTALL) -m 0640 daemon/syscollectord.conf \ + $(DESTDIR)$(sysconfdir)/syscollector/syscollectord.conf.pkg-orig; \ + else \ + $(INSTALL) -m 0640 daemon/syscollectord.conf \ + $(DESTDIR)$(sysconfdir)/syscollector/syscollectord.conf; \ + fi + diff --git a/src/backend/collectd.c b/src/backend/collectd.c new file mode 100644 index 0000000..ad5cad1 --- /dev/null +++ b/src/backend/collectd.c @@ -0,0 +1,388 @@ +/* + * syscollector - src/backend/collectd.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "syscollector.h" +#include "core/plugin.h" +#include "core/store.h" +#include "utils/string.h" +#include "utils/unixsock.h" + +#include "liboconfig/utils.h" + +#include + +#include + +#include +#include +#include + +SC_PLUGIN_MAGIC; + +/* + * private helper functions + */ + +static int +sc_collectd_parse_value(char *line, + sc_time_t *timestamp, char **host, char **svc) +{ + char *timestamp_str; + double timestamp_dbl; + + char *hostname, *service; + + char *endptr = NULL; + + timestamp_str = line; + hostname = strchr(timestamp_str, ' '); + + if (! hostname) { + fprintf(stderr, "collectd backend: Failed to find hostname " + "in LISTVAL output, line: %s\n", line); + return -1; + } + + *hostname = '\0'; + ++hostname; + + service = strchr(hostname, '/'); + + if (! service) + fprintf(stderr, "collectd backend: Failed to find service name " + "in LISTVAL output, line: %s\n", line); + else { + *service = '\0'; + ++service; + } + + errno = 0; + timestamp_dbl = strtod(timestamp_str, &endptr); + if (errno || (timestamp_str == endptr)) { + char errbuf[1024]; + fprintf(stderr, "collectd backend: Failed to " + "parse timestamp (%s): %s\n", timestamp_str, + sc_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + if (endptr && (*endptr != '\0')) + fprintf(stderr, "collectd backend: Ignoring garbage " + "after number when parsing timestamp: %s.\n", + endptr); + + *timestamp = DOUBLE_TO_SC_TIME(timestamp_dbl); + *host = hostname; + *svc = service; + return 0; +} /* sc_collectd_parse_value */ + +static int +sc_collectd_add_host(char *hostname, sc_time_t last_update) +{ + sc_host_t host = SC_HOST_INIT; + + host.host_name = hostname; + host.host_last_update = last_update; + + if (sc_store_host(&host)) { + fprintf(stderr, "collectd backend: Failed to store/update " + "host '%s'.\n", hostname); + return -1; + } + + fprintf(stderr, "collectd backend: Added/updated host '%s' " + "(last update timestamp = %"PRIscTIME").\n", + hostname, last_update); + return 0; +} /* sc_collectd_add_host */ + +static int +sc_collectd_add_svc(char *hostname, char *name, sc_time_t last_update) +{ + sc_service_t svc = SC_SVC_INIT; + + svc.hostname = hostname; + svc.svc_name = name; + svc.svc_last_update = last_update; + + if (sc_store_service(&svc)) { + fprintf(stderr, "collectd backend: Failed to store/update " + "service '%s/%s'.\n", hostname, name); + return -1; + } + return 0; +} /* sc_collectd_add_svc */ + +/* + * plugin API + */ + +static int +sc_collectd_init(sc_object_t *user_data) +{ + sc_unixsock_client_t *client; + + if (! user_data) + return -1; + + client = SC_OBJ_WRAPPER(user_data)->data; + if (sc_unixsock_client_connect(client)) { + fprintf(stderr, "collectd backend: " + "Failed to connect to collectd.\n"); + return -1; + } + + fprintf(stderr, "collectd backend: Successfully " + "connected to collectd @ %s.\n", + sc_unixsock_client_path(client)); + return 0; +} /* sc_collectd_init */ + +static int +sc_collectd_shutdown(__attribute__((unused)) sc_object_t *user_data) +{ + return 0; +} /* sc_collectd_shutdown */ + +static int +sc_collectd_collect(sc_object_t *user_data) +{ + sc_unixsock_client_t *client; + + char buffer[1024]; + char *line; + char *msg; + + char *endptr = NULL; + long int count, i; + + char *current_host = NULL; + sc_time_t current_timestamp = 0; + + int svc_updated = 0; + int svc_failed = 0; + + if (! user_data) + return -1; + + client = SC_OBJ_WRAPPER(user_data)->data; + + if (sc_unixsock_client_send(client, "LISTVAL") <= 0) { + fprintf(stderr, "collectd backend: Failed to send LISTVAL command " + "to collectd @ %s.\n", sc_unixsock_client_path(client)); + return -1; + } + + line = sc_unixsock_client_recv(client, buffer, sizeof(buffer)); + if (! line) { + fprintf(stderr, "collectd backend: Failed to read status " + "of LISTVAL command from collectd @ %s.\n", + sc_unixsock_client_path(client)); + return -1; + } + + msg = strchr(line, ' '); + if (msg) { + *msg = '\0'; + ++msg; + } + + errno = 0; + count = strtol(line, &endptr, /* base */ 0); + if (errno || (line == endptr)) { + fprintf(stderr, "collectd backend: Failed to parse status " + "of LISTVAL command from collectd @ %s.\n", + sc_unixsock_client_path(client)); + return -1; + } + + if (count < 0) { + fprintf(stderr, "collectd backend: Failed to get value list " + "from collectd @ %s: %s\n", sc_unixsock_client_path(client), + msg ? msg : line); + return -1; + } + + for (i = 0; i < count; ++i) { + char *hostname = NULL, *service = NULL; + sc_time_t last_update = 0; + + line = sc_unixsock_client_recv(client, buffer, sizeof(buffer)); + + if (sc_collectd_parse_value(line, &last_update, &hostname, &service)) + continue; + + if (! current_host) + current_host = strdup(hostname); + if (! current_host) { + char errbuf[1024]; + fprintf(stderr, "collectd backend: Failed to allocate " + "string buffer: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + + if (! sc_store_get_host(hostname)) + sc_collectd_add_host(hostname, last_update); + + if (sc_collectd_add_svc(hostname, service, last_update)) + ++svc_failed; + else + ++svc_updated; + + assert(hostname && service); + if (! strcasecmp(current_host, hostname)) { + if (last_update > current_timestamp) + current_timestamp = last_update; + continue; + } + + /* new host */ + sc_collectd_add_host(current_host, current_timestamp); + + fprintf(stderr, "collectd backend: Added/updated " + "%i service%s (%i failed) for host '%s'.\n", + svc_updated, svc_updated == 1 ? "" : "s", + svc_failed, current_host); + svc_updated = svc_failed = 0; + + free(current_host); + current_host = strdup(hostname); + current_timestamp = last_update; + } + + if (current_host) { + sc_collectd_add_host(current_host, current_timestamp); + fprintf(stderr, "collectd backend: Added/updated " + "%i service%s (%i failed) for host '%s'.\n", + svc_updated, svc_updated == 1 ? "" : "s", + svc_failed, current_host); + } + return 0; +} /* sc_collectd_collect */ + +static int +sc_collectd_config_instance(oconfig_item_t *ci) +{ + char *name = NULL; + char *socket = NULL; + + char cb_name[1024]; + + sc_object_t *user_data; + sc_unixsock_client_t *client; + + int i; + + if (oconfig_get_string(ci, &name)) { + fprintf(stderr, "collectd backend: Instance requires a single " + "string argument\n\tUsage: \n"); + return -1; + } + + for (i = 0; i < ci->children_num; ++i) { + oconfig_item_t *child = ci->children + i; + + if (! strcasecmp(child->key, "Socket")) + oconfig_get_string(child, &socket); + else + fprintf(stderr, "collectd backend: Ignoring unknown config " + "option '%s' inside .\n", + child->key, name); + } + + if (! socket) { + fprintf(stderr, "collectd backend: Instance '%s' missing " + "the 'Socket' option.\n", name); + return -1; + } + + snprintf(cb_name, sizeof(cb_name), "collectd-%s", name); + cb_name[sizeof(cb_name) - 1] = '\0'; + + client = sc_unixsock_client_create(socket); + if (! client) { + char errbuf[1024]; + fprintf(stderr, "collectd backend: Failed to create unixsock client: " + "%s\n", sc_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + + user_data = sc_object_create_wrapper(client, + (void (*)(void *))sc_unixsock_client_destroy); + if (! user_data) { + sc_unixsock_client_destroy(client); + fprintf(stderr, "collectd backend: Failed to allocate sc_object_t\n"); + return -1; + } + + sc_plugin_register_init(cb_name, sc_collectd_init, user_data); + sc_plugin_register_shutdown(cb_name, sc_collectd_shutdown, user_data); + + sc_plugin_register_collector(cb_name, sc_collectd_collect, + /* interval */ NULL, user_data); + + /* pass control to the list */ + sc_object_deref(user_data); + return 0; +} /* sc_collectd_config_instance */ + +static int +sc_collectd_config(oconfig_item_t *ci) +{ + int i; + + for (i = 0; i < ci->children_num; ++i) { + oconfig_item_t *child = ci->children + i; + + if (! strcasecmp(child->key, "Instance")) + sc_collectd_config_instance(child); + else + fprintf(stderr, "collectd backend: Ignoring unknown config " + "option '%s'.\n", child->key); + } + return 0; +} /* sc_collectd_config */ + +int +sc_module_init(sc_plugin_info_t *info) +{ + sc_plugin_set_info(info, SC_PLUGIN_INFO_NAME, "collectd"); + sc_plugin_set_info(info, SC_PLUGIN_INFO_DESC, + "backend accessing the system statistics collection daemon"); + sc_plugin_set_info(info, SC_PLUGIN_INFO_COPYRIGHT, + "Copyright (C) 2012 Sebastian 'tokkee' Harl "); + sc_plugin_set_info(info, SC_PLUGIN_INFO_LICENSE, "BSD"); + sc_plugin_set_info(info, SC_PLUGIN_INFO_VERSION, SC_VERSION); + sc_plugin_set_info(info, SC_PLUGIN_INFO_PLUGIN_VERSION, SC_VERSION); + + sc_plugin_register_config("collectd", sc_collectd_config); + return 0; +} /* sc_version_extra */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/core/object.c b/src/core/object.c new file mode 100644 index 0000000..711607a --- /dev/null +++ b/src/core/object.c @@ -0,0 +1,134 @@ +/* + * syscollector - src/core/object.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "core/object.h" + +#include + +#include +#include + +/* + * private helper functions + */ + +static int +sc_object_wrapper_init(sc_object_t *obj, va_list ap) +{ + void *data = va_arg(ap, void *); + void (*destructor)(void *) = va_arg(ap, void (*)(void *)); + + assert(obj); + + SC_OBJ_WRAPPER(obj)->data = data; + SC_OBJ_WRAPPER(obj)->destructor = destructor; + return 0; +} /* sc_object_wrapper_init */ + +static void +sc_object_wrapper_destroy(sc_object_t *obj) +{ + if (! obj) + return; + + assert(obj->ref_cnt <= 0); + + if (SC_OBJ_WRAPPER(obj)->destructor && SC_OBJ_WRAPPER(obj)->data) + SC_OBJ_WRAPPER(obj)->destructor(SC_OBJ_WRAPPER(obj)->data); + SC_OBJ_WRAPPER(obj)->data = NULL; +} /* sc_object_wrapper_destroy */ + +/* + * public API + */ + +sc_object_t * +sc_object_create(size_t size, int (*init)(sc_object_t *, va_list), + void (*destructor)(sc_object_t *), ...) +{ + sc_object_t *obj; + + obj = malloc(size); + if (! obj) + return NULL; + memset(obj, 0, sizeof(*obj)); + + if (init) { + va_list ap; + va_start(ap, destructor); + + if (init(obj, ap)) { + obj->ref_cnt = 1; + sc_object_deref(obj); + va_end(ap); + return NULL; + } + + va_end(ap); + } + + obj->ref_cnt = 1; + obj->destructor = destructor; + obj->size = size; + return obj; +} /* sc_object_create */ + +sc_object_t * +sc_object_create_wrapper(void *data, void (*destructor)(void *)) +{ + return sc_object_create(sizeof(sc_object_wrapper_t), + sc_object_wrapper_init, sc_object_wrapper_destroy, + data, destructor); +} /* sc_object_create_wrapper */ + +void +sc_object_deref(sc_object_t *obj) +{ + if (! obj) + return; + + --obj->ref_cnt; + if (obj->ref_cnt > 0) + return; + + if (obj->destructor) + obj->destructor(obj); + + free(obj); +} /* sc_object_deref */ + +void +sc_object_ref(sc_object_t *obj) +{ + if (! obj) + return; + assert(obj->ref_cnt > 0); + ++obj->ref_cnt; +} /* sc_object_ref */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/core/plugin.c b/src/core/plugin.c new file mode 100644 index 0000000..a4c8c2d --- /dev/null +++ b/src/core/plugin.c @@ -0,0 +1,637 @@ +/* + * syscollector - src/core/plugin.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "syscollector.h" +#include "core/plugin.h" +#include "utils/llist.h" +#include "utils/string.h" +#include "utils/time.h" + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +/* + * private data types + */ + +struct sc_plugin_info { + char *name; + + char *description; + char *copyright; + char *license; + + int version; + int plugin_version; +}; +#define SC_PLUGIN_INFO_INIT { "no name set", "no description set", \ + /* copyright */ "", /* license */ "", \ + /* version */ -1, /* plugin_version */ -1 } + +typedef struct { + sc_object_t super; + char cb_name[64]; + void *cb_callback; + sc_object_t *cb_user_data; + sc_plugin_ctx_t cb_ctx; +} sc_plugin_cb_t; +#define SC_PLUGIN_CB_INIT { SC_OBJECT_INIT, "", NULL, NULL, SC_PLUGIN_CTX_INIT } + +typedef struct { + sc_plugin_cb_t super; +#define ccb_name super.cb_name +#define ccb_callback super.cb_callback +#define ccb_user_data super.cb_user_data +#define ccb_ctx super.cb_ctx + sc_time_t ccb_interval; + sc_time_t ccb_next_update; +} sc_plugin_collector_cb_t; + +#define SC_PLUGIN_CB(obj) ((sc_plugin_cb_t *)(obj)) +#define SC_PLUGIN_CCB(obj) ((sc_plugin_collector_cb_t *)(obj)) + +/* + * private variables + */ + +static sc_plugin_ctx_t plugin_default_ctx = SC_PLUGIN_CTX_INIT; + +static pthread_key_t plugin_ctx_key; +static _Bool plugin_ctx_key_initialized = 0; + +static sc_llist_t *config_list = NULL; +static sc_llist_t *init_list = NULL; +static sc_llist_t *collector_list = NULL; +static sc_llist_t *shutdown_list = NULL; + +/* + * private helper functions + */ + +static void +sc_plugin_ctx_destructor(void *ctx) +{ + if (! ctx) + return; + free(ctx); +} /* sc_plugin_ctx_destructor */ + +static void +sc_plugin_ctx_init(void) +{ + if (plugin_ctx_key_initialized) + return; + + pthread_key_create(&plugin_ctx_key, sc_plugin_ctx_destructor); + plugin_ctx_key_initialized = 1; +} /* sc_plugin_ctx_init */ + +static sc_plugin_ctx_t * +sc_plugin_ctx_create(void) +{ + sc_plugin_ctx_t *ctx; + + ctx = malloc(sizeof(*ctx)); + if (! ctx) + return NULL; + + *ctx = plugin_default_ctx; + + if (! plugin_ctx_key_initialized) + sc_plugin_ctx_init(); + pthread_setspecific(plugin_ctx_key, ctx); + return ctx; +} /* sc_plugin_ctx_create */ + +static int +sc_plugin_cmp_name(const sc_object_t *a, const sc_object_t *b) +{ + const sc_plugin_cb_t *cb1 = (const sc_plugin_cb_t *)a; + const sc_plugin_cb_t *cb2 = (const sc_plugin_cb_t *)b; + + assert(cb1 && cb2); + return strcasecmp(cb1->cb_name, cb2->cb_name); +} /* sc_plugin_cmp_name */ + +static int +sc_plugin_cmp_next_update(const sc_object_t *a, const sc_object_t *b) +{ + const sc_plugin_collector_cb_t *ccb1 + = (const sc_plugin_collector_cb_t *)a; + const sc_plugin_collector_cb_t *ccb2 + = (const sc_plugin_collector_cb_t *)b; + + assert(ccb1 && ccb2); + + return (ccb1->ccb_next_update > ccb2->ccb_next_update) + ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update) + ? -1 : 0; +} /* sc_plugin_cmp_next_update */ + +static sc_plugin_cb_t * +sc_plugin_find_by_name(sc_llist_t *list, const char *name) +{ + sc_plugin_cb_t tmp = SC_PLUGIN_CB_INIT; + + sc_object_t *obj; + assert(name); + + if (! list) + return NULL; + + snprintf(tmp.cb_name, sizeof(tmp.cb_name), "%s", name); + tmp.cb_name[sizeof(tmp.cb_name) - 1] = '\0'; + obj = sc_llist_search(list, SC_OBJ(&tmp), sc_plugin_cmp_name); + if (! obj) + return NULL; + return SC_PLUGIN_CB(obj); +} /* sc_plugin_find_by_name */ + +static int +sc_plugin_cb_init(sc_object_t *obj, va_list ap) +{ + sc_llist_t **list = va_arg(ap, sc_llist_t **); + const char *type = va_arg(ap, const char *); + const char *name = va_arg(ap, const char *); + void *callback = va_arg(ap, void *); + sc_object_t *ud = va_arg(ap, sc_object_t *); + + assert(list); + assert(type); + assert(obj); + + if (sc_plugin_find_by_name(*list, name)) { + fprintf(stderr, "plugin: %s callback '%s' has already been " + "registered. Ignoring newly registered version.\n", + type, name); + return -1; + } + + snprintf(SC_PLUGIN_CB(obj)->cb_name, + sizeof(SC_PLUGIN_CB(obj)->cb_name), + "%s", name); + SC_PLUGIN_CB(obj)->cb_name[sizeof(SC_PLUGIN_CB(obj)->cb_name) - 1] = '\0'; + SC_PLUGIN_CB(obj)->cb_callback = callback; + SC_PLUGIN_CB(obj)->cb_ctx = sc_plugin_get_ctx(); + + sc_object_ref(ud); + SC_PLUGIN_CB(obj)->cb_user_data = ud; + return 0; +} /* sc_plugin_cb_init */ + +static void +sc_plugin_cb_destroy(sc_object_t *obj) +{ + assert(obj); + sc_object_deref(SC_PLUGIN_CB(obj)->cb_user_data); +} /* sc_plugin_cb_destroy */ + +static int +sc_plugin_add_callback(sc_llist_t **list, const char *type, + const char *name, void *callback, sc_object_t *user_data) +{ + sc_object_t *obj; + + if ((! name) || (! callback)) + return -1; + + assert(list); + + if (! *list) + *list = sc_llist_create(); + if (! *list) + return -1; + + obj = sc_object_create(sizeof(sc_plugin_cb_t), sc_plugin_cb_init, + sc_plugin_cb_destroy, list, type, name, callback, user_data); + if (! obj) + return -1; + + if (sc_llist_append(*list, obj)) { + sc_object_deref(obj); + return -1; + } + + /* pass control to the list */ + sc_object_deref(obj); + + fprintf(stderr, "plugin: Registered %s callback '%s'.\n", type, name); + return 0; +} /* sc_plugin_add_callback */ + +/* + * public API + */ + +int +sc_plugin_load(const char *name) +{ + char filename[1024]; + + lt_dlhandle lh; + + int (*mod_init)(sc_plugin_info_t *); + sc_plugin_info_t plugin_info = SC_PLUGIN_INFO_INIT; + + int status; + + snprintf(filename, sizeof(filename), "%s/%s.so", + PKGLIBDIR, name); + filename[sizeof(filename) - 1] = '\0'; + + if (access(filename, R_OK)) { + char errbuf[1024]; + fprintf(stderr, "plugin: Failed to load plugin '%s': %s\n", + name, sc_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + + lt_dlinit(); + lt_dlerror(); + + lh = lt_dlopen(filename); + if (! lh) { + fprintf(stderr, "plugin: Failed to load plugin '%s': %s\n" + "The most common cause for this problem are missing " + "dependencies.\n", name, lt_dlerror()); + return -1; + } + + mod_init = (int (*)(sc_plugin_info_t *))lt_dlsym(lh, "sc_module_init"); + if (! mod_init) { + fprintf(stderr, "plugin: Failed to load plugin '%s': " + "could not find symbol 'sc_module_init'\n", name); + return -1; + } + + status = mod_init(&plugin_info); + if (status) { + fprintf(stderr, "plugin: Failed to initialize plugin '%s'\n", name); + return -1; + } + + /* compare minor version */ + if ((plugin_info.version < 0) + || ((int)(plugin_info.version / 100) != (int)(SC_VERSION / 100))) + fprintf(stderr, "plugin: WARNING: version of plugin '%s' (%i.%i.%i) " + "does not match our version (%i.%i.%i); " + "this might cause problems\n", + name, SC_VERSION_DECODE(plugin_info.version), + SC_VERSION_DECODE(SC_VERSION)); + + fprintf(stderr, "plugin: Successfully loaded " + "plugin '%s' v%i (%s)\n\t%s\n", + plugin_info.name, plugin_info.plugin_version, + plugin_info.description, plugin_info.copyright); + return 0; +} /* sc_plugin_load */ + +int +sc_plugin_set_info(sc_plugin_info_t *info, int type, ...) +{ + va_list ap; + + if (! info) + return -1; + + va_start(ap, type); + + switch (type) { + case SC_PLUGIN_INFO_NAME: + { + char *name = va_arg(ap, char *); + info->name = name; + } + break; + case SC_PLUGIN_INFO_DESC: + { + char *desc = va_arg(ap, char *); + info->description = desc; + } + break; + case SC_PLUGIN_INFO_COPYRIGHT: + { + char *copyright = va_arg(ap, char *); + info->copyright = copyright; + } + break; + case SC_PLUGIN_INFO_LICENSE: + { + char *license = va_arg(ap, char *); + info->license = license; + } + break; + case SC_PLUGIN_INFO_VERSION: + { + int version = va_arg(ap, int); + info->version = version; + } + break; + case SC_PLUGIN_INFO_PLUGIN_VERSION: + { + int version = va_arg(ap, int); + info->plugin_version = version; + } + break; + default: + va_end(ap); + return -1; + } + + va_end(ap); + return 0; +} /* sc_plugin_set_info */ + +int +sc_plugin_register_config(const char *name, sc_plugin_config_cb callback) +{ + return sc_plugin_add_callback(&config_list, "init", name, + callback, NULL); +} /* sc_plugin_register_config */ + +int +sc_plugin_register_init(const char *name, sc_plugin_init_cb callback, + sc_object_t *user_data) +{ + return sc_plugin_add_callback(&init_list, "init", name, + callback, user_data); +} /* sc_plugin_register_init */ + +int +sc_plugin_register_shutdown(const char *name, sc_plugin_shutdown_cb callback, + sc_object_t *user_data) +{ + return sc_plugin_add_callback(&shutdown_list, "shutdown", name, + callback, user_data); +} /* sc_plugin_register_shutdown */ + +int +sc_plugin_register_collector(const char *name, sc_plugin_collector_cb callback, + const sc_time_t *interval, sc_object_t *user_data) +{ + sc_object_t *obj; + + if ((! name) || (! callback)) + return -1; + + if (! collector_list) + collector_list = sc_llist_create(); + if (! collector_list) + return -1; + + obj = sc_object_create(sizeof(sc_plugin_collector_cb_t), + sc_plugin_cb_init, sc_plugin_cb_destroy, + &collector_list, "collector", name, callback, user_data); + if (! obj) + return -1; + + if (interval) + SC_PLUGIN_CCB(obj)->ccb_interval = *interval; + else { + sc_time_t tmp = sc_plugin_get_ctx().interval; + + if (tmp > 0) + SC_PLUGIN_CCB(obj)->ccb_interval = tmp; + else + SC_PLUGIN_CCB(obj)->ccb_interval = 0; + } + + if (! (SC_PLUGIN_CCB(obj)->ccb_next_update = sc_gettime())) { + char errbuf[1024]; + fprintf(stderr, "plugin: Failed to determine current time: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + sc_object_deref(obj); + return -1; + } + + if (sc_llist_insert_sorted(collector_list, obj, + sc_plugin_cmp_next_update)) { + sc_object_deref(obj); + return -1; + } + + /* pass control to the list */ + sc_object_deref(obj); + + fprintf(stderr, "plugin: Registered collector callback '%s' " + "(interval = %.3fs).\n", name, + SC_TIME_TO_DOUBLE(SC_PLUGIN_CCB(obj)->ccb_interval)); + return 0; +} /* sc_plugin_register_collector */ + +sc_plugin_ctx_t +sc_plugin_get_ctx(void) +{ + sc_plugin_ctx_t *ctx; + + if (! plugin_ctx_key_initialized) + sc_plugin_ctx_init(); + ctx = pthread_getspecific(plugin_ctx_key); + + if (! ctx) + ctx = sc_plugin_ctx_create(); + if (! ctx) + return plugin_default_ctx; + return *ctx; +} /* sc_plugin_get_ctx */ + +sc_plugin_ctx_t +sc_plugin_set_ctx(sc_plugin_ctx_t ctx) +{ + sc_plugin_ctx_t *tmp; + sc_plugin_ctx_t old; + + if (! plugin_ctx_key_initialized) + sc_plugin_ctx_init(); + tmp = pthread_getspecific(plugin_ctx_key); + + if (! tmp) + tmp = sc_plugin_ctx_create(); + if (! tmp) + return plugin_default_ctx; + + old = *tmp; + *tmp = ctx; + return old; +} /* sc_plugin_set_ctx */ + +int +sc_plugin_configure(const char *name, oconfig_item_t *ci) +{ + sc_plugin_cb_t *plugin; + sc_plugin_config_cb callback; + + sc_plugin_ctx_t old_ctx; + + int status; + + if ((! name) || (! ci)) + return -1; + + plugin = sc_plugin_find_by_name(config_list, name); + if (! plugin) { + fprintf(stderr, "plugin: Plugin '%s' did not register " + "a config callback.\n", name); + errno = ENOENT; + return -1; + } + + old_ctx = sc_plugin_set_ctx(plugin->cb_ctx); + callback = plugin->cb_callback; + status = callback(ci); + sc_plugin_set_ctx(old_ctx); + return status; +} /* sc_plugin_configure */ + +int +sc_plugin_init_all(void) +{ + sc_llist_iter_t *iter; + + iter = sc_llist_get_iter(init_list); + while (sc_llist_iter_has_next(iter)) { + sc_plugin_init_cb callback; + sc_plugin_ctx_t old_ctx; + + sc_object_t *obj = sc_llist_iter_get_next(iter); + assert(obj); + + callback = SC_PLUGIN_CB(obj)->cb_callback; + + old_ctx = sc_plugin_set_ctx(SC_PLUGIN_CB(obj)->cb_ctx); + if (callback(SC_PLUGIN_CB(obj)->cb_user_data)) { + /* XXX: unload plugin */ + } + sc_plugin_set_ctx(old_ctx); + } + return 0; +} /* sc_plugin_init_all */ + +int +sc_plugin_collector_loop(sc_plugin_loop_t *loop) +{ + if ((! collector_list) || (! loop)) + return -1; + + while (loop->do_loop) { + sc_plugin_collector_cb callback; + sc_plugin_ctx_t old_ctx; + + sc_time_t interval, now; + + sc_object_t *obj = sc_llist_shift(collector_list); + if (! obj) + return -1; + + callback = SC_PLUGIN_CCB(obj)->ccb_callback; + + if (! (now = sc_gettime())) { + char errbuf[1024]; + fprintf(stderr, "plugin: Failed to determine current time: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + now = SC_PLUGIN_CCB(obj)->ccb_next_update; + } + + if (now < SC_PLUGIN_CCB(obj)->ccb_next_update) { + interval = SC_PLUGIN_CCB(obj)->ccb_next_update - now; + + errno = 0; + while (loop->do_loop && sc_sleep(interval, &interval)) { + if (errno != EINTR) { + char errbuf[1024]; + fprintf(stderr, "plugin: Failed to sleep: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + errno = 0; + } + + if (! loop->do_loop) + return 0; + } + + old_ctx = sc_plugin_set_ctx(SC_PLUGIN_CCB(obj)->ccb_ctx); + if (callback(SC_PLUGIN_CCB(obj)->ccb_user_data)) { + /* XXX */ + } + sc_plugin_set_ctx(old_ctx); + + interval = SC_PLUGIN_CCB(obj)->ccb_interval; + if (! interval) + interval = loop->default_interval; + if (! interval) { + fprintf(stderr, "plugin: No interval configured " + "for plugin '%s'; skipping any further " + "iterations.\n", SC_PLUGIN_CCB(obj)->ccb_name); + sc_object_deref(obj); + continue; + } + + SC_PLUGIN_CCB(obj)->ccb_next_update += interval; + + if (! (now = sc_gettime())) { + char errbuf[1024]; + fprintf(stderr, "plugin: Failed to determine current time: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + now = SC_PLUGIN_CCB(obj)->ccb_next_update; + } + + if (now > SC_PLUGIN_CCB(obj)->ccb_next_update) { + fprintf(stderr, "plugin: Plugin '%s' took too long; " + "skipping iterations to keep up.\n", + SC_PLUGIN_CCB(obj)->ccb_name); + SC_PLUGIN_CCB(obj)->ccb_next_update = now; + } + + if (sc_llist_insert_sorted(collector_list, obj, + sc_plugin_cmp_next_update)) { + fprintf(stderr, "plugin: Failed to re-insert " + "plugin '%s' into collector list.\n", + SC_PLUGIN_CCB(obj)->ccb_name); + sc_object_deref(obj); + return -1; + } + + /* pass control back to the list */ + sc_object_deref(obj); + } + return 0; +} /* sc_plugin_read_loop */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/core/store.c b/src/core/store.c new file mode 100644 index 0000000..9528a31 --- /dev/null +++ b/src/core/store.c @@ -0,0 +1,420 @@ +/* + * syscollector - src/core/store.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "syscollector.h" +#include "core/store.h" +#include "utils/llist.h" +#include "utils/string.h" + +#include + +#include + +#include +#include +#include + +#include + +/* + * private variables + */ + +static sc_llist_t *host_list = NULL; +static pthread_rwlock_t host_lock = PTHREAD_RWLOCK_INITIALIZER; + +/* + * private helper functions + */ + +static int +sc_store_obj_cmp_by_name(const sc_object_t *a, const sc_object_t *b) +{ + const sc_store_obj_t *h1 = (const sc_store_obj_t *)a; + const sc_store_obj_t *h2 = (const sc_store_obj_t *)b; + + assert(h1 && h2); + return strcasecmp(h1->name, h2->name); +} /* sc_store_obj_cmp_by_name */ + +static int +sc_host_init(sc_object_t *obj, va_list ap) +{ + char *name = va_arg(ap, char *); + + SC_HOST(obj)->host_name = strdup(name); + if (! SC_HOST(obj)->host_name) + return -1; + + SC_HOST(obj)->host_last_update = sc_gettime(); + /* ignore errors -> last_update will be updated later */ + + SC_HOST(obj)->services = sc_llist_create(); + if (! SC_HOST(obj)->services) + return -1; + return 0; +} /* sc_host_init */ + +static void +sc_host_destroy(sc_object_t *obj) +{ + assert(obj); + + if (SC_HOST(obj)->host_name) + free(SC_HOST(obj)->host_name); + + if (SC_HOST(obj)->services) + sc_llist_destroy(SC_HOST(obj)->services); +} /* sc_host_destroy */ + +static int +sc_svc_init(sc_object_t *obj, va_list ap) +{ + char *hostname = va_arg(ap, char *); + char *name = va_arg(ap, char *); + + SC_SVC(obj)->hostname = strdup(hostname); + SC_SVC(obj)->svc_name = strdup(name); + if ((! SC_SVC(obj)->hostname) || (! SC_SVC(obj)->svc_name)) + return -1; + + SC_SVC(obj)->svc_last_update = sc_gettime(); + /* ignore errors -> last_update will be updated later */ + return 0; +} /* sc_svc_init */ + +static void +sc_svc_destroy(sc_object_t *obj) +{ + assert(obj); + + if (SC_SVC(obj)->hostname) + free(SC_SVC(obj)->hostname); + if (SC_SVC(obj)->svc_name) + free(SC_SVC(obj)->svc_name); +} /* sc_svc_destroy */ + +/* + * public API + */ + +sc_host_t * +sc_host_create(char *name) +{ + sc_object_t *obj; + + if (! name) + return NULL; + + obj = sc_object_create(sizeof(sc_host_t), sc_host_init, + sc_host_destroy, name); + if (! obj) + return NULL; + return SC_HOST(obj); +} /* sc_host_create */ + +sc_host_t * +sc_host_clone(const sc_host_t *host) +{ + sc_host_t *clone; + + clone = sc_host_create(host->host_name); + if (! clone) + return NULL; + + clone->host_last_update = host->host_last_update; + if (host->services) { + clone->services = sc_llist_clone(host->services); + if (! clone->services) { + sc_object_deref(SC_OBJ(clone)); + return NULL; + } + } + else + clone->services = NULL; + return clone; +} /* sc_host_clone */ + +int +sc_store_host(const sc_host_t *host) +{ + sc_time_t last_update; + + sc_host_t *old; + int status = 0; + + if ((! host) || (! host->host_name)) + return -1; + + last_update = host->host_last_update; + if (last_update <= 0) + last_update = sc_gettime(); + + pthread_rwlock_wrlock(&host_lock); + + if (! host_list) { + if (! (host_list = sc_llist_create())) { + pthread_rwlock_unlock(&host_lock); + return -1; + } + } + + old = SC_HOST(sc_llist_search(host_list, (const sc_object_t *)host, + sc_store_obj_cmp_by_name)); + + if (old) { + if (old->host_last_update > last_update) { + fprintf(stderr, "store: Cannot update host '%s' - " + "value too old (%"PRIscTIME" < %"PRIscTIME")\n", + host->host_name, last_update, old->host_last_update); + status = -1; + } + else { + old->host_last_update = last_update; + } + } + else { + sc_host_t *new = sc_host_clone(host); + if (! new) { + char errbuf[1024]; + fprintf(stderr, "store: Failed to clone host object: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + + if (! new->services) { + if (! (new->services = sc_llist_create())) { + char errbuf[1024]; + fprintf(stderr, "store: Failed to initialize " + "host object '%s': %s\n", host->host_name, + sc_strerror(errno, errbuf, sizeof(errbuf))); + sc_object_deref(SC_OBJ(new)); + return -1; + } + } + + status = sc_llist_insert_sorted(host_list, SC_OBJ(new), + sc_store_obj_cmp_by_name); + + /* pass control to the list or destroy in case of an error */ + sc_object_deref(SC_OBJ(new)); + } + + pthread_rwlock_unlock(&host_lock); + return status; +} /* sc_store_host */ + +const sc_host_t * +sc_store_get_host(char *name) +{ + sc_host_t tmp = SC_HOST_INIT; + sc_host_t *host; + + if (! name) + return NULL; + + tmp.host_name = name; + host = SC_HOST(sc_llist_search(host_list, (const sc_object_t *)&tmp, + sc_store_obj_cmp_by_name)); + + if (! host) + return NULL; + return host; +} /* sc_store_get_host */ + +sc_service_t * +sc_service_create(char *hostname, char *name) +{ + sc_object_t *obj; + + if ((! hostname) || (! name)) + return NULL; + + obj = sc_object_create(sizeof(sc_service_t), sc_svc_init, + sc_svc_destroy, hostname, name); + if (! obj) + return NULL; + return SC_SVC(obj); +} /* sc_service_create */ + +sc_service_t * +sc_service_clone(const sc_service_t *svc) +{ + sc_service_t *clone; + + clone = sc_service_create(svc->hostname, svc->svc_name); + if (! clone) + return NULL; + + clone->svc_last_update = svc->svc_last_update; + return clone; +} /* sc_service_clone */ + +int +sc_store_service(const sc_service_t *svc) +{ + sc_host_t tmp = SC_HOST_INIT; + sc_host_t *host; + + sc_service_t *old; + + sc_time_t last_update; + + int status = 0; + + if (! svc) + return -1; + + last_update = svc->svc_last_update; + if (last_update <= 0) + last_update = sc_gettime(); + + if (! host_list) + return -1; + + pthread_rwlock_wrlock(&host_lock); + + tmp.host_name = svc->hostname; + host = SC_HOST(sc_llist_search(host_list, (const sc_object_t *)&tmp, + sc_store_obj_cmp_by_name)); + + if (! host) + return -1; + + old = SC_SVC(sc_llist_search(host->services, (const sc_object_t *)svc, + sc_store_obj_cmp_by_name)); + + if (old) { + if (old->host_last_update > last_update) { + fprintf(stderr, "store: Cannot update service '%s/%s' - " + "value too old (%"PRIscTIME" < %"PRIscTIME")\n", + svc->hostname, svc->svc_name, last_update, + old->host_last_update); + status = -1; + } + else { + old->svc_last_update = last_update; + } + } + else { + sc_service_t *new = sc_service_clone(svc); + if (! new) { + char errbuf[1024]; + fprintf(stderr, "store: Failed to clone service object: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + + status = sc_llist_insert_sorted(host->services, SC_OBJ(new), + sc_store_obj_cmp_by_name); + + /* pass control to the list or destroy in case of an error */ + sc_object_deref(SC_OBJ(new)); + } + + pthread_rwlock_unlock(&host_lock); + return status; +} /* sc_store_service */ + +const sc_service_t * +sc_store_get_service(const sc_host_t *host, char *name) +{ + sc_service_t tmp = SC_SVC_INIT; + sc_service_t *svc; + + if ((! host) || (! name)) + return NULL; + + tmp.svc_name = name; + svc = SC_SVC(sc_llist_search(host->services, (const sc_object_t *)&tmp, + sc_store_obj_cmp_by_name)); + + if (! svc) + return NULL; + return svc; +} /* sc_store_get_service */ + +int +sc_store_dump(FILE *fh) +{ + sc_llist_iter_t *host_iter; + + if (! fh) + return -1; + + pthread_rwlock_rdlock(&host_lock); + + host_iter = sc_llist_get_iter(host_list); + if (! host_iter) + return -1; + + while (sc_llist_iter_has_next(host_iter)) { + sc_host_t *host = SC_HOST(sc_llist_iter_get_next(host_iter)); + sc_llist_iter_t *svc_iter; + + char time_str[64]; + + assert(host); + + if (! sc_strftime(time_str, sizeof(time_str), + "%F %T %z", host->host_last_update)) + snprintf(time_str, sizeof(time_str), ""); + time_str[sizeof(time_str) - 1] = '\0'; + + fprintf(fh, "Host '%s' (last updated: %s):\n", + host->host_name, time_str); + + svc_iter = sc_llist_get_iter(host->services); + if (! svc_iter) { + char errbuf[1024]; + fprintf(fh, "Failed to retrieve services: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + continue; + } + + while (sc_llist_iter_has_next(svc_iter)) { + sc_service_t *svc = SC_SVC(sc_llist_iter_get_next(svc_iter)); + assert(svc); + + if (! sc_strftime(time_str, sizeof(time_str), + "%F %T %z", host->host_last_update)) + snprintf(time_str, sizeof(time_str), ""); + time_str[sizeof(time_str) - 1] = '\0'; + + fprintf(fh, "\tService '%s' (last updated: %s)\n", + svc->svc_name, time_str); + } + + sc_llist_iter_destroy(svc_iter); + } + + sc_llist_iter_destroy(host_iter); + return 0; +} /* sc_store_dump */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/daemon/config.c b/src/daemon/config.c new file mode 100644 index 0000000..0b7cc77 --- /dev/null +++ b/src/daemon/config.c @@ -0,0 +1,195 @@ +/* + * syscollector - src/daemon_config.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "syscollector.h" +#include "core/plugin.h" +#include "utils/time.h" + +#include "daemon/config.h" + +#include "liboconfig/oconfig.h" +#include "liboconfig/utils.h" + +#include +#include + +/* + * private variables + */ + +static sc_time_t default_interval = 0; + +/* + * private helper functions + */ + +static int +config_get_interval(oconfig_item_t *ci, sc_time_t *interval) +{ + double interval_dbl = 0.0; + + assert(ci && interval); + + if (oconfig_get_number(ci, &interval_dbl)) { + fprintf(stderr, "config: Interval requires " + "a single numeric argument\n" + "\tUsage: Interval SECONDS\n"); + return -1; + } + + if (interval_dbl <= 0.0) { + fprintf(stderr, "config: Invalid interval: %f\n" + "\tInterval may not be less than or equal to zero.\n", + interval_dbl); + return -1; + } + + *interval = DOUBLE_TO_SC_TIME(interval_dbl); + return 0; +} /* config_get_interval */ + +/* + * token parser + */ + +typedef struct { + char *name; + int (*dispatcher)(oconfig_item_t *); +} token_parser_t; + +static int +daemon_set_interval(oconfig_item_t *ci) +{ + return config_get_interval(ci, &default_interval); +} /* daemon_set_interval */ + +static int +daemon_load_backend(oconfig_item_t *ci) +{ + char plugin_name[1024]; + char *name; + + sc_plugin_ctx_t ctx = SC_PLUGIN_CTX_INIT; + sc_plugin_ctx_t old_ctx; + + int status, i; + + ctx.interval = default_interval; + + if (oconfig_get_string(ci, &name)) { + fprintf(stderr, "config: LoadBackend requires a single " + "string argument\n" + "\tUsage: LoadBackend BACKEND\n"); + return -1; + } + + snprintf(plugin_name, sizeof(plugin_name), "backend/%s", name); + + for (i = 0; i < ci->children_num; ++i) { + oconfig_item_t *child = ci->children + i; + + if (! strcasecmp(child->key, "Interval")) { + if (config_get_interval(child, &ctx.interval)) + return -1; + } + else { + fprintf(stderr, "config: Unknown option '%s' inside 'LoadBackend' " + "-- see the documentation for details.\n", child->key); + return -1; + } + } + + old_ctx = sc_plugin_set_ctx(ctx); + status = sc_plugin_load(plugin_name); + sc_plugin_set_ctx(old_ctx); + return status; +} /* daemon_load_backend */ + +static int +daemon_configure_plugin(oconfig_item_t *ci) +{ + char *name; + + assert(ci); + + if (oconfig_get_string(ci, &name)) { + fprintf(stderr, "config: %s requires a single " + "string argument\n" + "\tUsage: LoadBackend BACKEND\n", + ci->key); + return -1; + } + + return sc_plugin_configure(name, ci); +} /* daemon_configure_backend */ + +static token_parser_t token_parser_list[] = { + { "Interval", daemon_set_interval }, + { "LoadBackend", daemon_load_backend }, + { "Backend", daemon_configure_plugin }, + { "Plugin", daemon_configure_plugin }, + { NULL, NULL }, +}; + +/* + * public API + */ + +int +daemon_parse_config(const char *filename) +{ + oconfig_item_t *ci; + int retval = 0, i; + + ci = oconfig_parse_file(filename); + if (! ci) + return -1; + + for (i = 0; i < ci->children_num; ++i) { + oconfig_item_t *child = ci->children + i; + int status = 1, j; + + for (j = 0; token_parser_list[j].name; ++j) { + if (! strcasecmp(token_parser_list[j].name, child->key)) + status = token_parser_list[j].dispatcher(child); + } + + if (status) { + fprintf(stderr, "config: Failed to parse option '%s'\n", + child->key); + if (status > 0) + fprintf(stderr, "\tUnknown option '%s' -- " + "see the documentation for details\n", + child->key); + retval = -1; + } + } + return retval; +} /* daemon_parse_config */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/daemon/syscollectord.c b/src/daemon/syscollectord.c new file mode 100644 index 0000000..effc615 --- /dev/null +++ b/src/daemon/syscollectord.c @@ -0,0 +1,236 @@ +/* + * syscollector - src/syscollecord.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "syscollector.h" +#include "core/plugin.h" +#include "core/store.h" +#include "utils/string.h" + +#include "daemon/config.h" + +#if HAVE_LIBGEN_H +# include +#else /* HAVE_LIBGEN_H */ +# define basename(path) (path) +#endif /* ! HAVE_LIBGEN_H */ + +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#ifndef CONFIGFILE +# define CONFIGFILE SYSCONFDIR"/syscollector/syscollectord.conf" +#endif + +static sc_plugin_loop_t plugin_main_loop = SC_PLUGIN_LOOP_INIT; + +static void +sigintterm_handler(int __attribute__((unused)) signo) +{ + plugin_main_loop.do_loop = 0; +} /* sigintterm_handler */ + +static void +exit_usage(char *name, int status) +{ + printf( +"Usage: %s \n" + +"\nOptions:\n" +" -C FILE the main configuration file\n" +" default: "CONFIGFILE"\n" +" -d run in background (daemonize)\n" +"\n" +" -h display this help and exit\n" +" -V display the version number and copyright\n" + +"\nsyscollectord "SC_VERSION_STRING SC_VERSION_EXTRA", "PACKAGE_URL"\n", +basename(name)); + exit(status); +} /* exit_usage */ + +static void +exit_version(void) +{ + printf("syscollectord version "SC_VERSION_STRING SC_VERSION_EXTRA", " + "built "BUILD_DATE"\n" + "using libsyscollection verion %s%s\n" + "Copyright (C) 2012 "PACKAGE_MAINTAINER"\n" + + "\nThis is free software under the terms of the BSD license, see " + "the source for\ncopying conditions. There is NO WARRANTY; not " + "even for MERCHANTABILITY or\nFITNESS FOR A PARTICULAR " + "PURPOSE.\n", sc_version_string(), sc_version_extra()); + exit(0); +} /* exit_version */ + +static int +daemonize(void) +{ + pid_t pid; + + if ((pid = fork()) < 0) { + char errbuf[1024]; + fprintf(stderr, "Failed to fork to background: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return errno; + } + else if (pid != 0) { + /* parent */ + exit(0); + } + + if (chdir("/")) { + char errbuf[1024]; + fprintf(stderr, "Failed to change working directory to /: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return errno; + } + + /* detach from session */ + setsid(); + + close(0); + if (open("/dev/null", O_RDWR)) { + char errbuf[1024]; + fprintf(stderr, "Failed to connect stdin to '/dev/null': %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return errno; + } + + close(1); + if (dup(0) != 1) { + char errbuf[1024]; + fprintf(stderr, "Could not connect stdout to '/dev/null': %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return errno; + } + + close(2); + if (dup(0) != 2) { + char errbuf[1024]; + fprintf(stdout, "Could not connect stderr to '/dev/null': %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return errno; + } + return 0; +} /* daemonize */ + +int +main(int argc, char **argv) +{ + char *config_filename = NULL; + _Bool daemon = 0; + + struct sigaction sa_intterm; + + while (42) { + int opt = getopt(argc, argv, "C:dhV"); + + if (-1 == opt) + break; + + switch (opt) { + case 'C': + config_filename = optarg; + break; + case 'd': + daemon = 1; + break; + + case 'h': + exit_usage(argv[0], 0); + break; + case 'V': + exit_version(); + break; + default: + exit_usage(argv[0], 1); + } + } + + if (optind < argc) + exit_usage(argv[0], 1); + + if (! config_filename) + config_filename = CONFIGFILE; + + if (daemon_parse_config(config_filename)) { + fprintf(stderr, "Failed to parse configuration file.\n"); + exit(1); + } + + memset(&sa_intterm, 0, sizeof(sa_intterm)); + sa_intterm.sa_handler = sigintterm_handler; + sa_intterm.sa_flags = 0; + + if (sigaction(SIGINT, &sa_intterm, /* old action */ NULL)) { + char errbuf[1024]; + fprintf(stderr, "Failed to install signal handler for SIGINT: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + exit(1); + } + if (sigaction(SIGTERM, &sa_intterm, /* old action */ NULL)) { + char errbuf[1024]; + fprintf(stderr, "Failed to install signal handler for SIGTERM: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + exit(1); + } + + if (daemon) + if (daemonize()) + exit(1); + + fprintf(stderr, "syscollectord "SC_VERSION_STRING" (pid %i) " + "initialized successfully\n", (int)getpid()); + + sc_plugin_init_all(); + sc_plugin_collector_loop(&plugin_main_loop); + + fprintf(stderr, "Shutting down syscollector "SC_VERSION_STRING + " (pid %i)\n", (int)getpid()); + + fprintf(stderr, "Store dump:\n"); + sc_store_dump(stderr); + return 0; +} /* main */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/daemon/syscollectord.conf b/src/daemon/syscollectord.conf new file mode 100644 index 0000000..4fa379e --- /dev/null +++ b/src/daemon/syscollectord.conf @@ -0,0 +1,2 @@ +LoadBackend "collectd" + diff --git a/src/include/core/object.h b/src/include/core/object.h new file mode 100644 index 0000000..cd91086 --- /dev/null +++ b/src/include/core/object.h @@ -0,0 +1,109 @@ +/* + * syscollector - src/include/core/object.h + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#ifndef SC_CORE_OBJECT_H +#define SC_CORE_OBJECT_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sc_object; +typedef struct sc_object sc_object_t; + +struct sc_object { + int ref_cnt; + void (*destructor)(sc_object_t *); + size_t size; +}; +#define SC_OBJECT_INIT { 1, NULL, 0 } + +typedef struct { + sc_object_t super; + void *data; + void (*destructor)(void *); +} sc_object_wrapper_t; + +#define SC_OBJ(obj) ((sc_object_t *)(obj)) +#define SC_OBJ_WRAPPER(obj) ((sc_object_wrapper_t *)(obj)) + +/* + * sc_object_create: + * Allocates a new sc_object_t of the specified 'size'. The object will be + * initialized to zero and then passed on to the 'init' function (if + * specified). If specified, the 'destructor' will be called, when the + * reference count drops to zero and before freeing the memory allocated by + * the object itself. + * + * If the init function fails (returns a non-zero value), the object will be + * destructed and destroyed. + * + * The reference count of the new object will be 1. + * + * Returns: + * - the newly allocated object + * - NULL on error + */ +sc_object_t * +sc_object_create(size_t size, int (*init)(sc_object_t *, va_list), + void (*destructor)(sc_object_t *), ...); + +/* + * sc_object_create_wrapper: + * Create a new sc_object_t wrapping some arbitrary other object. + */ +sc_object_t * +sc_object_create_wrapper(void *data, void (*destructor)(void *)); + +/* + * sc_object_deref: + * Dereference the object and free the allocated memory in case the ref-count + * drops to zero. In case a 'destructor' had been registered with the object, + * it will be called before freeing the memory. + */ +void +sc_object_deref(sc_object_t *obj); + +/* + * sc_object_ref: + * Take ownership of the specified object, that is, increment the reference + * count by one. + */ +void +sc_object_ref(sc_object_t *obj); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SC_CORE_OBJECT_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/core/plugin.h b/src/include/core/plugin.h new file mode 100644 index 0000000..8d54089 --- /dev/null +++ b/src/include/core/plugin.h @@ -0,0 +1,224 @@ +/* + * syscollector - src/include/core/plugin.h + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#ifndef SC_CORE_PLUGIN_H +#define SC_CORE_PLUGIN_H 1 + +#include "syscollector.h" +#include "core/object.h" +#include "utils/time.h" + +#include "liboconfig/oconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + sc_time_t interval; +} sc_plugin_ctx_t; +#define SC_PLUGIN_CTX_INIT { 0 } + +struct sc_plugin_info; +typedef struct sc_plugin_info sc_plugin_info_t; + +/* this should be used in the header of a plugin to avoid + * missing prototype warnings/errors for the plugin init + * function */ +#define SC_PLUGIN_MAGIC \ + int sc_module_init(sc_plugin_info_t *info); + +typedef struct { + _Bool do_loop; + sc_time_t default_interval; +} sc_plugin_loop_t; +#define SC_PLUGIN_LOOP_INIT { 1, 0 } + +/* + * sc_plugin_load: + * Load (any type of) plugin by loading the shared object file and calling the + * sc_module_init function. + */ +int +sc_plugin_load(const char *name); + +/* + * sc_plugin_set_info: + * Fill in the fields of the sc_plugin_info_t object passed to the + * sc_module_init function. This information is used to identify the plugin + * and also to provide additional information to the user. + */ +enum { + SC_PLUGIN_INFO_NAME, /* plugin name: string */ + SC_PLUGIN_INFO_DESC, /* plugin description: string */ + SC_PLUGIN_INFO_COPYRIGHT, /* plugin copyright: string */ + SC_PLUGIN_INFO_LICENSE, /* plugin license: string */ + SC_PLUGIN_INFO_VERSION, /* libsyscollector version: integer */ + SC_PLUGIN_INFO_PLUGIN_VERSION /* plugin version: integer */ +}; + +int +sc_plugin_set_info(sc_plugin_info_t *info, int type, ...); + +/* + * plugin callback functions + */ + +typedef int (*sc_plugin_config_cb)(oconfig_item_t *ci); +typedef int (*sc_plugin_init_cb)(sc_object_t *user_data); +typedef int (*sc_plugin_collector_cb)(sc_object_t *user_data); +typedef int (*sc_plugin_shutdown_cb)(sc_object_t *user_data); + +/* + * sc_plugin_register_config: + * Register a "config" function. This will be used to pass on the + * configuration for a plugin. The plugin has to make sure that the function + * can be called multiple times in order to process multiple blocks + * specified in the configuration file(s). + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sc_plugin_register_config(const char *name, sc_plugin_config_cb callback); + +/* + * sc_plugin_register_init: + * Register an "init" function. All "init" functions will be called after + * finishing the config parsing and before starting any other work. The + * functions will be called in the same order as they have been registered, + * that is, functions of different plugins will be called in the same order as + * the appropriate "Load" statements in the config file. + * + * If the "init" function returns a non-zero value, *all* callbacks of the + * plugin will be unloaded. + * + * Arguments: + * - user_data: If specified, this will be passed on to each call of the + * callback. The function will take ownership of the object, that is, + * increment the reference count by one. In case the caller does not longer + * use the object for other purposes, it should thus deref it. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sc_plugin_register_init(const char *name, sc_plugin_init_cb callback, + sc_object_t *user_data); + +/* + * sc_plugin_register_collector: + * Register a "collector" function. This is where a backend is doing its main + * work. This function will be called whenever an update of a backend has been + * requested (either by regular interval or by user request). The backend + * should then query the appropriate data-source and submit all values to the + * core. + * + * Arguments: + * - interval: Specifies the regular interval at which to update the backend. + * If this is NULL, global settings will be used. + * - user_data: If specified, this will be passed on to each call of the + * callback. The function will take ownership of the object, that is, + * increment the reference count by one. In case the caller does not longer + * use the object for other purposes, it should thus deref it. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sc_plugin_register_collector(const char *name, sc_plugin_collector_cb callback, + const sc_time_t *interval, sc_object_t *user_data); + +/* + * sc_plugin_register_shutdown: + * Register a "shutdown" function to be called after stopping all update + * processes and before shutting down the daemon. + * + * Arguments: + * - user_data: If specified, this will be passed on to each call of the + * callback. The function will take ownership of the object, that is, + * increment the reference count by one. In case the caller does not longer + * use the object for other purposes, it should thus deref it. + */ +int +sc_plugin_register_shutdown(const char *name, sc_plugin_shutdown_cb callback, + sc_object_t *user_data); + +/* + * sc_plugin_get_ctx, sc_plugin_set_ctx: + * The plugin context defines a set of settings that are available whenever a + * plugin has been called. It may be used to pass around various information + * between the different component of the library without having each and + * every plugin care about it. + */ +sc_plugin_ctx_t +sc_plugin_get_ctx(void); +sc_plugin_ctx_t +sc_plugin_set_ctx(sc_plugin_ctx_t ctx); + +/* + * sc_plugin_configure: + * Configure the plugin called 'name' (according to the registered config + * callback) using the config tree 'ci'. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sc_plugin_configure(const char *name, oconfig_item_t *ci); + +/* + * sc_plugin_init_all: + * Initialize all plugins using their registered "init" function. + */ +int +sc_plugin_init_all(void); + +/* + * sc_plugin_collector_loop: + * Loop until loop->do_loop is false, calling the next collector function on + * each iteration and once its next update interval is passed. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sc_plugin_collector_loop(sc_plugin_loop_t *loop); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SC_CORE_PLUGIN_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/core/store.h b/src/include/core/store.h new file mode 100644 index 0000000..fe7eb75 --- /dev/null +++ b/src/include/core/store.h @@ -0,0 +1,105 @@ +/* + * syscollector - src/include/core/store.h + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#ifndef SC_CORE_STORE_H +#define SC_CORE_STORE_H 1 + +#include "syscollector.h" +#include "core/object.h" +#include "utils/time.h" +#include "utils/llist.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + sc_object_t parent; + + sc_time_t last_update; + char *name; +} sc_store_obj_t; +#define SC_STORE_OBJ_INIT { SC_OBJECT_INIT, 0, NULL } +#define SC_STORE_OBJ(obj) ((sc_store_obj_t *)(obj)) + +typedef struct { + sc_store_obj_t parent; +#define svc_last_update parent.last_update +#define svc_name parent.name + + char *hostname; +} sc_service_t; +#define SC_SVC_INIT { SC_STORE_OBJ_INIT, NULL } +#define SC_SVC(obj) ((sc_service_t *)(obj)) + +typedef struct { + sc_store_obj_t parent; +#define host_last_update parent.last_update +#define host_name parent.name + + sc_llist_t *services; +} sc_host_t; +#define SC_HOST_INIT { SC_STORE_OBJ_INIT, NULL } +#define SC_HOST(obj) ((sc_host_t *)(obj)) + +sc_host_t * +sc_host_create(char *name); + +sc_host_t * +sc_host_clone(const sc_host_t *host); + +int +sc_store_host(const sc_host_t *host); + +const sc_host_t * +sc_store_get_host(char *name); + +sc_service_t * +sc_service_create(char *hostname, char *name); + +sc_service_t * +sc_service_clone(const sc_service_t *svc); + +int +sc_store_service(const sc_service_t *svc); + +const sc_service_t * +sc_store_get_service(const sc_host_t *host, char *name); + +int +sc_store_dump(FILE *fh); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SC_CORE_STORE_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/syscollector.h.in b/src/include/syscollector.h.in new file mode 100644 index 0000000..ff35fa5 --- /dev/null +++ b/src/include/syscollector.h.in @@ -0,0 +1,69 @@ +/* + * syscollector - src/include/syscollector.h + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#ifndef SYSCOLLECTOR_H +#define SYSCOLLECTOR_H 1 + +#define SC_VERSION_MAJOR @SC_VERSION_MAJOR@ +#define SC_VERSION_MINOR @SC_VERSION_MINOR@ +#define SC_VERSION_PATCH @SC_VERSION_PATCH@ + +#define SC_VERSION_EXTRA "@SC_VERSION_EXTRA@" + +#define SC_VERSION_STRING "@SC_VERSION_STRING@" + +#define SC_VERSION_ENCODE(major, minor, patch) \ + ((major) * 10000 + (minor) * 100 + (patch)) +#define SC_VERSION_DECODE(version) \ + (int)((version) / 10000), \ + (int)((version) / 100) - (int)((version) / 10000) * 100, \ + (int)(version) - (int)((version) / 100) * 100 + +#define SC_VERSION SC_VERSION_ENCODE(SC_VERSION_MAJOR, SC_VERSION_MINOR, \ + SC_VERSION_PATCH) + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned int +sc_version(void); + +const char * +sc_version_string(void); + +const char * +sc_version_extra(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SYSCOLLECTOR_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/utils/llist.h b/src/include/utils/llist.h new file mode 100644 index 0000000..c115bf2 --- /dev/null +++ b/src/include/utils/llist.h @@ -0,0 +1,167 @@ +/* + * syscollector - src/include/utils/llist.h + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#ifndef SC_UTILS_LLIST_H +#define SC_UTILS_LLIST_H 1 + +#include "core/object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct sc_llist; +typedef struct sc_llist sc_llist_t; + +struct sc_llist_iter; +typedef struct sc_llist_iter sc_llist_iter_t; + +/* + * sc_llist_create, sc_llist_destroy: + * Create and destroy a doubly linked list object. + * + * sc_llist_create returns NULL on error. + * sc_llist_destroy will also destroy all remaining elements, thus releasing + * the included objects (decrement the ref-count). + */ +sc_llist_t * +sc_llist_create(void); +void +sc_llist_destroy(sc_llist_t *list); + +/* + * sc_llist_clone: + * Clone an existing list. The objects stored in the list will not be copied + * but rather their reference count incremented. + * + * Returns: + * - the copied list on success + * - NULL else + */ +sc_llist_t * +sc_llist_clone(sc_llist_t *list); + +/* + * sc_llist_append: + * Append the given 'obj' to the end of 'list'. The list will take ownership + * of the object, that is, increment the reference count by one. In case the + * caller does not longer use the object for other purposes, it should thus + * deref it. + * + * Returns: + * - 0 on success + * - a negative value on failure + */ +int +sc_llist_append(sc_llist_t *list, sc_object_t *obj); + +/* + * sc_llist_insert: + * Insert the new element at the specified position (zero being the head of + * the list; the length of the list being the tail)). If the index is greater + * than the length of the list (i.e. past the tail of the list), an error is + * returned. The list will take ownership of the object, that is, increment + * the reference count by one. In case the caller does not longer use the + * object for other purposes, it should thus deref it. + * + * Returns: + * - 0 on success + * - a negative value on failure + */ +int +sc_llist_insert(sc_llist_t *list, sc_object_t *obj, size_t index); + +/* + * sc_llist_insert_sorted: + * Insert the given 'obj' in the 'list' using a sort order as determined by + * the 'compare' function. The function will insert the new entry before the + * first entry which sorts later than the new entry. It will not ensure that + * the rest of the list is sorted. The list will take ownership of the object, + * that is, increment the reference count by one. In case the caller does not + * longer use the object for other purposes, it should thus deref it. + * + * The 'compare' function should return less than zero, zero, greater than + * zero if the first argument sorts less than, equal or greater than the + * second argument respectively. + * + * Returns: + * - 0 on success + * - a negative value on failure + */ +int +sc_llist_insert_sorted(sc_llist_t *list, sc_object_t *obj, + int (*compare)(const sc_object_t *, const sc_object_t *)); + +/* sc_llist_search: + * Search for a 'key' in the given 'list'. The function will return the first + * entry that matches the specified 'key'. For that purpose, the 'compare' + * function is used. It should return 0 iff the two arguments compare equal. + * + * Returns: + * - a pointer the sc_object_t containing the matching entry + * - NULL else + */ +sc_object_t * +sc_llist_search(sc_llist_t *list, const sc_object_t *key, + int (*compare)(const sc_object_t *, const sc_object_t *)); + +/* + * sc_llist_shift: + * Removes and returns the first element of the list. The ref-count of the + * item will not be changed, that is, if the element will not be used any + * further, it should be re-referenced by the caller. + * + * Returns: + * - the former first element of the list + * - NULL if the list is empty + */ +sc_object_t * +sc_llist_shift(sc_llist_t *list); + +/* sc_llist_get_iter, sc_llist_iter_has_next, sc_llist_iter_get_next: + * Iterate through the list, element by element. + * + * sc_llist_iter_get_next returns NULL if there is no next element. + */ +sc_llist_iter_t * +sc_llist_get_iter(sc_llist_t *list); +void +sc_llist_iter_destroy(sc_llist_iter_t *iter); + +_Bool +sc_llist_iter_has_next(sc_llist_iter_t *iter); +sc_object_t * +sc_llist_iter_get_next(sc_llist_iter_t *iter); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SC_UTILS_LLIST_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/utils/string.h b/src/include/utils/string.h new file mode 100644 index 0000000..a52205b --- /dev/null +++ b/src/include/utils/string.h @@ -0,0 +1,47 @@ +/* + * syscollector - src/include/utils/string.h + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#ifndef SC_UTILS_STRING_H +#define SC_UTILS_STRING_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +char * +sc_strerror(int errnum, char *strerrbuf, size_t buflen); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SC_UTILS_STRING_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/utils/time.h b/src/include/utils/time.h new file mode 100644 index 0000000..f67a46b --- /dev/null +++ b/src/include/utils/time.h @@ -0,0 +1,73 @@ +/* + * syscollector - src/include/utils/time.h + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#ifndef SC_UTILS_TIME_H +#define SC_UTILS_TIME_H 1 + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * sc_time_t: + * The time, in nano-seconds, since the epoch. + */ +typedef uint64_t sc_time_t; +#define PRIscTIME PRIu64 + +#define SECS_TO_SC_TIME(s) ((sc_time_t)(s) * (sc_time_t)1000000000) +#define SC_TIME_TO_SECS(t) ((t) / (sc_time_t)1000000000) + +#define NSECS_TO_SC_TIME(ns) ((sc_time_t)ns) + +#define DOUBLE_TO_SC_TIME(d) ((sc_time_t)((d) * 1000000000.0)) +#define SC_TIME_TO_DOUBLE(t) ((double)(t) / 1000000000.0) + +#define TIMESPEC_TO_SC_TIME(ts) (SECS_TO_SC_TIME((ts).tv_sec) \ + + NSECS_TO_SC_TIME((ts).tv_nsec)) + +sc_time_t +sc_gettime(void); + +int +sc_sleep(sc_time_t reg, sc_time_t *rem); + +size_t +sc_strftime(char *s, size_t len, const char *format, sc_time_t); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SC_UTILS_TIME_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/utils/unixsock.h b/src/include/utils/unixsock.h new file mode 100644 index 0000000..e51e4ac --- /dev/null +++ b/src/include/utils/unixsock.h @@ -0,0 +1,65 @@ +/* + * syscollector - src/include/utils/unixsock.h + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#ifndef SC_UTILS_UNIXSOCK_H +#define SC_UTILS_UNIXSOCK_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sc_unixsock_client; +typedef struct sc_unixsock_client sc_unixsock_client_t; + +sc_unixsock_client_t * +sc_unixsock_client_create(const char *path); + +int +sc_unixsock_client_connect(sc_unixsock_client_t *client); + +int +sc_unixsock_client_send(sc_unixsock_client_t *client, const char *msg); + +char * +sc_unixsock_client_recv(sc_unixsock_client_t *client, char *buffer, size_t buflen); + +void +sc_unixsock_client_destroy(sc_unixsock_client_t *client); + +const char * +sc_unixsock_client_path(sc_unixsock_client_t *client); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SC_UTILS_UNIXSOCK_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/liboconfig/COPYING b/src/liboconfig/COPYING new file mode 100644 index 0000000..623b625 --- /dev/null +++ b/src/liboconfig/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/liboconfig/Makefile.am b/src/liboconfig/Makefile.am new file mode 100644 index 0000000..7603834 --- /dev/null +++ b/src/liboconfig/Makefile.am @@ -0,0 +1,10 @@ +AUTOMAKE_OPTIONS = foreign no-dependencies + +BUILT_SOURCES = parser.h +#CLEANFILES = parser.[ch] scanner.c +AM_YFLAGS = -d + +noinst_LTLIBRARIES = liboconfig.la + +liboconfig_la_LDFLAGS = -version-info 0:0:0 $(LEXLIB) +liboconfig_la_SOURCES = oconfig.c oconfig.h aux_types.h scanner.l parser.y utils.c utils.h diff --git a/src/liboconfig/aux_types.h b/src/liboconfig/aux_types.h new file mode 100644 index 0000000..25b81ab --- /dev/null +++ b/src/liboconfig/aux_types.h @@ -0,0 +1,18 @@ +#ifndef AUX_TYPES_H +#define AUX_TYPES_H 1 + +struct statement_list_s +{ + oconfig_item_t *statement; + int statement_num; +}; +typedef struct statement_list_s statement_list_t; + +struct argument_list_s +{ + oconfig_value_t *argument; + int argument_num; +}; +typedef struct argument_list_s argument_list_t; + +#endif /* AUX_TYPES_H */ diff --git a/src/liboconfig/oconfig.c b/src/liboconfig/oconfig.c new file mode 100644 index 0000000..629775a --- /dev/null +++ b/src/liboconfig/oconfig.c @@ -0,0 +1,217 @@ +/** + * oconfig - src/oconfig.c + * Copyright (C) 2006,2007 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "oconfig.h" + +extern FILE *yyin; + +oconfig_item_t *ci_root; +const char *c_file; + +static void yyset_in (FILE *fd) +{ + yyin = fd; +} /* void yyset_in */ + +oconfig_item_t *oconfig_parse_fh (FILE *fh) +{ + int status; + oconfig_item_t *ret; + + char file[10]; + + yyset_in (fh); + + if (NULL == c_file) { + int status; + + status = snprintf (file, sizeof (file), "", fileno (fh)); + + if ((status < 0) || (status >= sizeof (file))) { + c_file = ""; + } + else { + file[sizeof (file) - 1] = '\0'; + c_file = file; + } + } + + status = yyparse (); + if (status != 0) + { + fprintf (stderr, "yyparse returned error #%i\n", status); + return (NULL); + } + + c_file = NULL; + + ret = ci_root; + ci_root = NULL; + yyset_in ((FILE *) 0); + + return (ret); +} /* oconfig_item_t *oconfig_parse_fh */ + +oconfig_item_t *oconfig_parse_file (const char *file) +{ + FILE *fh; + oconfig_item_t *ret; + + c_file = file; + + fh = fopen (file, "r"); + if (fh == NULL) + { + fprintf (stderr, "fopen (%s) failed: %s\n", file, strerror (errno)); + return (NULL); + } + + ret = oconfig_parse_fh (fh); + fclose (fh); + + c_file = NULL; + + return (ret); +} /* oconfig_item_t *oconfig_parse_file */ + +oconfig_item_t *oconfig_clone (const oconfig_item_t *ci_orig) +{ + oconfig_item_t *ci_copy; + + ci_copy = (oconfig_item_t *) malloc (sizeof (*ci_copy)); + if (ci_copy == NULL) + { + fprintf (stderr, "malloc failed.\n"); + return (NULL); + } + memset (ci_copy, 0, sizeof (*ci_copy)); + ci_copy->values = NULL; + ci_copy->parent = NULL; + ci_copy->children = NULL; + + ci_copy->key = strdup (ci_orig->key); + if (ci_copy->key == NULL) + { + fprintf (stderr, "strdup failed.\n"); + free (ci_copy); + return (NULL); + } + + if (ci_orig->values_num > 0) /* {{{ */ + { + int i; + + ci_copy->values = (oconfig_value_t *) calloc (ci_orig->values_num, + sizeof (*ci_copy->values)); + if (ci_copy->values == NULL) + { + fprintf (stderr, "calloc failed.\n"); + free (ci_copy->key); + free (ci_copy); + return (NULL); + } + ci_copy->values_num = ci_orig->values_num; + + for (i = 0; i < ci_copy->values_num; i++) + { + ci_copy->values[i].type = ci_orig->values[i].type; + if (ci_copy->values[i].type == OCONFIG_TYPE_STRING) + { + ci_copy->values[i].value.string + = strdup (ci_orig->values[i].value.string); + if (ci_copy->values[i].value.string == NULL) + { + fprintf (stderr, "strdup failed.\n"); + oconfig_free (ci_copy); + return (NULL); + } + } + else /* ci_copy->values[i].type != OCONFIG_TYPE_STRING) */ + { + ci_copy->values[i].value = ci_orig->values[i].value; + } + } + } /* }}} if (ci_orig->values_num > 0) */ + + if (ci_orig->children_num > 0) /* {{{ */ + { + int i; + + ci_copy->children = (oconfig_item_t *) calloc (ci_orig->children_num, + sizeof (*ci_copy->children)); + if (ci_copy->children == NULL) + { + fprintf (stderr, "calloc failed.\n"); + oconfig_free (ci_copy); + return (NULL); + } + ci_copy->children_num = ci_orig->children_num; + + for (i = 0; i < ci_copy->children_num; i++) + { + oconfig_item_t *child; + + child = oconfig_clone (ci_orig->children + i); + if (child == NULL) + { + oconfig_free (ci_copy); + return (NULL); + } + child->parent = ci_copy; + ci_copy->children[i] = *child; + free (child); + } /* for (i = 0; i < ci_copy->children_num; i++) */ + } /* }}} if (ci_orig->children_num > 0) */ + + return (ci_copy); +} /* oconfig_item_t *oconfig_clone */ + +void oconfig_free (oconfig_item_t *ci) +{ + int i; + + if (ci == NULL) + return; + + if (ci->key != NULL) + free (ci->key); + + for (i = 0; i < ci->values_num; i++) + if ((ci->values[i].type == OCONFIG_TYPE_STRING) + && (NULL != ci->values[i].value.string)) + free (ci->values[i].value.string); + + if (ci->values != NULL) + free (ci->values); + + for (i = 0; i < ci->children_num; i++) + oconfig_free (ci->children + i); + + if (ci->children != NULL) + free (ci->children); +} + +/* + * vim:shiftwidth=2:tabstop=8:softtabstop=2:fdm=marker + */ diff --git a/src/liboconfig/oconfig.h b/src/liboconfig/oconfig.h new file mode 100644 index 0000000..70fc623 --- /dev/null +++ b/src/liboconfig/oconfig.h @@ -0,0 +1,69 @@ +#ifndef OCONFIG_H +#define OCONFIG_H 1 + +#include + +/** + * oconfig - src/oconfig.h + * Copyright (C) 2006-2009 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Types + */ +#define OCONFIG_TYPE_STRING 0 +#define OCONFIG_TYPE_NUMBER 1 +#define OCONFIG_TYPE_BOOLEAN 2 + +struct oconfig_value_s +{ + union + { + char *string; + double number; + int boolean; + } value; + int type; +}; +typedef struct oconfig_value_s oconfig_value_t; + +struct oconfig_item_s; +typedef struct oconfig_item_s oconfig_item_t; +struct oconfig_item_s +{ + char *key; + oconfig_value_t *values; + int values_num; + + oconfig_item_t *parent; + oconfig_item_t *children; + int children_num; +}; + +/* + * Functions + */ +oconfig_item_t *oconfig_parse_fh (FILE *fh); +oconfig_item_t *oconfig_parse_file (const char *file); + +oconfig_item_t *oconfig_clone (const oconfig_item_t *ci); + +void oconfig_free (oconfig_item_t *ci); + +/* + * vim: shiftwidth=2:tabstop=8:softtabstop=2 + */ +#endif /* OCONFIG_H */ diff --git a/src/liboconfig/parser.y b/src/liboconfig/parser.y new file mode 100644 index 0000000..19f58b2 --- /dev/null +++ b/src/liboconfig/parser.y @@ -0,0 +1,259 @@ +/** + * oconfig - src/parser.y + * Copyright (C) 2007,2008 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +%{ +#include +#include +#include "oconfig.h" +#include "aux_types.h" + +static char *unquote (const char *orig); +static int yyerror (const char *s); + +/* Lexer variables */ +extern int yylineno; +extern char *yytext; + +extern oconfig_item_t *ci_root; +extern char *c_file; +%} + +%start entire_file + +%union { + double number; + int boolean; + char *string; + oconfig_value_t cv; + oconfig_item_t ci; + argument_list_t al; + statement_list_t sl; +} + +%token NUMBER +%token BTRUE BFALSE +%token QUOTED_STRING UNQUOTED_STRING +%token SLASH OPENBRAC CLOSEBRAC EOL + +%type string +%type identifier +/* arguments */ +%type argument +%type argument_list +/* blocks */ +%type block_begin +%type block +%type block_end +/* statements */ +%type option +%type statement +%type statement_list +%type entire_file + +/* pass an verbose, specific error message to yyerror() */ +%error-verbose + +%% +string: + QUOTED_STRING {$$ = unquote ($1);} + | UNQUOTED_STRING {$$ = strdup ($1);} + ; + +argument: + NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;} + | BTRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;} + | BFALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;} + | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;} + ; + +argument_list: + argument_list argument + { + $$ = $1; + $$.argument_num++; + $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t)); + $$.argument[$$.argument_num-1] = $2; + } + | argument + { + $$.argument = malloc (sizeof (oconfig_value_t)); + $$.argument[0] = $1; + $$.argument_num = 1; + } + ; + +identifier: + UNQUOTED_STRING {$$ = strdup ($1);} + ; + +option: + identifier argument_list EOL + { + memset (&$$, '\0', sizeof ($$)); + $$.key = $1; + $$.values = $2.argument; + $$.values_num = $2.argument_num; + } + ; + +block_begin: + OPENBRAC identifier CLOSEBRAC EOL + { + memset (&$$, '\0', sizeof ($$)); + $$.key = $2; + } + | + OPENBRAC identifier argument_list CLOSEBRAC EOL + { + memset (&$$, '\0', sizeof ($$)); + $$.key = $2; + $$.values = $3.argument; + $$.values_num = $3.argument_num; + } + ; + +block_end: + OPENBRAC SLASH identifier CLOSEBRAC EOL + { + $$ = $3; + } + ; + +block: + block_begin statement_list block_end + { + if (strcmp ($1.key, $3) != 0) + { + printf ("block_begin = %s; block_end = %s;\n", $1.key, $3); + yyerror ("Block not closed..\n"); + exit (1); + } + free ($3); $3 = NULL; + $$ = $1; + $$.children = $2.statement; + $$.children_num = $2.statement_num; + } + | block_begin block_end + { + if (strcmp ($1.key, $2) != 0) + { + printf ("block_begin = %s; block_end = %s;\n", $1.key, $2); + yyerror ("Block not closed..\n"); + exit (1); + } + free ($2); $2 = NULL; + $$ = $1; + $$.children = NULL; + $$.children_num = 0; + } + ; + +statement: + option {$$ = $1;} + | block {$$ = $1;} + | EOL {$$.values_num = 0;} + ; + +statement_list: + statement_list statement + { + $$ = $1; + if (($2.values_num > 0) || ($2.children_num > 0)) + { + $$.statement_num++; + $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t)); + $$.statement[$$.statement_num-1] = $2; + } + } + | statement + { + if (($1.values_num > 0) || ($1.children_num > 0)) + { + $$.statement = malloc (sizeof (oconfig_item_t)); + $$.statement[0] = $1; + $$.statement_num = 1; + } + else + { + $$.statement = NULL; + $$.statement_num = 0; + } + } + ; + +entire_file: + statement_list + { + ci_root = malloc (sizeof (oconfig_item_t)); + memset (ci_root, '\0', sizeof (oconfig_item_t)); + ci_root->children = $1.statement; + ci_root->children_num = $1.statement_num; + } + | /* epsilon */ + { + ci_root = malloc (sizeof (oconfig_item_t)); + memset (ci_root, '\0', sizeof (oconfig_item_t)); + ci_root->children = NULL; + ci_root->children_num = 0; + } + ; + +%% +static int yyerror (const char *s) +{ + char *text; + + if (*yytext == '\n') + text = ""; + else + text = yytext; + + fprintf (stderr, "Parse error in file `%s', line %i near `%s': %s\n", + c_file, yylineno, text, s); + return (-1); +} /* int yyerror */ + +static char *unquote (const char *orig) +{ + char *ret = strdup (orig); + int len; + int i; + + if (ret == NULL) + return (NULL); + + len = strlen (ret); + + if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"')) + return (ret); + + len -= 2; + memmove (ret, ret + 1, len); + ret[len] = '\0'; + + for (i = 0; i < len; i++) + { + if (ret[i] == '\\') + { + memmove (ret + i, ret + (i + 1), len - i); + len--; + } + } + + return (ret); +} /* char *unquote */ diff --git a/src/liboconfig/scanner.l b/src/liboconfig/scanner.l new file mode 100644 index 0000000..9f0cd8e --- /dev/null +++ b/src/liboconfig/scanner.l @@ -0,0 +1,137 @@ +/** + * oconfig - src/scanner.l + * Copyright (C) 2007 Florian octo Forster + * Copyright (C) 2008 Sebastian tokkee Harl + * + * 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; only version 2 of the License is applicable. + * + * 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +%{ +#include +#include "oconfig.h" +#include "aux_types.h" +#include "parser.h" + +/* multiline string buffer */ +static char *ml_buffer = NULL; +static int ml_pos = 0; +static int ml_len = 0; + +#define ml_free (ml_len - ml_pos) + +static void ml_append (char *); + +#ifdef yyterminate +# undef yyterminate +#endif +#define yyterminate() \ + do { free (ml_buffer); ml_buffer = NULL; ml_pos = 0; ml_len = 0; \ + return YY_NULL; } while (0) +%} +%option yylineno +%option noyywrap +%x ML +WHITE_SPACE [\ \t\b] +NON_WHITE_SPACE [^\ \t\b] +EOL (\r\n|\n) +QUOTED_STRING ([^\\"]+|\\.)* +UNQUOTED_STRING [0-9A-Za-z_]+ +HEX_NUMBER 0[xX][0-9a-fA-F]+ +OCT_NUMBER 0[0-7]+ +DEC_NUMBER [\+\-]?[0-9]+ +FLOAT_NUMBER [\+\-]?[0-9]*\.[0-9]+([eE][\+\-][0-9]+)? +NUMBER ({FLOAT_NUMBER}|{HEX_NUMBER}|{OCT_NUMBER}|{DEC_NUMBER}) +BOOL_TRUE (true|yes|on) +BOOL_FALSE (false|no|off) +COMMENT #.* +PORT (6(5(5(3[0-5]|[0-2][0-9])|[0-4][0-9][0-9])|[0-4][0-9][0-9][0-9])|[1-5][0-9][0-9][0-9][0-9]|[1-9][0-9]?[0-9]?[0-9]?) +IP_BYTE (2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]) +IPV4_ADDR {IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}(:{PORT})? + +%% +{WHITE_SPACE} | +{COMMENT} {/* ignore */} + +\\{EOL} {/* continue line */} + +{EOL} {return (EOL);} +"/" {return (SLASH);} +"<" {return (OPENBRAC);} +">" {return (CLOSEBRAC);} +{BOOL_TRUE} {yylval.boolean = 1; return (BTRUE);} +{BOOL_FALSE} {yylval.boolean = 0; return (BFALSE);} + +{IPV4_ADDR} {yylval.string = yytext; return (UNQUOTED_STRING);} + +{NUMBER} {yylval.number = strtod (yytext, NULL); return (NUMBER);} + +\"{QUOTED_STRING}\" {yylval.string = yytext; return (QUOTED_STRING);} +{UNQUOTED_STRING} {yylval.string = yytext; return (UNQUOTED_STRING);} + +\"{QUOTED_STRING}\\{EOL} { + int len = strlen (yytext); + + ml_pos = 0; + + /* remove "\\" */ + if ('\r' == yytext[len - 2]) + len -= 3; + else + len -= 2; + yytext[len] = '\0'; + + ml_append (yytext); + BEGIN (ML); +} +^{WHITE_SPACE}+ {/* remove leading white-space */} +{NON_WHITE_SPACE}{QUOTED_STRING}\\{EOL} { + int len = strlen (yytext); + + /* remove "\\" */ + if ('\r' == yytext[len - 2]) + len -= 3; + else + len -= 2; + yytext[len] = '\0'; + + ml_append(yytext); +} +{NON_WHITE_SPACE}{QUOTED_STRING}\" { + ml_append(yytext); + yylval.string = ml_buffer; + + BEGIN (INITIAL); + return (QUOTED_STRING); +} +%% +static void ml_append (char *string) +{ + int len = strlen (string); + int s; + + if (ml_free <= len) { + ml_len += len - ml_free + 1; + ml_buffer = (char *)realloc (ml_buffer, ml_len); + if (NULL == ml_buffer) + YY_FATAL_ERROR ("out of dynamic memory in ml_append"); + } + + s = snprintf (ml_buffer + ml_pos, ml_free, "%s", string); + if ((0 > s) || (ml_free <= s)) + YY_FATAL_ERROR ("failed to write to multiline buffer"); + + ml_pos += s; + return; +} /* ml_append */ + diff --git a/src/liboconfig/utils.c b/src/liboconfig/utils.c new file mode 100644 index 0000000..c713610 --- /dev/null +++ b/src/liboconfig/utils.c @@ -0,0 +1,77 @@ +/** + * oconfig - src/utils.h + * Copyright (C) 2012 2012 Sebastian 'tokkee' Harl + * + * 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; only version 2 of the License is applicable. + * + * 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef OCONFIG_UTILS_H +#define OCONFIG_UTILS_H 1 + +#include "liboconfig/oconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int +oconfig_get_string(oconfig_item_t *ci, char **value) +{ + if (! ci) + return -1; + + if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) + return -1; + + if (value) + *value = ci->values[0].value.string; + return 0; +} /* oconfig_get_string */ + +int +oconfig_get_number(oconfig_item_t *ci, double *value) +{ + if (! ci) + return -1; + + if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) + return -1; + + if (value) + *value = ci->values[0].value.number; + return 0; +} /* oconfig_get_number */ + +int +oconfig_get_boolean(oconfig_item_t *ci, _Bool *value) +{ + if (! ci) + return -1; + + if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) + return -1; + + if (value) + *value = ci->values[0].value.boolean != 0; + return 0; +} /* oconfig_get_boolean */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* OCONFIG_UTILS_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/liboconfig/utils.h b/src/liboconfig/utils.h new file mode 100644 index 0000000..5a2ae85 --- /dev/null +++ b/src/liboconfig/utils.h @@ -0,0 +1,50 @@ +/** + * oconfig - src/utils.h + * Copyright (C) 2012 2012 Sebastian 'tokkee' Harl + * + * 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; only version 2 of the License is applicable. + * + * 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef OCONFIG_UTILS_H +#define OCONFIG_UTILS_H 1 + +#include "liboconfig/oconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* oconfig_get_: + * Checks if the specified item has exactly one value of the respective type + * and returns that value through the appropriate parameter. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +oconfig_get_string(oconfig_item_t *ci, char **value); +int +oconfig_get_number(oconfig_item_t *ci, double *value); +int +oconfig_get_boolean(oconfig_item_t *ci, _Bool *value); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* OCONFIG_UTILS_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/syscollector.c b/src/syscollector.c new file mode 100644 index 0000000..b07cf54 --- /dev/null +++ b/src/syscollector.c @@ -0,0 +1,53 @@ +/* + * syscollector - src/syscollector.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "syscollector.h" + +/* + * public API + */ + +unsigned int +sc_version(void) +{ + return SC_VERSION; +} /* sc_version */ + +const char * +sc_version_string(void) +{ + return SC_VERSION_STRING; +} /* sc_version_string */ + +const char * +sc_version_extra(void) +{ + return SC_VERSION_EXTRA; +} /* sc_version_extra */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/utils/llist.c b/src/utils/llist.c new file mode 100644 index 0000000..765743f --- /dev/null +++ b/src/utils/llist.c @@ -0,0 +1,387 @@ +/* + * syscollector - src/utils/llist.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "utils/llist.h" + +#include +#include + +#include + +/* + * private data types + */ + +struct sc_llist_elem; +typedef struct sc_llist_elem sc_llist_elem_t; + +struct sc_llist_elem { + sc_object_t *obj; + + sc_llist_elem_t *next; + sc_llist_elem_t *prev; +}; + +struct sc_llist { + pthread_rwlock_t lock; + + sc_llist_elem_t *head; + sc_llist_elem_t *tail; + + size_t length; +}; + +struct sc_llist_iter { + sc_llist_t *list; + sc_llist_elem_t *elem; +}; + +/* + * private helper functions + */ + +/* Insert a new element after 'elem'. If 'elem' is NULL, insert at the head of + * the list. */ +static int +sc_llist_insert_after(sc_llist_t *list, sc_llist_elem_t *elem, + sc_object_t *obj) +{ + sc_llist_elem_t *new; + + assert(list); + + new = malloc(sizeof(*new)); + if (! new) + return -1; + + new->obj = obj; + if (elem) + new->next = elem->next; + else if (list->head) + new->next = list->head; + else + new->next = NULL; + new->prev = elem; + + if (elem) { + if (elem->next) + elem->next->prev = new; + else + list->tail = new; + elem->next = new; + } + else { + /* new entry will be new head */ + if (list->head) + list->head->prev = new; + + list->head = new; + if (! list->tail) + list->tail = new; + } + + assert(list->head && list->tail); + if (! list->length) { + assert(list->head == list->tail); + } + + sc_object_ref(obj); + ++list->length; + return 0; +} /* sc_llist_insert_after */ + +static sc_object_t * +sc_llist_remove_elem(sc_llist_t *list, sc_llist_elem_t *elem) +{ + sc_object_t *obj; + + assert(list && elem); + + obj = elem->obj; + + if (elem->prev) + elem->prev->next = elem->next; + else { + assert(elem == list->head); + list->head = elem->next; + } + + if (elem->next) + elem->next->prev = elem->prev; + else { + assert(elem == list->tail); + list->tail = elem->prev; + } + + elem->prev = elem->next = NULL; + free(elem); + + --list->length; + return obj; +} /* sc_llist_remove_elem */ + +/* + * public API + */ + +sc_llist_t * +sc_llist_create(void) +{ + sc_llist_t *list; + + list = malloc(sizeof(*list)); + if (! list) + return NULL; + + pthread_rwlock_init(&list->lock, /* attr = */ NULL); + + list->head = list->tail = NULL; + list->length = 0; + return list; +} /* sc_llist_create */ + +sc_llist_t * +sc_llist_clone(sc_llist_t *list) +{ + sc_llist_t *clone; + sc_llist_elem_t *elem; + + if (! list) + return NULL; + + clone = sc_llist_create(); + if (! clone) + return NULL; + + if (! list->length) { + assert((! list->head) && (! list->tail)); + return clone; + } + + for (elem = list->head; elem; elem = elem->next) { + if (sc_llist_append(clone, elem->obj)) { + sc_llist_destroy(clone); + return NULL; + } + } + return clone; +} /* sc_llist_clone */ + +void +sc_llist_destroy(sc_llist_t *list) +{ + sc_llist_elem_t *elem; + + if (! list) + return; + + pthread_rwlock_wrlock(&list->lock); + + elem = list->head; + while (elem) { + sc_llist_elem_t *tmp = elem->next; + + sc_object_deref(elem->obj); + free(elem); + + elem = tmp; + } + + list->head = list->tail = NULL; + list->length = 0; + + pthread_rwlock_unlock(&list->lock); + pthread_rwlock_destroy(&list->lock); + free(list); +} /* sc_llist_destroy */ + +int +sc_llist_append(sc_llist_t *list, sc_object_t *obj) +{ + int status; + + if ((! list) || (! obj)) + return -1; + + pthread_rwlock_wrlock(&list->lock); + status = sc_llist_insert_after(list, list->tail, obj); + pthread_rwlock_unlock(&list->lock); + return status; +} /* sc_llist_append */ + +int +sc_llist_insert(sc_llist_t *list, sc_object_t *obj, size_t index) +{ + sc_llist_elem_t *prev; + sc_llist_elem_t *next; + + int status; + + size_t i; + + if ((! list) || (! obj) || (index > list->length)) + return -1; + + pthread_rwlock_wrlock(&list->lock); + + prev = NULL; + next = list->head; + + for (i = 0; i < index; ++i) { + prev = next; + next = next->next; + } + status = sc_llist_insert_after(list, prev, obj); + pthread_rwlock_unlock(&list->lock); + return status; +} /* sc_llist_insert */ + +int +sc_llist_insert_sorted(sc_llist_t *list, sc_object_t *obj, + int (*compare)(const sc_object_t *, const sc_object_t *)) +{ + sc_llist_elem_t *prev; + sc_llist_elem_t *next; + + int status; + + if ((! list) || (! obj) || (! compare)) + return -1; + + pthread_rwlock_wrlock(&list->lock); + + prev = NULL; + next = list->head; + + while (next) { + if (compare(obj, next->obj) < 0) + break; + + prev = next; + next = next->next; + } + status = sc_llist_insert_after(list, prev, obj); + pthread_rwlock_unlock(&list->lock); + return status; +} /* sc_llist_insert_sorted */ + +sc_object_t * +sc_llist_search(sc_llist_t *list, const sc_object_t *key, + int (*compare)(const sc_object_t *, const sc_object_t *)) +{ + sc_llist_elem_t *elem; + + if ((! list) || (! compare)) + return NULL; + + pthread_rwlock_rdlock(&list->lock); + + for (elem = list->head; elem; elem = elem->next) + if (! compare(elem->obj, key)) + break; + + pthread_rwlock_unlock(&list->lock); + + if (elem) + return elem->obj; + return NULL; +} /* sc_llist_search */ + +sc_object_t * +sc_llist_shift(sc_llist_t *list) +{ + sc_object_t *obj; + + if ((! list) || (! list->head)) + return NULL; + + pthread_rwlock_wrlock(&list->lock); + obj = sc_llist_remove_elem(list, list->head); + pthread_rwlock_unlock(&list->lock); + return obj; +} /* sc_llist_shift */ + +sc_llist_iter_t * +sc_llist_get_iter(sc_llist_t *list) +{ + sc_llist_iter_t *iter; + + if (! list) + return NULL; + + iter = malloc(sizeof(*iter)); + if (! iter) + return NULL; + + pthread_rwlock_rdlock(&list->lock); + + iter->list = list; + iter->elem = list->head; + + /* XXX: keep lock until destroying the iterator? */ + pthread_rwlock_unlock(&list->lock); + return iter; +} /* sc_llist_get_iter */ + +void +sc_llist_iter_destroy(sc_llist_iter_t *iter) +{ + if (! iter) + return; + + iter->list = NULL; + iter->elem = NULL; + free(iter); +} /* sc_llist_iter_destroy */ + +_Bool +sc_llist_iter_has_next(sc_llist_iter_t *iter) +{ + if (! iter) + return 0; + return iter->elem != NULL; +} /* sc_llist_iter_has_next */ + +sc_object_t * +sc_llist_iter_get_next(sc_llist_iter_t *iter) +{ + sc_object_t *obj; + + if ((! iter) || (! iter->elem)) + return NULL; + + pthread_rwlock_rdlock(&iter->list->lock); + + obj = iter->elem->obj; + iter->elem = iter->elem->next; + + pthread_rwlock_unlock(&iter->list->lock); + return obj; +} /* sc_llist_iter_get_next */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/utils/string.c b/src/utils/string.c new file mode 100644 index 0000000..25d3e9e --- /dev/null +++ b/src/utils/string.c @@ -0,0 +1,63 @@ +/* + * syscollector - src/utils/string.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "utils/string.h" + +#include +#include + +/* + * public API + */ + +char * +sc_strerror(int errnum, char *strerrbuf, size_t buflen) +{ +#if STRERROR_R_CHAR_P + { + char *tmp = strerror_r(errnum, strerrbuf, buflen); + if (*strerrbuf = '\0') { + if (tmp && (tmp != strerrbuf) && (*tmp != '\0')) + strncpy(strerrbuf, tmp, buflen); + else + snprintf(strerrbuf, buflen, "unknown error #%i " + "(strerror_r(3) did not return an error message)", + errnum); + } + } +#else + if (strerror_r(errnum, strerrbuf, buflen)) + snprintf(strerrbuf, buflen, "unknown error #%i " + "(strerror_r(3) failed)", errnum); +#endif + + strerrbuf[buflen - 1] = '\0'; + return strerrbuf; +} /* sc_strerror */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/utils/time.c b/src/utils/time.c new file mode 100644 index 0000000..d3192c3 --- /dev/null +++ b/src/utils/time.c @@ -0,0 +1,80 @@ +/* + * syscollector - src/utils/time.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "utils/time.h" +#include "utils/string.h" + +#include + +#include + +/* + * public API + */ + +sc_time_t +sc_gettime(void) +{ + struct timespec ts_now = { 0, 0 }; + + if (clock_gettime(CLOCK_REALTIME, &ts_now)) + return 0; + return TIMESPEC_TO_SC_TIME(ts_now); +} /* sc_gettime */ + +int +sc_sleep(sc_time_t reg, sc_time_t *rem) +{ + struct timespec ts_reg, ts_rem = { 0, 0 }; + int status; + + ts_reg.tv_sec = (time_t)SC_TIME_TO_SECS(reg); + ts_reg.tv_nsec = (long int)(reg % (sc_time_t)1000000000); + + status = nanosleep(&ts_reg, &ts_rem); + if (rem) + *rem = TIMESPEC_TO_SC_TIME(ts_rem); + return status; +} /* sc_sleep */ + +size_t +sc_strftime(char *s, size_t len, const char *format, sc_time_t t) +{ + time_t tstamp; + struct tm tm; + + memset(&tm, 0, sizeof(tm)); + + tstamp = (time_t)SC_TIME_TO_SECS(t); + if (! localtime_r (&tstamp, &tm)) + return 0; + + return strftime(s, len, format, &tm); +} /* sc_strftime */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/utils/unixsock.c b/src/utils/unixsock.c new file mode 100644 index 0000000..1be17b9 --- /dev/null +++ b/src/utils/unixsock.c @@ -0,0 +1,189 @@ +/* + * syscollector - src/utils/unixsock.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. + */ + +#include "utils/unixsock.h" +#include "utils/string.h" + +#include + +#include +#include +#include + +#include + +#include +#include + +/* + * private data types + */ + +struct sc_unixsock_client { + char *path; + FILE *fh; +}; + +/* + * public API + */ + +sc_unixsock_client_t * +sc_unixsock_client_create(const char *path) +{ + sc_unixsock_client_t *client; + + if (! path) + return NULL; + + client = malloc(sizeof(*client)); + if (! client) + return NULL; + memset(client, 0, sizeof(*client)); + client->fh = NULL; + + client->path = strdup(path); + if (! client->path) { + sc_unixsock_client_destroy(client); + return NULL; + } + return client; +} /* sc_unixsock_client_create */ + +int +sc_unixsock_client_connect(sc_unixsock_client_t *client) +{ + struct sockaddr_un sa; + int fd; + + if ((! client) || (! client->path)) + return -1; + + memset(&sa, 0, sizeof(sa)); + + if (client->fh) + fclose(client->fh); + + fd = socket(AF_UNIX, SOCK_STREAM, /* protocol = */ 0); + if (fd < 0) { + char errbuf[1024]; + fprintf(stderr, "unixsock: Failed to open socket: %s\n", + sc_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, client->path, sizeof(sa.sun_path)); + sa.sun_path[sizeof(sa.sun_path) - 1] = '\0'; + + if (connect(fd, (struct sockaddr *)&sa, sizeof(sa))) { + char errbuf[1024]; + fprintf(stderr, "unixsock: Failed to connect to %s: %s\n", + sa.sun_path, sc_strerror(errno, errbuf, sizeof(errbuf))); + close(fd); + return -1; + } + + client->fh = fdopen(fd, "r+"); + if (! client->fh) { + char errbuf[1024]; + fprintf(stderr, "unixsock: Failed to open I/O stream for %s: %s\n", + sa.sun_path, sc_strerror(errno, errbuf, sizeof(errbuf))); + close(fd); + return -1; + } + return 0; +} /* sc_unixsock_client_connect */ + +int +sc_unixsock_client_send(sc_unixsock_client_t *client, const char *msg) +{ + int status; + + if ((! client) || (! client->fh)) + return -1; + + status = fprintf(client->fh, "%s\r\n", msg); + if (status < 0) { + char errbuf[1024]; + fprintf(stderr, "unixsock: Failed to write to socket (%s): %s\n", + client->path, sc_strerror(errno, errbuf, sizeof(errbuf))); + return status; + } + return status; +} /* sc_unixsock_client_send */ + +char * +sc_unixsock_client_recv(sc_unixsock_client_t *client, char *buffer, size_t buflen) +{ + if ((! client) || (! client->fh) || (! buffer)) + return NULL; + + buffer = fgets(buffer, (int)buflen - 1, client->fh); + if ((! buffer) && (! feof(client->fh))) { + char errbuf[1024]; + fprintf(stderr, "unixsock: Failed to read from socket (%s): %s\n", + client->path, sc_strerror(errno, errbuf, sizeof(errbuf))); + return buffer; + } + buffer[buflen - 1] = '\0'; + + buflen = strlen(buffer); + while ((buffer[buflen - 1] == '\n') || (buffer[buflen - 1] == '\r')) { + buffer[buflen - 1] = '\0'; + --buflen; + } + return buffer; +} /* sc_unixsock_client_recv */ + +void +sc_unixsock_client_destroy(sc_unixsock_client_t *client) +{ + if (! client) + return; + + if (client->path) + free(client->path); + client->path = NULL; + + if (client->fh) + fclose(client->fh); + client->fh = NULL; + + free(client); +} /* sc_unixsock_client_destroy */ + +const char * +sc_unixsock_client_path(sc_unixsock_client_t *client) +{ + if (! client) + return NULL; + return client->path; +} /* sc_unixsock_client_path */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/version-gen.sh b/version-gen.sh new file mode 100755 index 0000000..c2ff7c4 --- /dev/null +++ b/version-gen.sh @@ -0,0 +1,44 @@ +#! /bin/sh + +DEFAULT_VERSION="0.0.0.git" + +VERSION="$( git describe --tags 2> /dev/null \ + | sed -e 's/syscollector-//' || true )" + +if test -z "$VERSION"; then + VERSION="$DEFAULT_VERSION" +else + git update-index -q --refresh || true + if test -n "$( git diff-index --name-only HEAD || true )"; then + VERSION="$VERSION-dirty" + fi +fi + +VERSION="$( echo "$VERSION" | sed -e 's/-/./g' )" +if test "x`uname -s`" = "xAIX" || test "x`uname -s`" = "xSunOS" ; then + echo "$VERSION\c" +else + echo -n "$VERSION" +fi + +OLD_VERSION="" +if test -e version; then + OLD_VERSION=$( sed -ne 's/^VERSION="\(.*\)"/\1/p' version ) +fi + +if test "$OLD_VERSION" != "$VERSION"; then + VERSION_MAJOR=$( echo $VERSION | cut -d'.' -f1 ) + VERSION_MINOR=$( echo $VERSION | cut -d'.' -f2 ) + VERSION_PATCH=$( echo $VERSION | cut -d'.' -f3 ) + VERSION_EXTRA="\"$( echo $VERSION | cut -d'.' -f4- )\"" + test -z "$VERSION_EXTRA" || VERSION_EXTRA=".$VERSION_EXTRA" + ( + echo "VERSION=\"$VERSION\"" + echo "VERSION_MAJOR=$VERSION_MAJOR" + echo "VERSION_MINOR=$VERSION_MINOR" + echo "VERSION_PATCH=$VERSION_PATCH" + echo "VERSION_EXTRA=\"$VERSION_EXTRA\"" + echo "VERSION_STRING=\"$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH\"" + ) > version +fi +