Compare commits

...

70 Commits

Author SHA1 Message Date
Olaf Rempel f7cc362d4d cleanup hddtemp 2012-12-11 22:08:13 +01:00
Olaf Rempel 1b593fede8 add hddtemp plugin 2012-12-11 21:14:29 +01:00
Olaf Rempel 6746926791 buildsystem and lib update 2012-12-09 12:26:51 +01:00
Olaf Rempel 7aa19ecade misc fixes 2010-06-12 15:36:12 +02:00
Olaf Rempel 1c13dd3f58 missing files 2010-06-12 13:43:51 +02:00
Olaf Rempel f99924d77f diskstandby plugin 2010-06-12 13:41:50 +02:00
Olaf Rempel d38cbcc0c6 internal changes 2010-06-12 12:30:12 +02:00
Olaf Rempel 9ff2ebbffa add simple ts2 users/channel count graph 2010-02-05 21:48:45 +01:00
Olaf Rempel c750a1da1d Merge branch 'master' of ssh://razzor@kronk/home/razzor/public_git/sammler 2010-02-05 21:48:11 +01:00
razzor 4cebc53498 change logfile location during restart 2010-02-05 20:08:21 +01:00
Olaf Rempel 3417baa5f0 fix norrd compile 2009-06-12 16:26:43 +02:00
Olaf Rempel 454894f55d libupdate 2009-05-03 14:07:22 +02:00
Olaf Rempel d3c241b7a3 fix logfile handling on restart 2009-05-03 14:05:09 +02:00
Olaf Rempel aea79fe6cd use SIGUSR1 to reread config 2009-05-02 15:32:33 +02:00
Olaf Rempel 49f3f7b571 resolve namespace clash 2009-05-01 23:27:15 +02:00
Olaf Rempel eb69980908 alloc fwdbuf during init 2009-05-01 23:19:29 +02:00
Olaf Rempel 7f6e90e6b3 pidfile support 2009-05-01 22:57:15 +02:00
Olaf Rempel 1827e1a6a1 use sockaddr.[ch] 2009-05-01 22:45:50 +02:00
Olaf Rempel ea031e54e6 update lib functions 2009-05-01 21:29:17 +02:00
Olaf Rempel fab7e99eb1 move includes to source 2009-05-01 21:26:16 +02:00
Olaf Rempel d09c70d2aa move config parsing to init() functions 2009-05-01 21:24:12 +02:00
Olaf Rempel 22958bb820 Merge branch 'master' of ssh://razzor@kopf-tisch.de/home/razzor/public_git/sammler 2009-04-19 18:29:06 +02:00
Olaf Rempel dd5055a9a5 add alixusv plugin 2009-04-19 18:28:19 +02:00
Olaf Rempel 5e7100718b fix Makefile 2009-04-02 15:48:11 +02:00
Olaf Rempel 065505d8ab different name when compiled without rrd support 2009-01-11 23:21:42 +01:00
Olaf Rempel a68116f30c added hwmon plugin 2009-01-11 23:14:50 +01:00
Olaf Rempel 4f2c4be0fb fix DESTDIR 2009-01-11 23:09:00 +01:00
Olaf Rempel c081bf6112 autodetect hostname 2009-01-11 23:08:31 +01:00
Olaf Rempel b6363621ab update makefile, add install target 2009-01-11 22:49:02 +01:00
Olaf Rempel c008c25e10 adjust x-files factor in rrds 2009-01-11 21:11:02 +01:00
Olaf Rempel 713e8c5087 update graphs 2007-04-07 19:49:04 +02:00
Olaf Rempel 0ce47d53f5 conntrack plugin 2007-04-03 18:49:39 +02:00
Olaf Rempel b426ae7331 diskstat plugin 2007-04-03 17:12:53 +02:00
Olaf Rempel e476640b74 simple plugins: use fscanf 2007-04-02 19:47:32 +02:00
Olaf Rempel eb17f95748 network & mount plugin 2007-04-01 16:51:39 +02:00
Olaf Rempel 207649b7b6 plugin cleanup 2007-04-01 15:45:31 +02:00
Olaf Rempel 4ff80b5e24 remove plugin scratchpad memory 2007-04-01 15:23:09 +02:00
Olaf Rempel b71a7cfe04 include / plugins directory 2007-04-01 14:56:14 +02:00
Olaf Rempel f16b9a8169 create probe.[ch] 2007-04-01 14:30:05 +02:00
Olaf Rempel 8210d25ec4 cleanup network 2007-04-01 14:09:20 +02:00
Olaf Rempel 3d0063c419 do plugin_lookup() only when needed 2007-04-01 13:21:51 +02:00
Olaf Rempel 5d4148234e cleanup rrd/net_submit 2007-04-01 01:32:59 +02:00
Olaf Rempel d1e5e5a1dd added event.[ch] 2007-04-01 00:17:50 +02:00
Olaf Rempel b94e64cd45 global plugin scratchpad memory 2007-03-31 23:21:31 +02:00
Olaf Rempel 253a79584e const stuff 2007-03-31 22:31:07 +02:00
Olaf Rempel 042b7ce9a0 new configfile.[ch] & logging.[ch] 2007-03-31 22:15:00 +02:00
Olaf Rempel 576960f682 dunno 2007-03-31 21:32:24 +02:00
Olaf Rempel bc0bd5fffb use single net pkts 2006-10-11 16:47:48 +02:00
Olaf Rempel 135d209392 cleanup & fixes 2006-10-09 14:40:38 +02:00
Olaf Rempel b9e011d2aa fix cpu graph 2006-10-08 18:17:45 +02:00
Olaf Rempel 4e2f47c5f9 apache plugin 2006-10-08 18:05:47 +02:00
Olaf Rempel 4e60087e06 cleanup & fixes 2006-10-08 16:33:07 +02:00
Olaf Rempel bddb4b013a mysql plugin 2006-10-08 01:58:01 +02:00
Olaf Rempel ebf4af7f13 misc fixes 2006-10-07 20:48:20 +02:00
Olaf Rempel a44fad8ecc missed free() 2006-10-07 20:40:38 +02:00
Olaf Rempel 273218612e plugin init/fini functions 2006-10-07 20:37:30 +02:00
Olaf Rempel 9add656662 calculated new RRAs 2006-10-01 00:44:41 +02:00
Olaf Rempel 4384af83ea p_stat: add steal time 2006-09-30 23:25:59 +02:00
Olaf Rempel 867a97e60e build without librrd 2006-09-30 22:55:04 +02:00
Olaf Rempel dbdb641572 gcc4 cleanups 2006-09-30 21:31:53 +02:00
Olaf Rempel 5af595bd88 update php-script 2006-09-30 21:22:10 +02:00
Olaf Rempel cb48f5bd03 forwarding works 2006-09-30 20:27:56 +02:00
Olaf Rempel bce2358271 give plugins control over step/heartbeat
- basic/fast plugins can use 10s
- more complex plugins (apache, mysql, bind, ..) will use 60s
- this is a little bit hackish since RRAs in configfile are based on the step value :)
2006-09-30 17:10:32 +02:00
Olaf Rempel a1c55be85e configfile: multiple tuple per line 2006-08-26 14:07:45 +02:00
Olaf Rempel cc227cc7cc use hostname 2006-08-26 14:01:10 +02:00
Olaf Rempel e0c7daa6e9 remove plugin versions 2006-08-26 13:43:03 +02:00
Olaf Rempel f437881d52 network stuff 2006-08-03 19:49:07 +02:00
Olaf Rempel a7101d33a9 split rtstat rrd, update graph script 2006-08-03 19:20:36 +02:00
Olaf Rempel 9db670ee11 add graph script 2006-08-03 17:57:11 +02:00
Olaf Rempel 7ab72054ad p_mount: skip tmpfs 2006-07-27 16:12:34 +02:00
54 changed files with 5870 additions and 858 deletions

2
.gitignore vendored
View File

@ -2,4 +2,6 @@
*.so
*.d
sammler
sammler_norrd
sammler.log
rrd

114
Makefile
View File

@ -1,30 +1,110 @@
# Toplevel Makefile
WITH_RRD?=yes
SAMMLER_SRC := sammler.c config.c logging.c rrdtool.c plugins.c
PLUGIN_SRC := $(wildcard p_*.c)
CFLAGS := -O2 -Wall
LDFLAGS := -ldl -lrrd -rdynamic
PLUGINS := ctstat diskstat hwmon load memory mount netdev random rtstat stat uptime vmstat
#PLUGINS += apache mysql conntrack alixusv ts2 diskstandby hddtemp
DESTDIR =
BINARY_DIR = /usr/local/bin
CONFIG_DIR = /usr/local/etc
PLUGIN_DIR = /usr/local/lib/sammler
DATA_DIR = /var/lib/sammler
LOG_DIR = /var/log
PID_DIR = /var/run
WWW_DIR = /var/www
WWW_CONFIG = $(WWW_DIR)/sammler_graph.conf
WWW_OWNER = www-data
# ############################
all: sammler $(PLUGIN_SRC:%.c=%.so)
SRC := $(wildcard *.c)
BUILD_DIR = build
CFLAGS = -O2 -g -pipe -Wall -Wno-unused-result -I.
CFLAGS += -MMD -MF $(BUILD_DIR)/$(*D)/$(*F).d
LDFLAGS = -rdynamic -ldl
sammler: $(SAMMLER_SRC:%.c=%.o)
$(CC) $(LDFLAGS) $^ -o $@
# ############################
%.d: %.c
$(CC) $(CFLAGS) -MM -c $< -o $@
ifeq ("$(WITH_RRD)", "yes")
CFLAGS += -DWITH_RRD
LDFLAGS_TARGET = -lrrd
TARGET = sammler
else
LDFLAGS_TARGET =
TARGET = sammler_norrd
endif
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
ifeq ($(strip $(wildcard $(DESTDIR)$(CONFIG_DIR)/sammler.conf)),)
NEWCONF=sammler.conf
else
NEWCONF=sammler.conf.dist
endif
%_sh.o: %.c
$(CC) $(CFLAGS) -fPIC -o $@ -c $<
# ############################
%.so: %_sh.o
$(LD) -shared -o $@ $<
all: $(TARGET) plugins
$(TARGET): $(patsubst %,$(BUILD_DIR)/%, $(SRC:.c=.o))
@echo " Linking file: $@"
@$(CC) $^ $(LDFLAGS) $(LDFLAGS_TARGET) -o $@
$(BUILD_DIR)/%.o: %.c $(MAKEFILE_LIST)
@echo " Building file: $<"
@$(shell test -d $(BUILD_DIR)/$(*D) || mkdir -p $(BUILD_DIR)/$(*D))
@$(CC) $(CFLAGS) -o $@ -c $<
.PHONY: plugins
plugins: $(PLUGINS:%=plugins/%.so)
.SECONDARY: $(patsubst %,$(BUILD_DIR)/%, $(PLUGINS:%=plugins/%.o))
plugins/%.so: $(BUILD_DIR)/plugins/%.o
@echo " Linking file: $@"
@$(CC) $(LDFLAGS) -shared -o $@ $<
plugins/apache.so: $(BUILD_DIR)/plugins/apache.o
@echo " Linking file: $@"
@$(CC) $(LDFLAGS) -shared -lcurl -o $@ $<
plugins/conntrack.so: $(BUILD_DIR)/plugins/conntrack.o
@echo " Linking file: $@"
@$(CC) $(LDFLAGS) -shared -lnfnetlink -lnetfilter_conntrack -o $@ $<
plugins/mysql.so: $(BUILD_DIR)/plugins/mysql.o $(BUILD_DIR)/plugins/mysql_helper.o
@echo " Linking file: $@"
@$(CC) $(LDFLAGS) -shared -lmysqlclient -o $@ $^
plugins/diskstandby.so: $(BUILD_DIR)/plugins/diskstandby.o $(BUILD_DIR)/plugins/sgio.o
@echo " Linking file: $@"
@$(CC) $(LDFLAGS) -shared -o $@ $^
install: all
install -D -m 755 -s $(TARGET) $(DESTDIR)$(BINARY_DIR)/$(TARGET)
install -D -m 644 sammler.conf $(DESTDIR)$(CONFIG_DIR)/$(NEWCONF)
sed -i -e "s:^logfile .*$$:logfile $(LOG_DIR)/sammler.log:" \
-e "s:^pidfile .*$$:pidfile $(PID_DIR)/sammler.pid:" \
-e "s:^rrd_dir .*$$:rrd_dir $(DATA_DIR):" \
-e "s:^plugin_dir .*$$:plugin_dir $(PLUGIN_DIR):" \
$(DESTDIR)$(CONFIG_DIR)/$(NEWCONF)
install -d -m 755 $(DESTDIR)$(PLUGIN_DIR)
install -m 755 -s plugins/*.so $(DESTDIR)$(PLUGIN_DIR)
install -d -m 755 $(DESTDIR)$(LOG_DIR)
ifeq ("$(WITH_RRD)", "yes")
install -d -m 755 $(DESTDIR)$(DATA_DIR)
install -D -m 644 sammler.php $(DESTDIR)$(WWW_DIR)/sammler.php
sed -i -e "s:%%WWW_CONFIG%%:$(WWW_CONFIG):" \
-e "s:%%DATA_DIR%%:$(DATA_DIR)/:" \
$(DESTDIR)$(WWW_DIR)/sammler.php
ifeq ($(strip $(wildcard $(DESTDIR)$(WWW_CONFIG))),)
-install -D -m 644 -o $(WWW_OWNER) /dev/null $(DESTDIR)$(WWW_CONFIG)
endif
else
sed -i -e "s:^forward_only .*$$:forward_only true:" \
$(DESTDIR)$(CONFIG_DIR)/$(NEWCONF)
endif
clean:
rm -rf *.d *.o *.so sammler
rm -rf build plugins/*.so $(TARGET)
#-include $(SAMMLER_SRC:.c=.d) $(PLUGIN_SRC:.c=.d)
include $(shell find $(BUILD_DIR) -name \*.d 2> /dev/null)

182
config.c
View File

@ -1,182 +0,0 @@
/***************************************************************************
* Copyright (C) 06/2006 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "list.h"
#include "config.h"
#include "logging.h"
static LIST_HEAD(config_list);
static struct conf_section * config_add_section(char *name)
{
struct conf_section *section;
if (!name)
return NULL;
section = malloc(sizeof(struct conf_section));
if (section) {
INIT_LIST_HEAD(&section->list);
INIT_LIST_HEAD(&section->tupel);
strncpy(section->name, name, sizeof(section->name));
list_add_tail(&section->list, &config_list);
}
return section;
}
static int config_add_tupel(struct conf_section *section, char *option, char *parameter)
{
struct conf_tupel *tupel;
if (!section || !option || !parameter)
return 0;
if (!(tupel = malloc(sizeof(struct conf_tupel))))
return 0;
INIT_LIST_HEAD(&tupel->list);
tupel->option = strdup(option);
tupel->parameter = strdup(parameter);
list_add_tail(&tupel->list, &section->tupel);
return 1;
}
static void config_free(void)
{
struct conf_section *section, *section_tmp;
struct conf_tupel *tupel, *tupel_tmp;
list_for_each_entry_safe(section, section_tmp, &config_list, list) {
list_for_each_entry_safe(tupel, tupel_tmp, &section->tupel, list) {
list_del(&tupel->list);
free(tupel->option);
free(tupel->parameter);
free(tupel);
}
list_del(&section->list);
free(section);
}
}
int config_parse(char *config)
{
struct conf_section *section = NULL;
FILE *fz;
int i = 0, ret = 1;
char *row, *tok, *tok2;
if (!config)
return 0;
if (!(row = malloc(1024)))
return 0;
if (!(fz = fopen(config, "r"))) {
log_print(LOG_ERROR, "config_parse(): %s", config);
return 0;
}
while (fgets(row, 1024, fz)) {
i++;
if (row[0] == '#' || row[0] <= ' ') {
continue;
} else if (row[0] == '[') {
tok = strtok(row +1, " ]\n");
section = config_add_section(tok);
if (!section) {
log_print(LOG_WARN, "config_parse(): invalid section in row %d", i);
ret = 0;
break;
}
continue;
} else if (!section) {
log_print(LOG_WARN, "config_parse(): missing section in row %d", i);
ret = 0;
break;
}
if ((tok = strtok(row, " \n")) && (tok2 = strtok(NULL, " \n")))
if (!config_add_tupel(section, tok, tok2))
log_print(LOG_WARN, "config_parse(): invalid row %d", i);
}
fclose(fz);
free(row);
if (atexit(config_free) != 0) {
log_print(LOG_ERROR, "config_parse(): atexit()");
return 0;
}
return ret;
}
struct conf_section * config_get_section(char *name)
{
struct conf_section *section;
list_for_each_entry(section, &config_list, list) {
if (!strcmp(section->name, name))
return section;
}
return NULL;
}
char * config_get_parameter(struct conf_section *section, char *option)
{
struct conf_tupel *tupel;
list_for_each_entry(tupel, &section->tupel, list) {
if (!strcmp(tupel->option, option))
return tupel->parameter;
}
return NULL;
}
char * config_get_string(char *section, char *option, char *def)
{
struct conf_section *tmp;
char *ret;
tmp = config_get_section(section);
if (tmp && (ret = config_get_parameter(tmp, option)))
return ret;
return def;
}
int config_get_int(char *section, char *option, int def)
{
char *ret;
ret = config_get_string(section, option, NULL);
return ret ? atoi(ret) : def;
}

View File

@ -1,24 +0,0 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include "list.h"
struct conf_section {
struct list_head list;
char name[32];
struct list_head tupel;
};
struct conf_tupel {
struct list_head list;
char *option;
char *parameter;
};
int config_parse(char *config);
struct conf_section * config_get_section(char *name);
char * config_get_parameter(struct conf_section *section, char *option);
char * config_get_string(char *section, char *option, char *def);
int config_get_int(char *section, char *option, int def);
#endif /* _CONFIG_H_ */

292
configfile.c Normal file
View File

@ -0,0 +1,292 @@
/***************************************************************************
* Copyright (C) 03/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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; version 2 of the License *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "configfile.h"
#include "list.h"
#include "logging.h"
#define BUFSIZE 1024
struct conf_section {
struct list_head list;
struct list_head tupel_list;
const char *name;
};
struct conf_tupel {
struct list_head list;
const char *option;
const char *parameter;
};
static LIST_HEAD(config_list);
static struct conf_section * config_add_section(const char *name)
{
struct conf_section *section;
section = malloc(sizeof(struct conf_section) + strlen(name));
if (section == NULL)
return NULL;
INIT_LIST_HEAD(&section->list);
INIT_LIST_HEAD(&section->tupel_list);
section->name = strdup(name);
if (section->name == NULL) {
free(section);
return NULL;
}
list_add_tail(&section->list, &config_list);
return section;
}
static int config_add_tupel(struct conf_section *section, const char *option, const char *parameter)
{
struct conf_tupel *tupel = malloc(sizeof(struct conf_tupel));
if (tupel == NULL)
return -1;
INIT_LIST_HEAD(&tupel->list);
tupel->option = strdup(option);
tupel->parameter = strdup(parameter);
if (tupel->option == NULL || tupel->parameter == NULL) {
free(tupel);
return -1;
}
list_add_tail(&tupel->list, &section->tupel_list);
return 0;
}
int config_parse(const char *config)
{
FILE *fz = fopen(config, "r");
if (fz == NULL) {
log_print(LOG_ERROR, "%s(): failed to open config '%s'", __FUNCTION__, config);
return -1;
}
char *line = malloc(BUFSIZE);
if (line == NULL) {
log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
fclose(fz);
return -1;
}
int linenum = 0;
struct conf_section *section = NULL;
while (fgets(line, BUFSIZE, fz) != NULL) {
linenum++;
if (line[0] == '#' || line[0] <= ' ') {
continue;
} else if (line[0] == '[') {
char *tok = strtok(line +1, " ]\n");
if (tok == NULL || (section = config_add_section(tok)) == NULL) {
log_print(LOG_WARN, "%s(): invalid section in row %d", __FUNCTION__, linenum);
free(line);
fclose(fz);
return -1;
}
continue;
} else if (section == NULL) {
log_print(LOG_WARN, "%s(): missing section in row %d", __FUNCTION__, linenum);
free(line);
fclose(fz);
return -1;
}
char *tmp, *tok = strtok_r(line, " \t\n", &tmp);
if (tok != NULL) {
char *tok2;
while ((tok2 = strtok_r(NULL, " \n", &tmp))) {
if (config_add_tupel(section, tok, tok2) != 0)
log_print(LOG_WARN, "%s(): invalid row %d", __FUNCTION__, linenum);
}
}
}
fclose(fz);
free(line);
return 0;
}
void config_free(void)
{
struct conf_section *section, *section_tmp;
struct conf_tupel *tupel, *tupel_tmp;
list_for_each_entry_safe(section, section_tmp, &config_list, list) {
list_for_each_entry_safe(tupel, tupel_tmp, &section->tupel_list, list) {
list_del(&tupel->list);
free((char *)tupel->option);
free((char *)tupel->parameter);
free(tupel);
}
list_del(&section->list);
free(section);
}
}
static struct conf_section * config_get_section(const char *name)
{
struct conf_section *section;
list_for_each_entry(section, &config_list, list) {
if (!strcmp(section->name, name))
return section;
}
return NULL;
}
const char * config_get_string(const char *section_str, const char *option, const char *def)
{
struct conf_section *section = config_get_section(section_str);
if (section != NULL) {
struct conf_tupel *tupel;
list_for_each_entry(tupel, &section->tupel_list, list) {
if (!strcmp(tupel->option, option))
return tupel->parameter;
}
}
if (def != NULL)
log_print(LOG_WARN, "config [%s:%s] not found, using default: '%s'",
section_str, option, def);
return def;
}
int config_get_int(const char *section, const char *option, int *value, int def)
{
const char *ret = config_get_string(section, option, NULL);
if (ret == NULL) {
log_print(LOG_WARN, "config [%s:%s] not found, using default: '%d'",
section, option, def);
*value = def;
return -1;
}
char *tmp;
*value = strtol(ret, &tmp, 0);
if (*tmp != '\0' && !isspace(*tmp)) {
log_print(LOG_WARN, "config [%s:%s] not an integer: '%s', using default '%d'",
section, option, ret, def);
*value = def;
return -1;
}
return 0;
}
int config_get_strings(const char *section_str, const char *option,
int (*callback)(const char *value, void *privdata),
void *privdata)
{
struct conf_section *section = config_get_section(section_str);
if (section == NULL)
return -1;
int cnt = 0;
struct conf_tupel *tupel;
list_for_each_entry(tupel, &section->tupel_list, list) {
if (!strcmp(tupel->option, option))
if (callback(tupel->parameter, privdata) == 0)
cnt++;
}
return cnt;
}
struct strtoken * strtokenize(const char *input, const char *delim, int maxfields)
{
struct strtoken *tokens = malloc(sizeof(struct strtoken) +
(maxfields +1) * sizeof(char *) +
strlen(input));
if (tokens == NULL)
return NULL;
char *ptr = (char *)&tokens->field[maxfields];
strcpy(ptr, input);
tokens->input = input;
tokens->delim = delim;
tokens->maxfields = maxfields;
int i;
char *tmp;
tokens->count = 0;
for (i = 0; i < maxfields; i++) {
tokens->field[i] = strtok_r(ptr, delim, &tmp);
ptr = NULL;
if (tokens->field[i] != NULL)
tokens->count++;
}
return tokens;
}
struct strtoken * config_get_strtoken(const char *section, const char *option, const char *delim, int maxfields)
{
const char *ret = config_get_string(section, option, NULL);
if (ret == NULL) {
log_print(LOG_WARN, "config [%s:%s] not found", section, option);
return NULL;
}
return strtokenize(ret, delim, maxfields);
}
int config_get_strtokens(const char *section_str, const char *option, const char *delim, int maxfields,
int (*callback)(struct strtoken *data, void *privdata),
void *privdata)
{
struct conf_section *section = config_get_section(section_str);
if (section == NULL)
return -1;
int cnt = 0;
struct conf_tupel *tupel;
list_for_each_entry(tupel, &section->tupel_list, list) {
if (!strcmp(tupel->option, option)) {
struct strtoken *tokens = strtokenize(tupel->parameter, delim, maxfields);
if (tokens != NULL) {
if (callback(tokens, privdata) == 0)
cnt++;
free(tokens);
}
}
}
return cnt;
}

31
configfile.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
int config_parse(const char *config);
void config_free(void);
const char * config_get_string(const char *section_str, const char *option, const char *def);
int config_get_int(const char *section, const char *option, int *value, int def);
int config_get_strings(const char *section_str, const char *option,
int (*callback)(const char *value, void *privdata),
void *privdata);
struct strtoken {
const char *input;
const char *delim;
int maxfields;
int count;
char *field[0];
};
struct strtoken * strtokenize(const char *input, const char *delim, int maxfields);
struct strtoken * config_get_strtoken(const char *section_str, const char *option, const char *delim, int maxfields);
int config_get_strtokens(const char *section_str, const char *option, const char *delim, int maxfields,
int (*callback)(struct strtoken *tokens, void *privdata),
void *privdata);
#endif /* _CONFIG_H_ */

331
event.c Normal file
View File

