/*************************************************************************** * 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 #include #include #include #include #include #include #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 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); 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; } static int do_rrd(int mode, char *cmd) { int argc; char *argv[ARGCMAX]; 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[1], 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[1], rrd_get_error()); return -1; } } return 0; } static int rrd_create_file(char *filename, char *plugin_name, int ds_id) { struct sammler_plugin *plugin; int pos, step, retval; char *ds_def, *buffer; plugin = plugin_lookup(plugin_name); if (plugin == NULL) { log_print(LOG_ERROR, "Plugin not found (%s)", plugin_name); return -1; } 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; } buffer = malloc(ARGVSIZE); if (buffer == NULL) { log_print(LOG_ERROR, "append_ds_config: out of memory"); return -1; } step = plugin->interval; 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; } if (append_rra_config(buffer, ARGVSIZE, &pos) <= 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); if (pos < 0 || pos >= ARGVSIZE) { 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; } int rrd_submit(char *hostname, char *plugin, char *filename, int ds_id, char *data) { struct stat statbuf; static char *rrd_dir = NULL; char *fullfile; 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 -1; } 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; } 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, plugin, 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; }