/*************************************************************************** * 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. * ***************************************************************************/ #if (WITH_RRD) #include #include #include #include #include #include #include #include "configfile.h" #include "helper.h" #include "linebuffer.h" #include "list.h" #include "logging.h" #include "plugins.h" #define DEFAULT_STEP 10 #define ARGCMAX 64 #define ARGVSIZE 1024 #define BUFSIZE 1024 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 lbuf *buffer = (struct lbuf *)privdata; lbuf_printf(buffer, "%s ", parameter); return 0; } static int do_rrd(int (*rrd_func)(int, char **), struct lbuf *buffer) { size_t len; char *cmd = lbuf_getdata(buffer, &len); if (len < ARGVSIZE -1) cmd[len] = '\0'; 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()); } 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; } 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"); lbuf_free(buffer); return -1; } ret = config_get_strings("global", "rra", append_rra_config, buffer); if (ret <= 0) { lbuf_free(buffer); return -1; } ret = do_rrd(&rrd_create, buffer); lbuf_free(buffer); return ret; } static int rrd_update_file(const char *filename, const char *values) { struct lbuf *buffer = lbuf_create(ARGVSIZE); if (buffer == NULL) { log_print(LOG_ERROR, "append_ds_config: out of memory"); return -1; } int ret = lbuf_printf(buffer, "update %s N:%s", filename, values); if (ret == -1) { log_print(LOG_ERROR, "rrd_update_file: arguments too long"); lbuf_free(buffer); return -1; } ret = do_rrd(&rrd_update, buffer); lbuf_free(buffer); return ret; } 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; } #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) */