@ -0,0 +1,331 @@
/***************************************************************************
* Copyright (C) 03/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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; version 2 of the License *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include "list.h"
#include "logging.h"
#include "event.h"
static LIST_HEAD(event_fd_list);
static LIST_HEAD(event_timeout_list);
struct event_fd {
struct list_head list;
unsigned int flags;
int fd;
int (*read_cb)(int fd, void *privdata);
int (*write_cb)(int fd, void *privdata);
void *read_priv;
void *write_priv;
};
struct event_timeout {
struct list_head list;
unsigned int flags;
struct timeval intervall;
struct timeval nextrun;
int (*callback)(int timerid, void *privdata);
int timerid;
void *privdata;
};
struct event_fd * event_add_fd(
struct event_fd *entry,
int fd,
int type,
int (*callback)(int fd, void *privdata),
void *privdata)
{
/* check valid filediskriptor */
if (fd < 0 || fd > FD_SETSIZE) {
log_print(LOG_ERROR, "%s(): invalid fd", __FUNCTION__);
return NULL;
}
/* check valid type (read/write) */
if (!(type & FD_TYPES)) {
log_print(LOG_ERROR, "%s(): invalid type", __FUNCTION__);
return NULL;
}
/* create new entry */
if (entry == NULL) {
entry = malloc(sizeof(struct event_fd));
if (entry == NULL) {
log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
return NULL;
}
memset(entry, 0, sizeof(struct event_fd));
entry->flags |= EVENT_NEW;
entry->fd = fd;
/* put it on the list */
list_add_tail(&entry->list, &event_fd_list);
}
if (type & FD_READ) {
entry->flags = (callback != NULL) ? (entry->flags | FD_READ | EVENT_NEW) : (entry->flags & ~FD_READ);
entry->read_cb = callback;
entry->read_priv = privdata;
} else if (type & FD_WRITE) {
entry->flags = (callback != NULL) ? (entry->flags | FD_WRITE | EVENT_NEW) : (entry->flags & ~FD_WRITE);
entry->write_cb = callback;
entry->write_priv = privdata;
}
return entry;
}
int event_get_fd(struct event_fd *entry)
{
return (entry != NULL) ? entry->fd: -1;
}
void event_remove_fd(struct event_fd *entry)
{
/* mark the event as deleted -> remove in select() loop */
entry->flags |= EVENT_DELETE;
}
static void add_timeval(struct timeval *ret, struct timeval *a, struct timeval *b)
{
ret->tv_usec = a->tv_usec + b->tv_usec;
ret->tv_sec = a->tv_sec + b->tv_sec;
if (ret->tv_usec >= 1000000) {
ret->tv_usec -= 1000000;
ret->tv_sec++;
}
}
static void sub_timeval(struct timeval *ret, struct timeval *a, struct timeval *b)
{
ret->tv_usec = a->tv_usec - b->tv_usec;
ret->tv_sec = a->tv_sec - b->tv_sec;
if (ret->tv_usec < 0) {
ret->tv_usec += 1000000;
ret->tv_sec--;
}
}
static int cmp_timeval(struct timeval *a, struct timeval *b)
{
if (a->tv_sec > b->tv_sec)
return -1;
if (a->tv_sec < b->tv_sec)
return 1;
if (a->tv_usec > b->tv_usec)
return -1;
if (a->tv_usec < b->tv_usec)
return 1;
return 0;
}
static void schedule_nextrun(struct event_timeout *entry, struct timeval *now)
{
add_timeval(&entry->nextrun, now, &entry->intervall);
struct event_timeout *search;
list_for_each_entry(search, &event_timeout_list, list) {
if (search->nextrun.tv_sec > entry->nextrun.tv_sec) {
list_add_tail(&entry->list, &search->list);
return;
} else if (search->nextrun.tv_sec == entry->nextrun.tv_sec &&
search->nextrun.tv_usec > entry->nextrun.tv_usec) {
list_add_tail(&entry->list, &search->list);
return;
}
}
list_add_tail(&entry->list, &event_timeout_list);
}
struct event_timeout * event_add_timeout(
struct timeval *timeout,
int (*callback)(int timerid, void *privdata),
int timerid,
void *privdata)
{
struct event_timeout *entry;
entry = malloc(sizeof(struct event_timeout));
if (entry == NULL) {
log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
return NULL;
}
entry->flags = 0;
memcpy(&entry->intervall, timeout, sizeof(entry->intervall));
entry->callback = callback;
entry->timerid = timerid;
entry->privdata = privdata;
struct timeval now;
gettimeofday(&now, NULL);
schedule_nextrun(entry, &now);
return entry;
}
struct event_timeout * event_add_timeout_ms(
int timeout_ms,
int (*callback)(int timerid, void *privdata),
int timerid,
void *privdata)
{
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
return event_add_timeout(&tv, callback, timerid, privdata);
}
void event_remove_timeout(struct event_timeout *entry)
{
/* mark the event as deleted -> remove in select() loop */
entry->flags |= EVENT_DELETE;
}
int event_loop(int (*pre_select_cb)(int *maxfd, void *readfds, void *writefds, struct timeval *timeout, void *privdata),
int (*post_select_cb)(int retval, void *readfds, void *writefds, void *privdata),
void *privdata)
{
while (1) {
/* default value if no application timeout is present */
struct timeval timeout = {
.tv_sec = -1,
.tv_usec = -1,
};
if (!list_empty(&event_timeout_list)) {
struct timeval now;
gettimeofday(&now, NULL);
struct event_timeout *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &event_timeout_list, list) {
if (entry->flags & EVENT_DELETE) {
list_del(&entry->list);
free(entry);
continue;
}
/* first timeout not elapsed, exit search (since list is sorted) */
if (cmp_timeval(&entry->nextrun, &now) == -1)
break;
/* remove event from list */
list_del(&entry->list);
/* execute callback, when callback returns 0 -> schedule event again */
if (entry->callback(entry->timerid, entry->privdata)) {
free(entry);
} else {
schedule_nextrun(entry, &now);
}
}
if (!list_empty(&event_timeout_list)) {
entry = list_entry(event_timeout_list.next, typeof(*entry), list);
/* calc select() timeout */
sub_timeval(&timeout, &entry->nextrun, &now);
}
}
struct event_fd *entry, *tmp;
int maxfd = -1;
fd_set readfds, writefds;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
list_for_each_entry_safe(entry, tmp, &event_fd_list, list) {
entry->flags &= ~EVENT_NEW;
if (entry->flags & EVENT_DELETE) {
list_del(&entry->list);
free(entry);
continue;
}
if (entry->flags & FD_READ)
FD_SET(entry->fd, &readfds);
if (entry->flags & FD_WRITE)
FD_SET(entry->fd, &writefds);
maxfd = (entry->fd > maxfd) ? entry->fd : maxfd;
}
maxfd++;
/* exit loop if callback returns true */
if (pre_select_cb != NULL && pre_select_cb(&maxfd, (void *)&readfds, (void *)&writefds, &timeout, privdata) != 0)
break;
int retval;
if (timeout.tv_sec == -1 && timeout.tv_usec == -1)
retval = select(maxfd, &readfds, &writefds, NULL, NULL);
else
retval = select(maxfd, &readfds, &writefds, NULL, &timeout);
/* exit loop if callback returns true */
if (post_select_cb != NULL && post_select_cb(retval, (void *)&readfds, (void *)&writefds, privdata) != 0)
break;
if (retval < 0 && errno == EINTR) {
errno = 0;
continue;
} else if (retval < 0) {
log_print(LOG_ERROR, "%s(): select():", __FUNCTION__);
continue;
}
/* timeout */
if (retval == 0)
continue;
list_for_each_entry(entry, &event_fd_list, list) {
if (((entry->flags & (FD_READ | EVENT_NEW)) == FD_READ) && FD_ISSET(entry->fd, &readfds))
if (entry->read_cb(entry->fd, entry->read_priv) != 0)
entry->flags |= EVENT_DELETE;
if (((entry->flags & (FD_WRITE | EVENT_NEW)) == FD_WRITE) && FD_ISSET(entry->fd, &writefds))
if (entry->write_cb(entry->fd, entry->write_priv) != 0)
entry->flags |= EVENT_DELETE;
}
}
return 0;
}

51
event.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef _EVENT_H_
#define _EVENT_H_
#include <sys/time.h>
#define EVENT_NEW 0x1000
#define EVENT_DELETE 0x2000
#define FD_READ 0x0001
#define FD_WRITE 0x0002
#define FD_TYPES (FD_READ | FD_WRITE)
#define event_add_readfd(entry, fd, callback, privdata) \
event_add_fd(entry, fd, FD_READ, callback, privdata)
#define event_add_writefd(entry, fd, callback, privdata) \
event_add_fd(entry, fd, FD_WRITE, callback, privdata)
/* inner details are not visible to external users (TODO: size unknown) */
struct event_fd;
struct event_timeout;
struct event_fd * event_add_fd(
struct event_fd *entry,
int fd,
int type,
int (*callback)(int fd, void *privdata),
void *privdata);
int event_get_fd(struct event_fd *entry);
void event_remove_fd(struct event_fd *entry);
struct event_timeout * event_add_timeout(
struct timeval *timeout,
int (*callback)(int timerid, void *privdata),
int timerid,
void *privdata);
struct event_timeout * event_add_timeout_ms(
int timeout_ms,
int (*callback)(int timerid, void *privdata),
int timerid,
void *privdata);
void event_remove_timeout(struct event_timeout *entry);
int event_loop(int (*pre_select_cb)(int *maxfd, void *readfds, void *writefds, struct timeval *timeout, void *privdata),
int (*post_select_cb)(int retval, void *readfds, void *writefds, void *privdata),
void *privdata);
#endif /* _EVENT_H_ */

37
helper.c Normal file
View File

@ -0,0 +1,37 @@
/***************************************************************************
* Copyright (C) 10/2006 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strsplit(char *string, char *delim, char **fields, int size)
{
int i = 0;
char *tmp, *ptr = string;
while ((fields[i] = strtok_r(ptr, delim, &tmp)) != NULL) {
ptr = NULL;
i++;
if (i >= size)
break;
}
return i;
}

8
helper.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _HELPER_H_
#define _HELPER_H_
#define DFLT_DELIM " \n\t"
int strsplit(char *string, char *delim, char **fields, int size);
#endif /* _HELPER_H_ */

239
linebuffer.c Normal file
View File

@ -0,0 +1,239 @@
/***************************************************************************
* Copyright (C) 03/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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; version 2 of the License *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include "linebuffer.h"
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
struct lbuf {
size_t size;
size_t pos;
char *token;
char data[0];
};
/*
* creates linebuffer with given size
*/
struct lbuf * lbuf_create(size_t size)
{
struct lbuf *buf = malloc(sizeof(struct lbuf) + size);
if (buf == NULL)
return NULL;
buf->size = size;
buf->pos = 0;
return buf;
}
/*
* frees the linebuffer and all data in it
*/
void lbuf_free(struct lbuf *buf)
{
free(buf);
}
/*
* clears the linebuffer
* - returns the datasize it was holding
*/
int lbuf_clear(struct lbuf *buf)
{
int oldpos = buf->pos;
buf->pos = 0;
return oldpos;
}
/*
* get pointer to internal data
* - returns pointer to datasize
*/
char * lbuf_getdata(struct lbuf *buf, size_t *len)
{
if (len != NULL)
*len = buf->pos;
return buf->data;
}
/*
* appends data to the buffer
* - returns the number of bytes copied
*/
int lbuf_append(struct lbuf *buf, const char *src, size_t size)
{
int len = MIN(buf->size - buf->pos, size);
memcpy(buf->data + buf->pos, src, len);
buf->pos += len;
return len;
}
/*
* reads as much data as it can get from a FD
* - returns the number of bytes read, or -1 on error
*/
int lbuf_readfd(struct lbuf *buf, int fd)
{
int len = read(fd, buf->data + buf->pos, buf->size - buf->pos);
if (len <= 0)
return -1;
buf->pos += len;
return len;
}
/*
* parses as much data as it can get from a FD
* parses means: backspaces remove one byte from the end of the buffer
* - returns 0 on success, or -1 on error
*/
int lbuf_parsefd(struct lbuf *buf, int fd)
{
char tmp[32];
int len = read(fd, tmp, sizeof(tmp));
if (len <= 0)
return -1;
int i;
for (i = 0; i < len; i++) {
/* "understand" backspace */
if (tmp[i] == 0x08 && buf->pos > 0) {
buf->pos--;
/* copy */
} else if (tmp[i] >= ' ' || tmp[i] == '\n') {
*(buf->data + buf->pos++) = tmp[i];
}
if (buf->pos > buf->size)
return -1;
}
/* TODO: return bytes appended to buffer? */
return 0;
}
/*
* writes as much data as it can to a FD
* - returns the number of bytes written, or -1 on error
*/
int lbuf_writefd(struct lbuf *buf, int fd)
{
int len = write(fd, buf->data, buf->pos);
if (len <= 0)
return -1;
/* handle partial writes */
if (len != buf->pos)
memmove(buf->data, buf->data + len, buf->pos - len);
buf->pos -= len;
return len;
}
/*
* append va_list to buffer
* - returns number ob bytes appended, or -1 on error
*/
int lbuf_vprintf(struct lbuf *buf, const char *fmt, va_list az)
{
int len = vsnprintf(buf->data + buf->pos, buf->size - buf->pos, fmt, az);
if (len < 0 || len >= (buf->size - buf->pos))
return -1;
buf->pos += len;
return len;
}
/*
* printf into buffer
* - returns number of bytes appended, or -1 on error
*/
int lbuf_printf(struct lbuf *buf, const char *fmt, ...)
{
va_list az;
va_start(az, fmt);
int ret = lbuf_vprintf(buf, fmt, az);
va_end(az);
return ret;
}
/*
* get next non-empty token
* - returns pointer to next token
* - returns NULL if no delimter is found in buffer
*/
char * lbuf_gettok(struct lbuf *buf, const char *delim)
{
char *start = buf->data;
char *end = buf->data + buf->pos;
int dlen = strlen(delim);
while (1) {
buf->token = NULL;
/* find first delimiter in buffer */
int i;
for (i = 0; i < dlen; i++) {
char *tok = memchr(start, delim[i], end - start);
if (tok != NULL && (tok < buf->token || buf->token == NULL))
buf->token = tok;
}
/* nothing found */
if (buf->token == NULL)
return NULL;
/* delimter found on start pos -> skip empty token */
if (buf->token == start) {
start++;
if (start >= end)
return NULL;
} else {
/* non-empty token found, exit */
break;
}
}
/* overwrite token, return start ptr */
*(buf->token) = '\0';
return start;
}
/*
* release previous fetched line
* - returns number of remaining bytes in buffer
*/
int lbuf_freetok(struct lbuf *buf)
{
if (buf->token != NULL) {
buf->pos -= (buf->token - buf->data) +1;
memmove(buf->data, buf->token +1, buf->pos);
buf->token = NULL;
}
return buf->pos;
}

27
linebuffer.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef _LINEBUFFER_H_
#define _LINEBUFFER_H_
#include <stdarg.h>
/* hide details */
struct lbuf;
struct lbuf * lbuf_create(size_t size);
void lbuf_free(struct lbuf *buf);
int lbuf_clear(struct lbuf *buf);
int lbuf_readfd(struct lbuf *buf, int fd);
int lbuf_parsefd(struct lbuf *buf, int fd);
int lbuf_writefd(struct lbuf *buf, int fd);
char * lbuf_getdata(struct lbuf *buf, size_t *len);
int lbuf_append(struct lbuf *buf, const char *src, size_t size);
int lbuf_vprintf(struct lbuf *buf, const char *fmt, va_list ap);
int lbuf_printf(struct lbuf *buf, const char *fmt, ...);
char * lbuf_gettok(struct lbuf *buf, const char *delim);
int lbuf_freetok(struct lbuf *buf);
#endif /* _LINEBUFFER_H_ */

View File

@ -1,11 +1,10 @@
/***************************************************************************
* Copyright (C) 06/2006 by Olaf Rempel *
* Copyright (C) 07/2007 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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. *
* the Free Software Foundation; version 2 of the License *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
@ -19,85 +18,98 @@
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include "logging.h"
#define BUFSIZE 8192
static FILE *log_fd = NULL;
static FILE *log_file = NULL;
static int log_prio = LOG_EVERYTIME;
static char *buffer = NULL;
void log_print(int prio, const char *fmt, ...)
int log_print(int prio, const char *fmt, ...)
{
va_list az;
int len;
int len = 0, retval;
if (prio < log_prio)
return 0;
if (buffer == NULL) {
buffer = malloc(BUFSIZE);
if (buffer == NULL) {
fprintf(stderr, "log_print: out of memory\nBailing out!\n");
exit(-1);
fprintf(stderr, "%s(): out of memory\n", __FUNCTION__);
return -1;
}
}
if (log_file != NULL) {
time_t tzgr;
time(&tzgr);
len += strftime(buffer, BUFSIZE, "%b %d %H:%M:%S :", localtime(&tzgr));
}
va_start(az, fmt);
len = vsnprintf(buffer, BUFSIZE, fmt, az);
len += vsnprintf(buffer + len, BUFSIZE - len, fmt, az);
va_end(az);
if (len < 0 || len >= BUFSIZE) {
log_print(LOG_ERROR, "log_print: arguments too long");
errno = 0;
return;
return log_print(LOG_ERROR, "%s: arguments too long", __FUNCTION__);
}
if (errno) {
strncpy(buffer + len, ": ", BUFSIZE - len);
len += 2;
strncpy(buffer + len, strerror(errno), BUFSIZE - len);
len += snprintf(buffer + len, BUFSIZE - len, ": %s", strerror(errno));
errno = 0;
}
if (log_fd) {
char tbuf[64];
time_t tzgr;
time(&tzgr);
strftime(tbuf, sizeof(tbuf), "%b %d %H:%M:%S :", localtime(&tzgr));
fprintf(log_fd, "%s %s\n", tbuf, buffer);
fflush(log_fd);
} else {
fprintf(stderr, "%s\n", buffer);
}
errno = 0;
retval = fprintf((log_file ? log_file : stderr), "%s\n", buffer);
fflush(log_file);
return retval;
}
static void log_close(void)
void log_close(void)
{
if (buffer)
if (buffer) {
free(buffer);
buffer = NULL;
}
fclose(log_fd);
if (log_file) {
fclose(log_file);
log_file = NULL;
}
}
int log_init(char *logfile)
int log_init(const char *logfile)
{
log_fd = fopen(logfile, "a");
if (log_fd == NULL) {
log_print(LOG_ERROR, "log_open('%s'): %s", logfile);
return 0;
if (log_file != NULL)
log_close();
log_file = fopen(logfile, "a");
if (log_file == NULL) {
fprintf(stderr, "%s(): can not open logfile", __FUNCTION__);
return -1;
}
if (atexit(log_close) != 0) {
log_print(LOG_ERROR, "log_open(): atexit()");
return 0;
if (fcntl(fileno(log_file), F_SETFD, FD_CLOEXEC) < 0) {
fprintf(stderr, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
fclose(log_file);
return -1;
}
log_print(LOG_EVERYTIME, "==========================");
return 1;
log_prio = LOG_EVERYTIME;
return 0;
}
void log_setprio(int prio)
{
log_prio = prio;
}

View File

@ -1,16 +1,23 @@
#ifndef _LOGGING_H_
#define _LOGGING_H_
#define LOG_DEBUG 5
#define LOG_INFO 4
#define LOG_NOTICE 3
#define LOG_WARN 2
#define LOG_ERROR 1
#define LOG_CRIT 0
#define LOG_EMERG 0 /* system is unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARNING 4 /* warning conditions */
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */
#define LOG_EVERYTIME 0
#define LOG_EVERYTIME LOG_EMERG
#define LOG_ERROR LOG_ERR
#define LOG_WARN LOG_WARNING
int log_init(char *logfile);
void log_print(int prio, const char *fmt, ... );
int log_init(const char *logfile);
void log_close(void);
void log_setprio(int prio);
int log_print(int prio, const char *fmt, ... );
#endif /* _LOGGING_H_ */

206
network.c Normal file
View File

@ -0,0 +1,206 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include "configfile.h"
#include "event.h"
#include "helper.h"
#include "list.h"
#include "logging.h"
#include "network.h"
#include "plugins.h"
#include "rrdtool.h"
#include "sockaddr.h"
#define PKTSIZE 1400
struct net_entry {
struct list_head list;
struct event_fd *event;
struct sockaddr_in addr;
int socket;
};
static LIST_HEAD(srv_list);
static LIST_HEAD(cli_list);
static char *fwd_buf;
static int fwd_buf_len;
void net_submit_flush(void)
{
if (fwd_buf_len == 0)
return;
struct net_entry *entry;
list_for_each_entry(entry, &cli_list, list)
sendto(entry->socket, fwd_buf, fwd_buf_len, 0, (struct sockaddr *)&entry->addr, sizeof(entry->addr));
fwd_buf_len = 0;
}
int net_submit(const char *hostname, const char *pluginname, const char *filename, int ds_id, const char *data)
{
if (list_empty(&cli_list))
return 0;
int size = snprintf(fwd_buf + fwd_buf_len, PKTSIZE - fwd_buf_len, "%s:%s:%s:%d %s\n",
hostname, pluginname, filename, ds_id, data);
if (size < 0 || size >= PKTSIZE - fwd_buf_len) {
/* the complete buffer is already full */
if (fwd_buf_len == 0) {
log_print(LOG_ERROR, "net_submit(): arguments too long");
return -1;
}
/* flush & retry */
net_submit_flush();
return net_submit(hostname, pluginname, filename, ds_id, data);
}
fwd_buf_len += size;
return 0;
}
static int net_receive(int socket, void *privdata)
{
int recvsize;
if (ioctl(socket, FIONREAD, &recvsize) == -1) {
log_print(LOG_WARN, "net_receive(): ioctl(FIONREAD)");
return 0;
}
char *buf = malloc(recvsize);
if (buf == NULL) {
log_print(LOG_WARN, "net_receive(): out of memory");
return 0;
}
int size = recv(socket, buf, recvsize, 0);
if (size <= 0) {
log_print(LOG_WARN, "net_receive(): recv()");
free(buf);
return 0;
}
char *delim;
int pos = 0;
while ((delim = memchr(buf + pos, '\n', size - pos)) != NULL) {
*delim = '\0';
char *data[2];
int ret = strsplit(buf + pos, " ", data, 2);
pos = (delim - buf) +1;
if (ret != 2) {
log_print(LOG_ERROR, "net_receive(): abort data-split");
continue;
}
char *part[4];
ret = strsplit(data[0], ":", part, 4);
if (ret != 4) {
log_print(LOG_ERROR, "net_receive(): abort header-split");
continue;
}
rrd_submit(part[0], part[1], part[2], atoi(part[3]), data[1]);
}
free(buf);
return 0;
}
static struct net_entry * create_net_entry(const char *value)
{
struct net_entry *entry = malloc(sizeof(struct net_entry));
if (entry == NULL)
return NULL;
if (parse_sockaddr(value, &entry->addr) < 0) {
free(entry);
return NULL;
}
entry->socket = socket(PF_INET, SOCK_DGRAM, 0);
if (entry->socket < 0) {
free(entry);
return NULL;
}
return entry;
}
static int net_init_srv_cb(const char *value, void *privdata)
{
struct net_entry *entry = create_net_entry(value);
if (entry == NULL) {
log_print(LOG_ERROR, "net_init_srv_cb(): can not create net_entry");
return -1;
}
if (bind(entry->socket, (struct sockaddr *)&entry->addr, sizeof(entry->addr)) < 0) {
log_print(LOG_ERROR, "net_init_srv_cb(): bind()");
close(entry->socket);
free(entry);
return -1;
}
entry->event = event_add_readfd(NULL, entry->socket, net_receive, NULL);
list_add(&entry->list, &srv_list);
log_print(LOG_INFO, "listen on %s", get_sockaddr_buf(&entry->addr));
return 0;
}
static int net_init_cli_cb(const char *value, void *privdata)
{
struct net_entry *entry = create_net_entry(value);
if (entry == NULL) {
log_print(LOG_ERROR, "net_init_cli_cb(): can not create net_entry");
return -1;
}
list_add(&entry->list, &cli_list);
log_print(LOG_INFO, "forwarding to %s", get_sockaddr_buf(&entry->addr));
return 0;
}
int net_init(void)
{
config_get_strings("global", "listen", net_init_srv_cb, NULL);
config_get_strings("global", "forward", net_init_cli_cb, NULL);
fwd_buf = malloc(PKTSIZE);
if (fwd_buf == NULL) {
log_print(LOG_ERROR, "net_submit(): out of memory");
return -1;
}
return 0;
}
void net_close(void) {
struct net_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &cli_list, list) {
list_del(&entry->list);
close(entry->socket);
free(entry);
}
list_for_each_entry_safe(entry, tmp, &srv_list, list) {
list_del(&entry->list);
event_remove_fd(entry->event);
close(entry->socket);
free(entry);
}
fwd_buf_len = 0;
if (fwd_buf != NULL)
free(fwd_buf);
}

12
network.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _NETWORK_H_
#define _NETWORK_H_
#include "plugins.h"
int net_init(void);
void net_close(void);
int net_submit(const char *hostname, const char *pluginname, const char *filename, int ds_id, const char *data);
void net_submit_flush(void);
#endif /* _NETWORK_H_ */

73
pidfile.c Normal file
View File

@ -0,0 +1,73 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include "logging.h"
int pidfile_create(const char *filename)
{
int fd = open(filename, O_CREAT | O_EXCL | O_RDWR, 0644);
if (fd < 0)
return -1;
char buf[8];
int len = snprintf(buf, sizeof(buf), "%d", getpid());
write(fd, buf, len);
close(fd);
return 0;
}
int pidfile_remove(const char *filename)
{
return unlink(filename);
}
pid_t pidfile_check(const char *filename, int remove_stale)
{
int fd = open(filename, O_RDWR);
if (fd < 0) {
if (errno == ENOENT) {
errno = 0;
return 0;
}
return -1;
}
char buf[9];
int len = read(fd, buf, sizeof(buf) -1);
buf[len] = '\0';
close(fd);
char *tmp;
pid_t pid = strtol(buf, &tmp, 10);
if (len == 0 || tmp == buf)
pid = -1;
/* just return the pid */
if (!remove_stale)
return pid;
/* invalid pid, remove stale file */
if (pid == -1) {
pidfile_remove(filename);
return 0;
}
/* check if pid is still running */
if (kill(pid, 0) == 0 || errno != ESRCH) {
errno = 0;
return pid;
}
errno = 0;
pidfile_remove(filename);
return 0;
}

11
pidfile.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _PIDFILE_H_
#define _PIDFILE_H_
#include <sys/types.h>
int pidfile_create(const char *filename);
int pidfile_remove(const char *filename);
pid_t pidfile_check(const char *filename, int remove_stale);
#endif // _PIDFILE_H_

199
plugins.c
View File

