/*************************************************************************** * Copyright (C) 12/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 #include #include #include #include #include #include #include "configfile.h" #include "linebuffer.h" #include "list.h" #include "logging.h" #define DEFAULT_STEP 10 #define ARGCMAX 64 #define ARGVSIZE 1024 #define BUFSIZE 1024 static const char *rrd_dir; int my_rrd_init(void) { rrd_dir = config_get_string("global", "rrd_dir", "."); return 0; } static 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; } 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 *ds_define, int interval) { 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, interval, ds_define); if (ret == -1) { log_print(LOG_ERROR, "rrd_create_file: arguments too long"); 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 %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 *filename, const char *ds_define, int interval, 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", rrd_dir, 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, ds_define, interval) == -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; }