From aa6b6a3766187ef3151cc381876cf06b269aec08 Mon Sep 17 00:00:00 2001 From: octo Date: Tue, 29 Nov 2005 13:01:15 +0000 Subject: [PATCH] Added Niki Waibel's quota patch --- AUTHORS | 31 ++ configure.in | 444 +++++++++++++++++++++++++++ src/Makefile.am | 121 ++++++++ src/collectd.h | 62 ++++ src/config.h.in | 277 +++++++++++++++++ src/quota_debug.c | 31 ++ src/quota_debug.h | 61 ++++ src/quota_fs.c | 54 ++++ src/quota_fs.h | 33 +++ src/quota_mnt.c | 725 +++++++++++++++++++++++++++++++++++++++++++++ src/quota_mnt.h | 45 +++ src/quota_mntopt.h | 154 ++++++++++ src/quota_plugin.c | 140 +++++++++ src/quota_plugin.h | 42 +++ 14 files changed, 2220 insertions(+) create mode 100644 AUTHORS create mode 100644 configure.in create mode 100644 src/Makefile.am create mode 100644 src/collectd.h create mode 100644 src/config.h.in create mode 100644 src/quota_debug.c create mode 100644 src/quota_debug.h create mode 100644 src/quota_fs.c create mode 100644 src/quota_fs.h create mode 100644 src/quota_mnt.c create mode 100644 src/quota_mnt.h create mode 100644 src/quota_mntopt.h create mode 100644 src/quota_plugin.c create mode 100644 src/quota_plugin.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..3e803b89 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,31 @@ +This package was written by: + Florian octo Forster + +cpufreq module by: + Peter Holik + +hddtemp module by: + Vincent Stehlé + +nfs module by: + Jason Pepas + +processes module by: + Lyonel Vincent + +quota module by: + Niki Waibel + +serial module by: + David Bacher + +tape module by: + Scott Garrett + +don't-fork-patch by: + Alvaro Barcellos + +collectd is available at: + + +Enjoy :) diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..a50fa6b4 --- /dev/null +++ b/configure.in @@ -0,0 +1,444 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(src/collectd.c) +AM_INIT_AUTOMAKE(collectd, 3.4.0-quota) +AM_CONFIG_HEADER(src/config.h src/libping/config.h) +AC_LANG(C) + +#AC_PREFIX_DEFAULT("/opt/collectd-3.4.0") + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET + +dnl configure libtool +AC_DISABLE_STATIC +AC_LIBTOOL_DLOPEN +AC_PROG_LIBTOOL +#AC_PROG_RANLIB + +dnl Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h unistd.h) +AC_CHECK_HEADERS(signal.h) +AC_CHECK_HEADERS(sys/socket.h) +AC_CHECK_HEADERS(sys/select.h) +AC_CHECK_HEADERS(netdb.h) +AC_CHECK_HEADERS(sys/time.h sys/times.h) +AC_CHECK_HEADERS(sys/types.h) +AC_CHECK_HEADERS(sys/resource.h) +AC_CHECK_HEADERS(errno.h) +AC_CHECK_HEADERS(arpa/inet.h) +AC_CHECK_HEADERS(netinet/in.h) +AC_CHECK_HEADERS(netdb.h) +AC_CHECK_HEADERS(syslog.h) +AC_CHECK_HEADERS(dlfcn.h) +AC_CHECK_HEADERS(paths.h) +AC_CHECK_HEADERS(mntent.h) +AC_CHECK_HEADERS(sys/fs_types.h) +AC_CHECK_HEADERS(sys/mnttab.h) +AC_CHECK_HEADERS(sys/mount.h) +AC_CHECK_HEADERS(sys/vfstab.h) +AC_CHECK_HEADERS(xfs/xqm.h) + +dnl Checking for libraries +AC_CHECK_LIB(m, ext) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_HEADER_TIME + +dnl Checks for library functions. +AC_PROG_GCC_TRADITIONAL +AC_CHECK_FUNCS(gettimeofday select socket strdup strstr strtol) +AC_CHECK_FUNCS(socket, , AC_CHECK_LIB(socket, socket)) +AC_CHECK_FUNCS(gethostbyname, , AC_CHECK_LIB(nsl, gethostbyname)) +AC_CHECK_FUNCS(strchr memcpy strstr strcmp strncmp strncpy strlen) +AC_CHECK_FUNCS(strncasecmp strcasecmp strncmp) +AC_CHECK_FUNCS(getfsent getvfsent getmntent listmntent) + +AC_MSG_CHECKING([for kernel type ($host_os)]) +case $host_os in + *linux*) + AC_DEFINE([KERNEL_LINUX], [], [True if program is to be compiled for a Linux kernel]) + ac_system="Linux" + ;; + *solaris*) + AC_DEFINE([KERNEL_SOLARIS], [], [True if program is to be compiled for a Solaris kernel]) + ac_system="Solaris" + ;; + *) + ac_system="unknown" +esac +AC_MSG_RESULT([$ac_system]) + +dnl Checks for libraries. +AC_CHECK_LIB(socket, socket) +AC_CHECK_LIB(resolv, res_search) +AC_CHECK_LIB(dl, dlopen) + +# AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given]) +AC_ARG_WITH(rrdtool, AC_HELP_STRING([--with-rrdtool=PFX], [Path to rrdtool.]), +[ if test "x$withval" != "xno" -a "x$withval" != "xyes" + then + LDFLAGS="$LDFLAGS -L$withval/lib" + CPPFLAGS="$CPPFLAGS -I$withval/include" + with_rrdtool="yes" + fi +], [with_rrdtool="yes"]) +if test "x$with_rrdtool" = "xyes" +then + AC_CHECK_LIB(rrd, rrd_update,, [with_rrdtool="no"], [-lm]) +fi +if test "x$with_rrdtool" = "xyes" +then + AC_CHECK_HEADERS(rrd.h,, [with_rrdtool="no"]) +fi +AM_CONDITIONAL(BUILD_WITH_RRDTOOL, test "x$with_rrdtool" = "xyes") + +if test "$ac_system" = "Solaris" +then + with_kstat="yes" + AC_CHECK_LIB(kstat, kstat_open,, [with_kstat="no (not found)"]) + AC_CHECK_LIB(devinfo, di_init) + AC_CHECK_HEADERS(kstat.h,, [with_kstat="no (kstat.h not found)"]) +else + with_kstat="no (Solaris only)" +fi + +AC_ARG_WITH(libstatgrab, AC_HELP_STRING([--with-libstatgrab@<:@=PFX@:>@], [Path to libstatgrab.]), +[ + # given.. + if test "x$withval" != "xno" + then + if test "x$withval" != "xyes" + then + LDFLAGS="$LDFLAGS -L$withval/lib" + CPPFLAGS="$CPPFLAGS -I$withval/include" + with_libstatgrab="yes" + fi + fi +], +[ + # not given.. + if test "x$ac_system" != "xunknown" + then + with_libstatgrab="no" + else + with_libstatgrab="yes" + fi +]) +if test "x$with_libstatgrab" = "xyes" +then + AC_CHECK_LIB(statgrab, sg_init,, [with_libstatgrab="no (not found)"]) + AC_CHECK_HEADERS(statgrab.h,, [with_libstatgrab="no (not found)"]) +fi + +AC_ARG_WITH(lm-sensors, AC_HELP_STRING([--with-lm-sensors@<:@=PFX@:>@], [Path to lm_sensors.]), +[ + # given.. + if test "x$withval" != "xno" + then + if test "x$withval" != "xyes" + then + LDFLAGS="$LDFLAGS -L$withval/lib" + CPPFLAGS="$CPPFLAGS -I$withval/include" + with_lm_sensors="yes" + fi + fi +], +[ + # not given.. + if test "x$ac_system" = "xLinux" + then + with_lm_sensors="yes" + else + with_lm_sensors="no" + fi +]) +if test "x$with_lm_sensors" = "xyes" +then + AC_CHECK_LIB(sensors, sensors_init, + [ + with_lm_sensors="yes" + AC_DEFINE(HAVE_LIBSENSORS, 1, [Define to 1 if you have the sensors library (-lsensors).]) + ], + [with_lm_sensors="no (not found)"]) + AC_CHECK_HEADERS(sensors/sensors.h, + [ + with_lm_sensors="yes" + AC_DEFINE(HAVE_SENSORS_SENSORS_H, 1, [Define to 1 if you have the header file.]) + ], + [with_lm_sensors="no (not found)"]) +fi + + + +# +# Check for enabled/disabled features +# +AC_ARG_ENABLE(cpu, AC_HELP_STRING([--disable-cpu], [Disable CPU usage statistics]),, [enable_cpu="yes"]) +if test "x$enable_cpu" != "xno" +then + if test "x$ac_system" = "xLinux" -o "x$with_kstat" = "xyes" -o "x$with_libstatgrab" = "xyes" + then + enable_cpu="yes" + else + enable_cpu="no" + fi +fi +if test "x$enable_cpu" = "xno" +then + AC_DEFINE(COLLECT_CPU, 0, [Wether or not to collect CPU usage statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_CPU, test "x$enable_cpu" = "xyes") + +AC_ARG_ENABLE(cpufreq, AC_HELP_STRING([--disable-cpufreq], [Disable system cpu frequency statistics]),, [enable_cpufreq="yes"]) +if test "x$enable_cpufreq" != "xno" +then + if test "x$ac_system" = "xLinux" + then + enable_cpufreq="yes" + else + enable_cpufreq="no" + fi +fi +if test "x$enable_cpufreq" = "xno" +then + AC_DEFINE(COLLECT_CPUFREQ, 0, [Wether or not to collect cpu frequency statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_CPUFREQ, test "x$enable_cpufreq" = "xyes") + +AC_ARG_ENABLE(disk, AC_HELP_STRING([--disable-disk], [Disable disk/partition statistics]),, [enable_disk="yes"]) +if test "x$enable_disk" != "xno" +then + if test "x$ac_system" = "xLinux" -o "x$with_kstat" = "xyes" + then + enable_disk="yes" + else + enable_disk="no" + fi +fi +if test "x$enable_disk" = "xno" +then + AC_DEFINE(COLLECT_DISK, 0, [Wether or not to collect diskstats]) +fi +AM_CONDITIONAL(BUILD_MODULE_DISK, test "x$enable_disk" = "xyes") + +AC_ARG_ENABLE(quota, AC_HELP_STRING([--enable-quota], + [Enable quota statistics (experimental, off by default)]), + [], [enable_quota="no"]) +if test "x$enable_quota" = "xno" +then + collect_quota=0 +else + if test "x$enable_quota" = "xyes" + then + collect_quota=1 + enable_quota="yes" + else + AC_MSG_NOTICE([Please specify either --enable-quota or --disable-quota; Enabling quota statistics.]) + collect_quota=1 + enable_quota="yes" + fi +fi +AC_DEFINE_UNQUOTED(COLLECT_QUOTA, [$collect_quota], + [Wether or not to collect quotastats]) +AM_CONDITIONAL(BUILD_MODULE_QUOTA, test "x$enable_quota" = "xyes") + +AC_ARG_ENABLE(hddtemp, AC_HELP_STRING([--disable-hddtemp], [Disable hdd temperature statistics]),, [enable_hddtemp="yes"]) +if test "x$enable_hddtemp" = "xno" +then + AC_DEFINE(COLLECT_HDDTEMP, 0, [Wether or not to collect hdd temperature statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_HDDTEMP, test "x$enable_hddtemp" = "xyes") + +AC_ARG_ENABLE(load, AC_HELP_STRING([--disable-load], [Disable system load statistics]),, [enable_load="yes"]) +if test "x$enable_load" != "xno" +then + if test "x$ac_system" = "xLinux" -o "x$with_kstat" = "xyes" -o "x$with_libstatgrab" = "xyes" + then + enable_load="yes" + else + enable_load="no" + fi +fi +if test "x$enable_load" = "xno" +then + AC_DEFINE(COLLECT_LOAD, 0, [Wether or not to collect system load statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_LOAD, test "x$enable_load" = "xyes") + +AC_ARG_ENABLE(memory, AC_HELP_STRING([--disable-memory], [Disable memory statistics]),, [enable_memory="yes"]) +if test "x$enable_memory" != "xno" +then + if test "x$ac_system" = "xLinux" -o "x$with_kstat" = "xyes" -o "x$with_libstatgrab" = "xyes" + then + enable_memory="yes" + else + enable_memory="no" + fi +fi +if test "x$enable_memory" = "xno" +then + AC_DEFINE(COLLECT_MEMORY, 0, [Wether or not to collect memory statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_MEMORY, test "x$enable_memory" = "xyes") + +AC_ARG_ENABLE(nfs, AC_HELP_STRING([--disable-nfs], [Disable nfs statistics]),, [enable_nfs="yes"]) +if test "x$enable_nfs" != "xno" +then + if test "x$ac_system" = "xLinux" + then + enable_nfs="yes" + else + enable_nfs="no" + fi +fi +if test "x$enable_nfs" = "xno" +then + AC_DEFINE(COLLECT_NFS, 0, [Wether or not to collect nfs statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_NFS, test "x$enable_nfs" = "xyes") + +AC_ARG_ENABLE(ping, AC_HELP_STRING([--disable-ping], [Disable ping statistics]),, [enable_ping="yes"]) +if test "x$enable_ping" != "xno" +then + enable_ping="yes" +fi +if test "x$enable_ping" = "xno" +then + AC_DEFINE(COLLECT_PING, 0, [Wether or not to collect ping statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_PING, test "x$enable_ping" = "xyes") + +AC_ARG_ENABLE(processes, AC_HELP_STRING([--disable-processes], [Disable processes statistics]),, [enable_processes="yes"]) +if test "x$enable_processes" != "xno" +then + if test "x$ac_system" = "xLinux" + then + enable_processes="yes" + else + enable_processes="no" + fi +fi +if test "x$enable_processes" = "xno" +then + AC_DEFINE(COLLECT_PROCESSES, 0, [Wether or not to collect processes statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_PROCESSES, test "x$enable_processes" = "xyes") + +AC_ARG_ENABLE(sensors, AC_HELP_STRING([--disable-sensors], [Disable lm_sensors statistics]),, [enable_sensors=$with_lm_sensors]) +if test "x$enable_sensors" != "xno" +then + if test "x$with_lm_sensors" = "xyes" + then + enable_sensors="yes" + else + enable_sensors="no" + fi +fi +if test "x$enable_sensors" = "xno" +then + AC_DEFINE(COLLECT_SENSORS, 0, [Wether or not to collect lm_sensors statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_SENSORS, test "x$enable_sensors" = "xyes") + +AC_ARG_ENABLE(serial, AC_HELP_STRING([--disable-serial], [Disable serial statistics]),, [enable_serial="yes"]) +if test "x$enable_serial" != "xno" +then + if test "x$ac_system" = "xLinux" + then + enable_serial="yes" + else + enable_serial="no" + fi +fi +if test "x$enable_serial" = "xno" +then + AC_DEFINE(COLLECT_SERIAL, 0, [Wether or not to collect serial statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_SERIAL, test "x$enable_serial" = "xyes") + +AC_ARG_ENABLE(swap, AC_HELP_STRING([--disable-swap], [Disable swap statistics]),, [enable_swap="yes"]) +if test "x$enable_swap" != "xno" +then + if test "x$ac_system" = "xLinux" -o "x$with_kstat" = "xyes" -o "x$with_libstatgrab" = "xyes" + then + enable_swap="yes" + else + enable_swap="no" + fi +fi +if test "x$enable_swap" = "xno" +then + AC_DEFINE(COLLECT_SWAP, 0, [Wether or not to collect swap statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_SWAP, test "x$enable_swap" = "xyes") + +AC_ARG_ENABLE(tape, AC_HELP_STRING([--disable-tape], [Disable tape statistics]),, [enable_tape="yes"]) +if test "x$enable_tape" != "xno" +then + if test "x$with_kstat" = "xyes" + then + enable_tape="yes" + else + enable_tape="no" + fi +fi +if test "x$enable_tape" = "xno" +then + AC_DEFINE(COLLECT_TAPE, 0, [Wether or not to collect tape statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_TAPE, test "x$enable_tape" = "xyes") + +AC_ARG_ENABLE(traffic, AC_HELP_STRING([--disable-traffic], [Disable system traffic statistics]),, [enable_traffic="yes"]) +if test "x$enable_traffic" != "xno" +then + if test "x$ac_system" = "xLinux" -o "x$with_kstat" = "xyes" -o "x$with_libstatgrab" = "xyes" + then + enable_traffic="yes" + else + enable_traffic="no" + fi +fi +if test "x$enable_traffic" = "xno" +then + AC_DEFINE(COLLECT_TRAFFIC, 0, [Wether or not to collect network traffic statistics]) +fi +AM_CONDITIONAL(BUILD_MODULE_TRAFFIC, test "x$enable_traffic" = "xyes") + +AC_OUTPUT(Makefile src/libping/Makefile src/Makefile) + +cat <$@ diff --git a/src/collectd.h b/src/collectd.h new file mode 100644 index 00000000..eb07756a --- /dev/null +++ b/src/collectd.h @@ -0,0 +1,62 @@ +#ifndef COLLECTD_H +#define COLLECTD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#ifndef HAVE_RRD_H +#undef HAVE_LIBRRD +#endif + +#ifdef HAVE_LIBRRD +#include +#endif /* HAVE_LIBRRD */ + +/* Won't work without the header file */ +#ifndef HAVE_KSTAT_H +#undef HAVE_LIBKSTAT +#endif + +#ifdef HAVE_LIBKSTAT +#include +#include +#endif /* HAVE_LIBKSTAT */ + +/* Won't work without the header file */ +#ifndef HAVE_STATGRAB_H +#undef HAVE_LIBSTATGRAB +#endif + +#ifdef HAVE_LIBSTATGRAB +#include +#endif + +#ifndef DEBUG +#define DEBUG 0 +#endif + +#ifndef PLUGINDIR +#define PLUGINDIR "/usr/lib/collectd" +#endif + +#define MODE_SERVER 0x01 +#define MODE_CLIENT 0x02 +#define MODE_LOCAL 0x03 + +extern time_t curtime; +extern int operating_mode; + +#endif /* COLLECTD_H */ diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 00000000..b49392eb --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,277 @@ +/* src/config.h.in. Generated from configure.in by autoheader. */ + +/* Wether or not to collect CPU usage statistics */ +#undef COLLECT_CPU + +/* Wether or not to collect cpu frequency statistics */ +#undef COLLECT_CPUFREQ + +/* Wether or not to collect diskstats */ +#undef COLLECT_DISK + +/* Wether or not to collect hdd temperature statistics */ +#undef COLLECT_HDDTEMP + +/* Wether or not to collect system load statistics */ +#undef COLLECT_LOAD + +/* Wether or not to collect memory statistics */ +#undef COLLECT_MEMORY + +/* Wether or not to collect nfs statistics */ +#undef COLLECT_NFS + +/* Wether or not to collect ping statistics */ +#undef COLLECT_PING + +/* Wether or not to collect processes statistics */ +#undef COLLECT_PROCESSES + +/* Wether or not to collect quotastats */ +#undef COLLECT_QUOTA + +/* Wether or not to collect lm_sensors statistics */ +#undef COLLECT_SENSORS + +/* Wether or not to collect serial statistics */ +#undef COLLECT_SERIAL + +/* Wether or not to collect swap statistics */ +#undef COLLECT_SWAP + +/* Wether or not to collect tape statistics */ +#undef COLLECT_TAPE + +/* Wether or not to collect network traffic statistics */ +#undef COLLECT_TRAFFIC + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `getfsent' function. */ +#undef HAVE_GETFSENT + +/* Define to 1 if you have the `gethostbyname' function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define to 1 if you have the `getmntent' function. */ +#undef HAVE_GETMNTENT + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the `getvfsent' function. */ +#undef HAVE_GETVFSENT + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_KSTAT_H + +/* Define to 1 if you have the `devinfo' library (-ldevinfo). */ +#undef HAVE_LIBDEVINFO + +/* Define to 1 if you have the `dl' library (-ldl). */ +#undef HAVE_LIBDL + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +#undef HAVE_LIBKSTAT + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `rrd' library (-lrrd). */ +#undef HAVE_LIBRRD + +/* Define to 1 if you have the sensors library (-lsensors). */ +#undef HAVE_LIBSENSORS + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the `statgrab' library (-lstatgrab). */ +#undef HAVE_LIBSTATGRAB + +/* Define to 1 if you have the `listmntent' function. */ +#undef HAVE_LISTMNTENT + +/* Define to 1 if you have the `memcpy' function. */ +#undef HAVE_MEMCPY + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MNTENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PATHS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_RRD_H + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the header file. */ +#undef HAVE_SENSORS_SENSORS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#undef HAVE_STATGRAB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strcmp' function. */ +#undef HAVE_STRCMP + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlen' function. */ +#undef HAVE_STRLEN + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the `strncmp' function. */ +#undef HAVE_STRNCMP + +/* Define to 1 if you have the `strncpy' function. */ +#undef HAVE_STRNCPY + +/* Define to 1 if you have the `strstr' function. */ +#undef HAVE_STRSTR + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MNTTAB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MOUNT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_VFSTAB_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_XFS_XQM_H + +/* True if program is to be compiled for a Linux kernel */ +#undef KERNEL_LINUX + +/* True if program is to be compiled for a Solaris kernel */ +#undef KERNEL_SOLARIS + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/src/quota_debug.c b/src/quota_debug.c new file mode 100644 index 00000000..acaa94ca --- /dev/null +++ b/src/quota_debug.c @@ -0,0 +1,31 @@ +/** + * collectd - src/quota_plugin.c + * Copyright (C) 2005 Niki W. Waibel + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * Author: + * Niki W. Waibel +**/ + +#include "common.h" +#include "quota_debug.h" + +/* *** *** *** global variables *** *** *** */ +#if QUOTA_PLUGIN_DEBUG + FILE *QUOTA_DBG_FILE = NULL; +#endif + diff --git a/src/quota_debug.h b/src/quota_debug.h new file mode 100644 index 00000000..dcbdcd46 --- /dev/null +++ b/src/quota_debug.h @@ -0,0 +1,61 @@ +/** + * collectd - src/quota_debug.h + * Copyright (C) 2005 Niki W. Waibel + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * Author: + * Niki W. Waibel +**/ + +#if !COLLECTD_QUOTA_DEBUG_H +#define COLLECTD_QUOTA_DEBUG_H 1 + +#include "common.h" + +#define QUOTA_PLUGIN_DEBUG 1 + +#if QUOTA_PLUGIN_DEBUG + #include + extern FILE *QUOTA_DBG_FILE; + #define DBG(...) \ + { \ + if(QUOTA_DBG_FILE != NULL) { \ + fprintf(QUOTA_DBG_FILE, "%s:%d:%s(): ", \ + __FILE__, __LINE__, __func__); \ + fprintf(QUOTA_DBG_FILE, __VA_ARGS__); \ + fprintf(QUOTA_DBG_FILE, "\n"); \ + fflush(QUOTA_DBG_FILE); \ + } \ + } + #define DBG_INIT(...) \ + { \ + QUOTA_DBG_FILE = fopen("collectd.log", "a"); \ + if(QUOTA_DBG_FILE == NULL) { \ + /* stderr is redirected to /dev/null, so you \ + will not see anything */ \ + fprintf(stderr, "Cannot open quota debug file.\n"); \ + } else { \ + DBG(__VA_ARGS__); \ + } \ + } +#else /* !QUOTA_PLUGIN_DEBUG */ + #define DBG(...) /**/ + #define DBG_INIT(...) /**/ +#endif /* QUOTA_PLUGIN_DEBUG */ + +#endif /* !COLLECTD_QUOTA_DEBUG_H */ + diff --git a/src/quota_fs.c b/src/quota_fs.c new file mode 100644 index 00000000..bfd4d5ef --- /dev/null +++ b/src/quota_fs.c @@ -0,0 +1,54 @@ +/** + * collectd - src/quota_fs.c + * Copyright (C) 2005 Niki W. Waibel + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * Author: + * Niki W. Waibel +**/ + +#include "common.h" +#include "quota_debug.h" +#include "quota_fs.h" + +int +quota_fs_issupported(const char *fsname) +{ + if(!strcmp(fsname, "ext2") + || !strcmp(fsname, "ext3") + || !strcmp(fsname, "ufs") + || !strcmp(fsname, "vxfs") + || !strcmp(fsname, "zfs")) + { + return EXIT_SUCCESS; + } else { +#if 0 + DBG("%s filesystem not supported", fsname); +#endif + return EXIT_FAILURE; + } +} + +int +quota_fs_isnfs(const char *fsname) +{ + if(!strcmp(fsname, "nfs") || !strcmp(fsname, "nfs4")) { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } +} diff --git a/src/quota_fs.h b/src/quota_fs.h new file mode 100644 index 00000000..445b23d6 --- /dev/null +++ b/src/quota_fs.h @@ -0,0 +1,33 @@ +/** + * collectd - src/quota_fs.h + * Copyright (C) 2005 Niki W. Waibel + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * Author: + * Niki W. Waibel +**/ + +#if !COLLECTD_QUOTA_FS_H +#define COLLECTD_QUOTA_FS_H 1 + +#include "common.h" + +int quota_fs_issupported(const char *fsname); +int quota_fs_isnfs(const char *fsname); + +#endif /* !COLLECTD_QUOTA_FS_H */ + diff --git a/src/quota_mnt.c b/src/quota_mnt.c new file mode 100644 index 00000000..19cfa767 --- /dev/null +++ b/src/quota_mnt.c @@ -0,0 +1,725 @@ +/** + * collectd - src/quota_mnt.c + * Copyright (C) 2005 Niki W. Waibel + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * Author: + * Niki W. Waibel +**/ + +#include "common.h" +#include "quota_debug.h" +#include "quota_fs.h" +#include "quota_mnt.h" + +#include +#include +#include +#include +#if HAVE_MNTENT_H /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ +#include +#endif +#if HAVE_MNTTAB_H /* SVR2, SVR3. */ +#include +#endif +#if HAVE_PATHS_H +#include +#endif +#include +#include +#if HAVE_SYS_FS_TYPES_H /* Ultrix. */ +#include +#endif +#if HAVE_SYS_MNTTAB_H /* SVR4. */ +#include +#endif +#if HAVE_SYS_MOUNT_H /* 4.4BSD, Ultrix. */ +#include +#endif +#if HAVE_SYS_VFSTAB_H +#include +#endif +#include +#include +#include +#include +#if HAVE_XFS_XQM_H +#include +#define xfs_mem_dqinfo fs_quota_stat +#define Q_XFS_GETQSTAT Q_XGETQSTAT +#define XFS_SUPER_MAGIC_STR "XFSB" +#define XFS_SUPER_MAGIC2_STR "BSFX" +#endif + +#include "quota_mntopt.h" + +/* *** *** *** local functions *** *** *** */ + +/* stolen from quota-3.13 (quota-tools) */ + +#define PROC_PARTITIONS "/proc/partitions" +#define DEVLABELDIR "/dev" +#define UUID 1 +#define VOL 2 + +#define AUTOFS_DIR_MAX 64 /* Maximum number of autofs directories */ + +static struct uuidCache_s { + struct uuidCache_s *next; + char uuid[16]; + char *label; + char *device; +} *uuidCache = NULL; + +#define EXT2_SUPER_MAGIC 0xEF53 +struct ext2_super_block { + unsigned char s_dummy1[56]; + unsigned char s_magic[2]; + unsigned char s_dummy2[46]; + unsigned char s_uuid[16]; + char s_volume_name[16]; +}; +#define ext2magic(s) ((unsigned int)s.s_magic[0] \ + + (((unsigned int)s.s_magic[1]) << 8)) + +#if HAVE_XFS_XQM_H +struct xfs_super_block { + unsigned char s_magic[4]; + unsigned char s_dummy[28]; + unsigned char s_uuid[16]; + unsigned char s_dummy2[60]; + char s_fsname[12]; +}; +#endif /* HAVE_XFS_XQM_H */ + +#define REISER_SUPER_MAGIC "ReIsEr2Fs" +struct reiserfs_super_block { + unsigned char s_dummy1[52]; + unsigned char s_magic[10]; + unsigned char s_dummy2[22]; + unsigned char s_uuid[16]; + char s_volume_name[16]; +}; + +void +sstrncpy(char *d, const char *s, int len) +{ + strncpy(d, s, len); + d[len - 1] = 0; +} + +char * +sstrdup(const char *s) +{ + char *r = strdup(s); + if(r == NULL) { + DBG("Not enough memory."); + exit(3); + } + return r; +} + +void * +smalloc(size_t size) +{ + void *ret = malloc(size); + if(ret == NULL) { + DBG("Not enough memory."); + exit(3); + } + return ret; +} + +/* for now, only ext2 and xfs are supported */ +static int +get_label_uuid(const char *device, char **label, char *uuid) +{ + /* start with ext2 and xfs tests, taken from mount_guess_fstype */ + /* should merge these later */ + int fd, rv = 1; + size_t namesize; + struct ext2_super_block e2sb; + struct xfs_super_block xfsb; + struct reiserfs_super_block reisersb; + + fd = open(device, O_RDONLY); + if(fd == -1) { + return rv; + } + + if(lseek(fd, 1024, SEEK_SET) == 1024 + && read(fd, (char *)&e2sb, sizeof(e2sb)) == sizeof(e2sb) + && ext2magic(e2sb) == EXT2_SUPER_MAGIC) { + memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid)); + namesize = sizeof(e2sb.s_volume_name); + *label = smalloc(namesize + 1); + sstrncpy(*label, e2sb.s_volume_name, namesize); + rv = 0; +#if HAVE_XFS_XQM_H + } else if(lseek(fd, 0, SEEK_SET) == 0 + && read(fd, (char *)&xfsb, sizeof(xfsb)) == sizeof(xfsb) + && (strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC_STR, 4) == 0 || + strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC2_STR, 4) == 0)) { + memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid)); + namesize = sizeof(xfsb.s_fsname); + *label = smalloc(namesize + 1); + sstrncpy(*label, xfsb.s_fsname, namesize); + rv = 0; +#endif /* HAVE_XFS_XQM_H */ + } else if(lseek(fd, 65536, SEEK_SET) == 65536 + && read(fd, (char *)&reisersb, sizeof(reisersb)) == sizeof(reisersb) + && !strncmp((char *)&reisersb.s_magic, REISER_SUPER_MAGIC, 9)) { + memcpy(uuid, reisersb.s_uuid, sizeof(reisersb.s_uuid)); + namesize = sizeof(reisersb.s_volume_name); + *label = smalloc(namesize + 1); + sstrncpy(*label, reisersb.s_volume_name, namesize); + rv = 0; + } + close(fd); + return rv; +} + +static void +uuidcache_addentry(char *device, char *label, char *uuid) +{ + struct uuidCache_s *last; + + if(!uuidCache) { + last = uuidCache = smalloc(sizeof(*uuidCache)); + } else { + for(last = uuidCache; last->next; last = last->next); + last->next = smalloc(sizeof(*uuidCache)); + last = last->next; + } + last->next = NULL; + last->device = device; + last->label = label; + memcpy(last->uuid, uuid, sizeof(last->uuid)); +} + +static void +uuidcache_init(void) +{ + char line[100]; + char *s; + int ma, mi, sz; + static char ptname[100]; + FILE *procpt; + char uuid[16], *label = NULL; + char device[110]; + int firstPass; + int handleOnFirst; + + if(uuidCache) { + return; + } + + procpt = fopen(PROC_PARTITIONS, "r"); + if(procpt == NULL) { + return; + } + + for(firstPass = 1; firstPass >= 0; firstPass--) { + fseek(procpt, 0, SEEK_SET); + while(fgets(line, sizeof(line), procpt)) { + if(sscanf(line, " %d %d %d %[^\n ]", + &ma, &mi, &sz, ptname) != 4) + { + continue; + } + + /* skip extended partitions (heuristic: size 1) */ + if(sz == 1) { + continue; + } + + /* look only at md devices on first pass */ + handleOnFirst = !strncmp(ptname, "md", 2); + if(firstPass != handleOnFirst) { + continue; + } + + /* skip entire disk (minor 0, 64, ... on ide; + 0, 16, ... on sd) */ + /* heuristic: partition name ends in a digit */ + + for(s = ptname; *s; s++); + + if(isdigit(s[-1])) { + /* + * Note: this is a heuristic only - there is no reason + * why these devices should live in /dev. + * Perhaps this directory should be specifiable by option. + * One might for example have /devlabel with links to /dev + * for the devices that may be accessed in this way. + * (This is useful, if the cdrom on /dev/hdc must not + * be accessed.) + */ + snprintf(device, sizeof(device), "%s/%s", + DEVLABELDIR, ptname); + if(!get_label_uuid(device, &label, uuid)) { + uuidcache_addentry(sstrdup(device), + label, uuid); + } + } + } + } + fclose(procpt); +} + +static unsigned char +fromhex(char c) +{ + if(isdigit(c)) { + return (c - '0'); + } else if(islower(c)) { + return (c - 'a' + 10); + } else { + return (c - 'A' + 10); + } +} + +static char * +get_spec_by_x(int n, const char *t) +{ + struct uuidCache_s *uc; + + uuidcache_init(); + uc = uuidCache; + + while(uc) { + switch(n) { + case UUID: + if(!memcmp(t, uc->uuid, sizeof(uc->uuid))) { + return sstrdup(uc->device); + } + break; + case VOL: + if(!strcmp(t, uc->label)) { + return sstrdup(uc->device); + } + break; + } + uc = uc->next; + } + return NULL; +} + +static char * +get_spec_by_uuid(const char *s) +{ + char uuid[16]; + int i; + + if(strlen(s) != 36 + || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') { + goto bad_uuid; + } + + for(i=0; i<16; i++) { + if(*s == '-') { + s++; + } + if(!isxdigit(s[0]) || !isxdigit(s[1])) { + goto bad_uuid; + } + uuid[i] = ((fromhex(s[0]) << 4) | fromhex(s[1])); + s += 2; + } + return get_spec_by_x(UUID, uuid); + + bad_uuid: + DBG("Found an invalid UUID: %s", s); + return NULL; +} + +static char * +get_spec_by_volume_label(const char *s) +{ + return get_spec_by_x(VOL, s); +} + +const char * +get_device_name(const char *item) +{ + const char *rc; + + if(!strncmp(item, "UUID=", 5)) { + DBG("TODO: check UUID= code!"); + rc = get_spec_by_uuid(item + 5); + } else if(!strncmp(item, "LABEL=", 6)) { + DBG("TODO: check LABEL= code!"); + rc = get_spec_by_volume_label(item + 6); + } else { + rc = sstrdup(item); + } + if(!rc) { + DBG("Error checking device name: %s", item); + } + return rc; +} + +/* Return if given option has nonempty argument */ +char * +hasmntoptarg(struct mntent *mnt, char *opt) +{ + char *p = hasmntopt(mnt, opt); + + if(!p) { + return NULL; + } + p += strlen(opt); + if(*p == '=' && p[1] != ',') { + return p+1; + } + return NULL; +} + +/* + * Check whether give filesystem type is supported + */ +static int +correct_fstype(char *type) +{ + char *mtype = sstrdup(type), *next; + + type = mtype; + do { + next = strchr(type, ','); + if(next) { + *next = 0; + } + if(!strcmp(type, MNTTYPE_EXT2) + || !strcmp(type, MNTTYPE_EXT3) + || !strcmp(type, MNTTYPE_JFS) + || !strcmp(type, MNTTYPE_MINIX) + || !strcmp(type, MNTTYPE_UFS) + || !strcmp(type, MNTTYPE_UDF) + || !strcmp(type, MNTTYPE_REISER) + || !strcmp(type, MNTTYPE_XFS) + || !strcmp(type, MNTTYPE_NFS) + || !strcmp(type, MNTTYPE_NFS4)) + { + free(mtype); + return 1; + } + type = next+1; + } while(next); + free(mtype); + return 0; +} + +/* + * Check for various kinds of NFS filesystem + */ +int +nfs_fstype(char *type) +{ + return !strcmp(type, MNTTYPE_NFS) || !strcmp(type, MNTTYPE_NFS4); +} + +#if HAVE_XFS_XQM_H +/* + * Check for XFS filesystem with quota accounting enabled + */ +static int hasxfsquota(struct mntent *mnt, int type) +{ + int ret = 0; + u_int16_t sbflags; + struct xfs_mem_dqinfo info; + const char *dev = get_device_name(mnt->mnt_fsname); + + if(!dev) { + return ret; + } + + memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); + if(!quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info)) { + sbflags = (info.qs_flags & 0xff00) >> 8; + if(type == USRQUOTA && (info.qs_flags & XFS_QUOTA_UDQ_ACCT)) { + ret = 1; + } else if(type == GRPQUOTA && (info.qs_flags & XFS_QUOTA_GDQ_ACCT)) { + ret = 1; + } + #ifdef XFS_ROOTHACK + /* + * Old XFS filesystems (up to XFS 1.2 / Linux 2.5.47) had a + * hack to allow enabling quota on the root filesystem without + * having to specify it at mount time. + */ + else if(strcmp(mnt->mnt_dir, "/")) { + ret = 0; + } else if(type == USRQUOTA && (sbflags & XFS_QUOTA_UDQ_ACCT)) { + ret = 1; + } else if(type == GRPQUOTA && (sbflags & XFS_QUOTA_GDQ_ACCT)) { + ret = 1; + #endif /* XFS_ROOTHACK */ + } + free((char *)dev); + return ret; +} +#endif /* HAVE_XFS_XQM_H */ + +/* + * Check to see if a particular quota is to be enabled (filesystem mounted + * with proper option) + */ +int +hasquota(struct mntent *mnt, int type) +{ + if(!correct_fstype(mnt->mnt_type) || hasmntopt(mnt, MNTOPT_NOQUOTA)) { + return 0; + } +#if HAVE_XFS_XQM_H + if(!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { + return hasxfsquota(mnt, type); + } +#endif + if(nfs_fstype(mnt->mnt_type)) { + /* NFS always has quota or better there is + no good way how to detect it */ + return 1; + } + + if((type == USRQUOTA) && (hasmntopt(mnt, MNTOPT_USRQUOTA) + || hasmntoptarg(mnt, MNTOPT_USRJQUOTA))) { + return 1; + } + if((type == GRPQUOTA) && (hasmntopt(mnt, MNTOPT_GRPQUOTA) + || hasmntoptarg(mnt, MNTOPT_GRPJQUOTA))) { + return 1; + } + if((type == USRQUOTA) && hasmntopt(mnt, MNTOPT_QUOTA)) { + return 1; + } + + return 0; +} + +/* END stolen from quota-3.13 (quota-tools) */ + + + +#if HAVE_LISTMNTENT +static void +quota_mnt_listmntent(struct tabmntent *mntlist, quota_mnt_t **list) +{ + struct *p; + struct mntent *mnt; + + for(p = mntlist; p; p = p->next) { + mnt = p->ment; + *list = smalloc(sizeof(quota_mnt_t)); + list->device = strdup(mnt->mnt_fsname); + list->name = strdup(mnt->mnt_dir); + list->type = strdup(mnt->mnt_type); + list->next = NULL; + list = &(ist->next); + } + freemntlist(mntlist); +} +#endif /* HAVE_LISTMNTENT */ + + + +#if HAVE_GETVFSENT +static void +quota_mnt_getvfsmnt(FILE *mntf, quota_mnt_t **list) +{ + DBG("TODO: getvfsmnt"); + *list = NULL; +} +#endif /* HAVE_GETVFSENT */ + + + +#if HAVE_GETMNTENT +static void +quota_mnt_getmntent(FILE *mntf, quota_mnt_t **list) +{ + struct mntent *mnt; + + while((mnt = getmntent(mntf)) != NULL) { + const char *devname; + +#if 0 + DBG("------------------"); + DBG("mnt->mnt_fsname %s", mnt->mnt_fsname); + DBG("mnt->mnt_dir %s", mnt->mnt_dir); + DBG("mnt->mnt_type %s", mnt->mnt_type); + DBG("mnt->mnt_opts %s", mnt->mnt_opts); + DBG("mnt->mnt_freq %d", mnt->mnt_freq); + DBG("mnt->mnt_passno %d", mnt->mnt_passno); +#endif + if(!(devname = get_device_name(mnt->mnt_fsname))) { + DBG("can't get devicename for fs (%s) %s (%s): ignored", + mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); + continue; + } + if(hasmntopt(mnt, MNTOPT_NOQUOTA) != NULL) { + DBG("noquota option on fs (%s) %s (%s): ignored", + mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); + free((char *)devname); + continue; + } + if(hasmntopt(mnt, MNTOPT_QUOTA) == NULL + && hasmntopt(mnt, MNTOPT_USRQUOTA) == NULL + && hasmntopt(mnt, MNTOPT_GRPQUOTA) == NULL + && quota_fs_isnfs(mnt->mnt_type) == EXIT_FAILURE) + { + DBG("neither quota/usrquota/grpquota option" + " nor nfs fs (%s) %s (%s): ignored", + mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); + free((char *)devname); + continue; + } + if(quota_fs_issupported(mnt->mnt_type) == EXIT_FAILURE) + { + DBG("unsupportet fs (%s) %s (%s): ignored", + mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); + free((char *)devname); + continue; + } +#if 0 + DBG("------------------ OK"); +#endif + *list = (quota_mnt_t *)smalloc(sizeof(quota_mnt_t)); + (*list)->dir = sstrdup(mnt->mnt_dir); + (*list)->device = sstrdup(mnt->mnt_fsname); + (*list)->opts = QMO_NONE; + if(hasmntopt(mnt, MNTOPT_QUOTA) != NULL + || hasmntopt(mnt, MNTOPT_USRQUOTA) != NULL) { + (*list)->opts |= QMO_USRQUOTA; + } + if(hasmntopt(mnt, MNTOPT_GRPQUOTA) != NULL) { + (*list)->opts |= QMO_GRPQUOTA; + } + (*list)->next = NULL; + list = &((*list)->next); + } /* while((mnt = getmntent(mntf)) != NULL) */ +} +#endif /* HAVE_GETMNTENT */ + + + +quota_mnt_t * +quota_mnt_getlist(quota_mnt_t **list) +{ + /* yes, i know that the indentation is wrong. + but show me a better way to do this... */ + /* see lib/mountlist.c of coreutils for all + gory details! */ +#if HAVE_GETMNTENT && defined(_PATH_MOUNTED) + { + FILE *mntf = NULL; + if((mntf = setmntent(_PATH_MOUNTED, "r")) == NULL) { + DBG("opening %s failed: %s", _PATH_MOUNTED, strerror(errno)); +#endif +#if HAVE_GETMNTENT && defined(MNT_MNTTAB) + { + FILE *mntf = NULL; + if((mntf = setmntent(MNT_MNTTAB, "r")) == NULL) { + DBG("opening %s failed: %s", MNT_MNTTAB, strerror(errno)); +#endif +#if HAVE_GETMNTENT && defined(MNTTABNAME) + { + FILE *mntf = NULL; + if((mntf = setmntent(MNTTABNAME, "r")) == NULL) { + DBG("opening %s failed: %s", MNTTABNAME, strerror(errno)); +#endif +#if HAVE_GETMNTENT && defined(_PATH_MNTTAB) + { + FILE *mntf = NULL; + if((mntf = setmntent(_PATH_MNTTAB, "r")) == NULL) { + DBG("opening %s failed: %s", _PATH_MNTTAB, strerror(errno)); +#endif +#if HAVE_GETVFSENT && defined(VFSTAB) + { + FILE *mntf = NULL; + if((mntf = fopen(VFSTAB, "r")) == NULL) { + DBG("opening %s failed: %s", VFSTAB, strerror(errno)); +#endif +#if HAVE_LISTMNTENT + { + struct tabmntent *mntlist; + + if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0) { + DBG("calling listmntent() failed: %s", strerror(errno)); +#endif + /* give up */ + DBG("failed get local mountpoints"); + *list = NULL; + return(NULL); + +#if HAVE_LISTMNTENT + } else { quota_mnt_listmntent(mntlist, list); } + freemntlist(mntlist); + } +#endif +#if HAVE_GETVFSENT && defined(VFSTAB) + } else { quota_mnt_getvfsmnt(mntf, list); } + (void)fclose(mntf); + } +#endif +#if HAVE_GETMNTENT && defined(_PATH_MNTTAB) + } else { quota_mnt_getmntent(mntf, list); } + (void)endmntent(mntf); + } +#endif +#if HAVE_GETMNTENT && defined(MNTTABNAME) + } else { quota_mnt_getmntent(mntf, list); } + (void)endmntent(mntf); + } +#endif +#if HAVE_GETMNTENT && defined(MNT_MNTTAB) + } else { quota_mnt_getmntent(mntf, list); } + (void)endmntent(mntf); + } +#endif +#if HAVE_GETMNTENT && defined(_PATH_MOUNTED) + } else { quota_mnt_getmntent(mntf, list); } + (void)endmntent(mntf); + } +#endif + return(*list); +} + +void +quota_mnt_freelist(quota_mnt_t *list) +{ + quota_mnt_t *l = list, *p = NULL; + + while(l != NULL) { + while(l->next != NULL) { + p = l; + l = l->next; + } + if(p != NULL) { + p->next = NULL; + } + free(l->dir); + free(l->device); + free(l); + p = NULL; + if(l != list) { + l = list; + } else { + l = NULL; + } + } +} + diff --git a/src/quota_mnt.h b/src/quota_mnt.h new file mode 100644 index 00000000..9d98886c --- /dev/null +++ b/src/quota_mnt.h @@ -0,0 +1,45 @@ +/** + * collectd - src/quota_mnt.h + * Copyright (C) 2005 Niki W. Waibel + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * Author: + * Niki W. Waibel +**/ + +#if !COLLECTD_QUOTA_MNT_H +#define COLLECTD_QUOTA_MNT_H 1 + +#include "common.h" + +#define QMO_NONE (0) +#define QMO_USRQUOTA (1) +#define QMO_GRPQUOTA (2) + +typedef struct _quota_mnt_t quota_mnt_t; +struct _quota_mnt_t { + char *dir; + char *device; + int opts; + quota_mnt_t *next; +}; + +quota_mnt_t *quota_mnt_getlist(quota_mnt_t **list); +void quota_mnt_freelist(quota_mnt_t *list); + +#endif /* !COLLECTD_QUOTA_MNT_H */ + diff --git a/src/quota_mntopt.h b/src/quota_mntopt.h new file mode 100644 index 00000000..1160f359 --- /dev/null +++ b/src/quota_mntopt.h @@ -0,0 +1,154 @@ +/** + * collectd - src/quota_mntopt.h + * Copyright (C) 2005 Niki W. Waibel + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * Author: + * Niki W. Waibel +**/ + +#if !COLLECTD_QUOTA_MNTOPT_H +#define COLLECTD_QUOTA_MNTOPT_H 1 + +#include "common.h" + +/* filesystem type */ +#ifndef MNTTYPE_AUTOFS +#define MNTTYPE_AUTOFS "autofs" /* Automount mountpoint */ +#endif +#ifndef MNTTYPE_CAPIFS +#define MNTTYPE_CAPIFS "capifs" /* */ +#endif +#ifndef MNTTYPE_CRAMFS +#define MNTTYPE_CRAMFS "cramfs" /* */ +#endif +#ifndef MNTTYPE_DEVPTS +#define MNTTYPE_DEVPTS "devpts" /* */ +#endif +#ifndef MNTTYPE_EXT2 +#define MNTTYPE_EXT2 "ext2" /* 2nd Extended file system */ +#endif +#ifndef MNTTYPE_EXT3 +#define MNTTYPE_EXT3 "ext3" /* ext2 + journaling */ +#endif +#ifndef MNTTYPE_FUSE +#define MNTTYPE_FUSE "fuse" /* */ +#endif +#ifndef MNTTYPE_HSFS +#define MNTTYPE_HSFS "hsfs" /* */ +#endif +#ifndef MNTTYPE_ISO9660 +#define MNTTYPE_ISO9660 "iso9660" /* */ +#endif +#ifndef MNTTYPE_JFS +#define MNTTYPE_JFS "jfs" /* JFS file system */ +#endif +#ifndef MNTTYPE_MINIX +#define MNTTYPE_MINIX "minix" /* MINIX file system */ +#endif +#ifndef MNTTYPE_NFS +#define MNTTYPE_NFS "nfs" /* */ +#endif +#ifndef MNTTYPE_NFS4 +#define MNTTYPE_NFS4 "nfs4" /* NFSv4 filesystem */ +#endif +#ifndef MNTTYPE_NTFS +#define MNTTYPE_NTFS "ntfs" /* */ +#endif +#ifndef MNTTYPE_PROC +#define MNTTYPE_PROC "proc" /* */ +#endif +#ifndef MNTTYPE_RAMFS +#define MNTTYPE_RAMFS "ramfs" /* */ +#endif +#ifndef MNTTYPE_ROMFS +#define MNTTYPE_ROMFS "romfs" /* */ +#endif +#ifndef MNTTYPE_RELAYFS +#define MNTTYPE_RELAYFS "relayfs" /* */ +#endif +#ifndef MNTTYPE_REISER +#define MNTTYPE_REISER "reiserfs" /* Reiser file system */ +#endif +#ifndef MNTTYPE_SYSFS +#define MNTTYPE_SYSFS "sysfs" /* */ +#endif +#ifndef MNTTYPE_TMPFS +#define MNTTYPE_TMPFS "tmpfs" /* */ +#endif +#ifndef MNTTYPE_USBFS +#define MNTTYPE_USBFS "usbfs" /* */ +#endif +#ifndef MNTTYPE_UDF +#define MNTTYPE_UDF "udf" /* OSTA UDF file system */ +#endif +#ifndef MNTTYPE_UFS +#define MNTTYPE_UFS "ufs" /* UNIX file system */ +#endif +#ifndef MNTTYPE_XFS +#define MNTTYPE_XFS "xfs" /* SGI XFS file system */ +#endif +#ifndef MNTTYPE_VFAT +#define MNTTYPE_VFAT "vfat" /* */ +#endif +#ifndef MNTTYPE_ZFS +#define MNTTYPE_ZFS "zfs" /* */ +#endif + +/* mount options */ +#ifndef MNTOPT_RO +#define MNTOPT_RO "ro" /* */ +#endif +#ifndef MNTOPT_RQ +#define MNTOPT_RQ "rq" /* */ +#endif +#ifndef MNTOPT_PUBLIC +#define MNTOPT_PUBLIC "public" /* */ +#endif +#ifndef MNTOPT_NOQUOTA +#define MNTOPT_NOQUOTA "noquota" /* don't enforce quota */ +#endif +#ifndef MNTOPT_QUOTA +#define MNTOPT_QUOTA "quota" /* enforce user quota */ +#endif +#ifndef MNTOPT_USRQUOTA +#define MNTOPT_USRQUOTA "usrquota" /* enforce user quota */ +#endif +#ifndef MNTOPT_USRJQUOTA +#define MNTOPT_USRJQUOTA "usrjquota" /* enforce user quota */ +#endif +#ifndef MNTOPT_GRPQUOTA +#define MNTOPT_GRPQUOTA "grpquota" /* enforce group quota */ +#endif +#ifndef MNTOPT_GRPJQUOTA +#define MNTOPT_GRPJQUOTA "grpjquota" /* enforce group quota */ +#endif +#ifndef MNTOPT_RSQUASH +#define MNTOPT_RSQUASH "rsquash" /* root as ordinary user */ +#endif +#ifndef MNTOPT_BIND +#define MNTOPT_BIND "bind" /* binded mount */ +#endif +#ifndef MNTOPT_LOOP +#define MNTOPT_LOOP "loop" /* loopback mount */ +#endif +#ifndef MNTOPT_JQFMT +#define MNTOPT_JQFMT "jqfmt" /* journaled quota format */ +#endif + +#endif /* !COLLECTD_QUOTA_MNTOPT_H */ + diff --git a/src/quota_plugin.c b/src/quota_plugin.c new file mode 100644 index 00000000..15d772cf --- /dev/null +++ b/src/quota_plugin.c @@ -0,0 +1,140 @@ +/** + * collectd - src/quota_plugin.c + * Copyright (C) 2005 Niki W. Waibel + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * Author: + * Niki W. Waibel +**/ + +#include "common.h" +#include "plugin.h" + +#include "quota_debug.h" +#include "quota_mnt.h" +#include "quota_fs.h" +#include "quota_plugin.h" + +#define MODULE_NAME "quota" + +/* *** *** *** local constants *** *** *** */ + +static const char *quota_filename_template = "quota-%s.rrd"; + +static char *quota_ds_def[] = +{ + "DS:blocks:GAUGE:25:0:U", + "DS:block_quota:GAUGE:25:-1:U", + "DS:block_limit:GAUGE:25:-1:U", + "DS:block_grace:GAUGE:25:0:U", + "DS:block_timeleft:GAUGE:25:0:U", + "DS:inodes:GAUGE:25:0:U", + "DS:inode_quota:GAUGE:25:-1:U", + "DS:inode_limit:GAUGE:25:-1:U", + "DS:inode_grace:GAUGE:25:0:U", + "DS:inode_timeleft:GAUGE:25:0:U", + NULL +}; +static const int quota_ds_num = 10; + +/* *** *** *** local functions *** *** *** */ + +#define BUFSIZE 1024 +static void +quota_submit(quota_t *q) +{ + char buf[BUFSIZE]; + int r; + + r = snprintf(buf, BUFSIZE, + "%u:%llu:%lld:%lld:%llu:%llu:%llu:%lld:%lld:%llu:%llu", + (unsigned int)curtime, + q->blocks, q->bquota, q->blimit, q->bgrace, q->btimeleft, + q->inodes, q->iquota, q->ilimit, q->igrace, q->itimeleft); + if(r < 1 || r >= BUFSIZE) { + DBG("failed"); + return; + } + plugin_submit(MODULE_NAME, q->name, buf); +} +#undef BUFSIZE + +/* *** *** *** local plugin functions *** *** *** */ + +static void +quota_init(void) +{ + DBG_INIT("quota debug file opened."); +} + +static void +quota_read(void) +{ + quota_mnt_t *list = NULL, *l = NULL; + quota_t q = { + name: "test", + blocks: 0, bquota: -1, blimit: -1, + bgrace: 0, btimeleft: 0, + inodes: 0, iquota: -1, ilimit: -1, + igrace: 0, itimeleft: 0, + }; + + l = quota_mnt_getlist(&list); + DBG("local mountpoints:"); + while(l != NULL) { + DBG("\tdir: %s", l->dir); + DBG("\tdevice: %s", l->device); + DBG("\topts: %s (0x%04x)", + (l->opts == QMO_NONE) ? "-" + : (l->opts == QMO_USRQUOTA) ? "USRQUOTA" + : (l->opts == QMO_GRPQUOTA) ? "GRPQUOTA" + : (l->opts == (QMO_USRQUOTA|QMO_GRPQUOTA)) ? + "USRQUOTA GRPQUOTA" : " ??? ", + l->opts); + l = l->next; + if(l != NULL) { + DBG("\t-- "); + } + } + DBG("\t== "); + quota_submit(&q); + quota_mnt_freelist(list); +} + +static void +quota_write(char *host, char *inst, char *val) +{ + char file[512]; + int r; + + r = snprintf(file, 512, quota_filename_template, inst); + if(r < 1 || r >= 512) { + DBG("failed"); + return; + } + + rrd_update_file(host, file, val, quota_ds_def, quota_ds_num); +} + +/* *** *** *** global functions *** *** *** */ + +void +module_register(void) +{ + plugin_register(MODULE_NAME, quota_init, quota_read, quota_write); +} + diff --git a/src/quota_plugin.h b/src/quota_plugin.h new file mode 100644 index 00000000..785a51f0 --- /dev/null +++ b/src/quota_plugin.h @@ -0,0 +1,42 @@ +/** + * collectd - src/quota_plugin.h + * Copyright (C) 2005 Niki W. Waibel + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * Author: + * Niki W. Waibel +**/ + +#if !COLLECTD_QUOTA_PLUGIN_H +#define COLLECTD_QUOTA_PLUGIN_H 1 + +#include "common.h" + +typedef struct { + char *name; + unsigned long long blocks; + long long bquota, blimit; + unsigned long long bgrace, btimeleft; + unsigned long long inodes; + long long iquota, ilimit; + unsigned long long igrace, itimeleft; +} quota_t; + +void module_register(void); + +#endif /* !COLLECTD_QUOTA_PLUGIN_H */ + -- 2.30.2