sammler/rrdtool.c

252 lines
6.3 KiB
C

/***************************************************************************
* 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 <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <rrd.h>
#include "configfile.h"
#include "helper.h"
#include "list.h"
#include "logging.h"
#include "plugins.h"
#define DEFAULT_STEP 10
#define ARGCMAX 64
#define ARGVSIZE 1024
#define BUFSIZE 1024
struct rra_cb_data {
char *buffer;
int size;
int *pos;
};
static const char *rrd_dir;
int sammler_rrd_init(void)
{
rrd_dir = config_get_string("global", "rrd_dir", ".");
return 0;
}
static int append_rra_config(const char *parameter, void *privdata)
{
struct rra_cb_data *data = (struct rra_cb_data *)privdata;
int len = snprintf(data->buffer + *(data->pos), data->size - *(data->pos), "%s ", parameter);
if (len < 0 || len >= data->size - *(data->pos)) {
log_print(LOG_ERROR, "append_rra_config_cb: arguments too long");
return -1;
}
*(data->pos) += len;
return 0;
}
static int do_rrd(int (*rrd_func)(int, char **), char *cmd)
{
char *argv[ARGCMAX];
int argc = strsplit(cmd, " \t\n", argv, ARGCMAX -1);
argv[argc] = NULL;
optind = 0;
rrd_clear_error();
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());
}
free(cmd);
return retval;
}
static int rrd_create_file(const char *filename, const char *pluginname, int ds_id)
{
struct sammler_plugin *plugin = plugin_lookup(pluginname);
if (plugin == NULL) {
log_print(LOG_ERROR, "rrd_create_file: plugin not found (%s)", pluginname);
return -1;
}
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;
}
char *buffer = malloc(ARGVSIZE);
if (buffer == NULL) {
log_print(LOG_ERROR, "rrd_create_file: out of memory");
return -1;
}
int step = plugin->interval;
int pos = snprintf(buffer, ARGVSIZE, "create %s -s %d %s ", filename, step, ds_def);
if (pos < 0 || pos >= ARGVSIZE) {
log_print(LOG_ERROR, "rrd_create_file: arguments too long");
free(buffer);
return -1;
}
struct rra_cb_data data = {
.buffer = buffer,
.size = ARGVSIZE,
.pos = &pos,
};
int cnt = config_get_strings("global", "rra", append_rra_config, &data);
if (cnt <= 0) {
free(buffer);
return -1;
}
return do_rrd(&rrd_create, buffer);
}
static int rrd_update_file(const char *filename, const char *values)
{
char *buffer = malloc(ARGVSIZE);
if (buffer == NULL) {
log_print(LOG_ERROR, "append_ds_config: out of memory");
return -1;
}
int pos = snprintf(buffer, ARGVSIZE, "update %s N:%s", filename, values);
if (pos < 0 || pos >= ARGVSIZE) {
log_print(LOG_ERROR, "rrd_update_file: arguments too long");
free(buffer);
return -1;
}
return do_rrd(&rrd_update, buffer);
}
static int check_create_dir(const char *dir)
{
struct stat statbuf;
if (stat(dir, &statbuf) == -1) {
if (errno == ENOENT) {
errno = 0;
if (mkdir(dir, 0755) == -1) {
log_print(LOG_ERROR, "check_create_dir: mkdir(%s)", dir);
return -1;
}
} else {
log_print(LOG_ERROR, "check_create_dir: stat(%s)", dir);
return -1;
}
} else if (!S_ISDIR (statbuf.st_mode)) {
log_print(LOG_ERROR, "check_create_dir: stat(%s): Not a directory!", dir);
return -1;
}
return 0;
}
static int create_parent_dirs(char *filename)
{
char *nextslash = filename;
char *lastslash = strrchr(filename, '/');
if (lastslash == NULL) {
log_print(LOG_ERROR, "create_parent_dirs: invalid file name");
return -1;
}
*lastslash = '\0';
while (1) {
if (strchr(nextslash, '/') == NULL) {
if (*lastslash == '\0')
*lastslash = '/';
else
break;
}
nextslash = strchr(nextslash, '/');
*nextslash = '\0';
if (filename != nextslash) {
if (check_create_dir(filename) == -1) {
*nextslash = '/';
*lastslash = '/';
return -1;
}
}
*nextslash++ = '/';
}
return 0;
}
int rrd_submit(const char *hostname, const char *pluginname, const char *filename, int ds_id, const char *data)
{
char *fullfile = malloc(BUFSIZE);
if (fullfile == NULL) {
log_print(LOG_ERROR, "rrd_submit: out of memory");
return -1;
}
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 -1;
}
struct stat statbuf;
if (stat(fullfile, &statbuf) == -1) {
if (errno == ENOENT) {
errno = 0;
if (create_parent_dirs(fullfile) == -1) {
free(fullfile);
return -1;
}
if (rrd_create_file(fullfile, pluginname, ds_id) == -1) {
free(fullfile);
return -1;
}
} else {
log_print(LOG_ERROR, "rrd_submit: stat(%s):", fullfile);
free(fullfile);
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 -1;
}
rrd_update_file(fullfile, data);
free(fullfile);
return 0;
}