LD=ld
CFLAGS=-Wall -O2 -g
-RRDD_OBJS= main.o process.o rrdtool.o parser.o string.o \
+RRDD_OBJS= main.o process.o rrdtool.o parser.o built_in_parsers.o string.o \
debug.o config.o onewire_parser.o plugin_manager.o
ALL_OBJS = $(RRDD_OBJS)
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "parser.h"
+#include "process.h"
+#include "string.h"
+#include "debug.h"
+#include "utils.h"
+#include "built_in_parsers.h"
+
+#define STATFILE "/proc/stat"
+
+static int cpu_parser(char *data, const char **p)
+{
+ char buf[1024];
+ char *str = buf;
+ FILE *file = fopen(STATFILE, "r");
+ long long user, nice, sys, idle, wait, irq, softirq;
+
+ if (file == NULL) {
+ pr_err("Failed to open file %s\n", STATFILE);
+ return -1;
+ }
+
+ if (!fgets(buf, 1024, file)) {
+ pr_err("Failed to read file %s\n", STATFILE);
+ fclose(file);
+ return -1;
+ }
+
+ user = dec_to_longlong(str, &str);
+ nice = dec_to_longlong(str, &str);
+ sys = dec_to_longlong(str, &str);
+ idle = dec_to_longlong(str, &str);
+ wait = dec_to_longlong(str, &str);
+ irq = dec_to_longlong(str, &str);
+ softirq = dec_to_longlong(str, &str);
+
+ snprintf(data, RRD_DATA_MAX_LEN, "%lld:%lld:%lld:%lld:%lld:%lld:%lld",
+ user, nice, sys, idle, wait, irq, softirq);
+
+ fclose(file);
+ return 0;
+}
+
+#define MEMFILE "/proc/meminfo"
+
+static int mem_parser(char *data, const char **p)
+{
+ char buf[1024], word[1024];
+ int free = 0, buffered = 0, cache = 0, active = 0, inactive = 0,
+ swapfree = 0, anon = 0, slab = 0, tables = 0, other = 0,
+ swaptotal = 0, total = 0;
+ FILE *file = fopen(MEMFILE, "r");
+
+ if (file == NULL) {
+ pr_err("Failed to open file %s\n", MEMFILE);
+ return -1;
+ }
+
+ while (fgets(buf, 1024, file)) {
+ get_word(buf, 0, word, 1024);
+
+ if (!strcmp(word, "MemFree:")) {
+ free = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "MemTotal:")) {
+ total = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "Buffers:")) {
+ buffered = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "Cached:")) {
+ cache = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "Active:")) {
+ active = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "Inactive:")) {
+ inactive = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "SwapFree:")) {
+ swapfree = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "AnonPages:")) {
+ anon = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "Slab:")) {
+ slab = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "PageTables:")) {
+ tables = dec_to_int(buf, NULL);
+ } else if (!strcmp(word, "SwapTotal:")) {
+ swaptotal = dec_to_int(buf, NULL);
+ }
+ }
+ fclose(file);
+
+ other = total - free - buffered - cache - anon - slab - tables;
+
+ snprintf(data, RRD_DATA_MAX_LEN, "%f:%f:%f:%f:%f:%f:%f:%f:%f:%f:%f",
+ free / 1024.0,
+ buffered / 1024.0,
+ cache / 1024.0,
+ active / 1024.0,
+ inactive / 1024.0,
+ swapfree / 1024.0,
+ anon / 1024.0,
+ slab / 1024.0,
+ tables / 1024.0,
+ other / 1024.0,
+ (swaptotal - swapfree) / 1024.0);
+
+ return 0;
+}
+
+int cpu_mem_parser(char *data, const char **p)
+{
+ char cpu[1024], mem[1024];
+
+ cpu_parser(cpu, p);
+ mem_parser(mem, p);
+ snprintf(data, RRD_DATA_MAX_LEN, "%s:%s", cpu, mem);
+
+ return 0;
+}
+
+static int digitemp_parser(char *data, const char **p)
+{
+ const char digitemp_cmd[] = "/usr/bin/digitemp";
+ char *const digitemp_args[] = { "", "-o2", "-a", "-q", 0 };
+ FILE *readf;
+ int pid, ret;
+ float t1 = 0, t2 = 0, t3 = 0;
+ char buf[1024];
+
+ pid = run_piped_stream(digitemp_cmd, digitemp_args, 0, &readf, 0);
+ if (pid < 0) {
+ pr_err("Failed to parse digitemp\n");
+ sprintf(data, "U:U");
+ return -1;
+ }
+
+ ret = fscanf(readf, "%f %f %f", &t1, &t2, &t3);
+
+ if (ret != 3) {
+ pr_err("Failed to parse digitemp output: %m\n");
+ sprintf(data, "U:U");
+ return 1;
+ }
+
+ t2 += 2.16;
+ t3 += -0.44;
+
+ /* Read whatever the process might be still printing out */
+ while (fgets(buf, 1024, readf));
+
+ harvest_zombies(pid);
+ snprintf(data, RRD_DATA_MAX_LEN, "%.2f:%.2f", t3, t2);
+ return 0;
+}
+
+static int digitemp_parser_mod(char *data, const char **p)
+{
+ char buf[1024];
+ int ret;
+
+ ret = digitemp_parser(buf, p);
+ snprintf(data, RRD_DATA_MAX_LEN, "U:%s", buf);
+
+ return ret;
+}
+
+/* Run a command and feed the output from stdout directly to rrdtool */
+static int script_parser(char *rrd_data, const char **parser_data)
+{
+ FILE *readf;
+ int pid, ret;
+ void *tmp = parser_data;
+ char **cmd = tmp;
+
+ pid = run_piped_stream(cmd[0], &cmd[1], NULL, &readf, NULL);
+ ret = fread(rrd_data, 1, RRD_DATA_MAX_LEN, readf);
+
+ pr_info("Read %d bytes :%s\n", ret, rrd_data);
+ fclose(readf);
+
+ harvest_zombies(pid);
+
+ return 0;
+}
+
+struct iface_stats {
+ long long rx_bytes;
+ long long rx_packets;
+ long long tx_bytes;
+ long long tx_packets;
+};
+
+#define PROC_NETDEV "/proc/net/dev"
+
+static int get_iface_stats(const char *iface, struct iface_stats *stat)
+{
+ FILE *netdev;
+ char buf[1024];
+ char if_name[16];
+ char *str;
+ int error;
+
+ netdev = fopen(PROC_NETDEV, "r");
+
+ if (netdev == NULL) {
+ error = errno;
+ pr_err("Failed to open file %s: %d (%m)\n",
+ PROC_NETDEV, error);
+ return error;
+ }
+
+ while (fgets(buf, sizeof(buf), netdev)) {
+ get_word(buf, &str, if_name, sizeof(if_name));
+
+ /* Remove the ':' at the end of the if_name */
+ if_name[strlen(if_name) - 1] = 0;
+ if (strncmp(iface, if_name, sizeof(if_name)))
+ continue;
+
+ stat->rx_bytes = dec_to_longlong(str, &str);
+ stat->rx_packets = dec_to_longlong(str, &str);
+ /* errs */ dec_to_longlong(str, &str);
+ /* drop */ dec_to_longlong(str, &str);
+ /* fifo */ dec_to_longlong(str, &str);
+ /* frame */ dec_to_longlong(str, &str);
+ /* compressed */ dec_to_longlong(str, &str);
+ /* multicast */ dec_to_longlong(str, &str);
+ stat->tx_bytes = dec_to_longlong(str, &str);
+ stat->tx_packets = dec_to_longlong(str, &str);
+
+ pr_info("rx_b %lld rx_p %lld tx_b %lld tx_p %lld\n",
+ stat->rx_bytes, stat->rx_packets,
+ stat->tx_bytes, stat->tx_packets);
+
+ return 0;
+ }
+
+ pr_err("Interface %s not found\n", iface);
+ return -ENODEV;
+}
+
+int netstats_parser(char *rrd_data, const char **parser_data)
+{
+ struct iface_stats stat;
+ const char **iface_name = parser_data;
+ int max_str = RRD_DATA_MAX_LEN;
+ int ret;
+
+ if (!parser_data) {
+ pr_err("No device names specified\n");
+ return -1;
+ }
+
+ while(*iface_name) {
+ pr_info("getting data for iface %s\n", *iface_name);
+ ret = get_iface_stats(*iface_name, &stat);
+
+ if (!ret) {
+ ret = snprintf(rrd_data, max_str, "%lld:%lld:%lld:%lld",
+ stat.rx_bytes, stat.rx_packets,
+ stat.tx_bytes, stat.tx_packets);
+ } else {
+ ret = snprintf(rrd_data, max_str, "U:U:U:U");
+ }
+
+ max_str -= ret;
+ rrd_data += ret;
+
+ iface_name++;
+ if (!*iface_name)
+ break;
+
+ ret = snprintf(rrd_data, max_str, ":");
+ max_str -= ret;
+ rrd_data += ret;
+ }
+
+ return 0;
+}
+
+static struct parser_info built_in_parsers[] = {
+ {
+ .name = "cpu",
+ .parse = cpu_parser,
+ },
+ {
+ .name = "mem",
+ .parse = mem_parser,
+ },
+ {
+ .name = "cpu_mem",
+ .parse = cpu_mem_parser,
+ },
+ {
+ .name = "digitemp",
+ .parse = digitemp_parser,
+ },
+ {
+ .name = "digitemp_mod",
+ .parse = digitemp_parser_mod,
+ },
+ {
+ .name = "script",
+ .parse = script_parser,
+ },
+ {
+ .name = "netstats",
+ .parse = netstats_parser,
+ },
+ {
+ .name = "onewire",
+ .parse = onewire_parser,
+ },
+};
+
+int register_built_in_parsers(void)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(built_in_parsers); i++) {
+ ret = register_parser(&built_in_parsers[i]);
+
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
--- /dev/null
+#ifndef _BUILT_IN_PARSERS_H
+#define _BUILT_IN_PARSERS_H
+
+int register_built_in_parsers(void);
+
+int onewire_parser(char *rrd_data, const char **parser_data);
+
+#endif
return 0;
}
-static int (*str_to_parser(const char *str))(char *rrd_data, const char **parser_data)
-{
- if (!str)
- return NULL;
-
- if (!strcmp(str, "cpu"))
- return cpu_parser;
-
- if (!strcmp(str, "mem"))
- return mem_parser;
-
- if (!strcmp(str, "cpu_mem"))
- return cpu_mem_parser;
-
- if (!strcmp(str, "digitemp"))
- return digitemp_parser;
-
- if (!strcmp(str, "digitemp_mod"))
- return digitemp_parser_mod;
-
- if (!strcmp(str, "script"))
- return script_parser;
-
- if (!strcmp(str, "netstats"))
- return netstats_parser;
-
- if (!strcmp(str, "onewire"))
- return onewire_parser;
-
- return NULL;
-}
-
static int parse_data_sources(config_setting_t *rrd, struct rrd_database *db)
{
config_setting_t *list, *group;
/* Parser is not a mandatory parameter */
config_setting_lookup_string(rrd, "parser", &parser);
- db->parse = str_to_parser(parser);
+ db->parser = str_to_parser(parser);
list = config_setting_get_member(rrd, "image");
parse_images(list, db);
#include "debug.h"
#include "config.h"
+#include "built_in_parsers.h"
struct user_options {
int max_jobs;
if (read_args(argc, argv, &opts) < 0)
return -1;
+ register_built_in_parsers();
if (!opts.config_file) {
pr_err("No database config file given. Nothing to do\n");
-#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
#include "parser.h"
-#include "process.h"
-#include "string.h"
#include "debug.h"
-#include "utils.h"
-#define STATFILE "/proc/stat"
+static struct parser_info *parser_list;
-int cpu_parser(char *data, const char **p)
+int register_parser(struct parser_info *info)
{
- char buf[1024];
- char *str = buf;
- FILE *file = fopen(STATFILE, "r");
- long long user, nice, sys, idle, wait, irq, softirq;
+ struct parser_info *parser;
- if (file == NULL) {
- pr_err("Failed to open file %s\n", STATFILE);
+ if (!info->name) {
+ pr_err("Unable to register parser without a name\n");
return -1;
}
- if (!fgets(buf, 1024, file)) {
- pr_err("Failed to read file %s\n", STATFILE);
- fclose(file);
- return -1;
- }
-
- user = dec_to_longlong(str, &str);
- nice = dec_to_longlong(str, &str);
- sys = dec_to_longlong(str, &str);
- idle = dec_to_longlong(str, &str);
- wait = dec_to_longlong(str, &str);
- irq = dec_to_longlong(str, &str);
- softirq = dec_to_longlong(str, &str);
-
- snprintf(data, RRD_DATA_MAX_LEN, "%lld:%lld:%lld:%lld:%lld:%lld:%lld",
- user, nice, sys, idle, wait, irq, softirq);
-
- fclose(file);
- return 0;
-}
-
-#define MEMFILE "/proc/meminfo"
-
-int mem_parser(char *data, const char **p)
-{
- char buf[1024], word[1024];
- int free = 0, buffered = 0, cache = 0, active = 0, inactive = 0,
- swapfree = 0, anon = 0, slab = 0, tables = 0, other = 0,
- swaptotal = 0, total = 0;
- FILE *file = fopen(MEMFILE, "r");
+ pr_info("Registering parser %s\n", info->name);
- if (file == NULL) {
- pr_err("Failed to open file %s\n", MEMFILE);
- return -1;
- }
-
- while (fgets(buf, 1024, file)) {
- get_word(buf, 0, word, 1024);
-
- if (!strcmp(word, "MemFree:")) {
- free = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "MemTotal:")) {
- total = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "Buffers:")) {
- buffered = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "Cached:")) {
- cache = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "Active:")) {
- active = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "Inactive:")) {
- inactive = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "SwapFree:")) {
- swapfree = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "AnonPages:")) {
- anon = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "Slab:")) {
- slab = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "PageTables:")) {
- tables = dec_to_int(buf, NULL);
- } else if (!strcmp(word, "SwapTotal:")) {
- swaptotal = dec_to_int(buf, NULL);
- }
- }
- fclose(file);
-
- other = total - free - buffered - cache - anon - slab - tables;
-
- snprintf(data, RRD_DATA_MAX_LEN, "%f:%f:%f:%f:%f:%f:%f:%f:%f:%f:%f",
- free / 1024.0,
- buffered / 1024.0,
- cache / 1024.0,
- active / 1024.0,
- inactive / 1024.0,
- swapfree / 1024.0,
- anon / 1024.0,
- slab / 1024.0,
- tables / 1024.0,
- other / 1024.0,
- (swaptotal - swapfree) / 1024.0);
-
- return 0;
-}
-
-int cpu_mem_parser(char *data, const char **p)
-{
- char cpu[1024], mem[1024];
-
- cpu_parser(cpu, p);
- mem_parser(mem, p);
- snprintf(data, RRD_DATA_MAX_LEN, "%s:%s", cpu, mem);
-
- return 0;
-}
-
-int digitemp_parser(char *data, const char **p)
-{
- const char digitemp_cmd[] = "/usr/bin/digitemp";
- char *const digitemp_args[] = { "", "-o2", "-a", "-q", 0 };
- FILE *readf;
- int pid, ret;
- float t1 = 0, t2 = 0, t3 = 0;
- char buf[1024];
-
- pid = run_piped_stream(digitemp_cmd, digitemp_args, 0, &readf, 0);
- if (pid < 0) {
- pr_err("Failed to parse digitemp\n");
- sprintf(data, "U:U");
- return -1;
- }
-
- ret = fscanf(readf, "%f %f %f", &t1, &t2, &t3);
-
- if (ret != 3) {
- pr_err("Failed to parse digitemp output: %m\n");
- sprintf(data, "U:U");
- return 1;
+ if (!parser_list) {
+ parser_list = info;
+ return 0;
}
- t2 += 2.16;
- t3 += -0.44;
-
- /* Read whatever the process might be still printing out */
- while (fgets(buf, 1024, readf));
-
- harvest_zombies(pid);
- snprintf(data, RRD_DATA_MAX_LEN, "%.2f:%.2f", t3, t2);
- return 0;
-}
-
-int digitemp_parser_mod(char *data, const char **p)
-{
- char buf[1024];
- int ret;
-
- ret = digitemp_parser(buf, p);
- snprintf(data, RRD_DATA_MAX_LEN, "U:%s", buf);
-
- return ret;
-}
-
-/* Run a command and feed the output from stdout directly to rrdtool */
-int script_parser(char *rrd_data, const char **parser_data)
-{
- FILE *readf;
- int pid, ret;
- void *tmp = parser_data;
- char **cmd = tmp;
+ for (parser = parser_list; parser->next; parser = parser->next)
+ ;
- pid = run_piped_stream(cmd[0], &cmd[1], NULL, &readf, NULL);
- ret = fread(rrd_data, 1, RRD_DATA_MAX_LEN, readf);
-
- pr_info("Read %d bytes :%s\n", ret, rrd_data);
- fclose(readf);
-
- harvest_zombies(pid);
+ parser->next = info;
+ info->next = NULL;
return 0;
}
-struct iface_stats {
- long long rx_bytes;
- long long rx_packets;
- long long tx_bytes;
- long long tx_packets;
-};
-
-#define PROC_NETDEV "/proc/net/dev"
-
-static int get_iface_stats(const char *iface, struct iface_stats *stat)
+struct parser_info *str_to_parser(const char *str)
{
- FILE *netdev;
- char buf[1024];
- char if_name[16];
- char *str;
- int error;
-
- netdev = fopen(PROC_NETDEV, "r");
+ struct parser_info *parser;
- if (netdev == NULL) {
- error = errno;
- pr_err("Failed to open file %s: %d (%m)\n",
- PROC_NETDEV, error);
- return error;
+ for (parser = parser_list; parser; parser = parser->next) {
+ if (!strcmp(str, parser->name))
+ return parser;
}
- while (fgets(buf, sizeof(buf), netdev)) {
- get_word(buf, &str, if_name, sizeof(if_name));
-
- /* Remove the ':' at the end of the if_name */
- if_name[strlen(if_name) - 1] = 0;
- if (strncmp(iface, if_name, sizeof(if_name)))
- continue;
-
- stat->rx_bytes = dec_to_longlong(str, &str);
- stat->rx_packets = dec_to_longlong(str, &str);
- /* errs */ dec_to_longlong(str, &str);
- /* drop */ dec_to_longlong(str, &str);
- /* fifo */ dec_to_longlong(str, &str);
- /* frame */ dec_to_longlong(str, &str);
- /* compressed */ dec_to_longlong(str, &str);
- /* multicast */ dec_to_longlong(str, &str);
- stat->tx_bytes = dec_to_longlong(str, &str);
- stat->tx_packets = dec_to_longlong(str, &str);
-
- pr_info("rx_b %lld rx_p %lld tx_b %lld tx_p %lld\n",
- stat->rx_bytes, stat->rx_packets,
- stat->tx_bytes, stat->tx_packets);
-
- return 0;
- }
-
- pr_err("Interface %s not found\n", iface);
- return -ENODEV;
-}
-
-int netstats_parser(char *rrd_data, const char **parser_data)
-{
- struct iface_stats stat;
- const char **iface_name = parser_data;
- int max_str = RRD_DATA_MAX_LEN;
- int ret;
-
- if (!parser_data) {
- pr_err("No device names specified\n");
- return -1;
- }
-
- while(*iface_name) {
- pr_info("getting data for iface %s\n", *iface_name);
- ret = get_iface_stats(*iface_name, &stat);
-
- if (!ret) {
- ret = snprintf(rrd_data, max_str, "%lld:%lld:%lld:%lld",
- stat.rx_bytes, stat.rx_packets,
- stat.tx_bytes, stat.tx_packets);
- } else {
- ret = snprintf(rrd_data, max_str, "U:U:U:U");
- }
-
- max_str -= ret;
- rrd_data += ret;
-
- iface_name++;
- if (!*iface_name)
- break;
-
- ret = snprintf(rrd_data, max_str, ":");
- max_str -= ret;
- rrd_data += ret;
- }
-
- return 0;
+ return NULL;
}
#ifndef _PARSER_H
#define _PARSER_H
-#define RRD_DATA_MAX_LEN 4096
+typedef int (parse_fn_t)(char *rrd_data, const char **parser_data);
+
+struct parser_info {
+ struct parser_info *next;
+ const char *name;
+ parse_fn_t *parse;
+};
-int cpu_parser(char *data, const char **p);
-int mem_parser(char *data, const char **p);
-int cpu_mem_parser(char *data, const char **p);
-int digitemp_parser(char *data, const char **p);
-int digitemp_parser_mod(char *data, const char **p);
-int script_parser(char *rrd_data, const char **parser_data);
-int netstats_parser(char *rrd_data, const char **parser_data);
-int onewire_parser(char *rrd_data, const char **parser_data);
+int register_parser(struct parser_info *info);
+struct parser_info *str_to_parser(const char *str);
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define RRD_DATA_MAX_LEN 4096
#endif
l = sprintf(data, "N:");
- if (rrd->parse) {
- rrd->parse(data + l, rrd->parser_data);
+ if (rrd->parser && rrd->parser->parse) {
+ rrd->parser->parse(data + l, rrd->parser_data);
data[RRD_DATA_MAX_LEN + 2] = '\0';
pr_info("Data: %s\n", data);
int interval; /* Update interval */
/* Parser to aquire data for rrd */
- int (*parse)(char *rrd_data, const char **parser_data);
+ struct parser_info *parser;
const char **parser_data; /* data to be fed to the parser */
char *const *pre_draw_cmd; /* Command to execute prior drawing images*/
#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define ARRAY_SIZE(a) (sizeof(a) / (sizeof((a)[0])))
+
#endif