diff --git a/configure.in b/configure.in index d00ac98..22b7801 100644 --- a/configure.in +++ b/configure.in @@ -1457,6 +1457,56 @@ fi AM_CONDITIONAL(BUILD_WITH_LIBDBI, test "x$with_libdbi" = "xyes") # }}} +# --with-libcups {{{ +with_libcups_cppflags="" +with_libcups_ldflags="" +AC_ARG_WITH(libcups, [AS_HELP_STRING([--with-libcups@<:@=PREFIX@:>@], [Path to libcups.])], +[ + if test "x$withval" != "xno" && test "x$withval" != "xyes" + then + with_libcups_cppflags="-I$withval/include" + with_libcups_ldflags="-L$withval/lib" + with_libcups="yes" + else + with_libcups="$withval" + fi +], +[ + with_libcups="yes" +]) +if test "x$with_libcups" = "xyes" +then + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $with_libcups_cppflags" + + AC_CHECK_HEADERS(cups/cups.h, [with_libcups="yes"], [with_libcups="no (cups/cups.h not found)"]) + + CPPFLAGS="$SAVE_CPPFLAGS" +fi +if test "x$with_libcups" = "xyes" +then + SAVE_CPPFLAGS="$CPPFLAGS" + SAVE_LDFLAGS="$LDFLAGS" + CPPFLAGS="$CPPFLAGS $with_libcups_cppflags" + LDFLAGS="$LDFLAGS $with_libcups_ldflags" + + AC_CHECK_LIB(cups, cupsGetJobs, [with_libcups="yes"], [with_libcups="no (Symbol 'cupsGetJobs' not found)"]) + + CPPFLAGS="$SAVE_CPPFLAGS" + LDFLAGS="$SAVE_LDFLAGS" +fi +if test "x$with_libcups" = "xyes" +then + BUILD_WITH_LIBCUPS_CPPFLAGS="$with_libcups_cppflags" + BUILD_WITH_LIBCUPS_LDFLAGS="$with_libcups_ldflags" + BUILD_WITH_LIBCUPS_LIBS="-lcups" + AC_SUBST(BUILD_WITH_LIBCUPS_CPPFLAGS) + AC_SUBST(BUILD_WITH_LIBCUPS_LDFLAGS) + AC_SUBST(BUILD_WITH_LIBCUPS_LIBS) +fi +AM_CONDITIONAL(BUILD_WITH_LIBCUPS, test "x$with_libcups" = "xyes") +# }}} + # --with-libesmtp {{{ AC_ARG_WITH(libesmtp, [AS_HELP_STRING([--with-libesmtp@<:@=PREFIX@:>@], [Path to libesmtp.])], [ @@ -4473,6 +4523,7 @@ AC_PLUGIN([contextswitch], [$plugin_contextswitch], [context switch statistics]) AC_PLUGIN([cpufreq], [$plugin_cpufreq], [CPU frequency statistics]) AC_PLUGIN([cpu], [$plugin_cpu], [CPU usage statistics]) AC_PLUGIN([csv], [yes], [CSV output plugin]) +AC_PLUGIN([cups], [$with_libcups], [Query printer server for statistics]) AC_PLUGIN([curl], [$with_libcurl], [CURL generic web statistics]) AC_PLUGIN([curl_json], [$plugin_curl_json], [CouchDB statistics]) AC_PLUGIN([curl_xml], [$plugin_curl_xml], [CURL generic xml statistics]) @@ -4735,6 +4786,7 @@ cat < + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" + +#include + +/* + * Private data types + */ +#define MAX_NAME_LEN 128 +struct printer_entry_s +{ + char *name; + char *description; + int page_printed; + struct printer_entry_s *next; +}; +typedef struct printer_entry_s printer_entry_t; + +static printer_entry_t *printer_list_head = NULL; + +#if 0 +static const char *config_key[] = { + "", +}; +#endif + +void cups_destroy_printer (printer_entry_t *pe) +{ + if (pe == NULL) + return; + + if (pe->next != NULL) + cups_destroy_printer (pe->next); + + sfree(pe->name); + sfree(pe); +} + +static int cups_add_printer (const char *name, const char *description) +{ + printer_entry_t *pe, *cur; + + if (name == NULL) + return (-1); + + pe = calloc (1, sizeof (printer_entry_t)); + if (pe == NULL) + { + char errbuf[1024]; + ERROR ("cups plugin: calloc failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); + return (-1); + } + + pe->name = strdup (name); + pe->description = strdup (description); + pe->next = NULL; + + if (printer_list_head == NULL) + printer_list_head = pe; + else + { + for (cur = printer_list_head; cur->next != NULL; cur = cur->next); + cur->next = pe; + } + + return (0); +} + +static int cups_init (void) +{ + int status, i, num; + const char *description; + + cups_dest_t *dests; + cups_dest_t *dest; + + num = cupsGetDests (&dests); + if (num < 1) + { + ERROR ("cups plugin: no printer was found, " + "are you sure cups server is running ?"); + return (-1); + } + + for (i = 0, dest = dests; i < num; i++, dest++) + { + description = cupsGetOption ("printer-info", + dest->num_options, dest->options); + + status = cups_add_printer (dest->name, description); + if (status != 0) + { + ERROR ("cups plugin: cups_init: cups_add_printer failed."); + cups_destroy_printer (printer_list_head); + return (-1); + } + } + + cupsFreeDests (num, dests); + + return (0); +} /* static int cups_init */ + +static void cups_submit (const char *plugin_instance, + const char *type, counter_t cnt) +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + values[0].counter = cnt; + + vl.values = values; + vl.values_len = 1; + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "cups", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, plugin_instance, + sizeof (vl.plugin_instance)); + sstrncpy (vl.type, type, sizeof (vl.type)); + + plugin_dispatch_values (&vl); +} /* void cups_submit */ + +static void cups_submit_all (void) +{ + printer_entry_t *pe; + + for (pe = printer_list_head; pe != NULL; pe = pe->next) + cups_submit (pe->name, "cups_printed", pe->page_printed); +} /* void cups_submit_all */ + +static printer_entry_t *lookup_printer (const char *name) +{ + printer_entry_t *pe; + + if (name == NULL) + return NULL; + + for (pe = printer_list_head; pe != NULL; pe = pe->next) + { + if (strncasecmp (name, pe->name, MAX_NAME_LEN) == 0) + break; + } + + return pe; +} /* printer_entry_t *lookup_printer */ + +static int update_stats (cups_job_t *jobs, int start, int length) +{ + int i; + cups_job_t *job; + printer_entry_t *pe; + + if (jobs == NULL || start < 0 || length < 0) + return (-1); + + for (i = start, job = jobs + start; i < length; i++, job++) + { + /* quadratic complexity, use avl tree to get n log(n) ? */ + pe = lookup_printer (job->dest); + if (pe == NULL) + { + WARNING ("cups: update_stats: trying to update statistics " + "of an unexisting printer (`%s`)", job->dest); + continue; + } + pe->page_printed++; + } + + return (0); +} /* int update_stats */ + +static int last_num = 0; +static int cups_read (void) +{ + int num, status; + cups_job_t *jobs; + + num = cupsGetJobs (&jobs, NULL /* from all printers */, + 0 /* from all users */, -1 /* all states (completed, active) */); + + /* no new jobs ? */ + if (num - last_num > 0) + { + status = update_stats (jobs, last_num, num); + if (status != 0) + { + ERROR("cpus: cups_read: update_stats failed."); + cupsFreeJobs (num, jobs); + return (-1); + } + } + + last_num = num; + cupsFreeJobs (num, jobs); + + cups_submit_all (); + + return (0); +} /* int cups_read */ + +static int cups_shutdown (void) +{ + cups_destroy_printer (printer_list_head); + return (0); +} /* int cups_shutdown */ + +void module_register (void) +{ + plugin_register_read ("cups", cups_read); + plugin_register_init ("cups", cups_init); + plugin_register_shutdown ("cups", cups_shutdown); + return; +} /* void module_register */ diff --git a/src/types.db b/src/types.db index 1b0020f..e6451b2 100644 --- a/src/types.db +++ b/src/types.db @@ -108,6 +108,7 @@ node_rssi value:GAUGE:0:255 node_stat value:COUNTER:0:4294967295 node_tx_rate value:GAUGE:0:127 operations value:COUNTER:0:4294967295 +cups_printed value:COUNTER:0:U percent percent:GAUGE:0:100.1 pg_blks value:COUNTER:0:U pg_db_size value:GAUGE:0:U