2006-06-13 21:34:36 +02:00
|
|
|
/***************************************************************************
|
|
|
|
* 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 "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)
|
|
|
|
{
|
|
|
|
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, §ion->tupel, list) {
|
|
|
|
if (strcmp(tupel->option, "rra"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
len = snprintf(buffer + *pos, size - *pos, "%s ", tupel->parameter);
|
2006-06-22 20:33:30 +02:00
|
|
|
if (len < 0 || len >= size - *pos) {
|
2006-06-13 21:34:36 +02:00
|
|
|
log_print(LOG_ERROR, "append_ds_config: arguments too long");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pos += len;
|
|
|
|
rra_cnt++;
|
|
|
|
}
|
|
|
|
return rra_cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int append_ds_config(char *buffer, int size, int *pos, int heartbeat, char **ds_def)
|
|
|
|
{
|
|
|
|
int len, ds_cnt = 0;
|
|
|
|
char *dsbuild;
|
|
|
|
|
|
|
|
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);
|
2006-06-22 20:33:30 +02:00
|
|
|
if (len < 0 || len >= BUFSIZE) {
|
2006-06-13 21:34:36 +02:00
|
|
|
log_print(LOG_ERROR, "append_ds_config: arguments too long");
|
|
|
|
free(dsbuild);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = snprintf(buffer + *pos, size - *pos, "%s ", dsbuild);
|
2006-06-22 20:33:30 +02:00
|
|
|
if (len < 0 || len >= size - *pos) {
|
2006-06-13 21:34:36 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_rrd(int mode, char *cmd)
|
|
|
|
{
|
|
|
|
int argc;
|
|
|
|
char *argv[ARGCMAX];
|
|
|
|
|
|
|
|
argc = strsplit(cmd, 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rrd_create_file(char *filename, char **ds_def)
|
|
|
|
{
|
|
|
|
int pos, step, heartbeat, retval;
|
|
|
|
char *buffer;
|
|
|
|
|
|
|
|
buffer = malloc(ARGVSIZE);
|
|
|
|
if (buffer == NULL) {
|
|
|
|
log_print(LOG_ERROR, "append_ds_config: out of memory");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
step = config_get_int("global", "step", DEFAULT_STEP);
|
|
|
|
heartbeat = (step * 2) + (step / 2);
|
|
|
|
|
|
|
|
pos = snprintf(buffer, ARGVSIZE, "create %s -s %d ", filename, step);
|
2006-06-22 20:33:30 +02:00
|
|
|
if (pos < 0 || pos >= ARGVSIZE) {
|
2006-06-13 21:34:36 +02:00
|
|
|
log_print(LOG_ERROR, "rrd_create_file: arguments too long");
|
|
|
|
free(buffer);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (append_rra_config(buffer, ARGVSIZE, &pos) <= 0) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rrd_update_file(char *filename, char *values)
|
|
|
|
{
|
|
|
|
int pos, retval;
|
|
|
|
char *buffer;
|
|
|
|
|
|
|
|
buffer = malloc(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);
|
2006-06-22 20:33:30 +02:00
|
|
|
if (pos < 0 || pos >= ARGVSIZE) {
|
2006-06-13 21:34:36 +02:00
|
|
|
log_print(LOG_ERROR, "rrd_update_file: arguments too long");
|
|
|
|
free(buffer);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = do_rrd(RRDTOOL_UPDATE, buffer);
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_create_dir(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 *lastslash, *nextslash = filename;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rrd_submit(char *plugin, int version, char *filename, int ds_id, 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);
|
|
|
|
if (fullfile == NULL) {
|
|
|
|
log_print(LOG_ERROR, "rrd_submit: out of memory");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = snprintf(fullfile, BUFSIZE, "%s/%s", rrd_dir, filename);
|
2006-06-22 20:33:30 +02:00
|
|
|
if (len < 0 || len >= BUFSIZE) {
|
2006-06-13 21:34:36 +02:00
|
|
|
log_print(LOG_ERROR, "rrd_submit: arguments too long");
|
|
|
|
free(fullfile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stat(fullfile, &statbuf) == -1) {
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
if (create_parent_dirs(fullfile) == -1) {
|
|
|
|
free(fullfile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
free(fullfile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rrd_create_file(fullfile, ds_def) == -1) {
|
|
|
|
free(fullfile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
log_print(LOG_ERROR, "rrd_submit: stat(%s):", fullfile);
|
|
|
|
free(fullfile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (!S_ISREG (statbuf.st_mode)) {
|
|
|
|
log_print(LOG_ERROR, "rrd_submit: stat(%s): Not a regular file!", fullfile);
|
|
|
|
free(fullfile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rrd_update_file(fullfile, data);
|
|
|
|
free(fullfile);
|
|
|
|
}
|