@ -22,146 +22,127 @@
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <limits.h>
#include "list.h"
#include "plugins.h"
#include "config.h"
#include "configfile.h"
#include "event.h"
#include "logging.h"
#include "rrdtool.h"
#include "network.h"
#include "plugins.h"
#define BUFSIZE 1024
#define FLAGS_ACTIVE 0x01
static LIST_HEAD(plugin_list);
static struct event_timeout *probe_event;
static void plugin_load(char *filename)
static int plugin_init_cb(const char *filename, void *privdata)
{
struct sammler_plugin *plugin = NULL;
static char *plugin_dir;
const char *plugin_dir = (const char *)privdata;
char *buffer;
void *tmp;
int len;
if (plugin_dir == NULL)
plugin_dir = config_get_string("global", "plugin_dir", ".");
buffer = malloc(BUFSIZE);
if (buffer == NULL) {
log_print(LOG_ERROR, "plugin_load: out of memory");
return;
char *fullname = malloc(PATH_MAX);
if (fullname == NULL) {
log_print(LOG_ERROR, "plugin_init_cb(): out of memory");
return -1;
}
len = snprintf(buffer, BUFSIZE, "%s/%s", plugin_dir, filename);
if (len < 0 || len >= BUFSIZE) {
log_print(LOG_ERROR, "plugin_load: file name too long: %s/%s", plugin_dir, filename);
free(buffer);
return;
int len = snprintf(fullname, PATH_MAX, "%s/%s", plugin_dir, filename);
if (len < 0 || len >= PATH_MAX) {
log_print(LOG_ERROR, "plugin_init_cb(): file name too long: %s/%s", plugin_dir, filename);
free(fullname);
return -1;
}
dlerror();
tmp = dlopen(buffer, RTLD_NOW);
if (tmp == NULL) {
log_print(LOG_ERROR, "plugin_load: dlopen: %s", dlerror());
free(buffer);
return;
void *dlhandle = dlopen(fullname, RTLD_NOW);
if (dlhandle == NULL) {
log_print(LOG_ERROR, "plugin_init_cb(): dlopen: %s", dlerror());
free(fullname);
return -1;
}
plugin = dlsym(tmp, "plugin");
free(fullname);
struct sammler_plugin *plugin = dlsym(dlhandle, "plugin");
if (plugin == NULL) {
log_print(LOG_ERROR, "plugin_load: failed to load '%s'", filename);
dlclose(tmp);
free(buffer);
return;
log_print(LOG_ERROR, "plugin_init_cb(): failed to load '%s'", filename);
dlclose(dlhandle);
return -1;
}
log_print(LOG_INFO, "Plugin '%s' (v%d) loaded", plugin->name, plugin->version);
if (plugin->init != NULL && (plugin->init() != 0)) {
log_print(LOG_ERROR, "plugin_init_cb(): Plugin '%s': init() failed", plugin->name);
dlclose(dlhandle);
return -1;
}
log_print(LOG_INFO, "Plugin '%s' loaded", plugin->name);
plugin->lastprobe = 0;
plugin->flags = FLAGS_ACTIVE;
plugin->dlhandle = dlhandle;
list_add_tail(&plugin->list, &plugin_list);
free(buffer);
return;
return 0;
}
void plugin_load_all()
static int plugins_probe(int timerid, void *privdata)
{
struct conf_section *section;
struct conf_tupel *tupel;
time_t now;
time(&now);
section = config_get_section("global");
if (section == NULL)
return;
list_for_each_entry(tupel, &section->tupel, list)
if (!strcmp(tupel->option, "plugin"))
plugin_load(tupel->parameter);
}
void plugins_probe(void)
{
struct sammler_plugin *plugin;
list_for_each_entry(plugin, &plugin_list, list) {
if (!(plugin->flags & FLAGS_ACTIVE))
continue;
list_for_each_entry(plugin, &plugin_list, list)
plugin->probe();
if (plugin->lastprobe + plugin->interval <= now) {
if (plugin->probe() != 0) {
log_print(LOG_ERROR, "plugin_probe(): plugin '%s' disabled", plugin->name);
plugin->flags &= ~FLAGS_ACTIVE;
}
plugin->lastprobe = now;
}
}
net_submit_flush();
return 0;
}
char ** plugins_get_ds(char *name, int version, int ds_id)
int plugin_init(void)
{
const char *plugin_dir = config_get_string("global", "plugin_dir", "plugins");
int cnt = config_get_strings("global", "plugin", plugin_init_cb, (void *)plugin_dir);
if (cnt == 0) {
log_print(LOG_ERROR, "plugin_init(): no working plugins");
return -1;
}
probe_event = event_add_timeout_ms(1000, plugins_probe, 0, NULL);
return 0;
}
int plugin_close(void)
{
struct sammler_plugin *plugin, *tmp;
list_for_each_entry_safe(plugin, tmp, &plugin_list, list) {
list_del(&plugin->list);
if (plugin->fini != NULL && plugin->fini() != 0)
log_print(LOG_ERROR, "plugin_close(): Plugin '%s': fini() failed", plugin->name);
dlclose(plugin->dlhandle);
}
event_remove_timeout(probe_event);
return 0;
}
struct sammler_plugin * plugin_lookup(const char *name)
{
struct sammler_plugin *plugin;
list_for_each_entry(plugin, &plugin_list, list) {
if (strcmp(plugin->name, name))
continue;
if (plugin->version != version)
continue;
return plugin->get_ds(ds_id);
if (!strcmp(plugin->name, name))
return plugin;
}
return NULL;
}
void probe_submit(struct sammler_plugin *plugin, char *filename, int ds_id, const char *fmt, ... )
{
va_list az;
char *buffer;
int len;
buffer = malloc(BUFSIZE);
if (buffer == NULL) {
log_print(LOG_ERROR, "probe_submit: out of memory");
return;
}
va_start(az, fmt);
len = vsnprintf(buffer, BUFSIZE, fmt, az);
va_end(az);
if (len < 0 || len >= BUFSIZE) {
log_print(LOG_ERROR, "probe_submit: %s arguments too long", plugin->name);
free(buffer);
return;
}
rrd_submit(plugin->name, plugin->version, filename, ds_id, buffer);
// net_submit(plugin->name, plugin->version, filename, ds_id, buffer);
free(buffer);
}
int strsplit(char *string, char **fields, size_t size)
{
size_t i = 0;
char *ptr = string;
while ((fields[i] = strtok(ptr, " \n\t")) != NULL) {
ptr = NULL;
i++;
if (i >= size)
break;
}
return i;
}

View File

@ -1,25 +1,30 @@
#ifndef _PLUGINS_H_
#define _PLUGINS_H_
#include <time.h>
#include "list.h"
#include "logging.h"
struct sammler_plugin {
struct list_head list;
char *name;
int version;
void (*probe) (void);
char ** (*get_ds) (int ds_id);
void *dlhandle;
const char *name;
/* timing */
unsigned int interval;
time_t lastprobe;
/* flags */
int flags;
int (*init) (void);
int (*fini) (void);
int (*probe) (void);
const char * (*get_ds) (int ds_id);
};
void plugin_load_all(void);
int plugin_init(void);
int plugin_close(void);
void plugins_probe(void);
char ** plugins_get_ds(char *plugin, int version, int ds_id);
void probe_submit(struct sammler_plugin *plugin, char *filename, int ds_id, const char *fmt, ... );
int strsplit(char *string, char **fields, size_t size);
struct sammler_plugin * plugin_lookup(const char *name);
#endif /* _PLUGINS_H_ */

106
plugins/alixusv.c Normal file
View File

@ -0,0 +1,106 @@
/***************************************************************************
* Copyright (C) 04/2009 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include "configfile.h"
#include "helper.h"
#include "list.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
struct sammler_plugin plugin;
static const char *socket_path;
static const char *ds_def = {
"DS:ibat:GAUGE:15:U:U "
"DS:ubat:GAUGE:15:0:U "
"DS:uin:GAUGE:15:0:U "
};
static const char * get_ds(int ds_id)
{
return ds_def;
}
static int probe(void)
{
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
log_print(LOG_WARN, "plugin alixusv: socket()");
return -1;
}
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
int len = sizeof(addr.sun_family) + strlen(addr.sun_path);
if (connect(sockfd, (struct sockaddr *)&addr, len) < 0) {
log_print(LOG_ERROR, "plugin alixusv: connect(%s)", addr.sun_path);
close(sockfd);
return 0;
}
char buf[64] = "status";
write(sockfd, buf, strlen(buf));
len = read(sockfd, buf, sizeof(buf));
if (len <= 0) {
log_print(LOG_ERROR, "plugin alixusv: read()");
close(sockfd);
return -1;
}
close(sockfd);
char *field[4];
if (strsplit(buf, ": \t\n", field, 4) != 4)
return -1;
int ibat = strtoll(field[1], NULL, 10);
int ubat = strtoll(field[2], NULL, 10);
int uin = strtoll(field[3], NULL, 10);
probe_submit(&plugin, "alixusv.rrd", 0, "%d:%d:%d", ibat, ubat, uin);
return 0;
}
static int init(void)
{
socket_path = config_get_string("p_alixusv", "socket", NULL);
return (socket_path == NULL) ? -1 : 0;
}
struct sammler_plugin plugin = {
.name = "alixusv",
.interval = 10,
.init = &init,
.probe = &probe,
.get_ds = &get_ds,
};

223
plugins/apache.c Normal file
View File

@ -0,0 +1,223 @@
/***************************************************************************
* Copyright (C) 10/2006 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <curl/curl.h>
#include "configfile.h"
#include "helper.h"
#include "linebuffer.h"
#include "list.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#define BUFSIZE 8192
struct sammler_plugin plugin;
struct server_entry {
struct list_head list;
CURL *handle;
char *name;
};
static LIST_HEAD(server_list);
static const char *ds_def = {
"DS:total_accesses:COUNTER:90:0:U "
"DS:total_kbytes:COUNTER:90:0:U "
"DS:busy_workers:GAUGE:90:0:U "
"DS:idle_workers:GAUGE:90:0:U "
};
struct stats {
uint64_t total_accesses;
uint64_t total_kbytes;
uint64_t busy_workers;
uint64_t idle_workers;
};
static struct lbuf * rxbuf;
static const char * get_ds(int ds_id)
{
return ds_def;
}
static size_t curl_callback(void *buffer, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
lbuf_append(rxbuf, buffer, realsize);
return realsize;
}
static int probe(void)
{
struct server_entry *entry;
list_for_each_entry(entry, &server_list, list) {
lbuf_clear(rxbuf);
int ret = curl_easy_perform(entry->handle);
if (ret != 0) {
log_print(LOG_ERROR, "p_apache: %s", curl_easy_strerror(ret));
continue;
}
struct stats stats;
memset(&stats, 0, sizeof(stats));
char *line;
while ((line = lbuf_gettok(rxbuf, "\r\n")) != NULL) {
char *part[2];
strsplit(line, ":", part, 2);
if (!strcmp(part[0], "Total Accesses"))
stats.total_accesses = atoll(part[1]);
else if (!strcmp(part[0], "Total kBytes"))
stats.total_kbytes = atoll(part[1]);
else if (!strcmp(part[0], "BusyWorkers") || !strcmp(part[0], "BusyServers"))
stats.busy_workers = atoll(part[1]);
else if (!strcmp(part[0], "IdleWorkers") || !strcmp(part[0], "IdleServers"))
stats.idle_workers = atoll(part[1]);
lbuf_freetok(rxbuf);
}
char filename[32];
int len = snprintf(filename, sizeof(filename), "apache-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, 0, "%llu:%llu:%llu:%llu",
stats.total_accesses, stats.total_kbytes,
stats.busy_workers, stats.idle_workers);
}
return 0;
}
static int init_cb(struct strtoken *tokens, void *privdata)
{
if (tokens->count < 2) {
log_print(LOG_ERROR, "p_apache: parse error");
return -1;
}
struct server_entry *entry = malloc(sizeof(struct server_entry));
if (entry == NULL) {
log_print(LOG_ERROR, "p_apache: out of memory");
return -1;
}
entry->name = strdup(tokens->field[0]);
entry->handle = curl_easy_init();
if (entry->handle == NULL) {
free(entry);
return -1;
}
/* set URL */
int ret = curl_easy_setopt(entry->handle, CURLOPT_URL, tokens->field[1]);
if (ret != 0) {
log_print(LOG_ERROR, "p_apache: %s", curl_easy_strerror(ret));
curl_easy_cleanup(entry->handle);
free(entry);
return -1;
}
if (tokens->field[2] != NULL && tokens->field[3] != NULL) {
*(tokens->field[3] -1) = ':';
log_print(LOG_INFO, "p_apache: auth: '%s'", tokens->field[2]);
/* set username:password */
ret = curl_easy_setopt(entry->handle, CURLOPT_USERPWD, tokens->field[2]);
if (ret != 0) {
log_print(LOG_ERROR, "p_apache: %s", curl_easy_strerror(ret));
curl_easy_cleanup(entry->handle);
free(entry);
return -1;
}
}
ret = curl_easy_setopt(entry->handle, CURLOPT_WRITEFUNCTION, &curl_callback);
if (ret != 0) {
log_print(LOG_ERROR, "p_apache: %s", curl_easy_strerror(ret));
curl_easy_cleanup(entry->handle);
free(entry);
return -1;
}
ret = curl_easy_setopt(entry->handle, CURLOPT_WRITEDATA, entry);
if (ret != 0) {
log_print(LOG_ERROR, "p_apache: %s", curl_easy_strerror(ret));
curl_easy_cleanup(entry->handle);
free(entry);
return -1;
}
log_print(LOG_INFO, "p_apache: added server '%s'", entry->name);
list_add_tail(&entry->list, &server_list);
return 0;
}
static int init(void)
{
rxbuf = lbuf_create(BUFSIZE);
if (rxbuf == NULL) {
log_print(LOG_ERROR, "p_apache: out of memory");
return -1;
}
config_get_strtokens("p_apache", "server", ",", 4, init_cb, NULL);
return 0;
}
static int fini(void)
{
struct server_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &server_list, list) {
curl_easy_cleanup(entry->handle);
free(entry->name);
free(entry);
}
lbuf_free(rxbuf);
return 0;
}
struct sammler_plugin plugin = {
.name = "apache",
.interval = 60,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

176
plugins/conntrack.c Normal file
View File

@ -0,0 +1,176 @@
/***************************************************************************
* Copyright (C) 04/2007 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#define DS_L3PROTO 1
#define DS_L4PROTO 2
#define DS_TCP 3
struct sammler_plugin plugin;
static struct nfct_handle *cth;
struct ct_values {
int total;
int local;
int nated;
int unreplied;
int proto_tcp;
int proto_udp;
int proto_unknown;
int tcp_state[10];
};
static const char *l3proto_ds_def = {
"DS:total:GAUGE:15:0:U "
"DS:local:GAUGE:15:0:U "
"DS:nated:GAUGE:15:0:U "
"DS:unreplied:GAUGE:15:0:U "
};
static const char *l4proto_ds_def = {
"DS:tcp:GAUGE:15:0:U "
"DS:udp:GAUGE:15:0:U "
"DS:unknown:GAUGE:15:0:U "
};
static const char *tcp_ds_def = {
"DS:none:GAUGE:15:0:U "
"DS:syn_sent:GAUGE:15:0:U "
"DS:syn_recv:GAUGE:15:0:U "
"DS:established:GAUGE:15:0:U "
"DS:fin_wait:GAUGE:15:0:U "
"DS:close_wait:GAUGE:15:0:U "
"DS:last_ack:GAUGE:15:0:U "
"DS:time_wait:GAUGE:15:0:U "
"DS:close:GAUGE:15:0:U "
"DS:listen:GAUGE:15:0:U "
};
static const char * get_ds(int ds_id)
{
switch (ds_id) {
case DS_L3PROTO:
return l3proto_ds_def;
case DS_L4PROTO:
return l4proto_ds_def;
case DS_TCP:
return tcp_ds_def;
default:
return NULL;
}
}
static int probe_cb(void *arg, unsigned int flags, int type, void *privdata)
{
struct nfct_conntrack *ct = (struct nfct_conntrack *)arg;
struct ct_values *data = (struct ct_values *)privdata;
data->total++;
if (ct->status & IPS_NAT_MASK)
data->nated++;
else
data->local++;
if (!(ct->status & IPS_SEEN_REPLY))
data->unreplied++;
switch (ct->tuple[NFCT_DIR_ORIGINAL].protonum) {
case IPPROTO_TCP:
data->proto_tcp++;
data->tcp_state[ct->protoinfo.tcp.state]++;
break;
case IPPROTO_UDP:
data->proto_udp++;
break;
default:
data->proto_unknown++;
break;
}
return 0;
}
static int probe(void)
{
struct ct_values data;
memset(&data, 0, sizeof(data));
nfct_register_callback(cth, probe_cb, &data);
if (nfct_dump_conntrack_table(cth, AF_INET) < 0) {
log_print(LOG_WARN, "plugin conntrack: nfct_dump_conntrack_table()");
return -1;
}
probe_submit(&plugin, "conntrack.rrd", DS_L3PROTO, "%d:%d:%d:%d",
data.total, data.local, data.nated, data.unreplied);
probe_submit(&plugin, "conntrack-proto.rrd", DS_L4PROTO, "%d:%d:%d",
data.proto_tcp, data.proto_udp, data.proto_unknown);
probe_submit(&plugin, "conntrack-tcp.rrd", DS_TCP, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
data.tcp_state[0], data.tcp_state[1], data.tcp_state[2], data.tcp_state[3],
data.tcp_state[4], data.tcp_state[5], data.tcp_state[6], data.tcp_state[7],
data.tcp_state[8], data.tcp_state[9]);
return 0;
}
static int init(void)
{
cth = nfct_open(CONNTRACK, 0);
if (cth == NULL) {
log_print(LOG_WARN, "plugin conntrack: nfct_open()");
return -1;
}
return 0;
}
static int fini(void)
{
nfct_close(cth);
return 0;
}
struct sammler_plugin plugin = {
.name = "conntrack",
.interval = 10,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

View File

@ -21,62 +21,58 @@
#include <stdlib.h>
#include <string.h>
#include "helper.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#define BUFSIZE 1024
struct sammler_plugin plugin;
static char *buffer;
static char *ds_def[] = {
"DS:entries:GAUGE:%d:0:U",
"DS:searched:DERIVE:%d:0:U",
"DS:found:DERIVE:%d:0:U",
"DS:new:DERIVE:%d:0:U",
"DS:invalid:DERIVE:%d:0:U",
"DS:ignore:DERIVE:%d:0:U",
"DS:delete:DERIVE:%d:0:U",
"DS:delete_list:DERIVE:%d:0:U",
"DS:insert:DERIVE:%d:0:U",
"DS:insert_failed:DERIVE:%d:0:U",
"DS:drop:DERIVE:%d:0:U",
"DS:early_drop:DERIVE:%d:0:U",
"DS:icmp_error:DERIVE:%d:0:U",
"DS:expect_new:DERIVE:%d:0:U",
"DS:expect_create:DERIVE:%d:0:U",
"DS:expect_delete:DERIVE:%d:0:U",
NULL
static const char *ds_def = {
"DS:entries:GAUGE:15:0:U "
"DS:searched:DERIVE:15:0:U "
"DS:found:DERIVE:15:0:U "
"DS:new:DERIVE:15:0:U "
"DS:invalid:DERIVE:15:0:U "
"DS:ignore:DERIVE:15:0:U "
"DS:delete:DERIVE:15:0:U "
"DS:delete_list:DERIVE:15:0:U "
"DS:insert:DERIVE:15:0:U "
"DS:insert_failed:DERIVE:15:0:U "
"DS:drop:DERIVE:15:0:U "
"DS:early_drop:DERIVE:15:0:U "
"DS:icmp_error:DERIVE:15:0:U "
"DS:expect_new:DERIVE:15:0:U "
"DS:expect_create:DERIVE:15:0:U "
"DS:expect_delete:DERIVE:15:0:U "
};
static char ** get_ds(int ds_id)
static const char * get_ds(int ds_id)
{
return ds_def;
}
static void probe(void)
static int probe(void)
{
FILE *fp;
char *buffer, *val[16], filename[16];
char *val[16], filename[16];
unsigned long long arr[16];
int i, len, cpu = 0;
buffer = malloc(BUFSIZE);
if (buffer == NULL) {
log_print(LOG_WARN, "plugin ctstat: out of memory");
return;
}
fp = fopen("/proc/net/stat/ip_conntrack", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin ctstat");
free(buffer);
return;
return -1;
}
while (fgets(buffer, BUFSIZE, fp) != NULL) {
if (!strncmp(buffer, "entries", 7))
continue;
if (strsplit(buffer, val, 16) != 16)
if (strsplit(buffer, " \t\n", val, 16) != 16)
continue;
for (i = 0; i < 16; i++)
@ -96,12 +92,26 @@ static void probe(void)
cpu++;
}
fclose(fp);
return 0;
}
static int init(void)
{
buffer = malloc(BUFSIZE);
return (buffer == NULL) ? -1 : 0;
}
static int fini(void)
{
free(buffer);
return 0;
}
struct sammler_plugin plugin = {
.name = "ctstat",
.version = 1,
.interval = 10,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

152
plugins/diskstandby.c Normal file
View File

@ -0,0 +1,152 @@
/***************************************************************************
* Copyright (C) 06/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "configfile.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#include "sgio.h"
int verbose = 0;
int prefer_ata12 = 0;
struct sammler_plugin plugin;
struct device_entry {
struct list_head list;
char *devpath;
};
static LIST_HEAD(device_list);
static const char *ds_def = {
"DS:active:GAUGE:90:0:1 "
};
static const char * get_ds(int ds_id)
{
return ds_def;
}
static int probe(void)
{
struct device_entry *entry;
list_for_each_entry(entry, &device_list, list) {
int fd = open(entry->devpath, O_RDONLY|O_NONBLOCK);
if (fd < 0) {
log_print(LOG_ERROR, "%s: failed to open %s", plugin.name, entry->devpath);
continue;
}
uint8_t args[4] = { ATA_OP_CHECKPOWERMODE1, 0, 0, 0 };
if (do_drive_cmd(fd, args)) {
args[0] = ATA_OP_CHECKPOWERMODE2;
if (do_drive_cmd(fd, args)) {
log_print(LOG_ERROR, "%s: failed to query %s", plugin.name, entry->devpath);
close(fd);
continue;
}
}
/*
switch (args[2]) {
case 0x00: state = "standby"; break;
case 0x40: state = "NVcache_spindown"; break;
case 0x41: state = "NVcache_spinup"; break;
case 0x80: state = "idle"; break;
case 0xff: state = "active/idle"; break;
default: state = "unknown"; break;
}
*/
char *dev = strrchr(entry->devpath, '/');
if (dev == NULL) {
dev = entry->devpath;
} else {
dev++;
}
char filename[32];
int len = snprintf(filename, sizeof(filename), "diskstandby-%s.rrd", dev);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, 0, "%u", (args[2] == 0xff) ? 1 : 0);
close(fd);
}
return 0;
}
static int init_cb(struct strtoken *tokens, void *privdata)
{
if (tokens->count != 1) {
log_print(LOG_ERROR, "%s: parse error", plugin.name);
return -1;
}
struct device_entry *entry = malloc(sizeof(struct device_entry));
if (entry == NULL) {
log_print(LOG_ERROR, "%s: out of memory", plugin.name);
return -1;
}
entry->devpath = strdup(tokens->field[0]);
log_print(LOG_INFO, "%s: added device '%s'", plugin.name, entry->devpath);
list_add_tail(&entry->list, &device_list);
return 0;
}
static int init(void)
{
config_get_strtokens("p_diskstandby", "device", ",", 1, init_cb, NULL);
return 0;
}
static int fini(void)
{
struct device_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &device_list, list) {
free(entry->devpath);
free(entry);
}
return 0;
}
struct sammler_plugin plugin = {
.name = "diskstandby",
.interval = 60,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

102
plugins/diskstat.c Normal file
View File

@ -0,0 +1,102 @@
/***************************************************************************
* Copyright (C) 04/2007 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#define BUFSIZE 1024
struct sammler_plugin plugin;
static char *buffer;
static const char *ds_def = {
"DS:read_cnt:COUNTER:15:0:U "
"DS:read_sec:COUNTER:15:0:U "
"DS:read_ms:COUNTER:15:0:U "
"DS:write_cnt:COUNTER:15:0:U "
"DS:write_sec:COUNTER:15:0:U "
"DS:write_ms:COUNTER:15:0:U "
};
static const char * get_ds(int ds_id)
{
return ds_def;
}
static int probe(void)
{
FILE *fp = fopen("/proc/diskstats", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin diskstats: fopen()");
return -1;
}
while (fgets(buffer, BUFSIZE, fp) != NULL) {
int major, minor;
char device[16];
unsigned int val[11];
int cnt = sscanf(buffer, "%d %d %s %u %u %u %u %u %u %u %u %u %u %u",
&major, &minor, device, &val[0],
&val[1], &val[2], &val[3], &val[4],
&val[5], &val[6], &val[7], &val[8],
&val[9], &val[10]);
if (cnt != 14 || val[0] == 0 || val[1] == 0)
continue;
char filename[32];
int len = snprintf(filename, sizeof(filename), "disk-%s.rrd", device);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, 0,
"%u:%u:%u:%u:%u:%u",
val[0], val[2], val[3],
val[4], val[6], val[7]);
}
fclose(fp);
return 0;
}
static int init(void)
{
buffer = malloc(BUFSIZE);
return (buffer == NULL) ? -1 : 0;
}
static int fini(void)
{
free(buffer);
return 0;
}
struct sammler_plugin plugin = {
.name = "diskstat",
.interval = 10,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

212
plugins/hddtemp.c Normal file
View File

@ -0,0 +1,212 @@
/***************************************************************************
* Copyright (C) 12/2012 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include "configfile.h"
#include "helper.h"
#include "list.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#include "sockaddr.h"
#define RESP_SIZE 1024
struct sammler_plugin plugin;
struct server_entry {
struct list_head list;
char *name;
int errors;
struct sockaddr_in sa;
};
static LIST_HEAD(server_list);
static char *resp_buf;
static const char *ds_def = {
"DS:temperature:GAUGE:90:0:100"
};
static const char * get_ds(int ds_id)
{
return ds_def;
}
static int probe(void)
{
struct server_entry *entry;
list_for_each_entry(entry, &server_list, list) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
log_print(LOG_WARN, "%s: socket()", plugin.name);
continue;
}
int ret = connect(sock, (struct sockaddr *)&entry->sa, sizeof(entry->sa));
if (ret != 0) {
if (entry->errors++ == 0)
log_print(LOG_ERROR, "%s: connect(%s)", plugin.name, get_sockaddr_buf(&entry->sa));
close(sock);
continue;
}
int pos = 0;
int len;
do {
len = read(sock, resp_buf + pos, RESP_SIZE - pos);
if ((pos == 0) && (len <= 0)) {
if (entry->errors++ == 0)
log_print(LOG_ERROR, "%s: read()", plugin.name);
break;
}
pos += len;
} while (len > 0);
close(sock);
if (pos == 0)
continue;
resp_buf[pos] = '\0';
/* '|/dev/sda|OCZ-VERTEX3|128|C||/dev/sdb|HDT722525DLA380|SLP|*||/dev/sdc|Generic STORAGE DEVICE|NA|*|' */
char *tok, *tmp = NULL, *resp = resp_buf;
int i = 0;
char *device = NULL;
int temperature = 0;
while ((tok = strtok_r(resp, "|", &tmp)) != NULL) {
if ((i % 4) == 0) {
device = strrchr(tok, '/');
if (device != NULL && *(device +1) == '\0')
device = NULL;
else
device++;
} else if ((i % 4) == 2) {
char *tmp2;
temperature = strtol(tok, &tmp2, 10);
if (*tmp2 != '\0')
device = NULL;
} else if ((i % 4) == 3) {
if ((tok[0] == 'C') && (device != NULL)) {
char filename[32];
len = snprintf(filename, sizeof(filename), "%s-%s.rrd", plugin.name, device);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, 0, "%d", temperature);
}
device = NULL;
temperature = 0;
}
i++;
resp = NULL;
}
if (entry->errors > 0) {
log_print(LOG_ERROR, "%s: success (%s) after %d errors",
plugin.name, entry->name, entry->errors);
entry->errors = 0;
}
}
return 0;
}
static int init_cb(struct strtoken *tokens, void *privdata)
{
if (tokens->count != 2) {
log_print(LOG_ERROR, "%s: parse error", plugin.name);
return -1;
}
struct server_entry *entry = malloc(sizeof(struct server_entry));
if (entry == NULL) {
log_print(LOG_ERROR, "%s: out of memory", plugin.name);
return -1;
}
entry->name = strdup(tokens->field[0]);
entry->errors = 0;
if (parse_sockaddr(tokens->field[1], &entry->sa) < 0) {
log_print(LOG_ERROR, "%s: invalid address: <%s>", plugin.name, tokens->field[1]);
free(entry->name);
free(entry);
return -1;
}
log_print(LOG_INFO, "%s: added server '%s'", plugin.name, entry->name);
list_add_tail(&entry->list, &server_list);
return 0;
}
static int init(void)
{
resp_buf = malloc(RESP_SIZE);
if (resp_buf == NULL) {
log_print(LOG_ERROR, "%s: out of memory", plugin.name);
return -1;
}
config_get_strtokens("p_hddtemp", "server", ",", 2, init_cb, NULL);
return 0;
}
static int fini(void)
{
struct server_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &server_list, list) {
free(entry->name);
free(entry);
}
free(resp_buf);
return 0;
}
struct sammler_plugin plugin = {
.name = "hddtemp",
.interval = 60,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

125
plugins/hwmon.c Normal file
View File

@ -0,0 +1,125 @@
/***************************************************************************
* Copyright (C) 10/2006 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "configfile.h"
#include "helper.h"
#include "list.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
struct sammler_plugin plugin;
struct hwmon_entry {
struct list_head list;
char *name;
char *path;
};
static LIST_HEAD(hwmon_list);
static const char *ds_def = {
"DS:temp:GAUGE:15:0:U "
};
static const char * get_ds(int ds_id)
{
return ds_def;
}
static int probe(void)
{
struct hwmon_entry *entry;
list_for_each_entry(entry, &hwmon_list, list) {
FILE *fp = fopen(entry->path, "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin hwmon: fopen(%s)", entry->path);
continue;
}
int temp;
if (fscanf(fp, "%d\n", &temp) != 1) {
log_print(LOG_WARN, "plugin hwmon: fscanf()");
fclose(fp);
continue;
}
fclose(fp);
char filename[32];
int len = snprintf(filename, sizeof(filename), "hwmon-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, 0, "%d", temp);
}
return 0;
}
static int init_cb(struct strtoken *tokens, void *privdata)
{
if (tokens->count != 2) {
log_print(LOG_ERROR, "p_hwmon: parse error");
return -1;
}
struct hwmon_entry *entry = malloc(sizeof(struct hwmon_entry));
if (entry == NULL) {
log_print(LOG_ERROR, "p_hwmon: out of memory");
return -1;
}
entry->name = strdup(tokens->field[0]);
entry->path = strdup(tokens->field[1]);
log_print(LOG_DEBUG, "p_hwmon: added sensor '%s' (%s)", entry->name, entry->path);
list_add_tail(&entry->list, &hwmon_list);
return 0;
}
static int init(void)
{
config_get_strtokens("p_hwmon", "temp", ",", 2, init_cb, NULL);
return 0;
}
static int fini(void)
{
struct hwmon_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &hwmon_list, list) {
free(entry->name);
free(entry->path);
free(entry);
}
return 0;
}
struct sammler_plugin plugin = {
.name = "hwmon",
.interval = 10,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

View File

@ -20,51 +20,46 @@
#include <stdio.h>
#include <stdlib.h>
#include "logging.h"
#include "plugins.h"
#include "probe.h"
struct sammler_plugin plugin;
static char *ds_def[] = {
"DS:1min:GAUGE:%d:0:U",
"DS:5min:GAUGE:%d:0:U",
"DS:15min:GAUGE:%d:0:U",
NULL
static const char *ds_def = {
"DS:1min:GAUGE:15:0:U "
"DS:5min:GAUGE:15:0:U "
"DS:15min:GAUGE:15:0:U "
};
static char ** get_ds(int ds_id)
static const char * get_ds(int ds_id)
{
return ds_def;
}
static void probe(void)
static int probe(void)
{
FILE *fp;
char buffer[32];
char *val[3];
fp = fopen("/proc/loadavg", "r");
FILE *fp = fopen("/proc/loadavg", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin load");
return;
log_print(LOG_WARN, "plugin load: fopen()");
return -1;
}
if (fgets(buffer, sizeof(buffer), fp) == NULL) {
log_print(LOG_WARN, "plugin load");
double load1, load5, load15;
if (fscanf(fp, "%lf %lf %lf", &load1, &load5, &load15) != 3) {
log_print(LOG_WARN, "plugin load: fscanf()");
fclose(fp);
return;
return -1;
}
fclose(fp);
if (strsplit(buffer, val, 3) != 3)
return;
probe_submit(&plugin, "load.rrd", 0, "%s:%s:%s", val[0], val[1], val[2]);
probe_submit(&plugin, "load.rrd", 0, "%.02lf:%.02lf:%.02lf", load1, load5, load15);
return 0;
}
struct sammler_plugin plugin = {
.name = "load",
.version = 1,
.interval = 10,
.probe = &probe,
.get_ds = &get_ds,
};

View File

@ -21,30 +21,31 @@
#include <stdlib.h>
#include <string.h>
#include "logging.h"
#include "plugins.h"
#define BUFSIZE 1024
#include "probe.h"
#define DS_MEMORY 1
#define DS_SWAP 2
#define BUFSIZE 1024
struct sammler_plugin plugin;
static char *buffer;
static char *mem_ds_def[] = {
"DS:total:GAUGE:%d:0:U",
"DS:free:GAUGE:%d:0:U",
"DS:buffers:GAUGE:%d:0:U",
"DS:cached:GAUGE:%d:0:U",
NULL
static const char *mem_ds_def = {
"DS:total:GAUGE:15:0:U "
"DS:free:GAUGE:15:0:U "
"DS:buffers:GAUGE:15:0:U "
"DS:cached:GAUGE:15:0:U "
};
static char *swap_ds_def[] = {
"DS:total:GAUGE:%d:0:U",
"DS:free:GAUGE:%d:0:U",
NULL
static const char *swap_ds_def = {
"DS:total:GAUGE:15:0:U "
"DS:free:GAUGE:15:0:U "
};
static char ** get_ds(int ds_id)
static const char * get_ds(int ds_id)
{
switch (ds_id) {
case DS_MEMORY:
@ -67,23 +68,17 @@ struct meminfo_ {
unsigned long long swapfree;
};
static void probe(void)
static int probe(void)
{
FILE *fp;
char *buffer;
struct meminfo_ meminfo;
buffer = malloc(BUFSIZE);
if (buffer == NULL) {
log_print(LOG_WARN, "plugin memory: out of memory");
return;
}
memset(&meminfo, 0, sizeof(meminfo));
fp = fopen("/proc/meminfo", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin memory");
free(buffer);
return;
return -1;
}
while (fgets(buffer, BUFSIZE, fp) != NULL) {
@ -114,12 +109,26 @@ static void probe(void)
meminfo.swaptotal, meminfo.swapfree);
fclose(fp);
return 0;
}
static int init(void)
{
buffer = malloc(BUFSIZE);
return (buffer == NULL) ? -1 : 0;
}
static int fini(void)
{
free(buffer);
return 0;
}
struct sammler_plugin plugin = {
.name = "memory",
.version = 1,
.interval = 10,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

View File

@ -19,58 +19,92 @@
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <mntent.h>
#include <sys/vfs.h>
#include <string.h>
#include <mntent.h>
#include <sys/vfs.h>
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#define MAXFSNAME 16
struct sammler_plugin plugin;
static char *ds_def[] = {
"DS:block_total:GAUGE:%d:0:U",
"DS:block_free:GAUGE:%d:0:U",
NULL
static const char *ds_def = {
"DS:block_total:GAUGE:15:0:U "
"DS:block_free:GAUGE:15:0:U "
};
static char ** get_ds(int ds_id)
static const char * get_ds(int ds_id)
{
return ds_def;
}
static void probe(void)
static char * get_valid_fs(int *xcnt)
{
FILE *fp;
struct mntent *mnt;
struct statfs fs;
char *slash, filename[64];
int len;
FILE *fp = fopen("/proc/filesystems", "r");
if (fp == NULL)
return NULL;
fp = setmntent("/etc/mtab", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin mount");
return;
int cnt = 0;
char buffer[64];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
if (!strncmp(buffer, "nodev", 5))
continue;
cnt++;
}
char *valid_arr = malloc(cnt * MAXFSNAME);
if (valid_arr == NULL)
return NULL;
rewind(fp);
int i = 0;
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
if (!strncmp(buffer, "nodev", 5))
continue;
char *end = memccpy(valid_arr + (i++ * MAXFSNAME), buffer +1, '\n', MAXFSNAME);
*(end -1) = '\0';
}
fclose(fp);
*xcnt = cnt;
return valid_arr;
}
static int probe(void)
{
FILE *fp = setmntent("/etc/mtab", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin mount");
return -1;
}
int cnt;
char *valid_arr = get_valid_fs(&cnt);
if (valid_arr == NULL) {
log_print(LOG_WARN, "plugin mount");
endmntent(fp);
return -1;
}
struct mntent *mnt;
while ((mnt = getmntent(fp)) != NULL) {
if (!strcmp(mnt->mnt_fsname, "none"))
continue;
if (!strcmp(mnt->mnt_fsname, "proc"))
continue;
if (!strcmp(mnt->mnt_fsname, "sysfs"))
continue;
if (!strcmp(mnt->mnt_fsname, "udev"))
continue;
if (!strcmp(mnt->mnt_fsname, "devpts"))
continue;
if (!strcmp(mnt->mnt_type, "nfs"))
int i, valid = 0;
for (i = 0; i < cnt; i++)
if (strncmp(mnt->mnt_type, valid_arr + (i * MAXFSNAME), MAXFSNAME) == 0)
valid = 1;
if (valid == 0)
continue;
struct statfs fs;
if (statfs(mnt->mnt_dir, &fs) == -1) {
log_print(LOG_WARN, "plugin mount: statfs(%s)", mnt->mnt_dir);
continue;
@ -79,13 +113,14 @@ static void probe(void)
if (fs.f_blocks == 0)
continue;
slash = mnt->mnt_fsname;
char *slash = mnt->mnt_fsname;
while (slash && (slash = strchr(slash, '/'))) {
slash = strchr(slash, '/');
*slash++ = '_';
}
len = snprintf(filename, sizeof(filename), "mount%s.rrd", mnt->mnt_fsname);
char filename[64];
int len = snprintf(filename, sizeof(filename), "mount%s.rrd", mnt->mnt_fsname);
if (len < 0 || len >= sizeof(filename)) {
log_print(LOG_WARN, "plugin mount: file name too long", mnt->mnt_fsname);
continue;
@ -95,12 +130,15 @@ static void probe(void)
fs.f_blocks * (fs.f_bsize /1024),
fs.f_bfree * (fs.f_bsize /1024));
}
free(valid_arr);
endmntent(fp);
return 0;
}
struct sammler_plugin plugin = {
.name = "mount",
.version = 1,
.interval = 10,
.probe = &probe,
.get_ds = &get_ds,
};

204
plugins/mysql.c Normal file
View File

@ -0,0 +1,204 @@
/***************************************************************************
* Copyright (C) 10/2006 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "configfile.h"
#include "helper.h"
#include "list.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#include "mysql_helper.h"
#define DS_TRAFFIC 1
#define DS_COMMANDS 2
#define DS_QCACHE 3
#define DS_THREADS 4
struct sammler_plugin plugin;
struct server_entry {
struct list_head list;
void *mysql;
char *name;
};
static LIST_HEAD(server_list);
static const char *traffic_ds_def = {
"DS:bytes_received:COUNTER:90:0:U "
"DS:bytes_sent:COUNTER:90:0:U "
};
static const char *commands_ds_def = {
"DS:com_delete:COUNTER:90:0:U "
"DS:com_insert:COUNTER:90:0:U "
"DS:com_select:COUNTER:90:0:U "
"DS:com_update:COUNTER:90:0:U "
"DS:connections:COUNTER:90:0:U "
"DS:questions:COUNTER:90:0:U "
};
static const char *qcache_ds_def = {
"DS:qc_free_blocks:GAUGE:90:0:U "
"DS:qc_free_memory:GAUGE:90:0:U "
"DS:qc_hits:COUNTER:90:0:U "
"DS:qc_inserts:COUNTER:90:0:U "
"DS:qc_lowmem_prunes:COUNTER:90:0:U "
"DS:qc_not_cached:COUNTER:90:0:U "
"DS:qc_queries_in_cache:GAUGE:90:0:U "
"DS:qc_total_blocks:GAUGE:90:0:U "
};
static const char *threads_ds_def = {
"DS:threads_cached:GAUGE:90:0:U "
"DS:threads_connected:GAUGE:90:0:U "
"DS:threads_created:COUNTER:90:0:U "
"DS:threads_running:GAUGE:90:0:U "
};
static const char * get_ds(int ds_id)
{
switch (ds_id) {
case DS_TRAFFIC:
return traffic_ds_def;
case DS_COMMANDS:
return commands_ds_def;
case DS_QCACHE:
return qcache_ds_def;
case DS_THREADS:
return threads_ds_def;
default:
return NULL;
}
}
static int probe(void)
{
struct mysql_stats stats;
char filename[32];
int len;
memset(&stats, 0, sizeof(struct mysql_stats));
struct server_entry *entry;
list_for_each_entry(entry, &server_list, list) {
if (ping_connection(entry->mysql) != 0)
continue;
if (get_stats(entry->mysql, &stats) != 0)
continue;
len = snprintf(filename, sizeof(filename), "mysql-traffic-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, DS_TRAFFIC, "%llu:%llu",
stats.bytes_received, stats.bytes_sent);
len = snprintf(filename, sizeof(filename), "mysql-commands-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, DS_COMMANDS, "%llu:%llu:%llu:%llu:%llu:%llu",
stats.com_delete, stats.com_insert,
stats.com_select, stats.com_update,
stats.connections, stats.questions);
len = snprintf(filename, sizeof(filename), "mysql-qcache-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, DS_QCACHE, "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
stats.qc_free_blocks, stats.qc_free_memory,
stats.qc_hits, stats.qc_inserts,
stats.qc_lowmem_prunes, stats.qc_not_cached,
stats.qc_queries_in_cache, stats.qc_total_blocks);
len = snprintf(filename, sizeof(filename), "mysql-threads-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, DS_THREADS, "%llu:%llu:%llu:%llu",
stats.threads_cached, stats.threads_connected,
stats.threads_created, stats.threads_running);
}
return 0;
}
static int init_cb(struct strtoken *tokens, void *privdata)
{
if (tokens->count != 4) {
log_print(LOG_ERROR, "p_mysql: parse error");
return -1;
}
void *mysql = init_connection(tokens->field[1], tokens->field[2], tokens->field[3]);
if (mysql == NULL) {
return -1;
}
struct server_entry *entry = malloc(sizeof(struct server_entry));
if (entry == NULL) {
log_print(LOG_ERROR, "p_mysql: out of memory");
close_connection(mysql);
return -1;
}
entry->name = strdup(tokens->field[0]);
entry->mysql = mysql;
log_print(LOG_DEBUG, "p_mysql: added server '%s'", entry->name);
list_add_tail(&entry->list, &server_list);
return 0;
}
static int init(void)
{
config_get_strtokens("p_mysql", "server", ",", 4, init_cb, NULL);
return 0;
}
static int fini(void)
{
struct server_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &server_list, list) {
close_connection(entry->mysql);
free(entry->name);
free(entry);
}
return 0;
}
struct sammler_plugin plugin = {
.name = "mysql",
.interval = 60,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

141
plugins/mysql_helper.c Normal file
View File

@ -0,0 +1,141 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql/mysql.h>
#include "logging.h"
#include "mysql_helper.h"
void * init_connection(const char *host, const char *user, const char *pass)
{
MYSQL *con = NULL;
con = mysql_init(con);
if (con == NULL)
return NULL;
con = mysql_real_connect(con, host, user, pass, NULL, 0, NULL, 0);
if (con == NULL) {
log_print(LOG_ERROR, "p_mysql: %s", mysql_error(con));
return NULL;
}
return con;
}
int ping_connection(void *mysql)
{
MYSQL *con = mysql;
return mysql_ping(con);
}
int close_connection(void *mysql)
{
MYSQL *con = mysql;
mysql_close(con);
return 0;
}
int get_stats(void *mysql, struct mysql_stats *stats)
{
MYSQL *con = mysql;
char *query;
if (mysql_get_server_version(con) >= 50002)
query = "SHOW GLOBAL STATUS";
else
query = "SHOW STATUS";
if (mysql_real_query(con, query, strlen(query))) {
log_print(LOG_ERROR, "p_mysql: %s", mysql_error(con));
return -1;
}
MYSQL_RES *res;
res = mysql_store_result(con);
if (res == NULL) {
log_print(LOG_ERROR, "p_mysql: %s", mysql_error(con));
return -1;
}
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
char *key;
unsigned long long val;
key = row[0];
val = atoll(row[1]);
if (!strncmp(key, "Bytes_", 6)) {
if (!strcmp(key +6, "received"))
stats->bytes_received = val;
else if (!strcmp(key +6, "sent"))
stats->bytes_sent = val;
} else if (!strncmp(key, "Com_", 4)) {
if (!strcmp(key +4, "delete"))
stats->com_delete = val;
else if (!strcmp(key +4, "insert"))
stats->com_insert = val;
else if (!strcmp(key +4, "select"))
stats->com_select = val;
else if (!strcmp(key +4, "update"))
stats->com_update = val;
} else if (!strcmp(key, "Connections")) {
stats->connections = val;
} else if (!strncmp(key, "Qcache_", 7)) {
if (!strcmp(key +7, "free_blocks"))
stats->qc_free_blocks = val;
else if (!strcmp(key +7, "free_memory"))
stats->qc_free_memory = val;
else if (!strcmp(key +7, "hits"))
stats->qc_hits = val;
else if (!strcmp(key +7, "inserts"))
stats->qc_inserts = val;
else if (!strcmp(key +7, "lowmem_prunes"))
stats->qc_lowmem_prunes = val;
else if (!strcmp(key +7, "not_cached"))
stats->qc_not_cached = val;
else if (!strcmp(key +7, "queries_in_cache"))
stats->qc_queries_in_cache = val;
else if (!strcmp(key +7, "total_blocks"))
stats->qc_total_blocks = val;
} else if (!strcmp(key, "Questions")) {
stats->questions = val;
} else if (!strncmp(key, "Threads_", 8)) {
if (!strcmp(key, "Threads_cached"))
stats->threads_cached = val;
else if (!strcmp(key, "Threads_connected"))
stats->threads_connected = val;
else if (!strcmp(key, "Threads_created"))
stats->threads_created = val;
else if (!strcmp(key, "Threads_running"))
stats->threads_running = val;
}
}
mysql_free_result(res);
return 0;
}

35
plugins/mysql_helper.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _MYSQL_HELPER_H_
#define _MYSQL_HELPER_H_
#include <stdint.h>
struct mysql_stats {
uint64_t bytes_received;
uint64_t bytes_sent;
uint64_t com_delete;
uint64_t com_insert;
uint64_t com_select;
uint64_t com_update;
uint64_t connections;
uint64_t qc_free_blocks;
uint64_t qc_free_memory;
uint64_t qc_hits;
uint64_t qc_inserts;
uint64_t qc_lowmem_prunes;
uint64_t qc_not_cached;
uint64_t qc_queries_in_cache;
uint64_t qc_total_blocks;
uint64_t questions;
uint64_t threads_cached;
uint64_t threads_connected;
uint64_t threads_created;
uint64_t threads_running;
};
void * init_connection(const char *host, const char *user, const char *pass);
int ping_connection(void *mysql);
int close_connection(void *mysql);
int get_stats(void *mysql, struct mysql_stats *stats);
#endif /* _MYSQL_HELPER_H_ */

View File

@ -21,43 +21,39 @@
#include <stdlib.h>
#include <string.h>
#include "helper.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#define BUFSIZE 1024
struct sammler_plugin plugin;
static char *buffer;
static char *ds_def[] = {
"DS:byte_in:COUNTER:%d:0:U",
"DS:byte_out:COUNTER:%d:0:U",
"DS:pkt_in:COUNTER:%d:0:U",
"DS:pkt_out:COUNTER:%d:0:U",
NULL
static const char *ds_def = {
"DS:byte_in:COUNTER:15:0:U "
"DS:byte_out:COUNTER:15:0:U "
"DS:pkt_in:COUNTER:15:0:U "
"DS:pkt_out:COUNTER:15:0:U "
};
static char ** get_ds(int ds_id)
static const char * get_ds(int ds_id)
{
return ds_def;
}
static void probe(void)
static int probe(void)
{
FILE *fp;
char *buffer, *stats, *device;
char *stats, *device;
char *val[16], filename[32];
int len;
buffer = malloc(BUFSIZE);
if (buffer == NULL) {
log_print(LOG_WARN, "plugin netdev: out of memory");
return;
}
fp = fopen("/proc/net/dev", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin netdev");
free(buffer);
return;
return -1;
}
while (fgets(buffer, BUFSIZE, fp) != NULL) {
@ -74,7 +70,7 @@ static void probe(void)
if (*device == '\0')
continue;
if (strsplit(stats, val, 16) != 16)
if (strsplit(stats, " \t\n", val, 16) != 16)
continue;
len = snprintf(filename, sizeof(filename), "net-%s.rrd", device);
@ -85,12 +81,26 @@ static void probe(void)
val[0], val[8], val[1], val[9]);
}
fclose(fp);
return 0;
}
static int init(void)
{
buffer = malloc(BUFSIZE);
return (buffer == NULL) ? -1 : 0;
}
static int fini(void)
{
free(buffer);
return 0;
}
struct sammler_plugin plugin = {
.name = "netdev",
.version = 1,
.interval = 10,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

View File

@ -20,49 +20,44 @@
#include <stdio.h>
#include <stdlib.h>
#include "logging.h"
#include "plugins.h"
#include "probe.h"
struct sammler_plugin plugin;
static char *ds_def[] = {
"DS:entropy:GAUGE:%d:0:U",
NULL
static const char *ds_def = {
"DS:entropy:GAUGE:15:0:U "
};
static char ** get_ds(int ds_id)
static const char * get_ds(int ds_id)
{
return ds_def;
}
static void probe(void)
static int probe(void)
{
FILE *fp;
char buffer[32];
char *val[1];
fp = fopen("/proc/sys/kernel/random/entropy_avail", "r");
FILE *fp = fopen("/proc/sys/kernel/random/entropy_avail", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin random");
return;
log_print(LOG_WARN, "plugin random: fopen()");
return -1;
}
if (fgets(buffer, sizeof(buffer), fp) == NULL) {
log_print(LOG_WARN, "plugin random");
int entropy;
if (fscanf(fp, "%d", &entropy) != 1) {
log_print(LOG_WARN, "plugin random: fopen()");
fclose(fp);
return;
return -1;
}
fclose(fp);
if (strsplit(buffer, val, 1) != 1)
return;
probe_submit(&plugin, "random.rrd", 0, "%s", val[0]);
probe_submit(&plugin, "random.rrd", 0, "%d", entropy);
return 0;
}
struct sammler_plugin plugin = {
.name = "random",
.version = 1,
.interval = 10,
.probe = &probe,
.get_ds = &get_ds,
};

View File

@ -21,63 +21,74 @@
#include <stdlib.h>
#include <string.h>
#include "helper.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#define DS_STAT 1
#define DS_GC 2
#define BUFSIZE 1024
struct sammler_plugin plugin;
static char *buffer;
static char *ds_def[] = {
"DS:entries:GAUGE:%d:0:U",
"DS:in_hit:DERIVE:%d:0:U",
"DS:in_slow_tot:DERIVE:%d:0:U",
"DS:in_slow_mc:DERIVE:%d:0:U",
"DS:in_no_route:DERIVE:%d:0:U",
"DS:in_brd:DERIVE:%d:0:U",
"DS:in_martian_dst:DERIVE:%d:0:U",
"DS:in_martian_src:DERIVE:%d:0:U",
"DS:out_hit:DERIVE:%d:0:U",
"DS:out_slow_tot:DERIVE:%d:0:U",
"DS:out_slow_mc:DERIVE:%d:0:U",
"DS:gc_total:DERIVE:%d:0:U",
"DS:gc_ignored:DERIVE:%d:0:U",
"DS:gc_goal_miss:DERIVE:%d:0:U",
"DS:gc_dst_overflow:DERIVE:%d:0:U",
"DS:in_hlist_search:DERIVE:%d:0:U",
"DS:out_hlist_search:DERIVE:%d:0:U",
NULL
static const char *ds_def_stat = {
"DS:in_hit:DERIVE:15:0:U "
"DS:in_slow_tot:DERIVE:15:0:U "
"DS:in_slow_mc:DERIVE:15:0:U "
"DS:in_no_route:DERIVE:15:0:U "
"DS:in_brd:DERIVE:15:0:U "
"DS:in_martian_dst:DERIVE:15:0:U "
"DS:in_martian_src:DERIVE:15:0:U "
"DS:out_hit:DERIVE:15:0:U "
"DS:out_slow_tot:DERIVE:15:0:U "
"DS:out_slow_mc:DERIVE:15:0:U "
"DS:in_hlist_search:DERIVE:15:0:U "
"DS:out_hlist_search:DERIVE:15:0:U "
};
static char ** get_ds(int ds_id)
static const char *ds_def_gc = {
"DS:entries:GAUGE:15:0:U "
"DS:gc_total:DERIVE:15:0:U "
"DS:gc_ignored:DERIVE:15:0:U "
"DS:gc_goal_miss:DERIVE:15:0:U "
"DS:gc_dst_overflow:DERIVE:15:0:U "
};
static const char * get_ds(int ds_id)
{
return ds_def;
switch (ds_id) {
case DS_STAT:
return ds_def_stat;
case DS_GC:
return ds_def_gc;
default:
return NULL;
}
}
static void probe(void)
static int probe(void)
{
FILE *fp;
char *buffer, *val[17], filename[16];
char *val[17], filename[16];
unsigned long long arr[17];
int i, len, cpu = 0;
buffer = malloc(BUFSIZE);
if (buffer == NULL) {
log_print(LOG_WARN, "plugin rtstat: out of memory");
return;
}
fp = fopen("/proc/net/stat/rt_cache", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin rtstat");
free(buffer);
return;
return -1;
}
while (fgets(buffer, BUFSIZE, fp) != NULL) {
if (!strncmp(buffer, "entries", 7))
continue;
if (strsplit(buffer, val, 17) != 17)
if (strsplit(buffer, " \t\n", val, 17) != 17)
continue;
for (i = 0; i < 17; i++)
@ -87,22 +98,43 @@ static void probe(void)
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, 0,
"%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
arr[0], arr[1], arr[2], arr[3],
arr[4], arr[5], arr[6], arr[7],
arr[8], arr[9], arr[10], arr[11],
arr[12], arr[13], arr[14], arr[15],
arr[16]);
probe_submit(&plugin, filename, DS_STAT,
"%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
arr[1], arr[2], arr[3], arr[4],
arr[5], arr[6], arr[7], arr[8],
arr[9], arr[10], arr[15], arr[16]);
len = snprintf(filename, sizeof(filename), "rtcache-%d.rrd", cpu);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, DS_GC,
"%llu:%llu:%llu:%llu:%llu",
arr[0], arr[11], arr[12], arr[13], arr[14]);
cpu++;
}
fclose(fp);
return 0;
}
static int init(void)
{
buffer = malloc(BUFSIZE);
return (buffer == NULL) ? -1 : 0;
}
static int fini(void)
{
free(buffer);
return 0;
}
struct sammler_plugin plugin = {
.name = "rtstat",
.version = 1,
.interval = 10,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

492
plugins/sgio.c Normal file
View File

@ -0,0 +1,492 @@
/* sgio.c - by Mark Lord (C) 2007 -- freely distributable */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
#include "sgio.h"
//#include "hdparm.h"
#include <linux/hdreg.h>
extern int verbose;
extern int prefer_ata12;
/*
* Taskfile layout for SG_ATA_16 cdb:
*
* LBA48:
* cdb[ 3] = hob_feat
* cdb[ 5] = hob_nsect
* cdb[ 7] = hob_lbal
* cdb[ 9] = hob_lbam
* cdb[11] = hob_lbah
*
* LBA28/LBA48:
* cdb[ 4] = feat
* cdb[ 6] = nsect
* cdb[ 8] = lbal
* cdb[10] = lbam
* cdb[12] = lbah
* cdb[13] = device
* cdb[14] = command
*
* Taskfile layout for SG_ATA_12 cdb:
*
* cdb[ 3] = feat
* cdb[ 4] = nsect
* cdb[ 5] = lbal
* cdb[ 6] = lbam
* cdb[ 7] = lbah
* cdb[ 8] = device
* cdb[ 9] = command
*
* dxfer_direction choices:
* SG_DXFER_TO_DEV, SG_DXFER_FROM_DEV, SG_DXFER_NONE
*/
static inline int needs_lba48 (__u8 ata_op, __u64 lba, unsigned int nsect)
{
const __u64 lba28_limit = (1<<28) - 1;
switch (ata_op) {
case ATA_OP_READ_PIO_EXT:
case ATA_OP_READ_DMA_EXT:
case ATA_OP_WRITE_PIO_EXT:
case ATA_OP_WRITE_DMA_EXT:
case ATA_OP_READ_VERIFY_EXT:
case ATA_OP_WRITE_UNC_EXT:
case ATA_OP_READ_NATIVE_MAX_EXT:
case ATA_OP_SET_MAX_EXT:
case ATA_OP_FLUSHCACHE_EXT:
return 1;
}
if (lba >= lba28_limit)
return 1;
if (nsect) {
if (nsect > 0xff)
return 1;
if ((lba + nsect - 1) >= lba28_limit)
return 1;
}
return 0;
}
void tf_init (struct ata_tf *tf, __u8 ata_op, __u64 lba, unsigned int nsect)
{
memset(tf, 0, sizeof(*tf));
tf->command = ata_op;
tf->dev = ATA_USING_LBA;
tf->lob.lbal = lba;
tf->lob.lbam = lba >> 8;
tf->lob.lbah = lba >> 16;
tf->lob.nsect = nsect;
if (needs_lba48(ata_op, lba, nsect)) {
tf->is_lba48 = 1;
tf->hob.nsect = nsect >> 8;
tf->hob.lbal = lba >> 24;
tf->hob.lbam = lba >> 32;
tf->hob.lbah = lba >> 40;
} else {
tf->dev |= (lba >> 24) & 0x0f;
}
}
#ifdef SG_IO
__u64 tf_to_lba (struct ata_tf *tf)
{
__u32 lba24, lbah;
__u64 lba64;
lba24 = (tf->lob.lbah << 16) | (tf->lob.lbam << 8) | (tf->lob.lbal);
if (tf->is_lba48)
lbah = (tf->hob.lbah << 16) | (tf->hob.lbam << 8) | (tf->hob.lbal);
else
lbah = (tf->dev & 0x0f);
lba64 = (((__u64)lbah) << 24) | (__u64)lba24;
return lba64;
}
enum {
SG_CDB2_TLEN_NODATA = 0 << 0,
SG_CDB2_TLEN_FEAT = 1 << 0,
SG_CDB2_TLEN_NSECT = 2 << 0,
SG_CDB2_TLEN_BYTES = 0 << 2,
SG_CDB2_TLEN_SECTORS = 1 << 2,
SG_CDB2_TDIR_TO_DEV = 0 << 3,
SG_CDB2_TDIR_FROM_DEV = 1 << 3,
SG_CDB2_CHECK_COND = 1 << 5,
};
static void dump_bytes (const char *prefix, unsigned char *p, int len)
{
int i;
if (prefix)
fprintf(stderr, "%s: ", prefix);
for (i = 0; i < len; ++i)
fprintf(stderr, " %02x", p[i]);
fprintf(stderr, "\n");
}
int sg16 (int fd, int rw, int dma, struct ata_tf *tf,
void *data, unsigned int data_bytes, unsigned int timeout_secs)
{
unsigned char cdb[SG_ATA_16_LEN];
unsigned char sb[32], *desc;
struct scsi_sg_io_hdr io_hdr;
memset(&cdb, 0, sizeof(cdb));
memset(&sb, 0, sizeof(sb));
memset(&io_hdr, 0, sizeof(struct scsi_sg_io_hdr));
if (dma) {
//cdb[1] = data ? (rw ? SG_ATA_PROTO_UDMA_OUT : SG_ATA_PROTO_UDMA_IN) : SG_ATA_PROTO_NON_DATA;
cdb[1] = data ? SG_ATA_PROTO_DMA : SG_ATA_PROTO_NON_DATA;
} else {
cdb[1] = data ? (rw ? SG_ATA_PROTO_PIO_OUT : SG_ATA_PROTO_PIO_IN) : SG_ATA_PROTO_NON_DATA;
}
cdb[ 2] = SG_CDB2_CHECK_COND;
if (data) {
cdb[2] |= SG_CDB2_TLEN_NSECT | SG_CDB2_TLEN_SECTORS;
cdb[2] |= rw ? SG_CDB2_TDIR_TO_DEV : SG_CDB2_TDIR_FROM_DEV;
}
if (!prefer_ata12 || tf->is_lba48) {
cdb[ 0] = SG_ATA_16;
cdb[ 4] = tf->lob.feat;
cdb[ 6] = tf->lob.nsect;
cdb[ 8] = tf->lob.lbal;
cdb[10] = tf->lob.lbam;
cdb[12] = tf->lob.lbah;
cdb[13] = tf->dev;
cdb[14] = tf->command;
if (tf->is_lba48) {
cdb[ 1] |= SG_ATA_LBA48;
cdb[ 3] = tf->hob.feat;
cdb[ 5] = tf->hob.nsect;
cdb[ 7] = tf->hob.lbal;
cdb[ 9] = tf->hob.lbam;
cdb[11] = tf->hob.lbah;
}
io_hdr.cmd_len = SG_ATA_16_LEN;
} else {
cdb[ 0] = SG_ATA_12;
cdb[ 3] = tf->lob.feat;
cdb[ 4] = tf->lob.nsect;
cdb[ 5] = tf->lob.lbal;
cdb[ 6] = tf->lob.lbam;
cdb[ 7] = tf->lob.lbah;
cdb[ 8] = tf->dev;
cdb[ 9] = tf->command;
io_hdr.cmd_len = SG_ATA_12_LEN;
}
io_hdr.interface_id = 'S';
io_hdr.mx_sb_len = sizeof(sb);
io_hdr.dxfer_direction = data ? (rw ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV) : SG_DXFER_NONE;
io_hdr.dxfer_len = data ? data_bytes : 0;
io_hdr.dxferp = data;
io_hdr.cmdp = cdb;
io_hdr.sbp = sb;
io_hdr.pack_id = tf_to_lba(tf);
io_hdr.timeout = (timeout_secs ? timeout_secs : 5) * 1000; /* msecs */
if (verbose)
dump_bytes("outgoing cdb", cdb, sizeof(cdb));
if (ioctl(fd, SG_IO, &io_hdr) == -1) {
if (verbose)
perror("ioctl(fd,SG_IO)");
return -1; /* SG_IO not supported */
}
if (verbose)
fprintf(stderr, "SG_IO: ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x\n",
io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status);
if (io_hdr.host_status || io_hdr.driver_status != SG_DRIVER_SENSE
|| (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION))
{
if (verbose)
fprintf(stderr, "SG_IO: bad response (not CHECK_CONDITION)\n");
errno = EBADE;
return -1;
}
desc = sb + 8;
if (sb[0] != 0x72 || sb[7] < 14 || desc[0] != 0x09 || desc[1] < 0x0c) {
if (verbose)
dump_bytes("SG_IO: bad/missing sense data, sb[]", sb, sizeof(sb));
errno = EBADE;
return -1;
}
if (verbose)
dump_bytes("SG_IO: sb[]", sb, sizeof(sb));
if (verbose) {
int len = desc[1], maxlen = sizeof(sb) - 8 - 2;
if (len > maxlen)
len = maxlen;
dump_bytes("SG_IO: desc[]", desc, len);
}
tf->is_lba48 = desc[ 2] & 1;
tf->error = desc[ 3];
tf->lob.nsect = desc[ 5];
tf->lob.lbal = desc[ 7];
tf->lob.lbam = desc[ 9];
tf->lob.lbah = desc[11];
tf->dev = desc[12];
tf->status = desc[13];
tf->hob.feat = 0;
if (tf->is_lba48) {
tf->hob.nsect = desc[ 4];
tf->hob.lbal = desc[ 6];
tf->hob.lbam = desc[ 8];
tf->hob.lbah = desc[10];
} else {
tf->hob.nsect = 0;
tf->hob.lbal = 0;
tf->hob.lbam = 0;
tf->hob.lbah = 0;
}
if (verbose)
fprintf(stderr, " ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x lbam=%02x lbah=%02x dev=%02x\n",
io_hdr.cmd_len, tf->status, tf->error, tf->lob.nsect, tf->lob.lbal, tf->lob.lbam, tf->lob.lbah, tf->dev);
if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ)) {
if (verbose) {
fprintf(stderr, "I/O error, ata_op=0x%02x ata_status=0x%02x ata_error=0x%02x\n",
tf->command, tf->status, tf->error);
}
errno = EIO;
return -1;
}
return 0;
}
#endif /* SG_IO */
int do_drive_cmd (int fd, unsigned char *args)
{
#ifdef SG_IO
struct ata_tf tf;
void *data = NULL;
unsigned int data_bytes = 0;
int rc;
if (args == NULL)
goto use_legacy_ioctl;
/*
* Reformat and try to issue via SG_IO:
*/
if (args[3]) {
data_bytes = args[3] * 512;
data = args + 4;
}
tf_init(&tf, args[0], 0, args[1]);
tf.lob.feat = args[2];
if (tf.command == ATA_OP_SMART) {
tf.lob.nsect = args[3];
tf.lob.lbal = args[1];
tf.lob.lbam = 0x4f;
tf.lob.lbah = 0xc2;
}
rc = sg16(fd, SG_READ, SG_PIO, &tf, data, data_bytes, 0);
if (rc == -1) {
if (errno == EINVAL || errno == ENODEV)
goto use_legacy_ioctl;
}
if (rc == 0 || errno == EIO) {
args[0] = tf.status;
args[1] = tf.error;
args[2] = tf.lob.nsect;
}
return rc;
use_legacy_ioctl:
#endif /* SG_IO */
if (verbose)
fprintf(stderr, "Trying legacy HDIO_DRIVE_CMD\n");
return ioctl(fd, HDIO_DRIVE_CMD, args);
}
int do_taskfile_cmd (int fd, struct hdio_taskfile *r, unsigned int timeout_secs)
{
int rc;
#ifdef SG_IO
struct ata_tf tf;
void *data = NULL;
unsigned int data_bytes = 0;
int rw = SG_READ;
/*
* Reformat and try to issue via SG_IO:
*/
tf_init(&tf, 0, 0, 0);
#if 1 /* debugging */
if (verbose) {
printf("oflags.lob_all=0x%02x, flags={", r->oflags.lob_all);
if (r->oflags.lob.feat) printf(" feat");
if (r->oflags.lob.lbal) printf(" lbal");
if (r->oflags.lob.nsect)printf(" nsect");
if (r->oflags.lob.lbam) printf(" lbam");
if (r->oflags.lob.lbah) printf(" lbah");
if (r->oflags.lob.dev) printf(" dev");
if (r->oflags.lob.command) printf(" command");
printf(" }\n");
printf("oflags.hob_all=0x%02x, flags={", r->oflags.hob_all);
if (r->oflags.hob.feat) printf(" feat");
if (r->oflags.hob.lbal) printf(" lbal");
if (r->oflags.hob.nsect)printf(" nsect");
if (r->oflags.hob.lbam) printf(" lbam");
if (r->oflags.hob.lbah) printf(" lbah");
printf(" }\n");
}
#endif
if (r->oflags.lob.feat) tf.lob.feat = r->lob.feat;
if (r->oflags.lob.lbal) tf.lob.lbal = r->lob.lbal;
if (r->oflags.lob.nsect) tf.lob.nsect = r->lob.nsect;
if (r->oflags.lob.lbam) tf.lob.lbam = r->lob.lbam;
if (r->oflags.lob.lbah) tf.lob.lbah = r->lob.lbah;
if (r->oflags.lob.dev) tf.dev = r->lob.dev;
if (r->oflags.lob.command) tf.command = r->lob.command;
if (r->oflags.hob_all || r->iflags.hob_all) {
tf.is_lba48 = 1;
if (r->oflags.hob.feat) tf.hob.feat = r->hob.feat;
if (r->oflags.hob.lbal) tf.hob.lbal = r->hob.lbal;
if (r->oflags.hob.nsect)tf.hob.nsect = r->hob.nsect;
if (r->oflags.hob.lbam) tf.hob.lbam = r->hob.lbam;
if (r->oflags.hob.lbah) tf.hob.lbah = r->hob.lbah;
if (verbose)
fprintf(stderr, "using LBA48 taskfile\n");
}
switch (r->cmd_req) {
case TASKFILE_CMD_REQ_OUT:
case TASKFILE_CMD_REQ_RAW_OUT:
data_bytes = r->obytes;
data = r->data;
rw = SG_WRITE;
break;
case TASKFILE_CMD_REQ_IN:
data_bytes = r->ibytes;
data = r->data;
break;
}
rc = sg16(fd, rw, SG_PIO, &tf, data, data_bytes, timeout_secs);
if (rc == -1) {
if (errno == EINVAL || errno == ENODEV)
goto use_legacy_ioctl;
}
if (rc == 0 || errno == EIO) {
if (r->iflags.lob.feat) r->lob.feat = tf.error;
if (r->iflags.lob.lbal) r->lob.lbal = tf.lob.lbal;
if (r->iflags.lob.nsect) r->lob.nsect = tf.lob.nsect;
if (r->iflags.lob.lbam) r->lob.lbam = tf.lob.lbam;
if (r->iflags.lob.lbah) r->lob.lbah = tf.lob.lbah;
if (r->iflags.lob.dev) r->lob.dev = tf.dev;
if (r->iflags.lob.command) r->lob.command = tf.status;
if (r->iflags.hob.feat) r->hob.feat = tf.hob.feat;
if (r->iflags.hob.lbal) r->hob.lbal = tf.hob.lbal;
if (r->iflags.hob.nsect) r->hob.nsect = tf.hob.nsect;
if (r->iflags.hob.lbam) r->hob.lbam = tf.hob.lbam;
if (r->iflags.hob.lbah) r->hob.lbah = tf.hob.lbah;
}
return rc;
use_legacy_ioctl:
#else
timeout_secs = 0; /* keep compiler happy */
#endif /* SG_IO */
if (verbose)
fprintf(stderr, "trying legacy HDIO_DRIVE_TASKFILE\n");
errno = 0;
rc = ioctl(fd, HDIO_DRIVE_TASKFILE, r);
if (verbose) {
int err = errno;
fprintf(stderr, "rc=%d, errno=%d, returned ATA registers: ", rc, err);
if (r->iflags.lob.feat) fprintf(stderr, " er=%02x", r->lob.feat);
if (r->iflags.lob.nsect) fprintf(stderr, " ns=%02x", r->lob.nsect);
if (r->iflags.lob.lbal) fprintf(stderr, " ll=%02x", r->lob.lbal);
if (r->iflags.lob.lbam) fprintf(stderr, " lm=%02x", r->lob.lbam);
if (r->iflags.lob.lbah) fprintf(stderr, " lh=%02x", r->lob.lbah);
if (r->iflags.lob.dev) fprintf(stderr, " dh=%02x", r->lob.dev);
if (r->iflags.lob.command) fprintf(stderr, " st=%02x", r->lob.command);
if (r->iflags.hob.feat) fprintf(stderr, " err=%02x", r->hob.feat);
if (r->iflags.hob.nsect) fprintf(stderr, " err=%02x", r->hob.nsect);
if (r->iflags.hob.lbal) fprintf(stderr, " err=%02x", r->hob.lbal);
if (r->iflags.hob.lbam) fprintf(stderr, " err=%02x", r->hob.lbam);
if (r->iflags.hob.lbah) fprintf(stderr, " err=%02x", r->hob.lbah);
fprintf(stderr, "\n");
errno = err;
}
if (rc == -1 && errno == EINVAL) {
fprintf(stderr, "The running kernel lacks CONFIG_IDE_TASK_IOCTL support for this device.\n");
errno = EINVAL;
}
return rc;
}
void init_hdio_taskfile (struct hdio_taskfile *r, __u8 ata_op, int rw, int force_lba48,
__u64 lba, unsigned int nsect, int data_bytes)
{
memset(r, 0, sizeof(struct hdio_taskfile) + data_bytes);
if (!data_bytes) {
r->dphase = TASKFILE_DPHASE_NONE;
r->cmd_req = TASKFILE_CMD_REQ_NODATA;
} else if (rw == RW_WRITE) {
r->dphase = TASKFILE_DPHASE_PIO_OUT;
r->cmd_req = TASKFILE_CMD_REQ_RAW_OUT;
r->obytes = data_bytes;
} else { /* rw == RW_READ */
r->dphase = TASKFILE_DPHASE_PIO_IN;
r->cmd_req = TASKFILE_CMD_REQ_IN;
r->ibytes = data_bytes;
}
r->lob.command = ata_op;
r->oflags.lob.command = 1;
r->oflags.lob.dev = 1;
r->oflags.lob.lbal = 1;
r->oflags.lob.lbam = 1;
r->oflags.lob.lbah = 1;
r->oflags.lob.nsect = 1;
r->iflags.lob.command = 1;
r->iflags.lob.feat = 1;
r->lob.nsect = nsect;
r->lob.lbal = lba;
r->lob.lbam = lba >> 8;
r->lob.lbah = lba >> 16;
r->lob.dev = 0xa0 | ATA_USING_LBA;
if (needs_lba48(ata_op, lba, nsect) || force_lba48) {
r->hob.nsect = nsect >> 8;
r->hob.lbal = lba >> 24;
r->hob.lbam = lba >> 32;
r->hob.lbah = lba >> 40;
r->oflags.hob.nsect = 1;
r->oflags.hob.lbal = 1;
r->oflags.hob.lbam = 1;
r->oflags.hob.lbah = 1;
} else {
r->lob.dev |= (lba >> 24) & 0x0f;
}
}

230
plugins/sgio.h Normal file
View File

@ -0,0 +1,230 @@
/* prototypes and stuff for ATA command ioctls */
#include <linux/types.h>
enum {
ATA_OP_READ_PIO = 0x20,
ATA_OP_READ_PIO_ONCE = 0x21,
ATA_OP_READ_LONG = 0x22,
ATA_OP_READ_LONG_ONCE = 0x23,
ATA_OP_READ_PIO_EXT = 0x24,
ATA_OP_READ_DMA_EXT = 0x25,
ATA_OP_READ_FPDMA = 0x60, // NCQ
ATA_OP_WRITE_PIO = 0x30,
ATA_OP_WRITE_LONG = 0x32,
ATA_OP_WRITE_LONG_ONCE = 0x33,
ATA_OP_WRITE_PIO_EXT = 0x34,
ATA_OP_WRITE_DMA_EXT = 0x35,
ATA_OP_WRITE_FPDMA = 0x61, // NCQ
ATA_OP_READ_VERIFY = 0x40,
ATA_OP_READ_VERIFY_ONCE = 0x41,
ATA_OP_READ_VERIFY_EXT = 0x42,
ATA_OP_WRITE_UNC_EXT = 0x45, // lba48, no data, uses feat reg
ATA_OP_FORMAT_TRACK = 0x50,
ATA_OP_DOWNLOAD_MICROCODE = 0x92,
ATA_OP_STANDBYNOW2 = 0x94,
ATA_OP_CHECKPOWERMODE2 = 0x98,
ATA_OP_SLEEPNOW2 = 0x99,
ATA_OP_PIDENTIFY = 0xa1,
ATA_OP_READ_NATIVE_MAX = 0xf8,
ATA_OP_READ_NATIVE_MAX_EXT = 0x27,
ATA_OP_SMART = 0xb0,
ATA_OP_DCO = 0xb1,
ATA_OP_ERASE_SECTORS = 0xc0,
ATA_OP_READ_DMA = 0xc8,
ATA_OP_WRITE_DMA = 0xca,
ATA_OP_DOORLOCK = 0xde,
ATA_OP_DOORUNLOCK = 0xdf,
ATA_OP_STANDBYNOW1 = 0xe0,
ATA_OP_IDLEIMMEDIATE = 0xe1,
ATA_OP_SETIDLE = 0xe3,
ATA_OP_SET_MAX = 0xf9,
ATA_OP_SET_MAX_EXT = 0x37,
ATA_OP_SET_MULTIPLE = 0xc6,
ATA_OP_CHECKPOWERMODE1 = 0xe5,
ATA_OP_SLEEPNOW1 = 0xe6,
ATA_OP_FLUSHCACHE = 0xe7,
ATA_OP_FLUSHCACHE_EXT = 0xea,
ATA_OP_IDENTIFY = 0xec,
ATA_OP_SETFEATURES = 0xef,
ATA_OP_SECURITY_SET_PASS = 0xf1,
ATA_OP_SECURITY_UNLOCK = 0xf2,
ATA_OP_SECURITY_ERASE_PREPARE = 0xf3,
ATA_OP_SECURITY_ERASE_UNIT = 0xf4,
ATA_OP_SECURITY_FREEZE_LOCK = 0xf5,
ATA_OP_SECURITY_DISABLE = 0xf6,
};
/*
* Some useful ATA register bits
*/
enum {
ATA_USING_LBA = (1 << 6),
ATA_STAT_DRQ = (1 << 3),
ATA_STAT_ERR = (1 << 0),
};
/*
* Useful parameters for init_hdio_taskfile():
*/
enum { RW_READ = 0,
RW_WRITE = 1,
LBA28_OK = 0,
LBA48_FORCE = 1,
};
/*
* Definitions and structures for use with SG_IO + ATA_16:
*/
struct ata_lba_regs {
__u8 feat;
__u8 nsect;
__u8 lbal;
__u8 lbam;
__u8 lbah;
};
struct ata_tf {
__u8 dev;
__u8 command;
__u8 error;
__u8 status;
__u8 is_lba48;
struct ata_lba_regs lob;
struct ata_lba_regs hob;
};
/*
* Definitions and structures for use with HDIO_DRIVE_TASKFILE:
*/
enum {
/*
* These (redundantly) specify the category of the request
*/
TASKFILE_CMD_REQ_NODATA = 0, /* ide: IDE_DRIVE_TASK_NO_DATA */
TASKFILE_CMD_REQ_IN = 2, /* ide: IDE_DRIVE_TASK_IN */
TASKFILE_CMD_REQ_OUT = 3, /* ide: IDE_DRIVE_TASK_OUT */
TASKFILE_CMD_REQ_RAW_OUT= 4, /* ide: IDE_DRIVE_TASK_RAW_WRITE */
/*
* These specify the method of transfer (pio, dma, multi, ..)
*/
TASKFILE_DPHASE_NONE = 0, /* ide: TASKFILE_IN */
TASKFILE_DPHASE_PIO_IN = 1, /* ide: TASKFILE_IN */
TASKFILE_DPHASE_PIO_OUT = 4, /* ide: TASKFILE_OUT */
};
struct reg_flags {
union {
unsigned lob_all : 8;
struct {
unsigned data : 1;
unsigned feat : 1;
unsigned lbal : 1;
unsigned nsect : 1;
unsigned lbam : 1;
unsigned lbah : 1;
unsigned dev : 1;
unsigned command : 1;
} lob;
};
union {
unsigned hob_all : 8;
struct {
unsigned data : 1;
unsigned feat : 1;
unsigned lbal : 1;
unsigned nsect : 1;
unsigned lbam : 1;
unsigned lbah : 1;
unsigned dev : 1;
unsigned command : 1;
} hob;
};
};
struct taskfile_regs {
__u8 data;
__u8 feat;
__u8 nsect;
__u8 lbal;
__u8 lbam;
__u8 lbah;
__u8 dev;
__u8 command;
};
struct hdio_taskfile {
struct taskfile_regs lob;
struct taskfile_regs hob;
struct reg_flags oflags;
struct reg_flags iflags;
int dphase;
int cmd_req; /* IDE command_type */
unsigned long obytes;
unsigned long ibytes;
__u16 data[0];
};
struct scsi_sg_io_hdr {
int interface_id;
int dxfer_direction;
unsigned char cmd_len;
unsigned char mx_sb_len;
unsigned short iovec_count;
unsigned int dxfer_len;
void * dxferp;
unsigned char * cmdp;
void * sbp;
unsigned int timeout;
unsigned int flags;
int pack_id;
void * usr_ptr;
unsigned char status;
unsigned char masked_status;
unsigned char msg_status;
unsigned char sb_len_wr;
unsigned short host_status;
unsigned short driver_status;
int resid;
unsigned int duration;
unsigned int info;
};
#ifndef SG_DXFER_NONE
#define SG_DXFER_NONE -1
#define SG_DXFER_TO_DEV -2
#define SG_DXFER_FROM_DEV -3
#define SG_DXFER_TO_FROM_DEV -4
#endif
#define SG_READ 0
#define SG_WRITE 1
#define SG_PIO 0
#define SG_DMA 1
#define SG_CHECK_CONDITION 0x02
#define SG_DRIVER_SENSE 0x08
#define SG_ATA_16 0x85
#define SG_ATA_16_LEN 16
#define SG_ATA_12 0xa1
#define SG_ATA_12_LEN 12
#define SG_ATA_LBA48 1
#define SG_ATA_PROTO_NON_DATA ( 3 << 1)
#define SG_ATA_PROTO_PIO_IN ( 4 << 1)
#define SG_ATA_PROTO_PIO_OUT ( 5 << 1)
#define SG_ATA_PROTO_DMA ( 6 << 1)
#define SG_ATA_PROTO_UDMA_IN (11 << 1) /* not yet supported in libata */
#define SG_ATA_PROTO_UDMA_OUT (12 << 1) /* not yet supported in libata */
void tf_init (struct ata_tf *tf, __u8 ata_op, __u64 lba, unsigned int nsect);
__u64 tf_to_lba (struct ata_tf *tf);
int sg16 (int fd, int rw, int dma, struct ata_tf *tf, void *data, unsigned int data_bytes, unsigned int timeout_secs);
int do_drive_cmd (int fd, unsigned char *args);
int do_taskfile_cmd (int fd, struct hdio_taskfile *r, unsigned int timeout_secs);
int dev_has_sgio (int fd);
void init_hdio_taskfile (struct hdio_taskfile *r, __u8 ata_op, int rw, int force_lba48,
__u64 lba, unsigned int nsect, int data_bytes);

View File

@ -21,34 +21,37 @@
#include <stdlib.h>
#include <string.h>
#include "helper.h"
#include "logging.h"
#include "plugins.h"
#define BUFSIZE 1024
#include "probe.h"
#define DS_CPU 1
#define DS_PROC 2
#define BUFSIZE 1024
struct sammler_plugin plugin;
static char *buffer;
static char *cpu_ds_def[] = {
"DS:user:COUNTER:%d:0:U",
"DS:nice:COUNTER:%d:0:U",
"DS:syst:COUNTER:%d:0:U",
"DS:idle:COUNTER:%d:0:U",
"DS:wait:COUNTER:%d:0:U",
"DS:intr:COUNTER:%d:0:U",
"DS:sitr:COUNTER:%d:0:U",
NULL
static const char *cpu_ds_def = {
"DS:user:COUNTER:15:0:U "
"DS:nice:COUNTER:15:0:U "
"DS:system:COUNTER:15:0:U "
"DS:idle:COUNTER:15:0:U "
"DS:iowait:COUNTER:15:0:U "
"DS:irq:COUNTER:15:0:U "
"DS:softirq:COUNTER:15:0:U "
"DS:steal:COUNTER:15:0:U "
};
static char *proc_ds_def[] = {
"DS:intr:COUNTER:%d:0:U",
"DS:ctxt:COUNTER:%d:0:U",
"DS:fork:COUNTER:%d:0:U",
NULL
static const char *proc_ds_def = {
"DS:intr:COUNTER:15:0:U "
"DS:ctxt:COUNTER:15:0:U "
"DS:fork:COUNTER:15:0:U "
};
static char ** get_ds(int ds_id)
static const char * get_ds(int ds_id)
{
switch (ds_id) {
case DS_CPU:
@ -68,23 +71,17 @@ struct proc_ {
unsigned long long fork;
};
static void probe(void)
static int probe(void)
{
FILE *fp;
char *buffer;
struct proc_ proc;
buffer = malloc(BUFSIZE);
if (buffer == NULL) {
log_print(LOG_WARN, "plugin stat: out of memory");
return;
}
memset(&proc, 0, sizeof(proc));
fp = fopen("/proc/stat", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin stat");
free(buffer);
return;
return -1;
}
while (fgets(buffer, BUFSIZE, fp) != NULL) {
@ -102,21 +99,20 @@ static void probe(void)
strncpy(filename, "cpu.rrd", sizeof(filename));
}
numfields = strsplit(buffer, val, 9);
numfields = strsplit(buffer, " \t\n", val, 9);
if (numfields < 5)
continue;
if (numfields >= 8) {
probe_submit(&plugin, filename, DS_CPU,
"%s:%s:%s:%s:%s:%s:%s",
val[1], val[2], val[3], val[4],
val[5], val[6], val[7]);
else if (numfields == 5)
val[5] = val[6] = val[7] = val[8] = "0";
} else {
probe_submit(&plugin, filename, DS_CPU,
"%s:%s:%s:%s:0:0:0",
val[1], val[2], val[3], val[4]);
}
else if (numfields == 8)
val[8] = "0";
probe_submit(&plugin, filename, DS_CPU,
"%s:%s:%s:%s:%s:%s:%s:%s",
val[1], val[2], val[3], val[4],
val[5], val[6], val[7], val[8]);
} else if (!strncmp(buffer, "intr", 4)) {
proc.intr = atoll(buffer + 5);
@ -133,12 +129,26 @@ static void probe(void)
proc.intr, proc.ctxt, proc.fork);
fclose(fp);
return 0;
}
static int init(void)
{
buffer = malloc(BUFSIZE);
return (buffer == NULL) ? -1 : 0;
}
static int fini(void)
{
free(buffer);
return 0;
}
struct sammler_plugin plugin = {
.name = "stat",
.version = 1,
.interval = 10,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

213
plugins/ts2.c Normal file
View File

@ -0,0 +1,213 @@
/***************************************************************************
* Copyright (C) 02/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include "configfile.h"
#include "helper.h"
#include "list.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#include "sockaddr.h"
#define TS2_RESP_SIZE 1024
struct sammler_plugin plugin;
struct server_entry {
struct list_head list;
char *name;
int errors;
struct sockaddr_in sa;
};
static LIST_HEAD(server_list);
static char *ts2_resp_buf;
static const char *ds_def = {
"DS:users:GAUGE:90:0:U "
"DS:channels:GAUGE:90:0:U "
};
static const char * get_ds(int ds_id)
{
return ds_def;
}
static int probe(void)
{
struct server_entry *entry;
list_for_each_entry(entry, &server_list, list) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
log_print(LOG_WARN, "plugin ts2: socket()");
continue;
}
int ret = connect(sock, (struct sockaddr *)&entry->sa, sizeof(entry->sa));
if (ret != 0) {
if (entry->errors++ == 0)
log_print(LOG_ERROR, "plugin ts2: connect(%s)", get_sockaddr_buf(&entry->sa));
close(sock);
continue;
}
/* read prompt "[TS]" */
int len = read(sock, ts2_resp_buf, TS2_RESP_SIZE);
if (len <= 0) {
if (entry->errors++ == 0)
log_print(LOG_ERROR, "ts2: read(1)");
close(sock);
continue;
}
if (strncmp(ts2_resp_buf, "[TS]", 4) != 0) {
if (entry->errors++ == 0)
log_print(LOG_ERROR, "ts2: invalid prompt from server");
close(sock);
continue;
}
/* query "general informations" */
char cmd1[] = "gi\n";
write(sock, cmd1, sizeof(cmd1));
len = read(sock, ts2_resp_buf, TS2_RESP_SIZE);
if (len <= 0) {
if (entry->errors++ == 0)
log_print(LOG_ERROR, "ts2: read(2)");
close(sock);
continue;
}
/* send quit (but we close the socket anyway..) */
char cmd2[] = "quit";
write(sock, cmd2, sizeof(cmd2));
close(sock);
/* terminate response */
ts2_resp_buf[len] = '\0';
char *tok, *tmp, *resp = ts2_resp_buf;
int users = 0, channels = 0;
while ((tok = strtok_r(resp, "\r\n", &tmp)) != NULL) {
/* total_users_online=14 */
if (strncmp(tok, "total_users_online", 18) == 0) {
users = atoi(tok +19);
/* total_channels=3 */
} else if (strncmp(tok, "total_channels", 14) == 0) {
channels = atoi(tok +15);
}
resp = NULL;
}
char filename[32];
len = snprintf(filename, sizeof(filename), "ts2-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, 0, "%d:%d", users, channels);
if (entry->errors > 0) {
log_print(LOG_ERROR, "plugin ts2: success (%s) after %d errors",
entry->name, entry->errors);
entry->errors = 0;
}
}
return 0;
}
static int init_cb(struct strtoken *tokens, void *privdata)
{
if (tokens->count != 2) {
log_print(LOG_ERROR, "p_ts2: parse error");
return -1;
}
struct server_entry *entry = malloc(sizeof(struct server_entry));
if (entry == NULL) {
log_print(LOG_ERROR, "p_ts2: out of memory");
return -1;
}
entry->name = strdup(tokens->field[0]);
entry->errors = 0;
if (parse_sockaddr(tokens->field[1], &entry->sa) < 0) {
log_print(LOG_ERROR, "p_ts2: invalid address: <%s>", tokens->field[1]);
free(entry->name);
free(entry);
return -1;
}
log_print(LOG_INFO, "p_ts2: added server '%s'", entry->name);
list_add_tail(&entry->list, &server_list);
return 0;
}
static int init(void)
{
ts2_resp_buf = malloc(TS2_RESP_SIZE);
if (ts2_resp_buf == NULL) {
log_print(LOG_ERROR, "p_ts2: out of memory");
return -1;
}
config_get_strtokens("p_ts2", "server", ",", 2, init_cb, NULL);
return 0;
}
static int fini(void)
{
struct server_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &server_list, list) {
free(entry->name);
free(entry);
}
free(ts2_resp_buf);
return 0;
}
struct sammler_plugin plugin = {
.name = "ts2",
.interval = 60,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

View File

@ -20,50 +20,45 @@
#include <stdio.h>
#include <stdlib.h>
#include "logging.h"
#include "plugins.h"
#include "probe.h"
struct sammler_plugin plugin;
static char *ds_def[] = {
"DS:uptime:GAUGE:%d:0:U",
"DS:idletime:GAUGE:%d:0:U",
NULL
static const char *ds_def = {
"DS:uptime:GAUGE:15:0:U "
"DS:idletime:GAUGE:15:0:U "
};
static char ** get_ds(int ds_id)
static const char * get_ds(int ds_id)
{
return ds_def;
}
static void probe(void)
static int probe(void)
{
FILE *fp;
char buffer[32];
char *val[2];
fp = fopen("/proc/uptime", "r");
FILE *fp = fopen("/proc/uptime", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin uptime");
return;
log_print(LOG_WARN, "plugin uptime: fopen()");
return -1;
}
if (fgets(buffer, sizeof(buffer), fp) == NULL) {
log_print(LOG_WARN, "plugin uptime");
double uptime, idletime;
if (fscanf(fp, "%lf %lf\n", &uptime, &idletime) != 2) {
log_print(LOG_WARN, "plugin uptime: fscanf()");
fclose(fp);
return;
return -1;
}
fclose(fp);
if (strsplit(buffer, val, 2) != 2)
return;
probe_submit(&plugin, "uptime.rrd", 0, "%s:%s", val[0], val[1]);
probe_submit(&plugin, "uptime.rrd", 0, "%.02lf:%.02lf", uptime, idletime);
return 0;
}
struct sammler_plugin plugin = {
.name = "uptime",
.version = 1,
.interval = 10,
.probe = &probe,
.get_ds = &get_ds,
};

View File

@ -21,22 +21,24 @@
#include <stdlib.h>
#include <string.h>
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#define BUFSIZE 1024
struct sammler_plugin plugin;
static char *buffer;
static char *ds_def[] = {
"DS:pgalloc_high:DERIVE:%d:0:U",
"DS:pgalloc_normal:DERIVE:%d:0:U",
"DS:pgalloc_dma:DERIVE:%d:0:U",
"DS:pgfree:DERIVE:%d:0:U",
"DS:pgfault:DERIVE:%d:0:U",
NULL
static const char *ds_def = {
"DS:pgalloc_high:DERIVE:15:0:U "
"DS:pgalloc_normal:DERIVE:15:0:U "
"DS:pgalloc_dma:DERIVE:15:0:U "
"DS:pgfree:DERIVE:15:0:U "
"DS:pgfault:DERIVE:15:0:U "
};
static char ** get_ds(int ds_id)
static const char * get_ds(int ds_id)
{
return ds_def;
}
@ -49,23 +51,17 @@ struct vmstat_ {
unsigned long long pgfault;
};
static void probe(void)
static int probe(void)
{
FILE *fp;
char *buffer;
struct vmstat_ vmstat;
buffer = malloc(BUFSIZE);
if (buffer == NULL) {
log_print(LOG_WARN, "plugin vmstat: out of memory");
return;
}
memset(&vmstat, 0, sizeof(vmstat));
fp = fopen("/proc/vmstat", "r");
if (fp == NULL) {
log_print(LOG_WARN, "plugin vmstat");
free(buffer);
return;
return -1;
}
while (fgets(buffer, BUFSIZE, fp) != NULL) {
@ -90,12 +86,26 @@ static void probe(void)
vmstat.pgalloc_dma, vmstat.pgfree, vmstat.pgfault);
fclose(fp);
return 0;
}
static int init(void)
{
buffer = malloc(BUFSIZE);
return (buffer == NULL) ? -1 : 0;
}
static int fini(void)
{
free(buffer);
return 0;
}
struct sammler_plugin plugin = {
.name = "vmstat",
.version = 1,
.interval = 10,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

61
probe.c Normal file
View File

@ -0,0 +1,61 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include "configfile.h"
#include "logging.h"
#include "network.h"
#include "rrdtool.h"
#define BUFSIZE 512
#define SUBMIT_NET_ONLY 0x01
static int submit_flags;
static const char *hostname;
int probe_init(void)
{
const char *fwd_only = config_get_string("global", "forward_only", "false");
submit_flags = 0;
if (!strncmp(fwd_only, "true", 4))
submit_flags |= SUBMIT_NET_ONLY;
static char hostname_buf[32];
if (gethostname(hostname_buf, sizeof(hostname_buf)) != 0)
strcpy(hostname_buf, "localhost");
hostname = config_get_string("global", "hostname", hostname_buf);
return 0;
}
int probe_submit(struct sammler_plugin *plugin, const char *filename, int ds_id, const char *fmt, ... )
{
char *buffer = malloc(BUFSIZE);
if (buffer == NULL) {
log_print(LOG_ERROR, "probe_submit: out of memory");
return -1;
}
va_list az;
va_start(az, fmt);
int len = vsnprintf(buffer, BUFSIZE, fmt, az);
va_end(az);
if (len < 0 || len >= BUFSIZE) {
log_print(LOG_ERROR, "probe_submit: %s arguments too long", plugin->name);
free(buffer);
return -1;
}
net_submit(hostname, plugin->name, filename, ds_id, buffer);
if (!(submit_flags & SUBMIT_NET_ONLY))
rrd_submit(hostname, plugin->name, filename, ds_id, buffer);
free(buffer);
return 0;
}

9
probe.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _PROBE_H_
#define _PROBE_H_
#include "plugins.h"
int probe_init(void);
int probe_submit(struct sammler_plugin *plugin, const char *filename, int ds_id, const char *fmt, ... );
#endif /* _PROBE_H_ */

232
rrdtool.c
View File

@ -17,6 +17,7 @@
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#if (WITH_RRD)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -26,178 +27,117 @@
#include <rrd.h>
#include "configfile.h"
#include "helper.h"
#include "linebuffer.h"
#include "list.h"
#include "logging.h"
#include "config.h"
#include "plugins.h"
#define DEFAULT_STEP 10
#define ARGCMAX 64
#define ARGVSIZE 1024
#define RRDTOOL_CREATE 1
#define RRDTOOL_UPDATE 2
#define BUFSIZE 1024
static int append_rra_config(char *buffer, int size, int *pos)
static const char *rrd_dir;
int sammler_rrd_init(void)
{
struct conf_section *section;
struct conf_tupel *tupel;
int len, rra_cnt = 0;
section = config_get_section("global");
if (section == NULL) {
log_print(LOG_ERROR, "append_ds_config: conf-section 'global' not found");
return -1;
}
list_for_each_entry(tupel, &section->tupel, list) {
if (strcmp(tupel->option, "rra"))
continue;
len = snprintf(buffer + *pos, size - *pos, "%s ", tupel->parameter);
if (len < 0 || len >= size - *pos) {
log_print(LOG_ERROR, "append_ds_config: arguments too long");
return -1;
}
*pos += len;
rra_cnt++;
}
return rra_cnt;
rrd_dir = config_get_string("global", "rrd_dir", ".");
return 0;
}
static int append_ds_config(char *buffer, int size, int *pos, int heartbeat, char **ds_def)
static int append_rra_config(const char *parameter, void *privdata)
{
int len, ds_cnt = 0;
char *dsbuild;
struct lbuf *buffer = (struct lbuf *)privdata;
dsbuild = malloc(BUFSIZE);
if (dsbuild == NULL) {
log_print(LOG_ERROR, "append_ds_config: out of memory");
return -1;
}
while (*ds_def != NULL) {
len = snprintf(dsbuild, BUFSIZE, *ds_def, heartbeat);
if (len < 0 || len >= BUFSIZE) {
log_print(LOG_ERROR, "append_ds_config: arguments too long");
free(dsbuild);
return -1;
}
len = snprintf(buffer + *pos, size - *pos, "%s ", dsbuild);
if (len < 0 || len >= size - *pos) {
log_print(LOG_ERROR, "append_ds_config: arguments too long");
free(dsbuild);
return -1;
}
*pos += len;
*ds_def++;
ds_cnt++;
}
free(dsbuild);
return ds_cnt;
lbuf_printf(buffer, "%s ", parameter);
return 0;
}
static int do_rrd(int mode, char *cmd)
static int do_rrd(int (*rrd_func)(int, char **), struct lbuf *buffer)
{
int argc;
size_t len;
char *cmd = lbuf_getdata(buffer, &len);
if (len < ARGVSIZE -1)
cmd[len] = '\0';
char *argv[ARGCMAX];
argc = strsplit(cmd, argv, ARGCMAX -1);
int argc = strsplit(cmd, " \t\n", argv, ARGCMAX -1);
argv[argc] = NULL;
optind = 0;
rrd_clear_error();
if (mode == RRDTOOL_CREATE) {
if (rrd_create(argc, argv) == -1) {
errno = 0;
log_print(LOG_ERROR, "rrd_create failed: %s: %s",
argv[2], rrd_get_error());
return -1;
}
} else if (mode == RRDTOOL_UPDATE) {
if (rrd_update(argc, argv) == -1) {
errno = 0;
log_print(LOG_ERROR, "rrd_update failed: %s: %s",
argv[2], rrd_get_error());
return -1;
}
int retval = rrd_func(argc, argv);
if (retval == -1) {
errno = 0;
log_print(LOG_ERROR, "rrd_func failed: %s: %s", argv[1], rrd_get_error());
}
return 0;
return retval;
}
static int rrd_create_file(char *filename, char **ds_def)
static int rrd_create_file(const char *filename, const char *pluginname, int ds_id)
{
int pos, step, heartbeat, retval;
char *buffer;
buffer = malloc(ARGVSIZE);
if (buffer == NULL) {
log_print(LOG_ERROR, "append_ds_config: out of memory");
struct sammler_plugin *plugin = plugin_lookup(pluginname);
if (plugin == NULL) {
log_print(LOG_ERROR, "rrd_create_file: plugin not found (%s)", pluginname);
return -1;
}
step = config_get_int("global", "step", DEFAULT_STEP);
heartbeat = (step * 2) + (step / 2);
const char *ds_def = plugin->get_ds(ds_id);
if (ds_def == NULL) {
log_print(LOG_ERROR, "No vaild DS found (%s:%d)", plugin->name, ds_id);
return -1;
}
pos = snprintf(buffer, ARGVSIZE, "create %s -s %d ", filename, step);
if (pos < 0 || pos >= ARGVSIZE) {
struct lbuf *buffer = lbuf_create(ARGVSIZE);
if (buffer == NULL) {
log_print(LOG_ERROR, "rrd_create_file: out of memory");
return -1;
}
int ret = lbuf_printf(buffer, "create %s -s %d %s ", filename, plugin->interval, ds_def);
if (ret == -1) {
log_print(LOG_ERROR, "rrd_create_file: arguments too long");
free(buffer);
lbuf_free(buffer);
return -1;
}
if (append_rra_config(buffer, ARGVSIZE, &pos) <= 0) {
free(buffer);
ret = config_get_strings("global", "rra", append_rra_config, buffer);
if (ret <= 0) {
lbuf_free(buffer);
return -1;
}
if (append_ds_config(buffer, ARGVSIZE, &pos, heartbeat, ds_def) <= 0) {
free(buffer);
return -1;
}
retval = do_rrd(RRDTOOL_CREATE, buffer);
free(buffer);
return retval;
ret = do_rrd(&rrd_create, buffer);
lbuf_free(buffer);
return ret;
}
static int rrd_update_file(char *filename, char *values)
static int rrd_update_file(const char *filename, const char *values)
{
int pos, retval;
char *buffer;
buffer = malloc(ARGVSIZE);
struct lbuf *buffer = lbuf_create(ARGVSIZE);
if (buffer == NULL) {
log_print(LOG_ERROR, "append_ds_config: out of memory");
return -1;
}
pos = snprintf(buffer, ARGVSIZE, "update %s %lu:%s", filename, time(NULL), values);
if (pos < 0 || pos >= ARGVSIZE) {
int ret = lbuf_printf(buffer, "update %s N:%s", filename, values);
if (ret == -1) {
log_print(LOG_ERROR, "rrd_update_file: arguments too long");
free(buffer);
lbuf_free(buffer);
return -1;
}
retval = do_rrd(RRDTOOL_UPDATE, buffer);
free(buffer);
return retval;
ret = do_rrd(&rrd_update, buffer);
lbuf_free(buffer);
return ret;
}
static int check_create_dir(char *dir)
static int check_create_dir(const char *dir)
{
struct stat statbuf;
if (stat(dir, &statbuf) == -1) {
@ -222,9 +162,9 @@ static int check_create_dir(char *dir)
static int create_parent_dirs(char *filename)
{
char *lastslash, *nextslash = filename;
char *nextslash = filename;
lastslash = strrchr(filename, '/');
char *lastslash = strrchr(filename, '/');
if (lastslash == NULL) {
log_print(LOG_ERROR, "create_parent_dirs: invalid file name");
return -1;
@ -254,63 +194,61 @@ static int create_parent_dirs(char *filename)
return 0;
}
void rrd_submit(char *plugin, int version, char *filename, int ds_id, char *data)
int rrd_submit(const char *hostname, const char *pluginname, const char *filename, int ds_id, const char *data)
{
struct stat statbuf;
static char *rrd_dir = NULL;
char *fullfile, **ds_def;
int len;
if (rrd_dir == NULL)
rrd_dir = config_get_string("global", "rrd_dir", ".");
fullfile = malloc(BUFSIZE);
char *fullfile = malloc(BUFSIZE);
if (fullfile == NULL) {
log_print(LOG_ERROR, "rrd_submit: out of memory");
return;
return -1;
}
len = snprintf(fullfile, BUFSIZE, "%s/%s", rrd_dir, filename);
int len = snprintf(fullfile, BUFSIZE, "%s/%s/%s", rrd_dir, hostname, filename);
if (len < 0 || len >= BUFSIZE) {
log_print(LOG_ERROR, "rrd_submit: arguments too long");
free(fullfile);
return;
return -1;
}
struct stat statbuf;
if (stat(fullfile, &statbuf) == -1) {
if (errno == ENOENT) {
errno = 0;
if (create_parent_dirs(fullfile) == -1) {
free(fullfile);
return;
return -1;
}
ds_def = plugins_get_ds(plugin, version, ds_id);
if (ds_def == NULL) {
log_print(LOG_ERROR, "No vaild DS found (%s v%d %d)", plugin, version, ds_id);
if (rrd_create_file(fullfile, pluginname, ds_id) == -1) {
free(fullfile);
return;
}
if (rrd_create_file(fullfile, ds_def) == -1) {
free(fullfile);
return;
return -1;
}
} else {
log_print(LOG_ERROR, "rrd_submit: stat(%s):", fullfile);
free(fullfile);
return;
return -1;
}
} else if (!S_ISREG (statbuf.st_mode)) {
log_print(LOG_ERROR, "rrd_submit: stat(%s): Not a regular file!", fullfile);
free(fullfile);
return;
return -1;
}
rrd_update_file(fullfile, data);
free(fullfile);
return 0;
}
#else /* (WITH_RRD) */
int sammler_rrd_init(void)
{
return 0;
}
int rrd_submit(const char *hostname, const char *pluginname, const char *filename, int ds_id, const char *data)
{
return 0;
}
#endif /* (WITH_RRD) */

View File

@ -1,6 +1,7 @@
#ifndef _RRDTOOL_H_
#define _RRDTOOL_H_
void rrd_submit(char *plugin, int version, char *filename, int ds_id, char *data);
int sammler_rrd_init(void);
int rrd_submit(const char *hostname, const char *pluginname, const char *filename, int ds_id, const char *data);
#endif /* _RRDTOOL_H_ */

102
sammler.c
View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 06/2006 by Olaf Rempel *
* Copyright (C) 03/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
@ -23,13 +23,23 @@
#include <string.h>
#include <getopt.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include "config.h"
#include "configfile.h"
#include "event.h"
#include "logging.h"
#include "network.h"
#include "rrdtool.h"
#include "pidfile.h"
#include "plugins.h"
#include "probe.h"
#include "signals.h"
#define DEFAULT_CONFIG "sammler.conf"
#define DEFAULT_LOGFILE "sammler.log"
#define DEFAULT_PIDFILE "sammler.pid"
static struct option opts[] = {
{"config", 1, 0, 'c'},
@ -38,6 +48,23 @@ static struct option opts[] = {
{0, 0, 0, 0}
};
static int restart_var;
static void trigger_restart(void *privdata)
{
restart_var = 1;
}
static int check_restart(int *maxfd, void *readfds, void *writefds, struct timeval *timeout, void *privdata)
{
if (restart_var == 1) {
restart_var = 0;
return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
char *config = DEFAULT_CONFIG;
@ -66,7 +93,7 @@ int main(int argc, char *argv[])
break;
case '?': /* error */
exit(-1);
exit(1);
break;
default: /* unknown / all options parsed */
@ -75,27 +102,72 @@ int main(int argc, char *argv[])
} while (code != -1);
/* parse config file */
if (!config_parse(config))
exit(-1);
if (config_parse(config) < 0)
exit(1);
if (!debug) {
/* check pidfile */
const char *pidfile = config_get_string("global", "pidfile", DEFAULT_PIDFILE);
if (pidfile_check(pidfile, 1) != 0) {
log_print(LOG_ERROR, "sammler already running");
exit(1);
}
/* check logfile */
char *logfile = config_get_string("global", "logfile", DEFAULT_LOGFILE);
if (logfile != NULL && debug == 0) {
/* start logging */
if (!log_init(logfile))
exit(-1);
const char *logfile = config_get_string("global", "logfile", DEFAULT_LOGFILE);
if (log_init(logfile) < 0)
exit(1);
/* zum daemon mutieren */
daemon(-1, 0);
if (daemon(-1, 0) < 0) {
log_print(LOG_ERROR, "failed to daemonize");
exit(1);
}
/* create pidfile */
if (pidfile_create(pidfile) < 0) {
log_print(LOG_ERROR, "failed to create pidfile %s", pidfile);
exit(1);
}
}
log_print(LOG_EVERYTIME, "sammler started");
signal_init();
signal_add_callback(SIGHUP, trigger_restart, NULL);
plugin_load_all();
log_print(LOG_EVERYTIME, "sammler started (pid:%d)", getpid());
while (1) {
plugins_probe();
sleep (10);
if (probe_init())
break;
if (net_init())
break;
if (sammler_rrd_init())
break;
if (plugin_init())
break;
/* exited on restart / SIGUSR1 */
event_loop(check_restart, NULL, NULL);
plugin_close();
net_close();
log_close();
config_free();
if (config_parse(config) < 0)
break;
const char *logfile = config_get_string("global", "logfile", DEFAULT_LOGFILE);
if (!debug && log_init(logfile) < 0)
break;
log_print(LOG_EVERYTIME, "sammler restarted (pid:%d) ", getpid());
}
return 0;

View File

@ -1,35 +1,62 @@
[global]
#hostname localhost
#listen 127.0.0.1:5000
#forward 127.0.0.1:5000
forward_only false
logfile sammler.log
plugin_dir .
plugin p_stat.so
plugin p_load.so
plugin p_memory.so
plugin p_vmstat.so
plugin p_uptime.so
plugin p_netdev.so
plugin p_mount.so
#plugin p_ctstat.so
plugin p_rtstat.so
plugin p_random.so
pidfile sammler.pid
rrd_dir rrd
step 10
plugin_dir plugins
plugin stat.so
plugin load.so
plugin memory.so
plugin vmstat.so
plugin uptime.so
plugin netdev.so
plugin mount.so
plugin diskstat.so
plugin ctstat.so
plugin rtstat.so
plugin random.so
#plugin mysql.so
#plugin apache.so
#plugin conntrack.so
#plugin hwmon.so
#plugin alixusv.so
#plugin ts2.so
#plugin diskstandby.so
#plugin hddtemp.so
# 1h(10s), 48h(1min), 7d(5min), 4w(30min)
rra RRA:MIN:0.1:1:360
rra RRA:MIN:0.1:6:2880
rra RRA:MIN:0.1:30:2016
rra RRA:MIN:0.1:180:1344
# 1h(10s), 12h(1min), 48h(2min), 14d(15min), 4w(60min), 2y(12h)
rra RRA:MIN:0.5:1:360 RRA:AVERAGE:0.5:1:360 RRA:MAX:0.5:1:360
rra RRA:MIN:0.5:6:720 RRA:AVERAGE:0.5:6:720 RRA:MAX:0.5:6:720
rra RRA:MIN:0.5:12:1440 RRA:AVERAGE:0.5:12:1440 RRA:MAX:0.5:12:1440
rra RRA:MIN:0.5:90:1344 RRA:AVERAGE:0.5:90:1344 RRA:MAX:0.5:90:1344
rra RRA:MIN:0.5:360:1440 RRA:AVERAGE:0.5:360:1440 RRA:MAX:0.5:360:1440
rra RRA:MIN:0.5:4320:1440 RRA:AVERAGE:0.5:4320:1440 RRA:MAX:0.5:4320:1440
rra RRA:AVERAGE:0.1:1:360
rra RRA:AVERAGE:0.1:6:2880
rra RRA:AVERAGE:0.1:30:2016
rra RRA:AVERAGE:0.1:180:1344
[p_mysql]
#server name,host,user,password
rra RRA:MAX:0.1:1:360
rra RRA:MAX:0.1:6:2880
rra RRA:MAX:0.1:30:2016
rra RRA:MAX:0.1:180:13446
[p_apache]
#server name,url,user,password
[p_hwmon]
#temp board,/sys/class/hwmon/hwmon0/device/temp1_input
#temp cpu,/sys/class/hwmon/hwmon0/device/temp2_input
[p_alixusv]
#socket /var/run/alix-usvd.sock
[p_ts2]
#server localhost,127.0.0.1:51234
[p_diskstandby]
#device /dev/sda
[p_hddtemp]
#server test,127.0.0.1:7634

896
sammler.php Normal file
View File

@ -0,0 +1,896 @@
<?php
define('CONFIG', '%%WWW_CONFIG%%');
define('BASE_DIR', '%%DATA_DIR%%');
define('RRDTOOL', '/usr/bin/rrdtool');
function setup_html($conf) {
echo "<html><head><title>sammler graph setup</title>\n";
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-15\"/>\n";
echo "</head><body>\n";
echo "<form method=\"POST\" action=\"{$_SERVER['SCRIPT_NAME']}?action=setup\">\n";
echo "<table>\n";
echo "<tr><td><b>Graph Height:</b></td>\n";
echo "<td><input type=\"text\" name=\"height\" value=\"{$conf['height']}\"></td></tr>\n";
echo "<tr><td><b>Graph Width:</b></td>\n";
echo "<td><input type=\"text\" name=\"width\" value=\"{$conf['width']}\"></td></tr>\n";
echo "<tr><td colspan=\"4\"><hr></td></tr>\n";
echo "<tr><td><b>Available Views:</b></td><td colspan=\"2\"></td><td><b>default</b></td></tr>\n";
foreach ($conf['views'] as $name => $value) {
echo "<tr><td>({$value}s)</td>\n";
echo "<td><input type=\"text\" name=\"views[$value]\" value=\"{$name}\"></td><td></td>\n";
if ($conf['default_view'] == $value)
echo "<td><input type=\"radio\" name=\"default_view\" value=\"{$value}\" checked=\"checked\"></td>\n";
else
echo "<td><input type=\"radio\" name=\"default_view\" value=\"{$value}\"></td>\n";
echo "</tr>\n";
}
echo "<tr><td><b>add view:</b></td><td><input type=\"text\" name=\"views[new]\"></td></tr>\n";
echo "<tr><td colspan=\"4\"><hr></td></tr>\n";
foreach ($conf['hosts'] as $hostid => $host) {
echo "<tr><td><b>Hostname:</b></td>\n";
echo "<td><input type=\"text\" name=\"hosts[{$hostid}][hostname]\" value=\"{$host['hostname']}\"></td>\n";
echo "<td><a href=\"{$_SERVER['SCRIPT_NAME']}?action=setup&sub=move_host_up&host={$hostid}\">up</a>&nbsp;\n";
echo "<a href=\"{$_SERVER['SCRIPT_NAME']}?action=setup&sub=move_host_down&host={$hostid}\">down</a></td>\n";
if ($host['show'])
echo "<td><input type=\"checkbox\" name=\"hosts[{$hostid}][show]\" checked=\"checked\">show</td>";
else
echo "<td><input type=\"checkbox\" name=\"hosts[{$hostid}][show]\">show</td>";
echo "</tr>\n";
foreach ($host['rrds'] as $rrdid => $rrd) {
echo "<tr><td>&nbsp;&nbsp;{$rrd['rrd']}</td>\n";
echo "<td><input type=\"text\" name=\"hosts[{$hostid}][rrds][{$rrdid}][title]\" value=\"{$rrd['title']}\"></td>\n";
echo "<td><a href=\"{$_SERVER['SCRIPT_NAME']}?action=setup&sub=move_rrd_up&host={$hostid}&rrd={$rrdid}\">up</a>&nbsp;\n";
echo "<a href=\"{$_SERVER['SCRIPT_NAME']}?action=setup&sub=move_rrd_down&host={$hostid}&rrd={$rrdid}\">down</a></td>\n";
if ($rrd['show'])
echo "<td><input type=\"checkbox\" name=\"hosts[{$hostid}][rrds][{$rrdid}][show]\" checked=\"checked\">show</td>";
else
echo "<td><input type=\"checkbox\" name=\"hosts[{$hostid}][rrds][{$rrdid}][show]\">show</td>";
echo "</tr>\n";
}
echo "<tr><td colspan=\"4\"><hr></td></tr>\n";
}
echo "<tr><td colspan=\"4\" align=\"center\">\n";
echo "<input type=\"button\" value=\"Show\" onClick=\"javascript:window.location.href='{$_SERVER['SCRIPT_NAME']}?action=show'\">&nbsp\n";
echo "<input type=\"submit\" value=\"Save Config\">&nbsp\n";
echo "<input type=\"button\" value=\"Rebuild Config\" onClick=\"javascript:window.location.href='{$_SERVER['SCRIPT_NAME']}?action=init'\">\n";
echo "</td></tr>\n";
echo "</table></form>\n";
echo "</body></html>\n";
}
function show_html($conf) {
echo "<html><head><title>Stats</title>\n";
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-15\"/>\n";
echo "</head><body>\n";
$hostid = isset($_GET['host']) ? $_GET['host'] : 0;
$view = isset($_GET['view']) ? $_GET['view'] : $conf['default_view'];
echo "<b>Select Host:</b>\n";
echo "<select name=\"host\" OnChange=\"document.location.href='{$_SERVER['SCRIPT_NAME']}?action=show&host='+this.value+'&view={$view}'\">\n";
foreach ($conf['hosts'] as $id => $host) {
if (!$host['show'])
continue;
if ($hostid == $id)
echo "<option value=\"{$id}\" selected=\"selected\">{$host['hostname']}</option>\n";
else
echo "<option value=\"{$id}\">{$host['hostname']}</option>\n";
}
echo "</select>&nbsp;\n";
echo "<td><select name=\"view\" OnChange=\"document.location.href='{$_SERVER['SCRIPT_NAME']}?action=show&host={$hostid}&view='+this.value\">\n";
foreach ($conf['views'] as $name => $value) {
if ($view == $value)
echo "<option value=\"{$value}\" selected=\"selected\">{$name}</option>\n";
else
echo "<option value=\"{$value}\">{$name}</option>\n";
}
echo "</select><br><br>\n";
foreach ($conf['hosts'][$hostid]['rrds'] as $rrdid => $rrd) {
if (!$rrd['show'])
continue;
echo "<img src=\"{$_SERVER['SCRIPT_NAME']}?action=rrd&host={$hostid}&rrd={$rrdid}&view={$view}\" border=\"0\"><br><br>\n";
}
echo "</body></html>\n";
}
function read_config($filename) {
$handle = @fopen($filename, "r");
if ($handle !== false && filesize($filename) > 0) {
$contents = fread($handle, filesize($filename));
fclose($handle);
return unserialize($contents);
}
}
function write_config($filename, $config) {
$handle = fopen($filename, "w+");
if ($handle !== false) {
$contents = serialize($config);
fwrite($handle, $contents);
fclose($handle);
}
}
function get_hostdirs() {
$retval = array();
$dh = opendir(BASE_DIR);
while (($file = readdir($dh)) !== false)
if (is_dir(BASE_DIR.$file) && $file != "." && $file != "..")
$retval[] = $file;
closedir($dh);
natsort($retval);
return $retval;
}
function get_rrdfiles($directory) {
$retval = array();
$dh = opendir(BASE_DIR.$directory);
while (($file = readdir($dh)) !== false) {
if (is_dir(BASE_DIR.$file))
continue;
if (strstr($file, "rrd") !== false)
$retval[] = $file;
}
closedir($dh);
natsort($retval);
return $retval;
}
function get_rrd_type($filename) {
$types = array_flip(array(
"cpu",
"load",
"memory",
"swap",
"proc",
"vmstat",
"random",
"uptime",
"hwmon",
"alixusv",
"net",
"rtstat",
"rtcache",
"ctstat",
"conntrack",
"disk",
"mount",
"apache",
"mysql",
"ts2"
));
$tmp1 = explode('-', $filename);
$tmp2 = explode('_', $tmp1[0]);
$type = $tmp2[0];
if (isset($types[$type]))
return $types[$type];
return $filename;
}
function rrd_sort($a, $b) {
if (!is_numeric($a['type']) && !is_numeric($b['type']))
return strcmp($a['type'], $b['type']);
if (is_numeric($a['type']) && !is_numeric($b['type']))
return -1;
if (!is_numeric($a['type']) && is_numeric($b['type']))
return +1;
if ($a['type'] > $b['type'])
return +1;
if ($a['type'] < $b['type'])
return -1;
return strcmp($a['title'], $b['title']);
}
function create_config() {
$conf = array();
$conf['default_view'] = 86400;
$conf['views'] = array("1 hour" => 3600,
"6 hours" => 21600,
"1 day" => 86400,
"1 week" => 604800,
"1 month" => 2678400);
$conf['height'] = 120;
$conf['width'] = 800;
$conf['hosts'] = array();
$hosts = get_hostdirs();
foreach ($hosts as $host) {
$rrds = array();
$tmp = get_rrdfiles($host);
foreach ($tmp as $file) {
$basename = str_replace(".rrd", "", basename($file));
$rrds[] = array(
'show' => true,
'title' => $basename,
'rrd' => "$host/$file",
'type' => get_rrd_type($basename),
);
}
uasort($rrds, rrd_sort);
$conf['hosts'][] = array(
'hostname' => $host,
'show' => true,
'rrds' => $rrds,
);
}
return $conf;
}
function setup($conf) {
if (isset($_GET['sub']) && $_GET['sub'] == "move_host_up") {
$hostid = isset($_GET['host']) ? $_GET['host'] : -1;
if (isset($conf['hosts'][$hostid]) && isset($conf['hosts'][$hostid -1])) {
$a = $conf['hosts'][$hostid];
$b = $conf['hosts'][$hostid -1];
$conf['hosts'][$hostid] = $b;
$conf['hosts'][$hostid -1] = $a;
}
return $conf;
} else if (isset($_GET['sub']) && $_GET['sub'] == "move_host_down") {
$hostid = isset($_GET['host']) ? $_GET['host'] : -1;
if (isset($conf['hosts'][$hostid]) && isset($conf['hosts'][$hostid +1])) {
$a = $conf['hosts'][$hostid];
$b = $conf['hosts'][$hostid +1];
$conf['hosts'][$hostid] = $b;
$conf['hosts'][$hostid +1] = $a;
}
return $conf;
} else if (isset($_GET['sub']) && $_GET['sub'] == "move_rrd_up") {
$hostid = isset($_GET['host']) ? $_GET['host'] : -1;
$rrdid = isset($_GET['rrd']) ? $_GET['rrd'] : -1;
if (isset($conf['hosts'][$hostid]['rrds'][$rrdid]) && isset($conf['hosts'][$hostid]['rrds'][$rrdid -1])) {
$a = $conf['hosts'][$hostid]['rrds'][$rrdid];
$b = $conf['hosts'][$hostid]['rrds'][$rrdid -1];
$conf['hosts'][$hostid]['rrds'][$rrdid] = $b;
$conf['hosts'][$hostid]['rrds'][$rrdid -1] = $a;
}
return $conf;
} else if (isset($_GET['sub']) && $_GET['sub'] == "move_rrd_down") {
$hostid = isset($_GET['host']) ? $_GET['host'] : -1;
$rrdid = isset($_GET['rrd']) ? $_GET['rrd'] : -1;
if (isset($conf['hosts'][$hostid]['rrds'][$rrdid]) && isset($conf['hosts'][$hostid]['rrds'][$rrdid +1])) {
$a = $conf['hosts'][$hostid]['rrds'][$rrdid];
$b = $conf['hosts'][$hostid]['rrds'][$rrdid +1];
$conf['hosts'][$hostid]['rrds'][$rrdid] = $b;
$conf['hosts'][$hostid]['rrds'][$rrdid +1] = $a;
}
return $conf;
} else if (!empty($_POST)) {
$conf['default_view'] = $_POST['default_view'];
$conf['height'] = $_POST['height'];
$conf['width'] = $_POST['width'];
$conf['views'] = array();
foreach ($_POST['views'] as $name) {
if (empty($name))
continue;
$tmp = strtotime($name);
if ($tmp != -1)
$conf['views'][$name] = $tmp - time();
}
natsort($conf['views']);
foreach ($_POST['hosts'] as $hostid => $host) {
$conf['hosts'][$hostid]['hostname'] = $host['hostname'];
$conf['hosts'][$hostid]['show'] = ($host['show'] == "on");
foreach ($host['rrds'] as $rrdid => $rrd) {
$conf['hosts'][$hostid]['rrds'][$rrdid]['title'] = $_POST['hosts'][$hostid]['rrds'][$rrdid]['title'];
$conf['hosts'][$hostid]['rrds'][$rrdid]['show'] = ($_POST['hosts'][$hostid]['rrds'][$rrdid]['show'] == "on");
}
}
return $conf;
} else {
setup_html($conf);
}
}
function show_rrd($conf) {
$hostid = isset($_GET['host']) ? $_GET['host'] : -1;
$rrdid = isset($_GET['rrd']) ? $_GET['rrd'] : -1;
if (!isset($conf['hosts'][$hostid]['rrds'][$rrdid]['rrd']))
return;
$view = isset($_GET['view']) ? -$_GET['view'] : -$conf['default_view'];
$rrdfile = BASE_DIR.$conf['hosts'][$hostid]['rrds'][$rrdid]['rrd'];
$title = $conf['hosts'][$hostid]['rrds'][$rrdid]['title'];
$height = $conf['height'];
$width = $conf['width'];
$cmd = RRDTOOL." graph - --imgformat PNG --start {$view} --end -10 --title \"{$title}\" --rigid ";
$tmp1 = explode('-', basename($rrdfile));
$tmp2 = explode('_', $tmp1[0]);
$tmp3 = explode('.', $tmp2[0]);
switch ($tmp3[0]) {
case 'alixusv':
$height *= 2;
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale --vertical-label=\"Voltage\" ".
"DEF:a={$rrdfile}:ibat:AVERAGE ".
"DEF:b={$rrdfile}:ubat:AVERAGE ".
"DEF:c={$rrdfile}:uin:AVERAGE ".
'CDEF:aa=a,50,/ '.
'CDEF:bb=b,1000,/ '.
'CDEF:cc=c,1000,/ '.
'CDEF:perr=aa,UN,INF,UNKN,IF CDEF:nerr=aa,UN,-INF,UNKN,IF '.
'HRULE:0#808080 AREA:perr#FFD0D0 AREA:nerr#FFD0D0 '.
'LINE2:aa#FF0000:"Ibat " GPRINT:a:LAST:"Current\:%7.0lf%smA" GPRINT:a:MIN:"Minimum\:%7.0lf%smA" GPRINT:a:MAX:"Maximum\:%7.0lf%smA\n" '.
'LINE2:bb#00CF00:"Ubat " GPRINT:bb:LAST:"Current\:%7.3lf%s V" GPRINT:bb:MIN:"Minimum\:%7.3lf%s V" GPRINT:bb:MAX:"Maximum\:%7.3lf%s V\n" '.
'LINE2:cc#0000FF:"Uin " GPRINT:cc:LAST:"Current\:%7.3lf%s V" GPRINT:cc:MIN:"Minimum\:%7.3lf%s V" GPRINT:cc:MAX:"Maximum\:%7.3lf%s V\n" '.
'';
break;
case 'apache':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"Workers\" ".
"DEF:aa={$rrdfile}:total_accesses:AVERAGE ".
"DEF:b={$rrdfile}:total_kbytes:AVERAGE ".
"DEF:c={$rrdfile}:busy_workers:AVERAGE ".
"DEF:d={$rrdfile}:idle_workers:AVERAGE ".
'CDEF:a=aa,60,* '.
'CDEF:err=aa,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:c#FF0000:"Busy Workers" GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:d#00CF00:"Idle Workers" GPRINT:d:LAST:"Current\:%8.2lf %s" GPRINT:d:AVERAGE:"Average\:%8.2lf %s" GPRINT:d:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE2:a#0000FF:"Accesses " GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'';
break;
case 'cpu':
$height *= 2;
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"percent\" ".
"DEF:a={$rrdfile}:user:AVERAGE ".
"DEF:b={$rrdfile}:nice:AVERAGE ".
"DEF:c={$rrdfile}:system:AVERAGE ".
"DEF:e={$rrdfile}:iowait:AVERAGE ".
"DEF:f={$rrdfile}:irq:AVERAGE ".
"DEF:g={$rrdfile}:softirq:AVERAGE ".
"DEF:h={$rrdfile}:steal:AVERAGE ".
"DEF:amax={$rrdfile}:user:MAX ".
"DEF:bmax={$rrdfile}:nice:MAX ".
"DEF:cmax={$rrdfile}:system:MAX ".
"DEF:emax={$rrdfile}:iowait:MAX ".
"DEF:fmax={$rrdfile}:irq:MAX ".
"DEF:gmax={$rrdfile}:softirq:MAX ".
"DEF:hmax={$rrdfile}:steal:MAX ".
"CDEF:allmax=amax,bmax,cmax,emax,fmax,gmax,hmax,+,+,+,+,+,+ ".
'CDEF:err=allmax,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:allmax#C0C0C0 LINE1:allmax#808080 '.
'AREA:c#FF0000:"System " GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:f#EA8F00:"IRQ " GPRINT:f:LAST:"Current\:%8.2lf %s" GPRINT:f:AVERAGE:"Average\:%8.2lf %s" GPRINT:f:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:g#FFFF00:"Soft-IRQ" GPRINT:g:LAST:"Current\:%8.2lf %s" GPRINT:g:AVERAGE:"Average\:%8.2lf %s" GPRINT:g:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:h#0040FF:"IO-Wait " GPRINT:e:LAST:"Current\:%8.2lf %s" GPRINT:e:AVERAGE:"Average\:%8.2lf %s" GPRINT:e:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:a#00CFCF:"User " GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:b#00CF00:"Nice " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:h#FF00FF:"Stolen " GPRINT:h:LAST:"Current\:%8.2lf %s" GPRINT:h:AVERAGE:"Average\:%8.2lf %s" GPRINT:h:MAX:"Maximum\:%8.2lf %s\n" ';
break;
case 'conntrack':
$tmp3 = explode('.', $tmp1[1]);
switch ($tmp3[0]) {
case 'proto':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"Connections\" ".
"DEF:a={$rrdfile}:tcp:AVERAGE ".
"DEF:b={$rrdfile}:udp:AVERAGE ".
"DEF:c={$rrdfile}:unknown:AVERAGE ".
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:a#00CF00:"tcp " GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:b#0000FF:"udp " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:c#FF0000:"unknown" GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" ';
break;
case 'tcp':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"TCP Connections\" ".
"DEF:a={$rrdfile}:none:AVERAGE ".
"DEF:b={$rrdfile}:syn_sent:AVERAGE ".
"DEF:c={$rrdfile}:syn_recv:AVERAGE ".
"DEF:d={$rrdfile}:established:AVERAGE ".
"DEF:e={$rrdfile}:fin_wait:AVERAGE ".
"DEF:f={$rrdfile}:close_wait:AVERAGE ".
"DEF:g={$rrdfile}:last_ack:AVERAGE ".
"DEF:h={$rrdfile}:time_wait:AVERAGE ".
"DEF:i={$rrdfile}:close:AVERAGE ".
"DEF:j={$rrdfile}:listen:AVERAGE ".
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:b#FF0000:"SYN_SEND " GPRINT:b:LAST:"Current\:%8.2lf" GPRINT:b:AVERAGE:"Average\:%8.2lf" GPRINT:b:MAX:"Maximum\:%8.2lf\n" '.
'STACK:f#FF00FF:"CLOSE_WAIT " GPRINT:f:LAST:"Current\:%8.2lf" GPRINT:f:AVERAGE:"Average\:%8.2lf" GPRINT:f:MAX:"Maximum\:%8.2lf\n" '.
'STACK:g#0000FF:"LAST_ACK " GPRINT:g:LAST:"Current\:%8.2lf" GPRINT:g:AVERAGE:"Average\:%8.2lf" GPRINT:g:MAX:"Maximum\:%8.2lf\n" '.
'STACK:h#007FFF:"TIME_WAIT " GPRINT:h:LAST:"Current\:%8.2lf" GPRINT:h:AVERAGE:"Average\:%8.2lf" GPRINT:h:MAX:"Maximum\:%8.2lf\n" '.
'STACK:c#00FFFF:"SYN_RECV " GPRINT:c:LAST:"Current\:%8.2lf" GPRINT:c:AVERAGE:"Average\:%8.2lf" GPRINT:c:MAX:"Maximum\:%8.2lf\n" '.
'STACK:d#00FF00:"ESTABLISHED" GPRINT:d:LAST:"Current\:%8.2lf" GPRINT:d:AVERAGE:"Average\:%8.2lf" GPRINT:d:MAX:"Maximum\:%8.2lf\n" '.
'STACK:e#FFFF00:"FIN_WAIT " GPRINT:e:LAST:"Current\:%8.2lf" GPRINT:e:AVERAGE:"Average\:%8.2lf" GPRINT:e:MAX:"Maximum\:%8.2lf\n" '.
'STACK:i#FF7F00:"CLOSE " GPRINT:i:LAST:"Current\:%8.2lf" GPRINT:i:AVERAGE:"Average\:%8.2lf" GPRINT:i:MAX:"Maximum\:%8.2lf\n" ';
break;
default:
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"Connections\" ".
"DEF:a={$rrdfile}:total:AVERAGE ".
"DEF:b={$rrdfile}:local:AVERAGE ".
"DEF:c={$rrdfile}:nated:AVERAGE ".
"DEF:d={$rrdfile}:unreplied:AVERAGE ".
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'LINE1:a#000000:"Total " GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'AREA:b#00CF00:"Local " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:c#0000FF:"NATed " GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:d#FF0000:"Unreplied" GPRINT:d:LAST:"Current\:%8.2lf %s" GPRINT:d:AVERAGE:"Average\:%8.2lf %s" GPRINT:d:MAX:"Maximum\:%8.2lf %s\n" ';
break;
}
break;
case 'ctstat':
$height *= 2;
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"calls\" ".
"DEF:a={$rrdfile}:searched:AVERAGE ".
"DEF:b={$rrdfile}:found:AVERAGE ".
"DEF:c={$rrdfile}:new:AVERAGE ".
"DEF:d={$rrdfile}:invalid:AVERAGE ".
"DEF:e={$rrdfile}:ignore:AVERAGE ".
"DEF:f={$rrdfile}:delete:AVERAGE ".
"DEF:g={$rrdfile}:delete_list:AVERAGE ".
"DEF:h={$rrdfile}:insert:AVERAGE ".
"DEF:i={$rrdfile}:insert_failed:AVERAGE ".
"DEF:j={$rrdfile}:drop:AVERAGE ".
"DEF:k={$rrdfile}:early_drop:AVERAGE ".
"DEF:l={$rrdfile}:icmp_error:AVERAGE ".
"DEF:m={$rrdfile}:expect_new:AVERAGE ".
"DEF:n={$rrdfile}:expect_create:AVERAGE ".
"DEF:o={$rrdfile}:expect_delete:AVERAGE ".
'CDEF:ii=i,-1,* '.
'CDEF:jj=j,-1,* '.
'CDEF:kk=k,-1,* '.
'CDEF:ll=l,-1,* '.
'CDEF:mm=m,-1,* '.
'CDEF:nn=n,-1,* '.
'CDEF:oo=o,-1,* '.
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'LINE1:a#FF0000:"searched " GPRINT:a:LAST:"Current\:%8.0lf" GPRINT:a:AVERAGE:"Average\:%8.0lf" GPRINT:a:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:b#FF00FF:"found " GPRINT:b:LAST:"Current\:%8.0lf" GPRINT:b:AVERAGE:"Average\:%8.0lf" GPRINT:b:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:c#0000FF:"new " GPRINT:c:LAST:"Current\:%8.0lf" GPRINT:c:AVERAGE:"Average\:%8.0lf" GPRINT:c:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:d#007FFF:"invalid " GPRINT:d:LAST:"Current\:%8.0lf" GPRINT:d:AVERAGE:"Average\:%8.0lf" GPRINT:d:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:e#00FFFF:"ignore " GPRINT:e:LAST:"Current\:%8.0lf" GPRINT:e:AVERAGE:"Average\:%8.0lf" GPRINT:e:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:f#00FF00:"delete " GPRINT:f:LAST:"Current\:%8.0lf" GPRINT:f:AVERAGE:"Average\:%8.0lf" GPRINT:f:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:g#FFFF00:"delete_list " GPRINT:g:LAST:"Current\:%8.0lf" GPRINT:g:AVERAGE:"Average\:%8.0lf" GPRINT:g:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:h#FF7F00:"insert " GPRINT:h:LAST:"Current\:%8.0lf" GPRINT:h:AVERAGE:"Average\:%8.0lf" GPRINT:h:MAX:"Maximum\:%8.0lf\n" '.
'HRULE:0#000000:"-\n" '.
'LINE1:ii#FF0000:"insert_failed " GPRINT:i:LAST:"Current\:%8.0lf" GPRINT:i:AVERAGE:"Average\:%8.0lf" GPRINT:i:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:jj#FF00FF:"drop " GPRINT:j:LAST:"Current\:%8.0lf" GPRINT:j:AVERAGE:"Average\:%8.0lf" GPRINT:j:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:kk#0000FF:"early_drop " GPRINT:k:LAST:"Current\:%8.0lf" GPRINT:k:AVERAGE:"Average\:%8.0lf" GPRINT:k:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:ll#007FFF:"icmp_errore " GPRINT:l:LAST:"Current\:%8.0lf" GPRINT:l:AVERAGE:"Average\:%8.0lf" GPRINT:l:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:mm#00FFFF:"expect_new " GPRINT:m:LAST:"Current\:%8.0lf" GPRINT:m:AVERAGE:"Average\:%8.0lf" GPRINT:m:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:nn#00FF00:"expect_create " GPRINT:n:LAST:"Current\:%8.0lf" GPRINT:n:AVERAGE:"Average\:%8.0lf" GPRINT:n:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:oo#FFFF00:"expect_delete " GPRINT:o:LAST:"Current\:%8.0lf" GPRINT:o:AVERAGE:"Average\:%8.0lf" GPRINT:o:MAX:"Maximum\:%8.0lf\n" ';
break;
case 'disk':
$height *= 2;
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"sectors\" ".
"DEF:a={$rrdfile}:read_cnt:AVERAGE ".
"DEF:b={$rrdfile}:read_sec:AVERAGE ".
"DEF:c={$rrdfile}:read_ms:AVERAGE ".
"DEF:dd={$rrdfile}:write_cnt:AVERAGE ".
"DEF:ee={$rrdfile}:write_cnt:AVERAGE ".
"DEF:ff={$rrdfile}:write_ms:AVERAGE ".
'CDEF:d=dd,-1,* '.
'CDEF:e=ee,-1,* '.
'CDEF:f=ff,-1,* '.
'CDEF:oerr=a,UN,INF,UNKN,IF CDEF:ierr=dd,UN,-INF,UNKN,IF '.
'HRULE:0#FF0000 AREA:ierr#FFD0D0 AREA:oerr#FFD0D0 '.
'LINE1:a#FF0000:"read_count " GPRINT:a:LAST:"Current\:%8.0lf" GPRINT:a:AVERAGE:"Average\:%8.0lf" GPRINT:a:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:b#FF00FF:"read_sectors " GPRINT:b:LAST:"Current\:%8.0lf" GPRINT:b:AVERAGE:"Average\:%8.0lf" GPRINT:b:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:c#0000FF:"sectors / ms " GPRINT:c:LAST:"Current\:%8.0lf" GPRINT:c:AVERAGE:"Average\:%8.0lf" GPRINT:c:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:d#FF0000:"write_count " GPRINT:dd:LAST:"Current\:%8.0lf" GPRINT:dd:AVERAGE:"Average\:%8.0lf" GPRINT:dd:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:e#FF00FF:"write_sectors " GPRINT:ee:LAST:"Current\:%8.0lf" GPRINT:ee:AVERAGE:"Average\:%8.0lf" GPRINT:ee:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:f#0000FF:"writes / ms " GPRINT:ff:LAST:"Current\:%8.0lf" GPRINT:ff:AVERAGE:"Average\:%8.0lf" GPRINT:ff:MAX:"Maximum\:%8.0lf\n" '.
'';
break;
case 'diskstandby':
$height /= 2;
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"Active\" ".
"DEF:a={$rrdfile}:active:AVERAGE ".
"CDEF:b=1,a,- ".
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:a#FF0000:"Active\n" '.
'STACK:b#00CF00:"Standby" ';
break;
case 'hddtemp':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"Temperature\" ".
"DEF:a={$rrdfile}:temperature:AVERAGE ".
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:a#00CF00:"Temperature" GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:a#404040 ';
break;
case 'hwmon':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"Temperature\" ".
"DEF:a={$rrdfile}:temp:AVERAGE ".
"CDEF:aa=a,1000,/ ".
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:aa#00CF00:"Temperature" GPRINT:aa:LAST:"Current\:%8.2lf %s" GPRINT:aa:AVERAGE:"Average\:%8.2lf %s" GPRINT:aa:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:aa#404040 ';
break;
case 'load':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"load\" ".
"DEF:a={$rrdfile}:1min:MAX ".
"DEF:b={$rrdfile}:5min:MAX ".
"DEF:c={$rrdfile}:15min:MAX ".
'CDEF:x=a,b,c,MAX,MAX '.
'CDEF:err=x,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:a#EACC00:" 1 Minute Maximum " GPRINT:a:LAST:"Current\:%8.2lf %s\n" '.
'AREA:b#EA8F00:" 5 Minute Maximum " GPRINT:b:LAST:"Current\:%8.2lf %s\n" '.
'AREA:c#FF0000:"15 Minute Maximum " GPRINT:c:LAST:"Current\:%8.2lf %s\n" '.
'LINE1:x#404040:"Total"';
break;
case 'memory':
$cmd .= "--base=1024 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"kB\" ".
"DEF:aa={$rrdfile}:total:AVERAGE ".
"DEF:bb={$rrdfile}:free:AVERAGE ".
"DEF:cc={$rrdfile}:buffers:AVERAGE ".
"DEF:dd={$rrdfile}:cached:AVERAGE ".
'CDEF:a=aa,1024,* '.
'CDEF:b=bb,1024,* '.
'CDEF:c=cc,1024,* '.
'CDEF:d=dd,1024,* '.
'CDEF:x=aa,bb,cc,dd,+,+,-,1024,* '.
'CDEF:xc=x,c,+ '.
'CDEF:xcd=x,c,d,+,+ '.
'CDEF:err=xcd,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'LINE1:a#000000:"Total Memory " GPRINT:a:LAST:"Current\:%8.2lf %s\n" '.
'AREA:x#FF0000:"Used Memory " GPRINT:x:LAST:"Current\:%8.2lf %s" GPRINT:x:AVERAGE:"Average\:%8.2lf %s" GPRINT:x:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:c#FF7D00:"Buffer Memory " GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:d#FFC73B:"Cache Memory " GPRINT:d:LAST:"Current\:%8.2lf %s" GPRINT:d:AVERAGE:"Average\:%8.2lf %s" GPRINT:d:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:b#00CF00:"Free Memory " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:x#404040 LINE1:xc#404040 LINE1:xcd#404040';
break;
case 'mount':
$cmd .= "--base=1024 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"kB\" ".
"DEF:aa={$rrdfile}:block_total:AVERAGE ".
"DEF:cc={$rrdfile}:block_free:AVERAGE ".
'CDEF:a=aa,1024,* '.
'CDEF:b=aa,cc,-,1024,* '.
'CDEF:c=cc,1024,* '.
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'LINE1:a#000000:"Total " GPRINT:a:LAST:"Current\:%8.2lf %s\n" '.
'AREA:b#FF0000:"Used " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:c#00CF00:"Free " GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:b#404040 ';
break;
case 'mysql':
switch ($tmp1[1]) {
case 'commands':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"commands\" ".
"DEF:aa={$rrdfile}:com_delete:AVERAGE ".
"DEF:bb={$rrdfile}:com_insert:AVERAGE ".
"DEF:cc={$rrdfile}:com_select:AVERAGE ".
"DEF:dd={$rrdfile}:com_update:AVERAGE ".
"DEF:ee={$rrdfile}:questions:AVERAGE ".
'CDEF:a=aa,60,* '.
'CDEF:b=bb,60,* '.
'CDEF:c=cc,60,* '.
'CDEF:d=dd,60,* '.
'CDEF:e=ee,60,* '.
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:e#0000FF:"All Commands " GPRINT:e:LAST:"Current\:%8.2lf %s" GPRINT:e:AVERAGE:"Average\:%8.2lf %s" GPRINT:e:MAX:"Maximum\:%8.2lf %s\n" '.
'AREA:a#FF0000:"DELETE ... " GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:b#FF7D00:"INSERT ... " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:d#FFC73B:"UPDATE ... " GPRINT:d:LAST:"Current\:%8.2lf %s" GPRINT:d:AVERAGE:"Average\:%8.2lf %s" GPRINT:d:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:c#00CF00:"SELECT ... " GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" '.
'';
break;
case 'qcache':
$cmd .= "--base=1024 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"???\" ".
"DEF:a={$rrdfile}:qc_free_blocks:AVERAGE ".
"DEF:b={$rrdfile}:qc_free_memory:AVERAGE ".
"DEF:cc={$rrdfile}:qc_hits:AVERAGE ".
"DEF:dd={$rrdfile}:qc_inserts:AVERAGE ".
"DEF:ee={$rrdfile}:qc_lowmem_prunes:AVERAGE ".
"DEF:ff={$rrdfile}:qc_not_cached:AVERAGE ".
"DEF:g={$rrdfile}:qc_queries_in_cache:AVERAGE ".
"DEF:h={$rrdfile}:qc_total_blocks:AVERAGE ".
'CDEF:c=cc,60,* '.
'CDEF:d=dd,60,* '.
'CDEF:e=ee,60,* '.
'CDEF:f=ff,60,* '.
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'LINE1:a#FF0000:"qc_free_blocks " GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:b#FFFF00:"qc_free_memory " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:c#00FF00:"qc_hits " GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:d#00FFFF:"qc_inserts " GPRINT:d:LAST:"Current\:%8.2lf %s" GPRINT:d:AVERAGE:"Average\:%8.2lf %s" GPRINT:d:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:e#0000FF:"qc_lowmemprunes " GPRINT:e:LAST:"Current\:%8.2lf %s" GPRINT:e:AVERAGE:"Average\:%8.2lf %s" GPRINT:e:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:f#FF00FF:"qc_not_cached " GPRINT:f:LAST:"Current\:%8.2lf %s" GPRINT:f:AVERAGE:"Average\:%8.2lf %s" GPRINT:f:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:g#FF00FF:"qc_queries_in_cache" GPRINT:g:LAST:"Current\:%8.2lf %s" GPRINT:g:AVERAGE:"Average\:%8.2lf %s" GPRINT:g:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:h#000000:"qc_total_blocks " GPRINT:h:LAST:"Current\:%8.2lf %s" GPRINT:h:AVERAGE:"Average\:%8.2lf %s" GPRINT:h:MAX:"Maximum\:%8.2lf %s\n" '.
'';
break;
case 'threads':
$cmd .= "--base=1024 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"threads\" ".
"DEF:a={$rrdfile}:threads_cached:AVERAGE ".
"DEF:b={$rrdfile}:threads_connected:AVERAGE ".
"DEF:cc={$rrdfile}:threads_created:AVERAGE ".
"DEF:d={$rrdfile}:threads_running:AVERAGE ".
'CDEF:c=cc,60,* '.
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'LINE1:c#00CF00:"threads created " GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:d#FF0000:"threads running " GPRINT:d:LAST:"Current\:%8.2lf %s" GPRINT:d:AVERAGE:"Average\:%8.2lf %s" GPRINT:d:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:b#00FFFF:"threads connected" GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:a#0000FF:"threads cached " GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'';
break;
case 'traffic':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"bytes per second\" ".
"DEF:imax={$rrdfile}:bytes_received:MAX ".
"DEF:iavg={$rrdfile}:bytes_received:AVERAGE ".
"DEF:imin={$rrdfile}:bytes_received:MIN ".
"DEF:omax={$rrdfile}:bytes_sent:MAX ".
"DEF:oavg={$rrdfile}:bytes_sent:AVERAGE ".
"DEF:omin={$rrdfile}:bytes_sent:MIN ".
'CDEF:omaxn=omax,-1,* CDEF:oavgn=oavg,-1,* CDEF:ominn=omin,-1,* '.
'CDEF:imid=imax,imin,- CDEF:omid=omaxn,ominn,- '.
'CDEF:oerr=oavg,UN,INF,UNKN,IF CDEF:ierr=iavg,UN,-INF,UNKN,IF '.
'HRULE:0#FF0000 AREA:ierr#FFD0D0 AREA:oerr#FFD0D0 '.
'AREA:imin STACK:imid#A0FFA0:"min/max Inbound " GPRINT:imin:MIN:"%6.2lf%s" GPRINT:imax:MAX:"%6.2lf%s" '.
'LINE1:imin#a0a0a0 LINE1:imax#a0a0a0 LINE1:iavg#008000:"avg Inbound " '.
'GPRINT:iavg:MIN:"min\: %6.2lf%s" GPRINT:iavg:AVERAGE:"avg\: %6.2lf%s" GPRINT:iavg:MAX:"max\: %6.2lf%s\n" '.
'AREA:ominn STACK:omid#C0C0FF:"min/max Outbound" GPRINT:omin:MIN:"%6.2lf%s" GPRINT:omax:MAX:"%6.2lf%s" '.
'LINE1:ominn#a0a0a0 LINE1:omaxn#a0a0a0 LINE1:oavgn#000080:"avg Outbound" '.
'GPRINT:oavg:MIN:"min\: %6.2lf%s" GPRINT:oavg:AVERAGE:"avg\: %6.2lf%s" GPRINT:oavg:MAX:"max\: %6.2lf%s\n" ';
break;
}
break;
case 'net':
$height *= 2;
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"bytes per second\" ".
"DEF:imax={$rrdfile}:byte_in:MAX ".
"DEF:iavg={$rrdfile}:byte_in:AVERAGE ".
"DEF:imin={$rrdfile}:byte_in:MIN ".
"DEF:omax={$rrdfile}:byte_out:MAX ".
"DEF:oavg={$rrdfile}:byte_out:AVERAGE ".
"DEF:omin={$rrdfile}:byte_out:MIN ".
'CDEF:omaxn=omax,-1,* CDEF:oavgn=oavg,-1,* CDEF:ominn=omin,-1,* '.
'CDEF:imid=imax,imin,- CDEF:omid=omaxn,ominn,- '.
'CDEF:oerr=oavg,UN,INF,UNKN,IF CDEF:ierr=iavg,UN,-INF,UNKN,IF '.
'HRULE:0#FF0000 AREA:ierr#FFD0D0 AREA:oerr#FFD0D0 '.
'AREA:imin#E0FFE0 STACK:imid#A0FFA0:"min/max Inbound " GPRINT:imin:MIN:"%6.2lf%s" GPRINT:imax:MAX:"%6.2lf%s" '.
'LINE1:imin#a0a0a0 LINE1:imax#a0a0a0 LINE1:iavg#008000:"avg Inbound " '.
'GPRINT:iavg:MIN:"min\: %6.2lf%s" GPRINT:iavg:AVERAGE:"avg\: %6.2lf%s" GPRINT:iavg:MAX:"max\: %6.2lf%s\n" '.
'AREA:ominn#E0E0FF STACK:omid#C0C0FF:"min/max Outbound" GPRINT:omin:MIN:"%6.2lf%s" GPRINT:omax:MAX:"%6.2lf%s" '.
'LINE1:ominn#a0a0a0 LINE1:omaxn#a0a0a0 LINE1:oavgn#000080:"avg Outbound" '.
'GPRINT:oavg:MIN:"min\: %6.2lf%s" GPRINT:oavg:AVERAGE:"avg\: %6.2lf%s" GPRINT:oavg:MAX:"max\: %6.2lf%s\n" ';
break;
case 'proc':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"per second\" ".
"DEF:a={$rrdfile}:intr:AVERAGE ".
"DEF:b={$rrdfile}:ctxt:AVERAGE ".
"DEF:c={$rrdfile}:fork:AVERAGE ".
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:b#00AF00:"Context " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:a#FF0000:"Interrupts" GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:c#0000FF:"Forks " GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" ';
break;
case 'random':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit 0 --vertical-label=\"bytes\" ".
"DEF:a={$rrdfile}:entropy:AVERAGE ".
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:a#00CF00:"Available Entropy" GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:a#404040 ';
break;
case 'rtcache':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"calls\" ".
"DEF:a={$rrdfile}:entries:AVERAGE ".
"DEF:b={$rrdfile}:gc_total:AVERAGE ".
"DEF:c={$rrdfile}:gc_ignored:AVERAGE ".
"DEF:d={$rrdfile}:gc_goal_miss:AVERAGE ".
"DEF:e={$rrdfile}:gc_dst_overflow:AVERAGE ".
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'LINE1:a#FF0000:"entries " GPRINT:a:LAST:"Current\:%8.0lf" GPRINT:a:AVERAGE:"Average\:%8.0lf" GPRINT:a:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:b#FF00FF:"gc_total " GPRINT:b:LAST:"Current\:%8.0lf" GPRINT:b:AVERAGE:"Average\:%8.0lf" GPRINT:b:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:c#0000FF:"gc_ignored " GPRINT:c:LAST:"Current\:%8.0lf" GPRINT:c:AVERAGE:"Average\:%8.0lf" GPRINT:c:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:d#007FFF:"gc_goal_miss " GPRINT:d:LAST:"Current\:%8.0lf" GPRINT:d:AVERAGE:"Average\:%8.0lf" GPRINT:d:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:e#00FFFF:"gc_dst_overflow " GPRINT:e:LAST:"Current\:%8.0lf" GPRINT:e:AVERAGE:"Average\:%8.0lf" GPRINT:e:MAX:"Maximum\:%8.0lf\n" ';
break;
case 'rtstat':
$height *= 2;
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"calls\" ".
"DEF:a={$rrdfile}:in_hit:AVERAGE ".
"DEF:b={$rrdfile}:in_slow_tot:AVERAGE ".
"DEF:c={$rrdfile}:in_slow_mc:AVERAGE ".
"DEF:d={$rrdfile}:in_no_route:AVERAGE ".
"DEF:e={$rrdfile}:in_brd:AVERAGE ".
"DEF:f={$rrdfile}:in_martian_dst:AVERAGE ".
"DEF:g={$rrdfile}:in_martian_src:AVERAGE ".
"DEF:h={$rrdfile}:in_hlist_search:AVERAGE ".
"DEF:i={$rrdfile}:out_hit:AVERAGE ".
"DEF:j={$rrdfile}:out_slow_tot:AVERAGE ".
"DEF:k={$rrdfile}:out_slow_mc:AVERAGE ".
"DEF:l={$rrdfile}:out_hlist_search:AVERAGE ".
'CDEF:ii=i,-1,* '.
'CDEF:jj=j,-1,* '.
'CDEF:kk=k,-1,* '.
'CDEF:ll=l,-1,* '.
'CDEF:oerr=a,UN,INF,UNKN,IF CDEF:ierr=i,UN,-INF,UNKN,IF '.
'AREA:ierr#FFD0D0 AREA:oerr#FFD0D0 '.
'LINE1:a#FF0000:"in_hit " GPRINT:a:LAST:"Current\:%8.0lf" GPRINT:a:AVERAGE:"Average\:%8.0lf" GPRINT:a:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:b#FF00FF:"in_slow_tot " GPRINT:b:LAST:"Current\:%8.0lf" GPRINT:b:AVERAGE:"Average\:%8.0lf" GPRINT:b:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:c#0000FF:"in_slow_mc " GPRINT:c:LAST:"Current\:%8.0lf" GPRINT:c:AVERAGE:"Average\:%8.0lf" GPRINT:c:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:d#007FFF:"in_no_route " GPRINT:d:LAST:"Current\:%8.0lf" GPRINT:d:AVERAGE:"Average\:%8.0lf" GPRINT:d:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:e#00FFFF:"in_brd " GPRINT:e:LAST:"Current\:%8.0lf" GPRINT:e:AVERAGE:"Average\:%8.0lf" GPRINT:e:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:f#00FF00:"in_martian_dst " GPRINT:f:LAST:"Current\:%8.0lf" GPRINT:f:AVERAGE:"Average\:%8.0lf" GPRINT:f:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:g#FFFF00:"in_martian_src " GPRINT:g:LAST:"Current\:%8.0lf" GPRINT:g:AVERAGE:"Average\:%8.0lf" GPRINT:g:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:h#FF7F00:"in_hlist_search " GPRINT:h:LAST:"Current\:%8.0lf" GPRINT:h:AVERAGE:"Average\:%8.0lf" GPRINT:h:MAX:"Maximum\:%8.0lf\n" '.
'HRULE:0#FF0000:"-\n" '.
'LINE1:ii#FF0000:"out_hit " GPRINT:i:LAST:"Current\:%8.0lf" GPRINT:i:AVERAGE:"Average\:%8.0lf" GPRINT:i:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:jj#FF00FF:"out_slow_tot " GPRINT:j:LAST:"Current\:%8.0lf" GPRINT:j:AVERAGE:"Average\:%8.0lf" GPRINT:j:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:kk#0000FF:"out_slow_mc " GPRINT:k:LAST:"Current\:%8.0lf" GPRINT:k:AVERAGE:"Average\:%8.0lf" GPRINT:k:MAX:"Maximum\:%8.0lf\n" '.
'LINE1:ll#FF7F00:"out_hlist_search " GPRINT:l:LAST:"Current\:%8.0lf" GPRINT:l:AVERAGE:"Average\:%8.0lf" GPRINT:l:MAX:"Maximum\:%8.0lf\n" ';
break;
case 'swap':
$cmd .= "--base=1024 --height={$height} --width={$width} --alt-autoscale-max --lower-limit=0 --vertical-label=\"kB\" ".
"DEF:aa={$rrdfile}:total:AVERAGE ".
"DEF:bb={$rrdfile}:free:AVERAGE ".
'CDEF:a=aa,1024,* '.
'CDEF:b=bb,1024,* '.
'CDEF:x=aa,bb,-,1024,* '.
'CDEF:err=a,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'LINE1:a#000000:"Total Swap " GPRINT:a:LAST:"Current\:%8.2lf %s\n" '.
'AREA:x#FF0000:"Used Swap " GPRINT:x:LAST:"Current\:%8.2lf %s" GPRINT:x:AVERAGE:"Average\:%8.2lf %s" GPRINT:x:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:b#00CF00:"Free Swap " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" ';
break;
case 'ts2':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit 0 --vertical-label=\"users/chans\" ".
"DEF:users={$rrdfile}:users:AVERAGE ".
"DEF:chans={$rrdfile}:channels:AVERAGE ".
'CDEF:err=users,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:chans#00CF00:"Channels \n" '.
'LINE1:users#002A97:"Users "';
break;
case 'uptime':
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --lower-limit 0 --vertical-label=\"days\" ".
"DEF:ups={$rrdfile}:uptime:AVERAGE ".
"DEF:idles={$rrdfile}:idletime:AVERAGE ".
'CDEF:up=ups,86400,/ '.
'CDEF:idle=idles,86400,/ '.
'CDEF:err=ups,UN,INF,UNKN,IF '.
'AREA:err#FFD0D0 '.
'AREA:up#00CF00:"Uptime \n" '.
'LINE1:idle#002A97:"Idletime "';
break;
case 'vmstat':
$height *= 2;
$cmd .= "--base=1000 --height={$height} --width={$width} --alt-autoscale-max --vertical-label=\"allocs\" ".
"DEF:a={$rrdfile}:pgalloc_high:AVERAGE ".
"DEF:b={$rrdfile}:pgalloc_normal:AVERAGE ".
"DEF:c={$rrdfile}:pgalloc_dma:AVERAGE ".
"DEF:d={$rrdfile}:pgfree:AVERAGE ".
"DEF:e={$rrdfile}:pgfault:AVERAGE ".
"CDEF:ee=e,-1,* ".
'CDEF:oerr=a,UN,INF,UNKN,IF CDEF:ierr=e,UN,-INF,UNKN,IF '.
'AREA:ierr#FFD0D0 AREA:oerr#FFD0D0 '.
'HRULE:0#FF0000: '.
'AREA:c#FF0000:"pgalloc_dma " GPRINT:c:LAST:"Current\:%8.2lf %s" GPRINT:c:AVERAGE:"Average\:%8.2lf %s" GPRINT:c:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:b#00CF00:"pgalloc_normal " GPRINT:b:LAST:"Current\:%8.2lf %s" GPRINT:b:AVERAGE:"Average\:%8.2lf %s" GPRINT:b:MAX:"Maximum\:%8.2lf %s\n" '.
'STACK:a#00CFCF:"pgalloc_high " GPRINT:a:LAST:"Current\:%8.2lf %s" GPRINT:a:AVERAGE:"Average\:%8.2lf %s" GPRINT:a:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:d#FF7D00:"pgfree " GPRINT:d:LAST:"Current\:%8.2lf %s" GPRINT:d:AVERAGE:"Average\:%8.2lf %s" GPRINT:d:MAX:"Maximum\:%8.2lf %s\n" '.
'AREA:ee#0040FF:"pgfault " GPRINT:e:LAST:"Current\:%8.2lf %s" GPRINT:e:AVERAGE:"Average\:%8.2lf %s" GPRINT:e:MAX:"Maximum\:%8.2lf %s\n" '.
'LINE1:ee#002A97 ';
break;
}
header('Content-type: image/x-png');
passthru($cmd);
die();
}
$action = $_GET['action'];
switch ($action) {
case 'init':
$conf = create_config();
write_config(CONFIG, $conf);
header("Location: {$_SERVER['SCRIPT_NAME']}?action=setup");
break;
case 'setup':
$conf = read_config(CONFIG);
$conf = setup($conf);
if (isset($conf)) {
write_config(CONFIG, $conf);
header("Location: {$_SERVER['SCRIPT_NAME']}?action=setup");
}
break;
case 'rrd':
$conf = read_config(CONFIG);
show_rrd($conf);
break;
default:
case 'show':
$conf = read_config(CONFIG);
show_html($conf);
break;
}
?>

151
signals.c Normal file
View File

@ -0,0 +1,151 @@
/***************************************************************************
* Copyright (C) 05/2009 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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; version 2 of the License *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include "event.h"
#include "list.h"
#include "logging.h"
#include "signals.h"
struct signal_entry {
struct list_head list;
int signum;
int deleted;
void (*callback)(void *privdata);
void *privdata;
};
static LIST_HEAD(callback_list);
static int sig_pipe[2];
static void sig_handler(int signal)
{
unsigned char signum = (signal & 0xFF);
write(sig_pipe[1], &signum, 1);
}
int signal_remove_callback(int signum, int type)
{
/* mark all old handler for deletion */
struct signal_entry *search;
list_for_each_entry(search, &callback_list, list) {
if (search->signum == signum)
search->deleted = 1;
}
struct sigaction sig_action;
switch (type) {
case SIG_IGNORE:
sig_action.sa_handler = SIG_IGN;
break;
default:
case SIG_DEFAULT:
sig_action.sa_handler = SIG_DFL;
break;
}
if (sigaction(signum, &sig_action, NULL) < 0) {
log_print(LOG_WARN, "%s(): sigaction(%d)", __FUNCTION__, signum);
return -1;
}
/* trigger remove */
sig_handler(0);
return 0;
}
int signal_add_callback(int signum, void (*callback)(void *privdata), void *privdata)
{
struct signal_entry *entry = malloc(sizeof(struct signal_entry));
if (entry == NULL) {
log_print(LOG_WARN, "%s(): out of memory", __FUNCTION__);
return -1;
}
entry->signum = signum;
entry->deleted = 0;
entry->callback = callback;
entry->privdata = privdata;
list_add_tail(&entry->list, &callback_list);
struct sigaction sig_action = {
.sa_handler = sig_handler,
};
if (sigaction(signum, &sig_action, NULL) < 0) {
log_print(LOG_WARN, "%s(): sigaction(%d)", __FUNCTION__, signum);
list_del(&entry->list);
free(entry);
return -1;
}
return 0;
}
static int sig_event(int fd, void *privdata)
{
unsigned char signum;
int len = read(fd, &signum, 1);
if (len <= 0) {
log_print(LOG_WARN, "%s(): read()", __FUNCTION__);
return -1;
}
struct signal_entry *search, *tmp;
list_for_each_entry_safe(search, tmp, &callback_list, list) {
if (search->deleted) {
list_del(&search->list);
free(search);
continue;
}
if (search->signum == signum)
search->callback(search->privdata);
}
return 0;
}
int signal_init(void)
{
if (pipe(sig_pipe) < 0) {
log_print(LOG_ERROR, "%s(): pipe()", __FUNCTION__);
return -1;
}
if (fcntl(sig_pipe[0], F_SETFD, FD_CLOEXEC) < 0) {
log_print(LOG_WARN, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
return -1;
}
if (fcntl(sig_pipe[1], F_SETFD, FD_CLOEXEC) < 0) {
log_print(LOG_WARN, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
return -1;
}
event_add_readfd(NULL, sig_pipe[0], sig_event, NULL);
return 0;
}

12
signals.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _SIGNALS_H
#define _SIGNALS_H
#define SIG_DEFAULT 0x00
#define SIG_IGNORE 0x01
int signal_remove_callback(int signum, int type);
int signal_add_callback(int signum, void (*callback)(void *privdata), void *privdata);
int signal_init(void);
#endif // _SIGNALS_H

117
sockaddr.c Normal file
View File

@ -0,0 +1,117 @@
/***************************************************************************
* Copyright (C) 07/2007 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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; version 2 of the License *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int parse_sockaddr(const char *addr, struct sockaddr_in *sa)
{
char *buf = strdup(addr);
if (buf == NULL)
return -1;
char *tmp;
char *ipstr = strtok_r(buf, ":", &tmp);
if (ipstr == NULL) {
free(buf);
return -2;
}
sa->sin_family = AF_INET;
if (inet_pton(AF_INET, ipstr, &sa->sin_addr) <= 0) {
free(buf);
return -3;
}
char *portstr = strtok_r(NULL, " \r\n", &tmp);
if (portstr == NULL) {
free(buf);
return -4;
}
int port = atoi(portstr);
if (port < 0 || port > 65535) {
free(buf);
return -5;
}
sa->sin_port = htons(port);
free(buf);
return 0;
}
int parse_subnet(const char *addr, struct in_addr *net, struct in_addr *mask)
{
char *buf = strdup(addr);
if (buf == NULL)
return -1;
char *tmp;
char *netstr = strtok_r(buf, "/", &tmp);
if (netstr == NULL) {
free(buf);
return -2;
}
if (inet_pton(AF_INET, netstr, net) <= 0) {
free(buf);
return -3;
}
char *maskstr = strtok_r(NULL, " \r\n", &tmp);
if (maskstr == NULL) {
mask->s_addr = ~0;
} else if (inet_pton(AF_INET, maskstr, mask) <= 0) {
int maskbits = atoi(maskstr);
if (maskbits < 0 || maskbits > 32) {
free(buf);
return -4;
}
mask->s_addr = htonl(~0 << (32 - maskbits));
}
free(buf);
return 0;
}
int get_sockaddr(char *buf, int size, struct sockaddr_in *addr)
{
return snprintf(buf, size, "%s:%d", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
char * get_sockaddr_buf(struct sockaddr_in *addr)
{
static char ret[24];
get_sockaddr(ret, sizeof(ret), addr);
return ret;
}
int same_sockaddr(struct sockaddr_in *a, struct sockaddr_in *b)
{
return !((a->sin_family ^ b->sin_family) |
(a->sin_addr.s_addr ^ b->sin_addr.s_addr) |
(a->sin_port ^ b->sin_port));
}

14
sockaddr.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _SOCKADDR_H_
#define _SOCKADDR_H_
#include <netinet/in.h>
int parse_sockaddr(const char *addr, struct sockaddr_in *sa);
int parse_subnet(const char *addr, struct in_addr *net, struct in_addr *mask);
int get_sockaddr(char *buf, int size, struct sockaddr_in *addr);
char * get_sockaddr_buf(struct sockaddr_in *addr);
int same_sockaddr(struct sockaddr_in *a, struct sockaddr_in *b);
#endif /* _SOCKADDR_H_ */